Files
OpenVPN-Monitoring-Simple/DOCS/General/Deployment_Native.md
T
iclaoudezinandClaude Sonnet 5.5 9b2882d5f4 Docs: concise README, split deployment guides, add change records
- README: short overview, quick start, config table and links.
- DOCS/General: Deployment_Docker.md and Deployment_Native.md (system
  services, HTTPS, host hardening); refresh Index.md.
- DOCS/Changes: security hardening, admin username change and egress
  via Hysteria2 with results and verification.
- Drop mentions of the built-in admin/password account.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-09-30 12:12:09 +00:00

4.2 KiB

Deployment: system services (no containers)

Tested on Alpine 3.23 (OpenRC); Debian/Ubuntu (systemd) differs only in service manager. Unit/init templates: systemd/, openrc/. Generic notes: Deployment, Service management, Nginx.

1. Packages

  • Alpine: apk add python3 py3-pip nginx nodejs npm openvpn easy-rsa iptables bash
  • Debian/Ubuntu: apt install python3-venv nginx nodejs npm openvpn easy-rsa iptables

2. Backend

cd APP_CORE     && python3 -m venv venv && venv/bin/pip install -r requirements.txt gunicorn
cd APP_PROFILER && python3 -m venv venv && venv/bin/pip install -r requirements.txt
mkdir -p APP_PROFILER/easy-rsa && cp -r /usr/share/easy-rsa/* APP_PROFILER/easy-rsa/   # Docker entrypoint does this automatically

3. Environment file

/etc/ovpmon/env (chmod 600), loaded by the services:

OVPMON_API_SECRET_KEY=<openssl rand -hex 32>
OVPMON_API_HOST=127.0.0.1
OVPMON_API_PORT=5001
OVPMON_OPENVPN_MONITOR_DB_PATH=/var/lib/ovpmon/openvpn_monitor.db
OVPMON_OPENVPN_MONITOR_LOG_PATH=/var/log/openvpn/openvpn-status.log
OVPMON_PROFILER_DB_PATH=/var/lib/ovpmon/ovpn_profiler.db
OVPMON_LOGGING_LEVEL=INFO

Create /var/lib/ovpmon, /var/log/ovpmon, /var/log/openvpn. For the first start also set OVPMON_INITIAL_ADMIN_USER / OVPMON_INITIAL_ADMIN_PASSWORD, then remove them.

4. Services

Service Command Listens
ovpmon-api APP_CORE/venv/bin/gunicorn -w 2 -b 127.0.0.1:5001 openvpn_api_v3:app (cwd APP_CORE) 127.0.0.1:5001
ovpmon-gatherer APP_CORE/venv/bin/python openvpn_gatherer_v3.py (cwd APP_CORE) -
ovpmon-profiler APP_PROFILER/venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 (cwd APP_PROFILER) 127.0.0.1:8000

OpenRC (Alpine): supervisor=supervise-daemon, respawn_delay=3, source /etc/ovpmon/env in start_pre, then rc-update add <svc> default && rc-service <svc> start. systemd: use the units from systemd/ with EnvironmentFile=/etc/ovpmon/env.

The Profiler restarts OpenVPN through rc-service openvpn (Alpine) or systemctl openvpn; on Alpine link the config: ln -s server.conf /etc/openvpn/openvpn.conf and enable the openvpn service.

5. UI and Nginx (HTTPS on 8088)

cd APP_UI && npm install && npm run build
mkdir -p /var/www/ovpmon && cp -r dist/. /var/www/ovpmon/

Certificate (self-signed, replace with a real one when a domain is available):

mkdir -p /etc/ovpmon/tls && cd /etc/ovpmon/tls
openssl req -x509 -nodes -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -days 825 \
  -subj "/CN=ovpmon" -addext "subjectAltName=IP:<HOST-IP>,DNS:ovpmon" -keyout ovpmon.key -out ovpmon.crt
chmod 600 ovpmon.key

Nginx server (/etc/nginx/http.d/ovpmon.conf on Alpine): listen 8088 ssl, TLS 1.2/1.3, error_page 497 =301 https://$host:8088$request_uri, security headers, limit_req (5 r/min) on /api/auth/login, / → static UI, /api/ → 127.0.0.1:5001, /profiles-api/ → 127.0.0.1:8000/api/. Full listing: Nginx configuration. Do not declare a second ssl_session_cache shared:SSL zone with a different size than the main nginx.conf.

6. First run

  1. https://<host>:8088/ → sign in with the seeded admin → Account: change username/password, enable 2FA.
  2. PKI Configuration → Initialize PKI → generate server config → start OpenVPN → create profiles.
  • SSH: key-only (PasswordAuthentication no, KbdInteractiveAuthentication no, PermitRootLogin prohibit-password); note that cloud-init drop-ins in /etc/ssh/sshd_config.d/ can override the main file, so put settings in 00-*.conf.
  • fail2ban: jails sshd and one for POST /api/auth/login (401/429/503) on the Nginx access log.
  • Backends bound to 127.0.0.1; only 8088 (UI/API) and the VPN port are public.

8. Verify

rc-status | grep -E "ovpmon|nginx|openvpn"     # or: systemctl status ovpmon-*
ss -tlnp | grep -E ":(8088|5001|8000) "
curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:8088/          # 200
curl -sk -o /dev/null -w "%{http_code}\n" https://127.0.0.1:8088/profiles-api/config   # 401 without token