Featured image of post OpenVPN 自建 VPN 服务:证书签发、客户端配置与多用户管理

OpenVPN 自建 VPN 服务:证书签发、客户端配置与多用户管理

kylemanna/openvpn 容器化部署、CA 证书签发、客户端 .ovpn 导出、多用户管理脚本、duplicate-cn 多人共用证书、内网路由

企业内网里要远程办公、要让外网访问内部系统,传统方案是"公网 IP + 端口映射 + 防火墙白名单",但任意端口都暴露风险大。VPN(Virtual Private Network)是更安全的方案——所有流量走加密隧道,访问内网像在内网一样。OpenVPN 是开源 VPN 里的"老牌选手",协议成熟、客户端齐全、跨平台。这篇文章讲清楚容器化部署、CA 证书签发、客户端 .ovpn 配置、多用户管理。

阅读对象:要给团队搭企业 VPN、给客户搭远程访问通道的运维同学
覆盖范围:kylemanna/openvpn 容器化部署、CA 签发、客户端 .ovpn 生成、duplicate-cn 多人共用、多用户管理脚本

〇、本文与"VPN 与代理自托管"一文的关系

本篇侧重 OpenVPN 单协议的深度——性能调优、跨平台客户端、协议变体、与企业网络设备对接。如果想看 OpenVPN + V2Ray 两条路线的选型对比,请参考姐妹篇 VPN 与代理自托管:OpenVPN 与 V2Ray 部署实战

合规提示(必读):本文仅讨论 OpenVPN 用于企业远程办公、跨地域内网访问、出差员工接入公司内网等合法场景。部署、使用 VPN 服务务必遵守所在国家/地区法律法规未经电信主管部门批准擅自建立、使用其他信道进行国际联网在中国大陆境内属违法行为请勿用于违反所在国法律法规的用途

一、为什么是 OpenVPN

VPN 协议不止一种,主流对比:

协议特点适用
OpenVPNSSL/TLS 加密,UDP/TCP 都行,跨平台企业内网 VPN,老牌稳定
WireGuard新一代,Linux 内核态,配置极简追求性能与简洁
IPSec / IKEv2移动端友好,原生支持 iOS/macOS移动办公
Shadowsocks / V2Ray代理协议,不是真 VPN翻墙 / 流量伪装

When to use:要给企业员工/客户提供"访问内网"能力,OpenVPN 是最稳的方案——企业级防火墙一般不会拦 OpenVPN 流量(看是 TCP 443 还是 UDP 1194),客户端覆盖 Windows / macOS / Linux / iOS / Android。

二、容器化部署

2.1 拉镜像

1
docker pull kylemanna/openvpn

2.2 初始化配置

1
2
3
4
5
6
7
8
# 创建配置卷
OVPN_DATA="ovpn-data"
docker volume create --name $OVPN_DATA

# 生成 OpenVPN 服务端配置(UDP 协议,公网 IP 替换成实际 IP)
docker run -v $OVPN_DATA:/etc/openvpn --log-driver=none --rm \
  kylemanna/openvpn \
  ovpn_genconfig -u udp://{{PUBLIC_IP}}

协议选择

  • UDP 1194:性能好,主流选择
  • TCP 443:能穿透企业代理/防火墙,但性能略差

2.3 签发 CA 证书

1
2
3
4
5
6
7
8
9
docker run -v $OVPN_DATA:/etc/openvpn --rm -it \
  kylemanna/openvpn ovpn_initpki

# 交互式输入:
#   Confirm removal: yes
#   Enter PEM pass phrase: {{CA_PASSWORD}}    # CA 私钥密码
#   Verifying - Enter PEM pass phrase: {{CA_PASSWORD}}
#   Common Name (eg: your user,host,or server name) [Easy-RSA CA]: 直接回车
#   Enter pass phrase for /etc/openvpn/pki/private/ca.key: {{CA_PASSWORD}}

CA 密码保管:这个密码是 CA 私钥的"二次锁",必须记录下来备份——后面签发/吊销客户端证书时都要用到。

2.4 启动服务端

1
2
3
4
5
6
docker run -d --name openvpn --restart=always \
  -v $OVPN_DATA:/etc/openvpn \
  -p 1194:1194/udp \
  --cap-add=NET_ADMIN \
  --restart=always \
  kylemanna/openvpn

–cap-add=NET_ADMIN:让容器获得 NET_ADMIN 能力,能创建 tun 设备、改路由表。

2.5 验证

服务端启动后,查看日志:

1
docker logs -f openvpn

看到 Initialization Sequence Completed 说明成功。

三、签发客户端证书

3.1 单个客户端

1
2
3
4
5
6
7
# 签发 client 证书
docker run -v $OVPN_DATA:/etc/openvpn --rm -it \
  kylemanna/openvpn easyrsa build-client-full {{USERNAME}} nopass

