OpenVPN Server Docker Image (https://github.com/yjrszcq/openvpn-docker)
2.0K
English | 中文
An OpenVPN Community Edition server image with a Go control plane, SQLite state, Easy-RSA PKI, strict declarative YAML configuration, and an optional authenticated REST API for separate frontends and automation.
/etc/openvpn/meta/state.db is the sole authority for structured configuration, clients, addresses, artifact metadata, audit events, API keys, and operation recovery./etc/openvpn.linux/amd64 and linux/arm64.The VPN tunnel data plane remains IPv4. The image does not provide a built-in administration UI, TAP mode, IPv6 tunnel addressing, LDAP/RADIUS/OIDC, PostgreSQL/MySQL storage, HA coordination, or Kubernetes integration. REST API v1 is intended for a separate frontend or automation client and is disabled by default.
Create docker-compose.yaml. Replace the public endpoint and choose an IPv4 network that does not overlap existing server or client networks:
services:
openvpn:
image: szcq/openvpn:latest
container_name: openvpn
restart: unless-stopped
network_mode: host
environment:
OVPN_BOOTSTRAP_FROM_ENV: "true"
OVPN_BOOTSTRAP_ENDPOINT: vpn.example.com
OVPN_BOOTSTRAP_IPV4_NETWORK: 10.42.0.0/24
volumes:
- ./data:/etc/openvpn
- ./config:/etc/ovpn-conf
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
Create the mounted directories and start the service:
mkdir -p data config
chmod 750 data config
docker compose up -d
The three environment variables above generate the first /etc/ovpn-conf/config.yaml only for an empty instance. After the first successful start, set OVPN_BOOTSTRAP_FROM_ENV to "false"; later bootstrap values are ignored and never overwrite YAML or SQLite.
To manage YAML directly, copy config.example.yaml to config/config.yaml before the first start and remove the environment: block. The complete repository docker-compose.yaml also provides the profiled openvpn-maintenance service for offline diagnosis, migration, repair, backup, and recovery.
Docker Hub publishes the rolling latest tag and tags matching the embedded OpenVPN version. Pin a concrete version tag in production.
# Verify state and runtime health
docker exec openvpn ovpn state doctor
docker exec openvpn ovpn runtime health
# Create a client and write its profile on the host
docker exec openvpn \
ovpn client create laptop --ipv4 --output - > laptop.ovpn
chmod 600 laptop.ovpn
# Create a dynamic-address client
docker exec openvpn ovpn client create phone --ipv4 dynamic
# Inspect clients and current connections
docker exec openvpn ovpn client list --detail
docker exec openvpn ovpn runtime status
# Validate, preview, and apply YAML changes online
docker exec openvpn ovpn config validate
docker exec openvpn ovpn config plan
docker exec openvpn ovpn config apply --yes
Profiles contain private keys and must be stored and distributed as credentials. A live config apply temporarily restarts managed OpenVPN processes, disconnecting current VPN sessions while the container and optional API remain available.
Run docker exec openvpn ovpn to print the complete command tree. Every command and subcommand supports --help or -h. Query and plan commands provide human-readable output and stable JSON where documented.
ovpn
├── api
│ └── key
│ ├── create Create an API key.
│ ├── list List API keys without secret material.
│ └── delete Delete and immediately invalidate an API key.
├── server
│ ├── init Initialize an empty OpenVPN instance.
│ ├── run Supervise OpenVPN, broker, and optional API.
│ └── render Render the applied server configuration.
├── config
│ ├── validate Validate the desired YAML configuration.
│ ├── show Show the applied SQLite configuration.
│ ├── export Export applied configuration as YAML.
│ ├── plan Plan desired-to-applied changes.
│ └── apply Apply configuration and restart managed runtime.
├── client
│ ├── create Create a client and credentials.
│ ├── list List active and revoked clients.
│ ├── export Export an active client profile.
│ ├── rename Rename a client without changing its UUID.
│ ├── revoke Revoke a client certificate.
│ ├── reissue Reissue a client certificate and profile.
│ ├── delete Delete local credentials and retain a tombstone.
│ └── address
│ ├── set Set one active client's IPv4 intent.
│ ├── edit Edit multiple IPv4 assignments atomically.
│ └── release Release a revoked client's retained IPv4.
├── state
│ ├── show Show aggregate instance state.
│ └── doctor Diagnose SQLite, PKI, and artifact consistency.
├── repair
│ ├── plan Plan safe repairs and report blockers.
│ └── apply Apply eligible repairs transactionally.
├── migrate
│ ├── plan Plan an offline legacy data migration.
│ └── apply Migrate legacy state to the current format.
├── runtime
│ ├── status Show daemon and connected-client status.
│ ├── disconnect Disconnect a client session.
│ ├── health Check broker and OpenVPN health.
│ ├── capabilities Inspect OpenVPN compatibility.
│ ├── logs Read or follow persistent OpenVPN logs.
│ └── events Read or follow user-facing runtime events.
├── completion Generate Bash, Zsh, or Fish completion.
└── version Print build and data-format versions.
ovpn client, ovpn state, and ovpn runtime default to client list, state doctor, and runtime status, including their options. For example, ovpn client -d -j is equivalent to ovpn client list -d -j.
REST API v1 exposes 22 operations for process liveness, build metadata, state diagnostics, client lifecycle, profile download, IPv4 intent, session disconnect, runtime status and events, and optimistic configuration updates.
Both API environment variables are empty by default:
| Variable | Format | Purpose |
|---|---|---|
OVPN_API_LISTEN | address:port | Enables the HTTP API. Use 127.0.0.1:<unused-port> for host-only access or 0.0.0.0:<unused-port> for all IPv4 interfaces. Empty disables the API. |
OVPN_API_CORS_ORIGINS | comma-separated host values | Allows browser origins without schemes, such as vpn-admin.example.com,192.0.2.10:3000. * alone allows any HTTP(S) origin. Empty disables CORS. |
Example:
services:
openvpn:
environment:
OVPN_API_LISTEN: 127.0.0.1:11940
OVPN_API_CORS_ORIGINS: vpn-admin.example.com
The project uses host networking, so no Compose ports mapping is required. The API provides HTTP only; terminate HTTPS at a trusted reverse proxy and restrict access with the host firewall. Do not include http:// or https:// in either environment value.
Create and manage API keys through the local CLI:
docker exec openvpn ovpn api key create frontend-production
docker exec openvpn ovpn api key list
docker exec openvpn ovpn api key delete frontend-production --yes
The complete key is displayed only once. SQLite stores only its SHA-256 digest, and deletion invalidates subsequent requests immediately. Send the key as Authorization: Bearer ovpn_v1.<uuid>.<secret>; do not put it in URLs, query strings, cookies, logs, telemetry, or source control.
When enabled, the image serves frontend documentation directly:
http://<OVPN_API_LISTEN>/docs/ - interactive English and Chinese reference;http://<OVPN_API_LISTEN>/docs/openapi.json - OpenAPI 3.1 contract.The documentation follows the browser language by default and also provides a manual language switch. Each operation independently shows Header, Path, Query, and JSON Body fields, request examples, success responses, error responses, response fields, types, formats, constraints, and descriptions.
See the complete REST API guide.
Both registries publish latest. Use it for the copy-ready examples below; production deployments may pin a concrete tag according to their update policy.
| Registry | Image |
|---|---|
| Docker Hub | szcq/openvpn:latest |
| GHCR | ghcr.io/yjrszcq/openvpn-docker:latest |
Both registries deliver the same image content under different tag schemes. Pin a concrete tag in production and verify docker exec openvpn ovpn version --json after an update.
SQLite, PKI, profiles, YAML, and generated artifacts form one backup and restore unit. Stop the service before archiving both ./data and ./config; never restore only state.db.
docker compose stop
sudo tar --numeric-owner -czf openvpn-backup.tar.gz data config
After the backup completes, use this general update flow:
docker compose pull openvpn openvpn-maintenance
docker compose run --rm openvpn-maintenance state doctor
docker compose up -d
docker exec openvpn ovpn version --json
docker exec openvpn ovpn state doctor
docker exec openvpn ovpn runtime health
Review the target release notes before updating. If they require a data-schema migration, keep the service stopped and follow the target version's operations guide instead of starting it directly. To roll back, stop the service and restore the complete matching data and config backup; never mix files from different snapshots.
Project source and build configuration are licensed under GPL-2.0-only. OpenVPN, Easy-RSA, Go modules, and system packages retain their respective licenses as recorded in NOTICE.
English | 中文
基于 Go 控制平面、SQLite 状态存储、Easy-RSA PKI、严格声明式 YAML 配置,并可选启用认证 REST API 的 OpenVPN Community Edition 服务端镜像。REST API 面向独立前端和自动化集成。
/etc/openvpn/meta/state.db 中的 SQLite 数据库是结构化配置、客户端、地址、产物元数据、审计事件、API key 与操作恢复的唯一权威数据源。/etc/openvpn 下。linux/amd64 和 linux/arm64 构建校验和锁定的 OpenVPN 2.7.6 镜像。VPN 隧道数据平面仍为 IPv4。镜像不提供内置管理 UI、TAP、IPv6 隧道寻址、LDAP/RADIUS/OIDC、PostgreSQL/MySQL、HA 协调或 Kubernetes 集成。REST API v1 默认关闭。
创建 docker-compose.yaml。请替换公网端点,并选择一个与服务端或客户端现有网络不重叠的 IPv4 网段:
services:
openvpn:
image: szcq/openvpn:latest
container_name: openvpn
restart: unless-stopped
network_mode: host
environment:
OVPN_BOOTSTRAP_FROM_ENV: "true"
OVPN_BOOTSTRAP_ENDPOINT: vpn.example.com
OVPN_BOOTSTRAP_IPV4_NETWORK: 10.42.0.0/24
volumes:
- ./data:/etc/openvpn
- ./config:/etc/ovpn-conf
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
创建挂载目录并启动服务:
mkdir -p data config
chmod 750 data config
docker compose up -d
以上三个环境变量仅为空实例生成第一份 /etc/ovpn-conf/config.yaml。首次成功启动后,将 OVPN_BOOTSTRAP_FROM_ENV 设为 "false";后续 bootstrap 值会被忽略,绝不会覆盖 YAML 或 SQLite。
如需直接管理 YAML,请在首次启动前将 config.example.yaml 复制到 config/config.yaml,并删除 environment: 配置块。仓库中的完整 docker-compose.yaml 还提供通过 profile 启用的 openvpn-maintenance 服务,用于离线诊断、迁移、修复、备份与恢复。
Docker Hub 同时发布滚动更新的 latest 和与内置 OpenVPN 版本一致的标签。生产环境建议固定具体版本标签。
# 检查状态与运行时健康
docker exec openvpn ovpn state doctor
docker exec openvpn ovpn runtime health
# 创建客户端,并将配置文件写到宿主机
docker exec openvpn \
ovpn client create laptop --ipv4 --output - > laptop.ovpn
chmod 600 laptop.ovpn
# 创建使用动态地址的客户端
docker exec openvpn ovpn client create phone --ipv4 dynamic
# 查看客户端与当前连接
docker exec openvpn ovpn client list --detail
docker exec openvpn ovpn runtime status
# 在线校验、预览并应用 YAML 变更
docker exec openvpn ovpn config validate
docker exec openvpn ovpn config plan
docker exec openvpn ovpn config apply --yes
客户端配置文件包含私钥,必须作为凭据存储和分发。实时执行 config apply 会暂时重启受管理的 OpenVPN 进程,当前 VPN 会话会断开,但容器及可选 API 会保持可用。
运行 docker exec openvpn ovpn 可显示完整命令树。每条命令和子命令都支持 --help 或 -h。查询与规划命令提供人类可读输出,并在文档注明之处提供稳定 JSON。
ovpn
├── api
│ └── key
│ ├── create 创建 API key。
│ ├── list 列出 API key,不显示 secret。
│ └── delete 删除并立即使 API key 失效。
├── server
│ ├── init 初始化空 OpenVPN 实例。
│ ├── run 守护 OpenVPN、broker 与可选 API。
│ └── render 渲染已应用的服务端配置。
├── config
│ ├── validate 校验期望 YAML 配置。
│ ├── show 显示已应用的 SQLite 配置。
│ ├── export 将已应用配置导出为 YAML。
│ ├── plan 规划期望配置到已应用配置的变更。
│ └── apply 应用配置并重启受管理的运行时。
├── client
│ ├── create 创建客户端及凭据。
│ ├── list 列出有效与已吊销客户端。
│ ├── export 导出有效客户端配置文件。
│ ├── rename 重命名客户端且不改变 UUID。
│ ├── revoke 吊销客户端证书。
│ ├── reissue 重新签发客户端证书与配置文件。
│ ├── delete 删除本地凭据并保留墓碑记录。
│ └── address
│ ├── set 设置一个有效客户端的 IPv4 意图。
│ ├── edit 原子编辑多个 IPv4 分配。
│ └── release 释放已吊销客户端保留的 IPv4。
├── state
│ ├── show 显示实例汇总状态。
│ └── doctor 诊断 SQLite、PKI 与产物一致性。
├── repair
│ ├── plan 规划安全修复并报告阻塞项。
│ └── apply 以事务方式应用符合条件的修复。
├── migrate
│ ├── plan 规划离线旧数据迁移。
│ └── apply 将旧状态迁移到当前格式。
├── runtime
│ ├── status 显示守护进程与已连接客户端状态。
│ ├── disconnect 断开客户端会话。
│ ├── health 检查 broker 与 OpenVPN 健康状态。
│ ├── capabilities 查看 OpenVPN 兼容性。
│ ├── logs 读取或跟踪持久化 OpenVPN 日志。
│ └── events 读取或跟踪面向用户的运行时事件。
├── completion 生成 Bash、Zsh 或 Fish 补全脚本。
└── version 输出构建与数据格式版本。
ovpn client、ovpn state 与 ovpn runtime 分别默认执行 client list、state doctor 与 runtime status,并继承对应参数。例如,ovpn client -d -j 等同于 ovpn client list -d -j。
REST API v1 提供 22 条接口,覆盖进程存活、构建元数据、状态诊断、客户端生命周期、配置文件下载、IPv4 意图、会话断开、运行时状态与事件,以及乐观并发配置更新。
两个 API 环境变量默认均为空:
| 变量 | 格式 | 用途 |
|---|---|---|
OVPN_API_LISTEN | 地址:端口 | 启用 HTTP API。127.0.0.1:<空闲端口> 仅允许宿主机本地访问;0.0.0.0:<空闲端口> 监听所有 IPv4 网卡;留空关闭 API。 |
OVPN_API_CORS_ORIGINS | 英文逗号分隔的 host 值 | 允许不带协议的浏览器 origin,例如 vpn-admin.example.com,192.0.2.10:3000;单独填写 * 允许任意 HTTP(S) origin;留空关闭 CORS。 |
示例:
services:
openvpn:
environment:
OVPN_API_LISTEN: 127.0.0.1:11940
OVPN_API_CORS_ORIGINS: vpn-admin.example.com
项目使用 host network,不需要 Compose ports 映射。API 只提供 HTTP;远程访问应由可信反向代理终止 HTTPS,并使用宿主机防火墙限制访问。两个变量都不要填写 http:// 或 https://。
通过本地 CLI 创建和管理 API key:
docker exec openvpn ovpn api key create frontend-production
docker exec openvpn ovpn api key list
docker exec openvpn ovpn api key delete frontend-production --yes
完整 key 只显示一次。SQLite 仅保存 SHA-256 摘要,删除后后续请求立即失效。通过 Authorization: Bearer ovpn_v1.<uuid>.<secret> 发送 key;不要将其放入 URL、query、Cookie、日志、遥测或源码仓库。
启用 API 后,镜像会直接提供前端开发文档:
http://<OVPN_API_LISTEN>/docs/:可交互的中英文接口文档;http://<OVPN_API_LISTEN>/docs/openapi.json:OpenAPI 3.1 契约。文档默认跟随浏览器语言,也支持手动切换。每条接口独立展示 Header、Path、Query 与 JSON Body 字段、请求示例、成功返回、错误返回、返回字段、类型、格式、约束和说明。
完整内容见 REST API 指南。
两个注册表均提供 latest。以下可直接使用的示例统一采用 latest;生产环境也可根据自身更新策略固定具体标签。
| 注册表 | 镜像 |
|---|---|
| Docker Hub | szcq/openvpn:latest |
| GHCR | ghcr.io/yjrszcq/openvpn-docker:latest |
两个注册表使用不同标签方案提供相同镜像内容。生产环境应固定具体标签,并在更新后执行 docker exec openvpn ovpn version --json 核对版本。
SQLite、PKI、客户端配置、YAML 与生成产物构成一个备份和恢复单元。归档 ./data 与 ./config 前必须停止服务,切勿只恢复 state.db。
docker compose stop
sudo tar --numeric-owner -czf openvpn-backup.tar.gz data config
备份完成后,使用以下通用更新流程:
docker compose pull openvpn openvpn-maintenance
docker compose run --rm openvpn-maintenance state doctor
docker compose up -d
docker exec openvpn ovpn version --json
docker exec openvpn ovpn state doctor
docker exec openvpn ovpn runtime health
更新前应阅读目标版本的发布说明。如果目标版本要求迁移数据 schema,请保持服务停止,并按照目标版本的操作手册执行,不要直接启动。需要回退时,停止服务并恢复与目标镜像匹配的完整 data 和 config 备份;不要混用不同快照中的文件。
项目源码与构建配置基于 GPL-2.0-only 许可证发布。OpenVPN、Easy-RSA、Go 模块与系统包各自保留其许可证,详见 NOTICE。
Content type
Image
Digest
sha256:de05703ee…
Size
79.2 MB
Last updated
9 days ago
docker pull szcq/openvpn