Sign inSign up

szcq/openvpn

By szcq

Updated 9 days ago

OpenVPN Server Docker Image (https://github.com/yjrszcq/openvpn-docker)

Image
0

2.0K

szcq/openvpn repository overview

OpenVPN Server Docker Image

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.

Highlights

  • Go binaries provide the CLI, container entrypoint, OpenVPN hook, process supervisor, management broker, and optional REST API.
  • SQLite at /etc/openvpn/meta/state.db is the sole authority for structured configuration, clients, addresses, artifact metadata, audit events, API keys, and operation recovery.
  • Easy-RSA remains the PKI authority. Certificates, private keys, CRL, tls-crypt material, profiles, CCD files, and logs remain under /etc/openvpn.
  • Strict YAML rejects unknown or duplicate fields, null values, multiple documents, invalid types, noncanonical networks, and unsupported values.
  • Supports IPv4 TUN addressing, static and dynamic allocation, NAT, pushed routes and DNS, client-to-client traffic, and UDP or TCP transport over public IPv4 or IPv6.
  • Provides transactional client, address, configuration, repair, recovery, and migration workflows with human-readable and documented JSON output.
  • Builds checksum-pinned OpenVPN 2.7.6 images for linux/amd64 and linux/arm64.
  • Diagnoses SQLite, PKI, certificates, CRL, profiles, CCD, derived artifacts, and interrupted operations before unsafe state changes.

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.

Quick Start

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.

Common Operations

# 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.

Command Tree

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.

Optional REST API v1

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:

VariableFormatPurpose
OVPN_API_LISTENaddress:portEnables 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_ORIGINScomma-separated host valuesAllows 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.

Tags

Both registries publish latest. Use it for the copy-ready examples below; production deployments may pin a concrete tag according to their update policy.

RegistryImage
Docker Hubszcq/openvpn:latest
GHCRghcr.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.

Upgrades and Backups

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.

Documentation

License

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.

OpenVPN 服务端 Docker 镜像

English | 中文

基于 Go 控制平面、SQLite 状态存储、Easy-RSA PKI、严格声明式 YAML 配置,并可选启用认证 REST API 的 OpenVPN Community Edition 服务端镜像。REST API 面向独立前端和自动化集成。

主要特性

  • Go 二进制程序提供 CLI、容器入口点、OpenVPN 钩子、进程守护、管理代理与可选 REST API。
  • /etc/openvpn/meta/state.db 中的 SQLite 数据库是结构化配置、客户端、地址、产物元数据、审计事件、API key 与操作恢复的唯一权威数据源。
  • Easy-RSA 仍是 PKI 权威;证书、私钥、CRL、tls-crypt 材料、客户端配置文件、CCD 文件与日志保存在 /etc/openvpn 下。
  • 严格 YAML 会拒绝未知或重复字段、空值、多文档、无效类型、非规范网络与不支持的取值。
  • 支持 IPv4 TUN 寻址、静态与动态地址分配、NAT、下发路由与 DNS、客户端间流量,以及通过公网 IPv4 或 IPv6 承载的 UDP 或 TCP 传输。
  • 提供事务化的客户端、地址、配置、修复、恢复与迁移流程,并在文档注明之处提供稳定 JSON 输出。
  • linux/amd64linux/arm64 构建校验和锁定的 OpenVPN 2.7.6 镜像。
  • 在不安全的状态变更前诊断 SQLite、PKI、证书、CRL、客户端配置、CCD、派生产物与中断操作。

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 clientovpn stateovpn runtime 分别默认执行 client liststate doctorruntime status,并继承对应参数。例如,ovpn client -d -j 等同于 ovpn client list -d -j

可选 REST API v1

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 Hubszcq/openvpn:latest
GHCRghcr.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,请保持服务停止,并按照目标版本的操作手册执行,不要直接启动。需要回退时,停止服务并恢复与目标镜像匹配的完整 dataconfig 备份;不要混用不同快照中的文件。

文档

许可证

项目源码与构建配置基于 GPL-2.0-only 许可证发布。OpenVPN、Easy-RSA、Go 模块与系统包各自保留其许可证,详见 NOTICE

Tag summary

Content type

Image

Digest

sha256:de05703ee

Size

79.2 MB

Last updated

9 days ago

docker pull szcq/openvpn