# Deployment: Docker Uses `docker-compose.yml` from the repository root. ## Services | Service | Container | Ports | Notes | |---|---|---|---| | `app-ui` | `ovp-ui` | 80 | Nginx + built UI; proxies `/api/` and `/profiles-api/` | | `app-api` | `ovp-api` | 5001 | Flask monitoring API | | `app-gatherer` | `ovp-gatherer` | - | Parses `openvpn-status.log` | | `app-profiler` | `ovp-profiler` | 8000, 1194/udp | FastAPI + OpenVPN; needs `NET_ADMIN` and `/dev/net/tun` | Volumes: `ovp_logs`, `ovp_config`, `ovp_pki`, `ovp_client_config`, `db_data`. ## Steps 1. Create `.env` next to `docker-compose.yml` (`JWT_SECRET` is mandatory: compose refuses to start without it): ```bash cat > .env < OVPMON_INITIAL_ADMIN_PASSWORD= EOT chmod 600 .env ``` 2. `docker-compose up -d --build` 3. Open `http://`, sign in, **PKI Configuration → Initialize PKI**. 4. Remove `OVPMON_INITIAL_ADMIN_*` from `.env` and run `docker-compose up -d app-api` (the seed is used only while the users table is empty). ## Compose settings | Item | Value | |---|---| | Published ports | `80/tcp` (UI) and `1194/udp` (VPN) only; `5001` and `8000` are `expose`d on `ovp-net` and reached through Nginx in `app-ui` | | Secrets | `JWT_SECRET` (required) → `OVPMON_API_SECRET_KEY` for both APIs | | Initial admin | `OVPMON_INITIAL_ADMIN_USER` / `OVPMON_INITIAL_ADMIN_PASSWORD` (optional, first start) | | CORS | `OVPMON_CORS_ORIGINS` (optional, comma-separated; off by default because the UI is same-origin) | | Restart policy | `unless-stopped` | ## Hardening - Terminate TLS in front of `app-ui` (reverse proxy or a certificate mounted into the UI container); see [Nginx configuration](Nginx_Configuration.md). The container serves plain HTTP on 80. - `ovp-profiler` is privileged (`NET_ADMIN`, TUN): keep its API off the host network. - Back up the `db_data` and `ovp_pki` volumes; never commit `.env`. ## Operations ```bash docker-compose ps docker-compose logs -f app-api app-profiler docker-compose up -d --build app-ui # after UI changes ```