前言

在云服务器上搭建自己的 VPN 服务,既能保障数据传输安全,又能灵活管理用户权限。本文记录了在 Ubuntu 24.04 服务器上从零部署 OpenVPN 的完整过程,包括:

  • EasyRSA 证书体系搭建
  • 服务端配置(UDP 1194)
  • 证书 + 密码双重认证
  • PAM 对接 MariaDB 数据库管理用户
  • 客户端配置文件生成
  • 路由模式选择(全流量代理 / 分流 / 仅内网)
  • 踩坑记录和解决方案

环境信息

项目配置
系统Ubuntu 24.04 LTS
CPU2 核 Intel Xeon Platinum
内存1.6GB + 4GB Swap
磁盘40GB
OpenVPN2.6.19
MariaDB10.11.14

一、安装 OpenVPN 和 EasyRSA

apt update
apt install -y openvpn easy-rsa

二、搭建 CA 证书体系

# 进入 EasyRSA 目录
cd /etc/openvpn/easy-rsa

# 初始化 PKI
./easyrsa init-pki

# 生成 CA 证书(无密码,一路回车)
./easyrsa build-ca nopass

# 生成服务器证书和密钥
./easyrsa gen-req server nopass
./easyrsa sign-req server server <<< "yes"

# 生成 DH 参数
./easyrsa gen-dh

# 生成 TLS 认证密钥(防 DDoS 和端口扫描)
openvpn --genkey secret ta.key

生成的文件位于 /etc/openvpn/easy-rsa/pki/ 目录下:

  • ca.crt — CA 根证书
  • issued/server.crt — 服务器证书
  • private/server.key — 服务器私钥
  • dh.pem — DH 参数

将这些文件复制到 OpenVPN 配置目录:

cp pki/ca.crt /etc/openvpn/
cp pki/issued/server.crt /etc/openvpn/
cp pki/private/server.key /etc/openvpn/
cp pki/dh.pem /etc/openvpn/
cp ta.key /etc/openvpn/

三、配置 OpenVPN 服务端

创建 /etc/openvpn/server/server.conf

port 1194
proto udp
dev tun

# 证书
ca ca.crt
cert server.crt
key server.key
dh dh.pem
tls-auth ta.key 0

# 网段
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /var/log/openvpn/ipp.txt

# DNS(推荐使用国内 DNS)
push "dhcp-option DNS 223.5.5.5"
push "dhcp-option DNS 119.29.29.29"

# 路由(根据需求选择,见下方路由章节)
push "redirect-gateway def1 bypass-dhcp"

keepalive 10 120
cipher AES-256-GCM
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305

# 降权运行
user nobody
group nogroup

persist-key
persist-tun

status /var/log/openvpn/openvpn-status.log
log-append /var/log/openvpn/openvpn.log
verb 3

DNS 选择:国内服务器建议使用阿里 DNS(223.5.5.5)和腾讯 DNSPod(119.29.29.29),比 Google DNS(8.8.8.8)解析更快。

启动服务

systemctl enable openvpn-server@server
systemctl start openvpn-server@server

注意:Ubuntu 使用 openvpn-server@server.service,它读取 /etc/openvpn/server/server.conf。不要用旧的 openvpn.service(那个会启动后立即退出)。

开启 IP 转发

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

配置 NAT

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

防火墙放行

ufw allow 1194/udp

如果是阿里云等云服务器,还需要在安全组中放行 UDP 1194 端口。

四、生成客户端证书

cd /etc/openvpn/easy-rsa

# 生成客户端密钥和请求(用 --batch 避免交互式 CN 输入问题)
./easyrsa --batch gen-req client1 nopass

# 签发客户端证书
./easyrsa --batch sign-req client client1

五、生成 .ovpn 配置文件

将所有证书和密钥内嵌到一个 .ovpn 文件中,方便客户端导入:

cat > /etc/openvpn/client/client1.ovpn << 'EOF'
client
dev tun
proto udp
remote YOUR_SERVER_IP 1194
resolv-retry infinite
nobind
persist-tun
auth-nocache
remote-cert-tls server
cipher AES-256-GCM
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
verb 3
auth-user-pass
key-direction 1
EOF

# 内嵌证书和密钥
echo "<ca>" >> /etc/openvpn/client/client1.ovpn
cat /etc/openvpn/ca.crt >> /etc/openvpn/client/client1.ovpn
echo "</ca>" >> /etc/openvpn/client/client1.ovpn