# 导出 .ovpn 配置文件
docker run -v $OVPN_DATA:/etc/openvpn --rm \
  kylemanna/openvpn ovpn_getclient {{USERNAME}} > {{USERNAME}}.ovpn

nopass:客户端证书不设密码。nopass 适合自动化/移动端,有密码更安全(每次连接输密码),按业务取舍。

3.2 .ovpn 文件内容

导出的 .ovpn 文件包含

  • CA 证书
  • 客户端证书
  • 客户端私钥
  • 服务端配置(IP、端口、协议、压缩方式)

直接发给用户用 OpenVPN 客户端导入即可:

  • Windows / macOS:OpenVPN Connect 客户端
  • Linux:openvpn --config xxx.ovpn
  • iOS / Android:OpenVPN Connect APP

不要通过微信/邮件明文传 .ovpn——里面是私钥。建议企业内 IM(如企业微信)传或加密压缩。

3.3 客户端连接

1
2
3
# Linux
sudo apt install openvpn
sudo openvpn --config /path/to/{{USERNAME}}.ovpn

连接成功后,客户端会拿到 10.8.x.x 的 VPN IP,访问内网(如 192.168.0.0/16)就自动走 VPN 隧道。

四、关键配置

/var/lib/docker/volumes/ovpn-data/_data/openvpn.conf(核心):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
server 10.8.0.0 255.255.255.0
verb 3
key /etc/openvpn/pki/private/{{SERVER_NAME}}.key
ca /etc/openvpn/pki/ca.crt
cert /etc/openvpn/pki/issued/{{SERVER_NAME}}.crt
dh /etc/openvpn/pki/dh.pem
tls-auth /etc/openvpn/pki/ta.key
key-direction 0
keepalive 10 60
persist-key
persist-tun
proto udp
port 1194
dev tun0
status /tmp/openvpn-status.log
user nobody
group nogroup
comp-lzo no

# 路由推送(让客户端能访问内网)
route 192.168.0.0 255.255.0.0

# DNS 推送
push "block-outside-dns"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
push "comp-lzo no"

五、多用户管理

5.1 duplicate-cn(多人共用证书)

默认 OpenVPN 一个证书只允许一个连接。多人用同一个 .ovpn:

1
2
3
4
5
# 在 openvpn.conf 末尾加
echo "duplicate-cn" >> /var/lib/docker/volumes/ovpn-data/_data/openvpn.conf

# 重启
docker restart openvpn

不推荐生产用:所有用户用同一个证书,审计不到具体人,吊销就是"全部吊销"。建议每个用户独立签发证书。

5.2 批量添加用户脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/bash
# vim add_user.sh
OVPN_DATA="ovpn-data"
read -p "please your username: " NAME

docker run -v $OVPN_DATA:/etc/openvpn --rm -it \
  kylemanna/openvpn easyrsa build-client-full $NAME nopass

docker run -v $OVPN_DATA:/etc/openvpn --rm \
  kylemanna/openvpn ovpn_getclient $NAME > /root/"$NAME".ovpn

docker restart openvpn

5.3 删除用户脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash
# vim del_user.sh
OVPN_DATA="ovpn-data"
read -p "Delete username: " DNAME

docker run -v $OVPN_DATA:/etc/openvpn --rm -it \
  kylemanna/openvpn easyrsa revoke $DNAME

docker run -v $OVPN_DATA:/etc/openvpn --rm -it \
  kylemanna/openvpn easyrsa gen-crl

docker run -v $OVPN_DATA:/etc/openvpn --rm \
  kylemanna/openvpn rm -f /etc/openvpn/pki/reqs/"$DNAME".req

docker run -v $OVPN_DATA:/etc/openvpn --rm \
  kylemanna/openvpn rm -f /etc/openvpn/pki/private/"$DNAME".key

docker run -v $OVPN_DATA:/etc/openvpn --rm \
  kylemanna/openvpn rm -f /etc/openvpn/pki/issued/"$DNAME".crt

docker restart openvpn

六、踩坑清单

  1. UDP 1194 被防火墙拦——换 TCP 443,重启 ovpn_genconfig -u tcp://{{IP}}
  2. 客户端连上但访问不了内网——服务端没 push "route 192.168.x.x 255.255.x.x",或者内网机器防火墙拦截了 VPN 客户端 IP(10.8.0.0/24)
  3. DNS 解析失败——客户端拿到了 VPN IP 但解析不到内网域名,添加 push "dhcp-option DNS 10.0.0.2"
  4. 证书过期——Easy-RSA 默认 825 天,吊销旧证书、签发新证书
  5. .ovpn 文件被截断——> 重定向可能被 shell 解释,证书里的 --- 等特殊字符要用 <<EOFtee 输出
  6. 多人共用证书审计不到——生产用 duplicate-cn 是"省事但危险",强烈建议一证一人

