Production-ready ocserv (OpenConnect VPN server) in Docker. Built from source with GPG verification, supervised by s6-overlay, with optional Prometheus metrics via ocserv-exporter.
Key highlights:
- Multi-stage build on
debian:bookworm-slim— minimal final image, no build toolchain - Latest ocserv built from source with OIDC auth support (see releases for version)
- Multi-architecture support:
amd64,arm64 - Optional Prometheus metrics via ocserv-exporter
- Idempotent iptables setup with clean teardown on shutdown
git clone https://github.com/gifi71/ocserv-docker.git && cd ocserv-docker
# Prepare your config
mkdir -p config
# Place your ocserv.conf, server-cert.pem, server-key.pem in config/
cp .env.example .env
# Edit .env — set VPN_NETWORK to match your ocserv.conf ipv4-network
docker compose up -dOr with docker run:
docker run -d \
--name ocserv \
--restart unless-stopped \
--cap-add NET_ADMIN \
--device /dev/net/tun:/dev/net/tun \
--network host \
--env-file .env \
-v ./config:/etc/ocserv \
-v ./config/ocserv.conf:/etc/ocserv/ocserv.conf:ro \
--security-opt no-new-privileges \
ghcr.io/gifi71/ocserv-docker:latest| Requirement | Why |
|---|---|
| Docker with BuildKit | Multi-stage build, cache mounts |
--cap-add NET_ADMIN |
iptables rules and TUN device creation |
--device /dev/net/tun |
Kernel interface for VPN tunnels |
net.ipv4.ip_forward=1 |
Route traffic between VPN clients and the network |
Enable IP forwarding on the host (required for host mode; in bridge mode it is set automatically via --sysctl):
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.d/99-vpn.conf
sysctl -p /etc/sysctl.d/99-vpn.confOptional — improve TCP performance with BBR:
cat >> /etc/sysctl.d/99-vpn.conf <<'EOF'
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl -p /etc/sysctl.d/99-vpn.confThis project does not ship a default config. Create your own based on the upstream example:
Required settings for this container:
# Healthcheck and exporter depend on occtl
use-occtl = true
# The image ships a dedicated system user
run-as-user = ocserv
run-as-group = ocserv
# TLS — mount your certs into /etc/ocserv
server-cert = /etc/ocserv/server-cert.pem
server-key = /etc/ocserv/server-key.pem
Use any method you prefer: certtool, openssl, ACME (certbot, acme.sh), etc. Mount the resulting cert and key into config/.
cp .env.example .env| Variable | Required | Default | Description |
|---|---|---|---|
VPN_NETWORK |
yes | — | NAT MASQUERADE CIDR, must match ipv4-network in ocserv.conf |
EXPORTER_ENABLED |
no | 0 |
1 to enable Prometheus exporter |
EXPORTER_INTERVAL |
no | 30s |
Delay between occtl scrapes |
EXPORTER_BIND |
no | 127.0.0.1:8000 |
Exporter HTTP listen address |
docker compose up -d # start
docker compose logs -f # logs
docker compose down # stopHost mode (default) — the container shares the host network stack. VPN clients get TUN interfaces visible on the host. The listening ports depend on your ocserv.conf and must be free on the host.
Bridge mode — isolated network namespace, only forwarded ports are accessible. Edit docker-compose.yml: comment out network_mode: host, uncomment the ports/sysctls section.
Bridge mode via docker run:
docker run -d \
--name ocserv \
--restart unless-stopped \
--cap-add NET_ADMIN \
--device /dev/net/tun:/dev/net/tun \
--sysctl net.ipv4.ip_forward=1 \
-p 443:443/tcp \
-p 443:443/udp \
--env-file .env \
-v ./config:/etc/ocserv \
-v ./config/ocserv.conf:/etc/ocserv/ocserv.conf:ro \
--security-opt no-new-privileges \
ghcr.io/gifi71/ocserv-docker:latestmake build # local build for current arch
make build-multiarch # multi-platform build + push
make test # build + run integration tests
make lint # run all linters (hadolint, shellcheck, yamllint)Contributions are welcome — open an issue or submit a PR.
Setup:
# Install pre-commit using your preferred method (pipx, pip, brew, OS package manager, etc.)
pre-commit installThe project uses Conventional Commits and enforces it via pre-commit hook.
Linters: hadolint, shellcheck, yamllint.
This repository (Dockerfile, scripts, configuration) is licensed under MIT.
It includes ocserv, which is licensed under GNU GPLv2. The two are independent works (aggregation per GPL terms).