echo "<cert>" >> /etc/openvpn/client/client1.ovpn
cat /etc/openvpn/easy-rsa/pki/issued/client1.crt >> /etc/openvpn/client/client1.ovpn
echo "</cert>" >> /etc/openvpn/client/client1.ovpn

echo "<key>" >> /etc/openvpn/client/client1.ovpn
cat /etc/openvpn/easy-rsa/pki/private/client1.key >> /etc/openvpn/client/client1.ovpn
echo "</key>" >> /etc/openvpn/client/client1.ovpn

echo "<tls-auth>" >> /etc/openvpn/client/client1.ovpn
cat /etc/openvpn/ta.key >> /etc/openvpn/client/client1.ovpn
echo "</tls-auth>" >> /etc/openvpn/client/client1.ovpn

客户端配置说明

  • persist-tun:断线重连时保持 TUN 设备,不用重新创建
  • auth-nocache:连接成功后立即清除内存中的密码,防止被 dump 进程获取
  • 不要使用 persist-key:新版 OpenVPN(2.6+)已将其设为默认行为,写了会产生 deprecated 警告

六、添加密码认证(PAM)

纯证书认证已经足够安全,但如果你需要管理大量用户、记录登录日志、对接统一身份系统,就需要加上密码认证。

方案对比

方案优点缺点
自定义脚本 (auth-user-pass-verify)灵活,可对接任意后端以 nobody 运行,受 systemd 安全限制,踩坑多
PAM 共享库插件 (openvpn-auth-pam.so)特权分离、虚拟内存传密码、官方推荐需要 PAM 模块支持

官方建议:生产环境用共享库插件,不要用脚本。

配置 PAM

创建 /etc/pam.d/openvpn

# 方式一:使用系统用户(简单场景)
auth required pam_unix.so
account required pam_unix.so

# 方式二:对接 MariaDB(大量用户)
auth required pam_mysql.so user=vpn_auth passwd=YOUR_DB_PASSWORD host=localhost db=vpn_users table=users usercolumn=username passwdcolumn=password crypt=0
account required pam_mysql.so user=vpn_auth passwd=YOUR_DB_PASSWORD host=localhost db=vpn_users table=users usercolumn=username passwdcolumn=password crypt=0

修改服务端配置

server.conf 中添加:

plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn
verify-client-cert require
username-as-common-name

修改客户端配置

.ovpn 文件中添加:

auth-user-pass

七、对接 MariaDB 数据库

安装 MariaDB

apt install -y mariadb-server mariadb-client
systemctl enable mariadb
systemctl start mariadb

创建数据库和用户表

