ovpn
For operators and engineers

ovpn

A source-available Go CLI for operating self-hosted Xray VLESS + REALITY servers. State stays local, deploys go over SSH/SCP, and the runtime runs as Docker Compose on Linux hosts.

Local state ~/.ovpn stores servers, users, quotas, and deploy metadata.
SSH deploy The CLI renders runtime bundles locally and applies them over SSH/SCP.
Docker runtime Xray, agent, proxy, and monitoring run under Compose in /opt/ovpn.
HA option HAProxy can front several VPN backends and apply country preset routing.

Control plane without a public admin API

ovpn is built around files, SSH access, and reproducible deploys. The public repository contains the tool and templates; real inventory, hostnames, tokens, keys, and local state stay outside it.

Desired state on the operator machine

Servers, users, quotas, and deploy metadata live under ~/.ovpn. Deploy renders that state into the remote runtime.

Go CLI, Linux runtime

The operator uses one CLI. Release builds embed Linux runtime assets for ovpn-agent and the Telegram bot.

Docker Compose on hosts

Xray, the agent, monitoring, optional proxy, and backups are kept under /opt/ovpn for predictable maintenance.

Multi-host operations

User add/remove/enable/disable, expiry, and quota commands can apply to all enabled VPN hosts by default.

Security defaults

The minimal Xray profile blocks BitTorrent and public tracker domains. Ansible can add host-level Tor exit filtering.

Operational checks

doctor, status, logs, backup, restore, cleanup, monitoring, and release smoke checks are first-class workflows.

Architecture

Operations start from the operator machine. VPN hosts receive rendered Compose bundles. Clients connect directly to one or more VPN hosts, or through an optional HA entrypoint.

local control / remote runtime

SSH/SCP Docker Compose Desired state Optional HA
Operator machine
ovpn CLI Deploys, user changes, quotas, status checks, logs, backup, restore, cleanup, and monitoring setup.
Local state ~/.ovpn stores desired state and metadata. Private operational data stays local.
Ansible baseline Bootstrap and maintenance playbooks handle Docker, firewall, SSH, unattended upgrades, and host hardening.
VPN hosts
VPN host A /opt/ovpn contains Docker Compose, Xray on 443/tcp, ovpn-agent, config, and snapshots.
VPN host B..N Additional hosts use the same runtime model for users, quotas, health, and metrics.
Monitoring Optional Prometheus, Grafana, Alertmanager, cAdvisor, node-exporter, and Telegram operator bot.
Traffic path
HAProxy entrypoint Optional proxy node with country presets, local-destination bypass, foreign relay, and backend pool failover.
Clients Mobile and desktop clients import a VLESS link or QR and use the public 443/tcp endpoint.
Release archives contain only ovpn; embedded runtime assets are materialized during deploy.
Runtime mutations use the agent fast path and fall back to full deploy when needed.
The public workflows validate Go, Ansible, security scans, docs, and release packaging.

Automation surface

The CLI is the operator surface for initial bootstrap, normal deploys, user lifecycle, quotas, monitoring, and recovery.

  • server init and deploy render desired state and apply it through SSH/SCP.
  • user add, user rm, quota-set, and expiry commands mirror users across enabled servers.
  • doctor, status, logs, backups, restore, cleanup, and monitoring are built-in workflows.
  • GitHub Actions cover Go quality, Ansible quality, security scans, and self-contained release packaging.
./ovpn version

./ovpn server add \
  --name <server> \
  --host <server-ip> \
  --domain <domain> \
  --ssh-user root \
  --ssh-port 22

./ovpn server init <server>
./ovpn deploy <server>
./ovpn doctor <server>
./ovpn user quota-set --username <user> --monthly-gb 400
./ovpn user link --server <server> --username <user>

Documentation

Documentation links open in the GitHub Pages renderer so Markdown files remain readable outside GitHub.

Project updates and support

Follow development notes on X, or support maintenance through the donation page.