七、OpenVPN 性能优化(独有)

性能调优是与 VPN 与代理自托管 姐妹篇不重叠的部分。

7.1 协议层

协议性能兼容适用
UDP最高大多数客户端默认推荐
TCP略低所有环境穿透强约束网络
TCP 443全部跨公网 NAT / 严格防火墙

proto udp 默认选;只有 UDP 被防火墙挡才换 TCP

7.2 加密层

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 高性能(默认)
cipher AES-256-CBC
auth SHA256
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384

# 极致性能(牺牲一些安全性)
cipher AES-128-GCM     # 128 vs 256 性能差 30%
auth SHA1

# 强制 TLS 1.2+(强烈推荐)
tls-version-min 1.2

2024+ 推荐:CPU 支持 AES-NI 硬件加速(所有现代 Intel/AMD CPU 都支持),AESGCM 比 CBC 快 2-3 倍。改用 cipher AES-256-GCM

7.3 压缩(注意历史教训)

1
2
3
4
5
# 禁用 comp-lzo(VORACLE 攻击)
comp-lzo no
push "comp-lzo no"

# 不用 compress(如果用了 LZ4 也建议禁)

7.4 keepalive 与 MTU

1
2
3
4
5
6
# 客户端断线 60s 内重连,服务端 120s 释放
keepalive 10 60

# 关键 MTU 调优(避免分片)
tun-mtu 1400
mssfix 1360

7.5 大规模并发(千人级)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 服务端配置
max-clients 1000
max-routes-per-client 50
duplicate-cn              # 仅审计可放弃时使用
tcp-nodelay

# /etc/sysctl.conf(宿主)
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216

7.6 性能基准(参考)

配置单客户端带宽CPU 占用(单核)
AES-256-CBC + UDP~800 Mbps60%
AES-256-GCM + UDP~2 Gbps30%
AES-128-GCM + UDP~3 Gbps20%
TCP 443~500 Mbps70%

实际值取决于 CPU、MTU、网络环境。1 Gbps 客户端+ AES-NI 可跑到 1.5+ Gbps 隧道吞吐

八、跨平台客户端实战(独有)

8.1 Windows

  • OpenVPN Connect 官方客户端
  • OpenVPN GUI2018 起停更,但仍是事实标准)
  • Tunnelblick(仅 macOS)→ Windows 对应 OpenVPN Connect

8.2 macOS

  • Tunnelblick 开源 GUI(事实标准
  • OpenVPN Connect 官方
  • Viscosity 商业(订阅制,UI 友好)

8.3 Linux

1
2
3
4
5
6
7
# 命令行
sudo apt install openvpn
sudo openvpn --config client.ovpn

# NetworkManager 图形
sudo apt install network-manager-openvpn network-manager-openvpn-gnome
# 系统设置 → 网络 → + → VPN → OpenVPN → 选 .ovpn 文件

8.4 iOS / Android

  • OpenVPN Connect(官方)
  • 导入 .ovpn 后会自动保存,连接时输入证书密码(如果签发时设了)

8.5 路由器(OpenWrt / iKuaiOS)

1
2
3
4
5
6
7
8
9
# OpenWrt 安装
opkg install openvpn-openssl

# 复制 .ovpn 到 /etc/openvpn/
# 启动
/etc/init.d/openvpn enable
/etc/init.d/openvpn start

# 路由器下所有设备都走 VPN("硬路由级" VPN)

进阶:把 OpenVPN 装到企业网关(pfSense / OPNsense),整个网段接入 VPN。

九、协议变体与互操作(独有)

9.1 OpenVPN Access Server(商业版)

  • 官方商业版,免证书签发
  • 提供 Web 管理后台、用户自助注册
  • 适合中小企业(< 200 用户)不想自己维护 CA
  • 授权 10 用户起售

9.2 OpenVPN Cloud

  • 2020+ 推出的 SaaS 版
  • 全球 Anycast 节点
  • 适合跨国企业、远程办公团队
  • 按用户订阅

9.3 WireGuard 替代?

维度OpenVPNWireGuard
内核态否(用户态)是(Linux 5.6+)
性能极高(UDP 单线程 ~1 Gbps)
配置中(CA + 证书)极简(公私钥对)
抗检测低(流量特征明显)
跨平台全平台全平台(2019+)
适用企业内网、远程办公高性能场景、移动端

2024 选型:传统企业 → OpenVPN(稳定、审计、客户端全);新项目 / 高性能 → WireGuard(配置极简、性能强)。

十、参考资料

  • kylemanna/openvpn:https://github.com/kylemanna/docker-openvpn
  • OpenVPN 官方文档:https://openvpn.net/community-resources/
  • OpenVPN Connect 客户端下载:https://openvpn.net/client/

下一步

使用 Hugo 构建
主题 StackJimmy 设计