CREATE DATABASE vpn_users;
USE vpn_users;

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(64) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    email VARCHAR(128),
    status TINYINT DEFAULT 1,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    last_login DATETIME NULL,
    INDEX idx_username (username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE USER 'vpn_auth'@'localhost' IDENTIFIED BY 'YourSecurePassword';
GRANT SELECT ON vpn_users.users TO 'vpn_auth'@'localhost';
FLUSH PRIVILEGES;

安装 pam_mysql

apt install -y libpam-mysql

重启 OpenVPN:

systemctl restart openvpn-server@server

八、路由模式选择

OpenVPN 支持多种路由模式,根据你的需求选择:

模式一:全流量代理(Full Tunnel)

效果:所有流量都走 VPN 服务器,对外 IP 变成服务器 IP。

适用场景

  • 需要隐藏真实 IP
  • 在不安全的网络(公共 WiFi)下加密所有流量
  • 翻越网络限制

服务端配置

push "redirect-gateway def1 bypass-dhcp"

原理def1 会向客户端推送三条路由:

  • 0.0.0.0/1(覆盖所有流量)
  • 128.0.0.0/1(覆盖剩余流量)
  • 原默认网关(保留直连路由)

bypass-dhcp 排除 DHCP 广播流量,避免干扰本地网络。

模式二:分流模式(Split Tunnel)

效果:只有访问特定网段走 VPN,其余流量走本地网络。

适用场景

  • 只需要访问公司/学校内网
  • 节省 VPN 服务器带宽
  • 降低延迟(日常上网不绕路)

服务端配置

# 删除或注释掉 redirect-gateway
# push "redirect-gateway def1 bypass-dhcp"

# 只推送内网路由(按需修改网段)
push "route 10.0.0.0 255.0.0.0"
push "route 172.16.0.0 255.240.0.0"
push "route 192.168.0.0 255.255.0.0"

模式三:仅 VPN 子网(Minimal)

效果:只路由 VPN 子网(10.8.0.0/24),客户端之间可以互通,其余流量全部走本地。

适用场景

  • 组建虚拟局域网(联机游戏、文件共享)
  • 不需要通过 VPN 上网

服务端配置

# 删除或注释掉 redirect-gateway
# push "redirect-gateway def1 bypass-dhcp"

# 不推送任何路由,VPN 子网自动路由
# server 指令已隐含 10.8.0.0/24 的路由

模式四:客户端自定义路由

效果:服务端不推送路由,由客户端 .ovpn 文件自行决定。

适用场景

  • 不同客户端需要不同路由策略
  • 高级用户自行控制

服务端配置

# 不推送路由
# push "redirect-gateway def1 bypass-dhcp"

客户端配置(在 .ovpn 中按需添加):

# 全流量代理
redirect-gateway def1

# 或者只代理特定网段
route 10.0.0.0 255.0.0.0
route 192.168.1.0 255.255.255.0

路由模式对比

模式服务端配置流量走向带宽消耗隐私保护
全流量代理push "redirect-gateway def1"全部走 VPN
分流模式push "route x.x.x.x"指定网段走 VPN部分
仅 VPN 子网不推送路由仅 VPN 内互通
客户端自定义不推送路由客户端决定取决于配置取决于配置

提示:修改服务端路由配置后需要重启 OpenVPN:systemctl restart openvpn-server@server。客户端需要重新连接才能生效。

九、踩坑记录

1. openvpn.service 启动后立即退出

现象systemctl status openvpn 显示 active (exited),端口 1194 无进程监听。

解决:使用 openvpn-server@server.service,配置文件放在 /etc/openvpn/server/server.conf

2. TLS 握手超时

现象:客户端显示 TLS key negotiation failed

排查:服务端无连接记录 → 数据包未到达 → 检查云安全组。

解决:在阿里云安全组中添加 UDP 1194 入站规则。

3. 自定义认证脚本不执行

现象:脚本手动测试通过,OpenVPN 调用时失败。

原因:systemd 安全限制(PrivateTmp、ProtectSystem)+ via-env 密码编码问题。

解决:改用 PAM 共享库插件。

4. pam_mysql 密码格式不兼容

现象:MySQL SHA2() 的十六进制哈希,pam_mysql crypt=3 无法匹配。

原因:crypt=3 对应 MD5,不支持 SHA-256。

解决:使用 crypt=0(明文对比)或应用层使用兼容的哈希格式。

5. 密码文件权限问题

现象:nobody 用户无法读取权限 600 的密码文件。

解决:改用 PAM 插件(特权分离机制自动处理权限)。

6. 客户端红色告警:persist-key deprecated

现象:连接时显示 DEPRECATED OPTION: --persist-key option ignored

原因:OpenVPN 2.6+ 已将密钥持久化作为默认行为,persist-key 选项被废弃。

解决:从 .ovpn 文件中删除 persist-key 这一行。

7. 客户端红色告警:password cache in memory

现象:连接时显示 WARNING: this configuration may cache passwords in memory

原因:OpenVPN 默认会把用户名密码缓存在内存中,方便断线自动重连。

解决:在 .ovpn 文件中添加 auth-nocache。代价是断线后需要重新输入密码。

十、最终架构

客户端 (OpenVPN GUI / Tunnelblick)
    │
    ├─ 证书认证 (TLS 1.3)
    │
    └─ 密码认证
        │
        ▼
OpenVPN Server (nobody, UDP 1194)
    │
    ▼
openvpn-auth-pam.so (特权分离)
    │
    ▼
pam_mysql.so
    │
    ▼
MariaDB (vpn_users.users)

十一、客户端使用

  1. 下载 OpenVPN 客户端(Windows: OpenVPN Connect,macOS: Tunnelblick,iOS/Android: OpenVPN Connect)
  2. 导入 .ovpn 文件
  3. 连接,输入用户名和密码

总结

关键经验:

  1. openvpn-server@server 而不是 openvpn.service
  2. 云服务器别忘了安全组放行 UDP 1194
  3. 生产环境用 PAM 插件,不要用自定义脚本
  4. pam_mysql 的 crypt 参数要和密码存储格式匹配
  5. 国内服务器用阿里/腾讯 DNS,比 Google DNS 解析更快
  6. 客户端配置去掉 persist-key(已废弃),加上 auth-nocache(安全)
  7. 根据需求选择路由模式:全流量代理、分流、仅内网

OpenVPN + PAM + MariaDB 的组合,既能满足小团队几十人的使用,也能扩展到上万人的学校或企业场景。