The -x flag requires exact process name match which doesn't work reliably on OpenWrt/BusyBox. Removed -x from all pgrep calls in: - luci-app-bandwidth-manager - luci-app-secubox-security-threats - luci-app-auth-guardian - luci-app-media-flow - luci-app-vhost-manager - luci-app-network-modes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| .github/workflows | ||
| demo | ||
| htdocs/luci-static/resources | ||
| root | ||
| Makefile | ||
| README.md | ||
VHost Manager - Reverse Proxy & SSL Certificate Management
Version: 2.0.0 Last Updated: 2026-01-01 Status: Active
LuCI application for managing nginx reverse proxy virtual hosts and SSL certificates via Let's Encrypt with integrated service templates and redirect management.
Features
Internal Services Catalog (v2.0+)
- 🏠 Pre-configured Service Templates - 19 ready-to-deploy internal services
- 🚀 One-Click Activation - Deploy services with optimal SSL, auth, and WebSocket settings
- 📊 Real-Time Status - Auto-refresh dashboard showing active/configured services
- 🎯 Smart Feature Detection - Automatic SSL, authentication, and WebSocket configuration
- 📦 Category Organization - Services grouped by type (IoT, Media, Security, Productivity, etc.)
- 🔄 Auto-Refresh - Live updates every 10 seconds
- 🎨 Modern Grid UI - Responsive card-based layout with feature badges
Redirect Rules Management (v2.0+)
- ↪️ Pre-built Redirect Templates - 6 common redirect patterns (CDN cache, privacy redirects, failover)
- 🎯 HTTP Redirect Codes - Support for 301 (permanent), 302 (temporary), 307 (temporary, preserve method)
- 🔄 Template Activation - One-click deployment of redirect rules
- 📊 Active Redirects Dashboard - Real-time status of configured redirects
- 🎨 Category Organization - Templates grouped by use case (Productivity, Media, Security, Network)
- 🔄 Auto-Refresh - Live updates every 10 seconds
Virtual Host Management (v1.0+)
- Create and manage nginx reverse proxy configurations
- Support for HTTP and HTTPS virtual hosts
- Backend connectivity testing before deployment
- WebSocket protocol support
- HTTP Basic Authentication
- Automatic nginx reload on configuration changes
- Enable/Disable toggle - Quick service control without deletion
- Remove button - Clean VHost deletion with confirmation
SSL Certificate Management (v1.0+)
- Let's Encrypt certificate provisioning via acme.sh
- Certificate status monitoring with expiry tracking
- Color-coded expiry warnings (red < 7 days, orange < 30 days)
- Certificate details viewer
- Automatic certificate renewal support
Access Log Monitoring (v1.0+)
- Real-time nginx access log viewer
- Per-domain log filtering
- Configurable line display (50-500 lines)
- Terminal-style log display
Profile Activation System (v2.0+)
- 🎯 Template-Based Deployment - Create VHosts from pre-configured templates
- 🔐 Smart Feature Configuration - Automatic SSL/Auth/WebSocket setup based on service requirements
- 📝 Template Notes - Contextual information displayed during activation
- ✅ Confirmation Modals - Review settings before deployment
- 🔄 Activate/Deactivate - Easy template management with visual feedback
Installation
opkg update
opkg install luci-app-vhost-manager
/etc/init.d/rpcd restart
/etc/init.d/uhttpd restart
Dependencies
- luci-base: LuCI framework
- rpcd: RPC daemon for backend communication
- nginx-ssl: Nginx web server with SSL support
- acme: ACME client for Let's Encrypt certificates
- curl: HTTP client for backend testing
Configuration
UCI Configuration (/etc/config/vhosts)
Virtual hosts now live in /etc/config/vhosts, allowing other SecuBox components to declaratively install proxies. A default file is dropped during install; edit it like any other UCI config:
config global 'global'
option enabled '1'
option auto_reload '1'
config vhost 'myapp'
option domain 'app.example.com'
option upstream 'http://127.0.0.1:8080'
option tls 'acme' # off|acme|manual
option cert_path '/etc/custom/fullchain.pem' # used when tls=manual
option key_path '/etc/custom/privkey.pem'
option auth '1'
option auth_user 'admin'
option auth_pass 'secretpassword'
option websocket '1'
option enabled '1'
Legacy installations may still ship
/etc/config/vhost_managerfor backwards compatibility, but the RPC backend now generates/etc/nginx/conf.d/*.confexclusively from/etc/config/vhosts.
Options
Global Section
enabled: Enable/disable VHost Manager (default: 1)auto_reload: Automatically reload nginx on config changes (default: 1)log_retention: Days to retain access logs (default: 30)
VHost Section
domain: Domain name for this virtual host (required)upstream: Backend URL to proxy to (required, e.g., http://192.168.1.100:8080)tls: TLS strategy (off,acme, ormanual)cert_path/key_path: Required whentls=manualto point to PEM filesauth: Enable HTTP Basic Authentication (default: 0)auth_user/auth_pass: Credentials used whenauth=1websocket: Enable WebSocket headers (default: 0)enabled: Disable the vhost without deleting it (default: 1)
Usage
Web Interface
Navigate to Services → VHost Manager in LuCI.
Overview Tab
- System status (Nginx running, ACME availability)
- Virtual host statistics (SSL enabled, auth protected, WebSocket)
- Certificate count and expiry status
- Recent virtual hosts list
Virtual Hosts Tab
- Add new virtual hosts
- Edit existing configurations
- Test backend connectivity before saving
- Enable/disable SSL, authentication, WebSocket
- Delete virtual hosts
Certificates Tab
- Request new Let's Encrypt certificates
- View installed certificates with expiry dates
- Certificate details viewer
- Color-coded expiry warnings
Logs Tab
- View nginx access logs per domain
- Select number of lines to display (50-500)
- Real-time log streaming
Internal Services Tab (v2.0+)
The Internal Services tab provides a catalog of 19 pre-configured service templates for popular self-hosted applications.
Dashboard Metrics:
- Active - Services currently enabled and running
- Configured - Total services with VHost entries
- Available - Total templates in catalog
Active Services Grid:
Each configured service displays:
- Service icon and name
- Status badge (Active/Disabled)
- Category and description
- Domain, backend URL, and port
- Feature badges (🔒 SSL, 🔐 Auth, ⚡ WebSocket)
- Three action buttons:
- Edit - Navigate to VHost configuration
- Enable/Disable - Toggle service status
- Remove - Delete VHost configuration (with confirmation)
Service Templates:
Templates are organized by category:
| Category | Services |
|---|---|
| Core Services | LuCI UI |
| Monitoring | Netdata |
| Security | CrowdSec, Vaultwarden |
| Network | NoDogSplash, AdGuard Home, Uptime Kuma |
| IoT & Home Automation | Domoticz, Zigbee2MQTT, Home Assistant, MagicMirror² |
| Media | Lyrion Music Server, Jellyfin |
| AI & Machine Learning | LocalAI |
| Productivity | Citadel, ISPConfig, Mail-in-a-Box, Nextcloud, Gitea |
| Hosting & Control Panels | Portainer |
Template Activation Workflow:
- Click Activate on any template
- Review activation modal showing:
- Service name and icon
- Domain and backend URL
- Required features (SSL, Auth, WebSocket)
- Special notes (e.g., "Nextcloud handles its own authentication")
- Click Activate to create VHost
- Service automatically configured with optimal settings
Example: Activating Nextcloud
Template configuration:
Icon: ☁️
Name: Nextcloud
Domain: cloud.local
Backend: http://127.0.0.1:80
Port: 80
Category: Productivity
Features:
- SSL/TLS required
- WebSocket support
Notes: "Nextcloud handles its own authentication. Configure trusted domains in config.php."
After activation:
- VHost created at
cloud.local - SSL automatically configured (ACME mode)
- WebSocket headers enabled
- Backend proxied to port 80
- Service marked as "Active" in dashboard
Redirects Tab (v2.0+)
The Redirects tab manages nginx HTTP redirect rules with pre-built templates for common use cases.
Dashboard Metrics:
- Active - Currently enabled redirect rules
- Total - All configured redirects
- Templates - Available redirect templates
Active Redirects Grid:
Each configured redirect displays:
- Redirect icon (↪️)
- Domain name
- Status badge (Active/Disabled)
- From domain
- To URL
- HTTP code badge (301, 302, 307)
- Three action buttons:
- Edit - Navigate to VHost configuration
- Enable/Disable - Toggle redirect status
- Remove - Delete redirect rule (with confirmation)
Redirect Templates:
| Template | HTTP Code | Category | Use Case |
|---|---|---|---|
| Nextcloud → LAN | 301 | Productivity | Force remote users to LAN-hosted Nextcloud |
| Steam CDN cache | 302 | Media | Redirect downloads to on-prem cache |
| YouTube → Invidious | 307 | Media | Privacy-friendly YouTube redirect |
| Mail failover | 302 | Productivity | Failover to alternate mail service |
| Ad Blocker Redirect | 301 | Security | Redirect ad servers to localhost |
| CDN → Local Cache | 302 | Network | Cache CDN assets locally |
HTTP Redirect Codes:
- 301 (Permanent) - Browser caches redirect, use for permanent moves
- 302 (Temporary) - Browser doesn't cache, use for temporary redirects
- 307 (Temporary, Preserve Method) - Like 302 but preserves HTTP method (POST/GET)
Template Activation Workflow:
- Click Activate on any redirect template
- Review activation modal showing:
- Redirect name
- From domain pattern
- To URL
- HTTP redirect code
- Click Activate to create redirect
- Redirect rule automatically configured
Example: Steam CDN Cache
Template configuration:
Icon: 🕹️
Name: Steam CDN cache
From: *.cdn.steamstatic.com
To: http://steamcache.lan
Code: 302
Category: Media
Generated nginx config:
server {
listen 80;
server_name *.cdn.steamstatic.com;
return 302 http://steamcache.lan$request_uri;
}
Command Line
List Virtual Hosts
ubus call luci.vhost-manager list_vhosts
Get VHost Manager Status
ubus call luci.vhost-manager status
Add Virtual Host
ubus call luci.vhost-manager add_vhost '{
"domain": "app.example.com",
"backend": "http://192.168.1.100:8080",
"tls_mode": "acme",
"auth": true,
"auth_user": "admin",
"auth_pass": "secret",
"websocket": true,
"enabled": true
}'
Test Backend Connectivity
ubus call luci.vhost-manager test_backend '{
"backend": "http://192.168.1.100:8080"
}'
Request SSL Certificate
ubus call luci.vhost-manager request_cert '{
"domain": "app.example.com",
"email": "admin@example.com"
}'
List Certificates
ubus call luci.vhost-manager list_certs
Reload Nginx
ubus call luci.vhost-manager reload_nginx
Get Access Logs
ubus call luci.vhost-manager get_access_logs '{
"domain": "app.example.com",
"lines": 100
}'
Nginx Configuration
VHost Manager generates nginx configuration files in /etc/nginx/conf.d/.
Example Generated Configuration (HTTP Only)
server {
listen 80;
server_name app.example.com;
access_log /var/log/nginx/app.example.com.access.log;
error_log /var/log/nginx/app.example.com.error.log;
location / {
proxy_pass http://192.168.1.100:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Example Generated Configuration (HTTPS with WebSocket)
server {
listen 80;
server_name app.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/acme/app.example.com/fullchain.cer;
ssl_certificate_key /etc/acme/app.example.com/app.example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
access_log /var/log/nginx/app.example.com.access.log;
error_log /var/log/nginx/app.example.com.error.log;
location / {
proxy_pass http://192.168.1.100:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
}
Example with Authentication
server {
listen 443 ssl http2;
server_name app.example.com;
ssl_certificate /etc/acme/app.example.com/fullchain.cer;
ssl_certificate_key /etc/acme/app.example.com/app.example.com.key;
location / {
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/htpasswd/app.example.com;
proxy_pass http://192.168.1.100:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
SSL Certificate Workflow
- DNS Configuration: Ensure your domain points to your router's public IP
- Port Forwarding: Forward ports 80 and 443 to your router
- Request Certificate: Use the Certificates tab to request a Let's Encrypt certificate
- Configure VHost: Enable SSL for your virtual host
- Monitor Expiry: Certificates expire after 90 days, monitor in the Certificates tab
ACME Certificate Locations
- Certificates:
/etc/acme/{domain}/fullchain.cer - Private keys:
/etc/acme/{domain}/{domain}.key - ACME account:
/etc/acme/account.conf
ubus API Reference
status()
Get VHost Manager and nginx status.
Returns:
{
"nginx_running": true,
"nginx_version": "1.23.3",
"acme_available": true,
"acme_version": "3.0.5",
"vhost_count": 5
}
list_vhosts()
List all configured virtual hosts.
Returns:
{
"vhosts": [
{
"domain": "app.example.com",
"backend": "http://192.168.1.100:8080",
"upstream": "http://192.168.1.100:8080",
"tls_mode": "acme",
"ssl": true,
"cert_file": "/etc/acme/app.example.com/fullchain.cer",
"cert_expires": "2025-03-15",
"auth": true,
"auth_user": "admin",
"websocket": true,
"enabled": true,
"config_file": "/etc/nginx/conf.d/app.example.com.conf"
}
]
}
get_vhost(domain)
Get details for a specific virtual host.
Parameters:
domain: Domain name
Returns:
{
"domain": "app.example.com",
"backend": "http://192.168.1.100:8080",
"tls_mode": "acme",
"ssl": true,
"cert_expires": "2025-03-15",
"cert_issuer": "R3",
"auth": true,
"auth_user": "admin",
"websocket": true,
"enabled": true
}
add_vhost(payload)
Add a new virtual host.
Parameters:
domain: Domain name (required)backend: Backend URL (required)tls_mode:off,acme, ormanual(required)auth: Enable authentication (boolean)auth_user/auth_pass: Credentials when auth is enabledwebsocket: Enable WebSocket (boolean)enabled: Disable the vhost without deleting (boolean)cert_path/key_path: Required whentls_mode=manual
Returns:
{
"success": true,
"reload_required": true
}
update_vhost(payload)
Update an existing virtual host.
Parameters: Same as add_vhost. Omitted fields retain their previous value.
Returns:
{
"success": true,
"reload_required": true
}
delete_vhost(domain)
Delete a virtual host.
Parameters:
domain: Domain name
Returns:
{
"success": true,
"reload_required": true
}
test_backend(backend)
Test connectivity to a backend server.
Parameters:
backend: Backend URL
Returns:
{
"backend": "http://192.168.1.100:8080",
"reachable": true,
"status": "Backend is reachable"
}
request_cert(domain, email)
Request a Let's Encrypt SSL certificate.
Parameters:
domain: Domain name (required)email: Email address for ACME account (required)
Returns:
{
"success": true,
"message": "Certificate requested"
}
list_certs()
List all installed SSL certificates.
Returns:
{
"certificates": [
{
"domain": "app.example.com",
"subject": "CN=app.example.com",
"issuer": "R3",
"expires": "2025-03-15",
"cert_file": "/etc/acme/app.example.com/fullchain.cer"
}
]
}
reload_nginx()
Reload nginx configuration.
Returns:
{
"success": true
}
get_access_logs(domain, lines)
Get nginx access logs for a domain.
Parameters:
domain: Domain name (required)lines: Number of lines to retrieve (default: 50)
Returns:
{
"domain": "app.example.com",
"logs": [
"192.168.1.50 - - [24/Dec/2025:10:30:15 +0000] \"GET / HTTP/1.1\" 200 1234",
"192.168.1.51 - - [24/Dec/2025:10:30:16 +0000] \"GET /api HTTP/1.1\" 200 5678"
]
}
Troubleshooting
Nginx Won't Start
Check nginx configuration syntax:
nginx -t
View nginx error log:
logread | grep nginx
Certificate Request Fails
Ensure:
- Domain DNS points to your public IP
- Ports 80 and 443 are forwarded to your router
- Firewall allows incoming connections on ports 80 and 443
- No other service is using port 80 (acme.sh needs it for validation)
Check ACME logs:
cat /var/log/acme.log
Backend Unreachable
Test backend manually:
curl -I http://192.168.1.100:8080
Check if backend is listening:
netstat -tuln | grep 8080
WebSocket Not Working
Ensure:
- WebSocket support is enabled in virtual host configuration
- Backend application supports WebSocket
- No proxy timeouts are too short (default: 86400s)
Authentication Not Working
Check htpasswd file exists:
ls -l /etc/nginx/.luci-app-vhost-manager_{domain}
Regenerate htpasswd file:
# Update UCI entry
uci set vhosts.myapp.auth='1'
uci set vhosts.myapp.auth_user='newuser'
uci set vhosts.myapp.auth_pass='newpass'
uci commit vhosts
# Trigger config regeneration
ubus call luci.vhost-manager update_vhost '{
"domain": "myapp.example.com",
"auth": true,
"auth_user": "newuser",
"auth_pass": "newpass"
}'
Security Considerations
- SSL Certificates: Always use HTTPS for production services
- Strong Passwords: Use strong passwords for HTTP Basic Authentication
- Backend Security: Ensure backend services are not directly accessible from the internet
- Firewall Rules: Configure firewall to only allow necessary ports
- Log Monitoring: Regularly review access logs for suspicious activity
- Certificate Renewal: Monitor certificate expiry and ensure auto-renewal is working
License
Apache-2.0
Maintainer
SecuBox Project support@secubox.com
Version
2.0.0