_____ _ _ _ _ _
/ ____| | (_) \ | | | |
| | __| | ______ _| \| | ___| |_
| | |_ | | |______| | . ` |/ _ \ __|
| |__| | |____ | | |\ | __/ |_
\_____|______| |_|_| \_|\___|\__|
OpenSpeedTest for GL-iNet
π‘ Production-ready OpenSpeedTest deployment for OpenWRT-based routers with optimized NGINX configuration
Note: This is a fork of phantasm22/OpenSpeedTestServer with enhanced performance optimizations, error handling, and resource management for embedded devices.
- π¦ Installs and configures NGINX to run OpenSpeedTest
- π§ Custom NGINX configuration that avoids conflicts with the GL.iNet web UI
- π Installs to
/www2, with automatic detection of available storage space - π Supports symlinking to external drives (e.g. SD cards or USB) if internal space is insufficient
- β¬οΈ Supports persistence after firmware updates via
/etc/sysupgrade.conf - π§Ή Clean uninstall that removes configs, startup scripts, and any symlinked storage
β€΅οΈ Automatic self-update with version checking
- π Auto-tuned for embedded devices - Detects CPU cores and RAM, adjusts NGINX workers and connections
- β‘ Optimized for low-resource routers - Conservative memory usage and buffer sizes
- π Hardware-aware configuration:
- <128MB RAM: 1 worker, 256 connections
- <256MB RAM: 1 worker, 512 connections
- 256MB+ RAM: 2 workers, 1024 connections
- π Connection timeout protection - Prevents resource exhaustion from hung connections
- πΎ Minimal disk I/O - No access logs, error-only logging
- π‘οΈ Robust error handling - Automatic cleanup on failures
- β Configuration validation - Tests NGINX config before applying
- π Automatic rollback - Restores previous config if new one fails
- π Port conflict detection - Checks port availability before installation
- π₯ Download validation - Verifies file integrity after downloads
- π Lock file protection - Prevents concurrent installations
- π procd support - Modern OpenWrt process supervision with auto-restart
- π Traditional init.d fallback - Compatible with older OpenWrt versions
- π©Ί Enhanced diagnostics - System resource monitoring, config validation, log preview
- π Aggressive log rotation - Errors only, auto-rotate at 100KB, 2-day retention
- π Debug mode - Detailed execution logs for troubleshooting
- π’ Verbose mode - Additional informational output
- ποΈ Custom port support - Override default port 8888
- π§ͺ Interactive CLI with confirmations and safe prompts
- π Let's Encrypt integration - Automatic SSL certificate generation
- π€ acme.sh client - Industry-standard ACME protocol
- π Auto-renewal - Daily certificate expiry checks
- π TLS 1.2/1.3 - Modern encryption standards
- β»οΈ HTTP β HTTPS redirect - Automatic upgrade to secure connection
- π Certificate persistence - Survives firmware updates
- π§ͺ GL-BE9300, GL-BE3600, GL-MT3000, GL-MT1300 (with SD card)
- β Any OpenWrt-based router with 64MB+ free space
- π Licensed under GPLv3
ssh root@192.168.8.1wget -O install_openspeedtest.sh https://raw.githubusercontent.com/frankstutz/OpenSpeedTestServer/main/install_openspeedtest.sh && chmod +x install_openspeedtest.sh
./install_openspeedtest.shAfter installation, open:
http://<router-ip>:8888
Example:
http://192.168.8.1:8888
Customize installation behavior with environment variables:
# Enable debug mode for troubleshooting
DEBUG=1 ./install_openspeedtest.sh
# Enable verbose output
VERBOSE=1 ./install_openspeedtest.sh
# Use custom port (instead of default 8888)
PORT=9999 ./install_openspeedtest.sh
# Combine options
DEBUG=1 VERBOSE=1 PORT=9090 ./install_openspeedtest.shIf port 8888 is already in use, the script will:
- Detect the conflict
- Prompt you to enter a different port
- Validate the new port (1024-65535)
- Retry until a free port is found
You can also set a custom port before installation:
PORT=9999 ./install_openspeedtest.shYou can safely cancel the installation at any time by pressing Ctrl-C. The script will:
- Immediately stop all background processes (downloads, extraction, etc.)
- Clean up partial installations:
- Stop any NGINX processes started during installation
- Remove incomplete downloads
- Restore previous configuration (if it existed)
- Release resources (lock files, temporary files)
- Exit gracefully with proper cleanup
Example output when cancelled:
β οΈ Installation interrupted by user (Ctrl-C)
π§Ή Cleaning up partial installation...
β
Restored previous configuration
β
Cleanup completed
Installation cancelled. Exiting.
Note: The interrupt handler ensures your system is left in a clean state even if you cancel mid-installation.
The installer supports automatic SSL certificate generation using Let's Encrypt with three validation methods:
1. HTTP-01 Challenge (Traditional - requires public IP)
- Prerequisites:
- Valid domain name pointing to your router's public IP
- Port 80 accessible from the internet
- Port forwarding configured on your router if behind NAT
2. DNS-01 Challenge (Recommended - NO public IP required) β¨
-
Prerequisites:
- Valid domain name
- DNS API access (Cloudflare, AWS Route53, etc.)
- NO public IP or port forwarding needed!
-
Supported DNS Providers:
- βοΈ Cloudflare (recommended - easy API setup)
- π AWS Route53
- π΅ Google Cloud DNS
- π§ DigitalOcean
- π ½ Namecheap
- π Ά GoDaddy
- π¦ Duck DNS (FREE!)
- And 100+ more via acme.sh
3. Manual DNS (For testing or manual management)
- Script pauses and shows TXT record to create
- Works without API access
- Suitable for one-time setup
When prompted "Do you want to enable SSL/HTTPS with Let's Encrypt?":
- Answer Y to enable SSL
- Enter your fully qualified domain name (e.g.,
speedtest.example.com) - Choose validation method:
- Option 1: HTTP-01 (requires public IP + port 80)
- Option 2: DNS-01 (works without public IP!)
- Option 3: Manual DNS (for testing)
- If DNS-01: Select your DNS provider and enter API credentials
- Confirm the setup
π Do you want to enable SSL/HTTPS with Let's Encrypt? [y/N]: y
π Enter your fully qualified domain name (FQDN): speedtest.example.com
π Choose certificate validation method:
1οΈβ£ HTTP-01 (requires public IP and port 80 accessible)
2οΈβ£ DNS-01 (works without public IP, requires DNS API)
3οΈβ£ Manual DNS (for testing or manual DNS record management)
Choose [1-3]: 2
π Select your DNS provider:
1οΈβ£ Cloudflare (recommended)
Choose [1-9]: 1
π Cloudflare Configuration:
Visit: https://dash.cloudflare.com/profile/api-tokens
Create token with Zone:DNS:Edit permissions
Enter Cloudflare API Token: [paste your token]
β
DNS provider configured: dns_cf
π Using DNS-01 validation (dns_cf)
β
No public IP or open ports required!
The installer will:
- Install
acme.sh(Let's Encrypt client) - Request and validate certificate using your chosen method
- Configure NGINX with SSL on port 8443
- Set up HTTP β HTTPS redirect on port 80
- Configure automatic certificate renewal (daily check)
# Access after SSL setup
https://speedtest.example.com:8443
# HTTP automatically redirects to HTTPS (if port 80 available)
http://speedtest.example.com β https://speedtest.example.com:8443- Automatic: Cron job checks daily, renews if within 60 days of expiry
- DNS-01 renewals: Use saved API credentials (no manual intervention)
- Manual renewal:
/root/.acme.sh/acme.sh --cron --force - Certificate location:
/etc/nginx/ssl/
Cloudflare (Easiest):
- Login to Cloudflare dashboard
- Go to: Profile β API Tokens
- Create token with "Zone:DNS:Edit" permission
- Copy token and paste during installation
Duck DNS (Free!):
- Visit https://www.duckdns.org/
- Sign in with social account
- Get your free subdomain (e.g.,
myspeed.duckdns.org) - Copy your token from the dashboard
AWS Route53:
- Create IAM user with Route53 permissions
- Generate access key ID and secret
- Enter both during installation
If certificate issuance fails:
- HTTP-01: Verify domain DNS points to your router's public IP, ensure port 80 is open
- DNS-01: Check API credentials are correct and have sufficient permissions
- Manual DNS: Verify TXT record was created correctly, wait 5-30 min for DNS propagation
- Installation will continue with HTTP only if SSL fails
When running the script, choose from:
- Install OpenSpeedTest β Full installation with hardware detection and optimization
- Run diagnostics β Comprehensive system check including:
- NGINX process status
- Port availability
- Configuration validation
- System resources (CPU, RAM, disk)
- Recent error logs
- Uninstall everything β Complete removal of all components
- Check for update β Manually check for script updates
- Exit β Quit the installer
The installer automatically optimizes NGINX based on your router's hardware:
- Reads CPU cores from
/proc/cpuinfo - Reads total RAM from
/proc/meminfo - Configures NGINX workers and connections accordingly
| Router RAM | Worker Processes | Max Connections | File Descriptors |
|---|---|---|---|
| < 128MB | 1 | 256 | 4096 |
| < 256MB | 1 | 512 | 4096 |
| 256MB+ | 2 | 1024 | 4096 |
- epoll: Efficient Linux event handling
- Connection timeouts: 30s to prevent hangs
- Keepalive: 30s timeout, 50 request limit
- Buffer sizes: Minimized (8k body, 1k headers)
- Client body size: 1GB (realistic for speed tests)
- Static files: 7-day cache
- Compression: Disabled (speed tests shouldn't compress)
- Reset timedout connections: Enabled
To conserve disk space on embedded devices:
- Error-only logging at
critlevel (critical errors only) - No access logs - Completely disabled
- Automatic rotation when log exceeds 100KB
- 2-day retention - Old logs auto-deleted
- Cron-based - Daily check via
/etc/cron.daily/nginx_openspeedtest_logrotate - Signal-based reload - NGINX reopens logs without restart (USR1 signal)
- Error log:
/var/log/nginx_openspeedtest_error.log - Rotated logs:
/var/log/nginx_openspeedtest_error.log.1
# Force log rotation
/etc/cron.daily/nginx_openspeedtest_logrotate
# View current errors
tail -20 /var/log/nginx_openspeedtest_error.log
# Clear logs manually
> /var/log/nginx_openspeedtest_error.logIf your router uses procd (most modern GL.iNet routers):
# Start service
/etc/init.d/nginx_speedtest start
# Stop service
/etc/init.d/nginx_speedtest stop
# Restart service
/etc/init.d/nginx_speedtest restart
# Reload configuration (no downtime)
/etc/init.d/nginx_speedtest reload
# Enable auto-start on boot
/etc/init.d/nginx_speedtest enable
# Disable auto-start
/etc/init.d/nginx_speedtest disable
# Check status
/etc/init.d/nginx_speedtest statusprocd features:
- Auto-restart on crashes
- Respawn limits (3600s threshold, 5s timeout)
- Daemon mode with proper supervision
- Graceful reload with config validation
Same commands as above, but without auto-restart features.
Option 2 in the menu provides comprehensive diagnostics:
π Running OpenSpeedTest diagnostics...
β
OpenSpeedTest NGINX process is running (PID: 12345)
β
Port 8888 is open and listening on 192.168.8.1
π You can access OpenSpeedTest at: http://192.168.8.1:8888
β
Configuration file exists: /etc/nginx/nginx_openspeedtest.conf
β
Configuration is valid
π Error log: /var/log/nginx_openspeedtest_error.log (2.5K)
π» System Resources:
CPU cores: 4
Total RAM: 512MB
Free RAM: 234MB
Disk space at /www2: 45MB free
Symptom: "Port 8888 already in use" Solution:
# Find what's using the port
netstat -tuln | grep 8888
# Use custom port
PORT=9999 ./install_openspeedtest.shSymptom: NGINX starts but immediately stops Solution:
# Check configuration
nginx -t -c /etc/nginx/nginx_openspeedtest.conf
# View error log
tail -50 /var/log/nginx_openspeedtest_error.log
# Check for port conflicts
netstat -tuln | grep 8888Symptom: "Not enough free space" Solution:
- Use external drive (script will prompt)
- Free up space:
opkg list-installedand remove unused packages - Required: 64MB free space
Symptom: "Download failed or timed out" Solution:
# Check internet connectivity
ping -c 3 github.com
# Try GL.iNet mirror during installation (option 2)
# Manual download with debug
DEBUG=1 ./install_openspeedtest.shSymptom: "Invalid NGINX configuration" Solution:
- Script automatically restores backup
- Check error details in output
- Verify port is not already in use
Symptom: "Failed to issue certificate" Solutions:
- Verify DNS:
# Check if domain resolves to your public IP
nslookup speedtest.example.com
dig speedtest.example.com
# Get your public IP
curl ifconfig.me- Check Port 80 Access:
# From external network, test port 80
curl -I http://your-domain.com
# Check if port 80 is listening
netstat -tuln | grep :80- Firewall Rules:
# Check OpenWrt firewall (if applicable)
iptables -L -n | grep 80
# Allow HTTP for Let's Encrypt validation
uci set firewall.http=rule
uci set firewall.http.name='Allow-HTTP'
uci set firewall.http.src='wan'
uci set firewall.http.dest_port='80'
uci set firewall.http.proto='tcp'
uci set firewall.http.target='ACCEPT'
uci commit firewall
/etc/init.d/firewall reload- Manual Certificate Request:
# Test acme.sh manually
/root/.acme.sh/acme.sh --issue --standalone -d your-domain.com --debug
# Check acme.sh logs
cat /root/.acme.sh/acme.sh.log- Use DNS Challenge (Alternative):
# If port 80 is unavailable, use DNS challenge
/root/.acme.sh/acme.sh --issue --dns -d your-domain.comNote: If SSL fails, installation continues with HTTP only. You can manually configure SSL later.
Symptom: Certificate expired Solution:
# Check renewal cron job
crontab -l | grep acme
# Force renewal
/root/.acme.sh/acme.sh --cron --force
# Check certificate expiry
/root/.acme.sh/acme.sh --list
# Reload NGINX after renewal
/etc/init.d/nginx_speedtest reloadEnable detailed logging:
DEBUG=1 ./install_openspeedtest.shOutput includes:
- Function entry/exit
- Variable values
- Download details
- Configuration checks
- Cleanup operations
# Check if NGINX is running
ps | grep nginx
# Check PID file
cat /var/run/nginx_OpenSpeedTest.pid
# Test configuration
nginx -t -c /etc/nginx/nginx_openspeedtest.conf
# Check port listener
netstat -tuln | grep 8888
# View NGINX config
cat /etc/nginx/nginx_openspeedtest.conf
# Check disk space
df -h /www2
# View system resources
free -m
cat /proc/cpuinfo | grep processorRe-run the script and choose option 3: Uninstall everything.
This removes:
- OpenSpeedTest files (
/www2) - NGINX configuration
- Startup scripts
- Log files and rotated logs
- Persistence entries from
/etc/sysupgrade.conf - Symlinks (if external drive was used)
If the script is unavailable:
# Stop service
/etc/init.d/nginx_speedtest stop
/etc/init.d/nginx_speedtest disable
# Remove files
rm -rf /www2/Speed-Test-main
rm -f /etc/nginx/nginx_openspeedtest.conf
rm -f /etc/nginx/nginx_openspeedtest.conf.backup
rm -f /etc/init.d/nginx_speedtest
rm -f /etc/cron.daily/nginx_openspeedtest_logrotate
rm -f /var/log/nginx_openspeedtest_error.log*
rm -f /var/run/nginx_OpenSpeedTest.pid
# Remove symlink (if used external drive)
rm -f /www2
# Remove persistence entries
sed -i '/www2/d' /etc/sysupgrade.conf
sed -i '/nginx_speedtest/d' /etc/sysupgrade.conf
sed -i '/nginx_openspeedtest/d' /etc/sysupgrade.confWhen you choose to enable persistence during installation, the following paths are added to /etc/sysupgrade.conf:
/www2(or custom install directory)/etc/nginx/nginx_openspeedtest.conf/etc/init.d/nginx_speedtest/etc/cron.daily/nginx_openspeedtest_logrotate- All rc.d symlinks for the service
This ensures OpenSpeedTest survives OpenWrt firmware upgrades.
Note: External drive installations (symlinked to /www2) are automatically preserved.
- OpenSpeedTest runs on LAN only by default (port 8888)
- No external exposure unless you configure port forwarding
- CORS headers allow cross-origin requests (required for speed test)
- NGINX runs as
nobody:nogroup(unprivileged) - Configuration files:
root:rootwith 644 permissions - Scripts:
root:rootwith 755 permissions
- Keep router firmware updated
- Use strong SSH passwords
- Don't expose port 8888 to WAN
- Run diagnostics after installation to verify
Contributions welcome! Please:
- Test on actual GL.iNet/OpenWrt hardware
- Verify compatibility with different router models
- Include debug output for any issues
- Follow existing code style
When reporting issues, include:
# Run with debug mode
DEBUG=1 VERBOSE=1 ./install_openspeedtest.sh
# Include diagnostics output (option 2)
# Include system info
cat /etc/openwrt_release
free -m
df -h- 2025-12-23: Major rewrite with performance optimizations, error handling, procd support, log rotation
- 2025-11-13: Initial release
| Path | Purpose |
|---|---|
/www2/Speed-Test-main/ |
OpenSpeedTest application files |
/etc/nginx/nginx_openspeedtest.conf |
NGINX configuration (auto-tuned) |
/etc/init.d/nginx_speedtest |
Service startup script (procd or init.d) |
/etc/cron.daily/nginx_openspeedtest_logrotate |
Automatic log rotation |
/var/log/nginx_openspeedtest_error.log |
Error log (critical only) |
/var/run/nginx_OpenSpeedTest.pid |
NGINX process ID |
/etc/sysupgrade.conf |
Persistence configuration (if enabled) |
nginx-ssl- NGINX with SSL supportcurl- HTTP clientwget- File downloaderunzip- Archive extractioncoreutils-timeout- Command timeouts
Typical resource consumption on a 512MB RAM router:
- RAM: 10-20MB for NGINX workers
- Disk: ~40-50MB for OpenSpeedTest files
- CPU: <5% idle, scales with active speed tests
frankstutz - Current maintainer and performance optimizations
phantasm22 - Original author
This project is a fork of phantasm22/OpenSpeedTestServer with significant enhancements for production use on resource-constrained embedded devices.
Contributions, suggestions, and PRs welcome!
This project is licensed under the GNU GPL v3.0 License - see the LICENSE file for details.
- OpenSpeedTest - The speed test application
- NGINX - High-performance web server
- OpenWrt - Linux distribution for embedded devices
- GL.iNet - Router hardware and firmware