Anolis 8.10 系统 OpenVPN 服务端完整部署流程(优化版)
📋 目录
- 一、环境准备
- 二、编译安装 OpenVPN
- 三、配置 PKI 证书体系
- 四、配置 OpenVPN 服务器
- 五、配置网络转发
- 六、启动和验证服务
- 七、生成客户端配置
- 八、客户端连接测试
- 九、证书管理
- 十、安全加固
- 十一、监控和维护
- 十二、常见问题排查
- 十三、工作原理详解
一、环境准备
1.1 系统信息检查
# 查看系统版本
cat /etc/os-release
# 查看内核版本
uname -r
# 检查 TUN 模块支持
lsmod | grep tun
modprobe tun
echo "tun" >> /etc/modules-load.d/tun.conf
# 确认 TUN 设备存在
ls -l /dev/net/tun
1.2 安装依赖包
# 更新系统
dnf update -y
# 安装 EPEL 仓库
dnf install epel-release -y
# 安装编译工具链
dnf groupinstall -y "Development Tools"
# 安装 OpenVPN 编译依赖
dnf install -y \
gcc \
make \
rpm-build \
pkgconfig \
wget \
tar \
openssl-devel \
zlib-devel \
pam-devel \
systemd-devel \
krb5-devel \
libnl3-devel \
lzo-devel \
lz4-devel \
libcap-ng-devel \
net-tools \
iptables-services \
pkcs11-helper \
pkcs11-helper-devel
# 安装 Easy-RSA
dnf install easy-rsa -y
#或直接下载
wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.2.4/EasyRSA-3.2.4.tgz
tar -xvf EasyRSA-3.2.4.tgz -C /server/tools
# 验证关键依赖
rpm -qa | grep -E "(gcc|openssl-devel|lz4-devel|easy-rsa)"
1.3 创建工作目录(用于编译安装)
# 创建工具目录
mkdir -p /server/tools
cd /server/tools
二、编译安装 OpenVPN
2.1 下载源码
# 下载 OpenVPN 2.6.17(推荐使用国内镜像加速)
wget https://github.com/OpenVPN/openvpn/releases/download/v2.6.17/openvpn-2.6.17.tar.gz
# 如下载慢,使用镜像加速
# wget https://ghproxy.com/https://github.com/OpenVPN/openvpn/releases/download/v2.6.17/openvpn-2.6.17.tar.gz
# 验证下载完整性(可选)
sha256sum openvpn-2.6.17.tar.gz
2.2 编译安装
# 解压源码
tar -zxf openvpn-2.6.17.tar.gz -C /server/tools
cd /server/tools/openvpn-2.6.17
# 配置编译参数
./configure \
--prefix=/usr/local \
--sysconfdir=/etc/openvpn \
--enable-systemd \
--enable-lz4 \
--enable-lzo \
--enable-pkcs11 \
--enable-async-push
# 查看配置摘要
# 确认显示:
# systemd support: yes
# LZ4 compression: yes
# 编译(使用多核加速)
make -j$(nproc)
# 安装
make install
# 验证安装
/usr/local/sbin/openvpn --version
# 应显示:OpenVPN 2.6.17
# 创建符号链接(方便使用)
ln -sf /usr/local/sbin/openvpn /usr/sbin/openvpn
2.3 创建必要目录
# 创建配置目录结构
mkdir -p /etc/openvpn/server/{keys,ccd,logs}
mkdir -p /etc/openvpn/client
mkdir -p /var/log/openvpn
# 目录说明:
# /etc/openvpn/server/ - 服务器配置根目录
# /etc/openvpn/server/keys/ - 证书和密钥存放目录
# /etc/openvpn/server/ccd/ - 客户端特定配置目录
# /etc/openvpn/server/logs/ - 日志目录
# /var/log/openvpn/ - 系统日志目录
2.4 配置 systemd 服务
# 创建 systemd 服务文件
cat > /etc/systemd/system/openvpn-server@.service <<'EOF'
[Unit]
Description=OpenVPN service for %I
After=network-online.target
Wants=network-online.target
Documentation=man:openvpn(8)
Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage
[Service]
Type=notify
PrivateTmp=true
WorkingDirectory=/etc/openvpn/server
ExecStart=/usr/local/sbin/openvpn --status /var/log/openvpn/%i-status.log --status-version 2 --cd /etc/openvpn/server --config %i.conf
CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE CAP_AUDIT_WRITE
LimitNPROC=100
DeviceAllow=/dev/null rw
DeviceAllow=/dev/net/tun rw
ProtectSystem=true
ProtectHome=true
KillMode=process
RestartSec=5s
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 重新加载 systemd
systemctl daemon-reload
# 验证服务文件
systemctl cat openvpn-server@server
三、配置 PKI 证书体系
3.1 初始化 Easy-RSA
# 进入工作目录
cd /etc/openvpn/server
mkdir -p easy-rsa
cd easy-rsa
# 复制 Easy-RSA 脚本
#(yum安装)
cp -r /usr/share/easy-rsa/3/* .
#(github下载)
cp -r /server/tools/EasyRSA-3.2.4/* .
# 确认复制成功
ls -l easyrsa
./easyrsa --version
3.2 配置 PKI 参数(推荐)
# 创建 vars 配置文件
cat > vars <<'EOF'
# Easy-RSA 配置变量
# 证书信息(根据实际情况修改)
set_var EASYRSA_REQ_COUNTRY "CN"
set_var EASYRSA_REQ_PROVINCE "Shanghai"
set_var EASYRSA_REQ_CITY "Shanghai"
set_var EASYRSA_REQ_ORG "linuxjk.cn"
set_var EASYRSA_REQ_EMAIL "zhangpeng@linuxjk.cn"
set_var EASYRSA_REQ_OU "IT Department"
# 证书有效期(天)
set_var EASYRSA_CA_EXPIRE 3650 # CA证书10年
set_var EASYRSA_CERT_EXPIRE 3650 # 服务器/客户端证书10年
# 密钥参数
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CURVE secp384r1
set_var EASYRSA_DIGEST "sha256"
# CRL 有效期
set_var EASYRSA_CRL_DAYS 3650
EOF
# 让配置生效
chmod +x vars
3.3 初始化 PKI 并创建 CA
# 初始化 PKI 目录结构
./easyrsa init-pki
# 构建 CA(无密码模式,适合自动化)
./easyrsa build-ca nopass
# 提示输入 Common Name,输入示例:
# Common Name: OpenVPN-CA
# ⚠️ 生产环境推荐使用带密码的 CA:
# ./easyrsa build-ca
# 会提示设置 CA 私钥密码
# 验证 CA 证书
openssl x509 -in pki/ca.crt -noout -text | grep -A 2 "Validity"
3.4 生成服务器证书(完整步骤)
# ===== 方法1:标准分步骤(推荐用于生产环境)=====
# 步骤1:生成服务器私钥和证书请求
./easyrsa gen-req server nopass
# 提示输入 Common Name,输入:server(或服务器FQDN)
# 步骤2:签发服务器证书
./easyrsa sign-req server server
# 输入 yes 确认
# 如果 CA 有密码,需要输入密码
# ===== 方法2:快捷命令(等同于上述两步)=====
# ./easyrsa build-server-full server nopass
# 验证服务器证书
openssl x509 -in pki/issued/server.crt -noout -text | head -20
# 验证证书链
openssl verify -CAfile pki/ca.crt pki/issued/server.crt
# 应显示:pki/issued/server.crt: OK
3.5 生成 DH 参数
# 生成 2048 位 DH 参数(推荐,约需 2-5 分钟)
./easyrsa gen-dh
# 如需更高安全性(4096 位,可能需要 20-30 分钟)
# 先修改 vars: set_var EASYRSA_KEY_SIZE 4096
# 然后执行: ./easyrsa gen-dh
# 验证生成
ls -lh pki/dh.pem
# 应显示约 424 字节的文件
3.6 生成 TLS 认证密钥
# 生成 tls-auth 密钥(防 DDoS 攻击)
openvpn --genkey secret pki/ta.key
# 验证生成
ls -lh pki/ta.key
cat pki/ta.key | head -5
3.7 生成 CRL(证书吊销列表)
# 生成初始 CRL
./easyrsa gen-crl
# 验证
ls -lh pki/crl.pem
openssl crl -in pki/crl.pem -noout -text
3.8 生成客户端证书(示例)
# 定义客户端名称
CLIENT_NAME="client1"
# ===== 方法1:完整步骤(推荐)=====
# 步骤1:生成证书请求
./easyrsa gen-req $CLIENT_NAME nopass
# Common Name: client1
# 步骤2:签发客户端证书(注意类型是 client)
./easyrsa sign-req client $CLIENT_NAME
# 输入 yes 确认
# ===== 方法2:快捷命令 =====
# ./easyrsa build-client-full $CLIENT_NAME nopass
# 验证客户端证书
openssl verify -CAfile pki/ca.crt pki/issued/$CLIENT_NAME.crt
3.9 复制证书到服务器配置目录
cd /etc/openvpn/server/easy-rsa
# 复制 CA 证书
cp pki/ca.crt /etc/openvpn/server/keys/
# 复制服务器证书和私钥
cp pki/issued/server.crt /etc/openvpn/server/keys/
cp pki/private/server.key /etc/openvpn/server/keys/
# 复制 DH 参数(重命名以便识别)
cp pki/dh.pem /etc/openvpn/server/keys/dh2048.pem
# 复制 TLS 认证密钥
cp pki/ta.key /etc/openvpn/server/keys/
# 复制 CRL(可选但推荐)
cp pki/crl.pem /etc/openvpn/server/keys/
# 设置严格权限(重要!)
#私钥600,公钥644
chmod 600 /etc/openvpn/server/keys/server.key
chmod 600 /etc/openvpn/server/keys/ta.key
chmod 644 /etc/openvpn/server/keys/*.crt
chmod 644 /etc/openvpn/server/keys/dh2048.pem
chmod 644 /etc/openvpn/server/keys/crl.pem
# 设置所有者
chown -R root:root /etc/openvpn/server/keys
# 验证文件完整性
ls -lh /etc/openvpn/server/keys/
root@anolis810:/etc/openvpn/server/easy-rsa# ls -lh /etc/openvpn/server/keys/
总用量 28K
-rw-r--r-- 1 root root 1.2K 12月 4 09:40 ca.crt
-rw-r--r-- 1 root root 646 12月 4 09:41 crl.pem
-rw-r--r-- 1 root root 424 12月 4 09:40 dh2048.pem
-rw-r--r-- 1 root root 4.5K 12月 4 09:40 server.crt
-rw------- 1 root root 1.7K 12月 4 09:40 server.key
-rw------- 1 root root 636 12月 4 09:40 ta.key
四、配置 OpenVPN 服务器
4.1 创建服务器配置文件
cat > /etc/openvpn/server/server.conf <<'EOF'
#################################################
# OpenVPN 2.6.17 服务器配置文件
# 系统: Anolis 8.10
# 创建时间: 2025-12-03
#################################################
# ===== 基本网络设置 =====
# 监听端口(默认 1194)
port 1194
# 协议类型(UDP 性能更好,TCP 更稳定)
proto udp
# 如需使用 TCP,取消下行注释并注释上一行
# proto tcp
# 虚拟网卡类型(TUN=路由模式,TAP=桥接模式)
dev tun
# 网络拓扑(subnet 是推荐模式)
topology subnet
# ===== 证书和密钥路径 =====
# CA 根证书
ca keys/ca.crt
# 服务器证书
cert keys/server.crt
# 服务器私钥(严格保密!)
key keys/server.key
# Diffie-Hellman 参数
dh keys/dh2048.pem
# TLS 认证密钥(0 = 服务器模式)
tls-auth keys/ta.key 0
# 证书吊销列表(推荐启用)
crl-verify keys/crl.pem
# ===== 加密和安全设置 =====
# 数据通道加密算法(OpenVPN 2.6+ 推荐)
cipher AES-256-GCM
# 支持的加密算法列表(协商用)
data-ciphers AES-256-GCM:AES-128-GCM:AES-256-CBC
# 认证算法
auth SHA256
# TLS 最低版本(增强安全)
tls-version-min 1.2
# TLS 加密套件(可选,更严格的安全策略)
# tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256
# ===== VPN 网络配置 =====
# VPN 子网(服务器自动获得 10.8.0.1)
server 10.8.0.0 255.255.255.0
# 维护客户端 IP 分配关系(重启后保持)
ifconfig-pool-persist /var/log/openvpn/ipp.txt
# ===== 路由设置 =====
# 推送路由到客户端(访问公司内网)
# 假设公司内网是 192.168.1.0/24
#push "route 192.168.1.0 255.255.255.0"
push "route 10.0.0.0 255.255.255.0"
# 推送所有流量走 VPN(全局代理模式,将客户端所有流量都路由到 VPN,可能影响速度)
# push "redirect-gateway def1 bypass-dhcp"
# 推送 DNS 服务器(客户端连接 VPN 后,会使用这些 DNS 服务器解析域名)
# 主 DNS:Windows Server(解析内网域名)
push "dhcp-option DNS 192.168.1.112"
# 备用 DNS:公网 DNS(解析外网域名,提高速度)
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 223.5.5.5" # 阿里 DNS(国内推荐)
# 推送 AD 域后缀
push "dhcp-option DOMAIN example.local"
# 推送 NTP 服务器(统一时间同步)
# push "dhcp-option NTP 192.168.1.1"
# ===== 客户端配置 =====
# 允许客户端之间通信(按需启用)
client-to-client
# 最大客户端连接数(在当前 /24 网段内# 最多可设为 252)
max-clients 200
# 同一证书只允许一个客户端连接(推荐)
# duplicate-cn 默认禁用,生产环境不要启用
# 客户端特定配置目录(为不同客户端分配固定 IP 或特定路由规则),创建客户端证书时的Common name
#/etc/openvpn/server/ccd/client1 文件可配置 client1 的专属设置
client-config-dir ccd
# ===== 连接保持 =====
# 每 10 秒 ping 一次,120 秒无响应则断线
keepalive 10 120
# ===== 压缩设置 =====
# LZ4 压缩(LZ4 压缩算法,减少传输数据量,降低带宽消耗,LZ4 压缩/解压速度快,CPU 占用低)
#注意: 客户端也必须支持 LZ4
compress lz4-v2
push "compress lz4-v2"
# 或禁用压缩(更安全,防 VORACLE 攻击)
# comp-lzo no
# push "comp-lzo no"
# ===== 权限和安全 =====
# 降低运行权限(启动后切换到 nobody 用户,即使 OpenVPN 被攻破,攻击者也只有 nobody 用户权限)
user nobody
group nobody
# 重启后保持密钥和 TUN 设备
persist-key
persist-tun
# ===== 日志设置 =====
# 状态日志(显示连接的客户端)
status /var/log/openvpn/openvpn-status.log
# 运行日志(log-append:追加模式;log: 覆盖模式(每次启动清空旧日志))
log-append /var/log/openvpn/openvpn.log
# 日志详细级别(0=静默, 3=正常, 9=极详细)
verb 3
# 重复消息静默(避免日志刷屏)
mute 20
# ===== 性能优化 =====
# 发送/接收缓冲区大小(字节)
sndbuf 393216
rcvbuf 393216
push "sndbuf 393216"
push "rcvbuf 393216"
# 快速 I/O(减少 CPU 使用)
fast-io
# ===== 管理接口(可选)=====
# 启用管理接口(用于监控,仅本地访问)
management 127.0.0.1 7505
# ===== 其他选项 =====
# UDP 模式下显式退出通知(客户端断开时明确通知服务器)
explicit-exit-notify 1
# 脚本安全级别(允许运行外部脚本,0: 禁止脚本;1: 只允许内置脚本;2: 允许所有脚本(含 shell 命令))
# script-security 2
# 客户端连接/断开时执行自定义脚本
# client-connect /etc/openvpn/server/scripts/client-connect.sh
# client-disconnect /etc/openvpn/server/scripts/client-disconnect.sh
EOF
4.2 配置优化建议
# 根据实际需求调整配置
# 场景1:仅访问内网(推荐,不影响客户端上网)
# 保持当前配置:push "route 192.168.1.0 255.255.255.0"
# 场景2:全局代理(所有流量走 VPN)
# 启用:push "redirect-gateway def1 bypass-dhcp"
# 场景3:双栈支持(IPv4 + IPv6)
# 添加:
# server-ipv6 fd00:abcd::/64
# push "route-ipv6 2000::/3"
# 场景4:多个内网段
# 添加多条 push "route" 指令
4.3 创建客户端特定配置(可选)
# 为 client1 分配固定 IP
cat > /etc/openvpn/server/ccd/client1 <<EOF
# 固定 IP 分配(必须在 server 网段内)
ifconfig-push 192.168.1.1 255.255.255.0
# 推送特定路由
push "route 192.168.1.0 255.255.255.0"
# 限制带宽(单位:字节/秒)
# shaper 1024000
EOF
五、配置网络转发
5.1 启用 IP 转发
# 临时启用
sysctl -w net.ipv4.ip_forward=1
# 永久启用
cat >> /etc/sysctl.conf <<EOF
# OpenVPN IP 转发
net.ipv4.ip_forward = 1
# 可选:IPv6 转发
# net.ipv6.conf.all.forwarding = 1
EOF
# 应用配置
sysctl -p
# 验证
sysctl net.ipv4.ip_forward
# 应显示:net.ipv4.ip_forward = 1
5.2 配置防火墙(firewalld)
# 检查 firewalld 状态
systemctl status firewalld
# 如果未启动,启动 firewalld
systemctl enable --now firewalld
# 获取网卡名称(通常是 eth0 或 ens33)
INTERFACE=$(ip route | grep default | awk '{print $5}')
echo "外网网卡: $INTERFACE"
# 添加 OpenVPN 服务
firewall-cmd --permanent --add-service=openvpn
# 或直接开放端口(如果上述命令无效)
firewall-cmd --permanent --add-port=1194/udp
# 添加 NAT 伪装(关键!)
firewall-cmd --permanent --add-masquerade
# 添加直接规则(NAT 转发)
firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 \
-s 10.8.0.0/24 -o $INTERFACE -j MASQUERADE
# 允许 VPN 流量转发
firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 \
-i tun0 -j ACCEPT
firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 \
-o tun0 -j ACCEPT
# 重载防火墙
firewall-cmd --reload
# 验证规则
firewall-cmd --list-all
firewall-cmd --direct --get-all-rules
[root@localhost easy-rsa]# firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: ens192
sources:
services: cockpit dhcpv6-client openvpn ssh
ports: 1194/udp
protocols:
forward: no
masquerade: yes
forward-ports:
source-ports:
icmp-blocks:
rich rules:
rule priority="1" family="ipv4" source address="192.168.20.222" port port="37017" protocol="tcp" accept
rule priority="10" family="ipv4" port port="37017" protocol="tcp" drop
[root@localhost easy-rsa]# firewall-cmd --direct --get-all-rules
ipv4 nat POSTROUTING 0 -s 10.8.0.0/24 -o ens192 -j MASQUERADE
ipv4 filter FORWARD 0 -i tun0 -j ACCEPT
ipv4 filter FORWARD 0 -o tun0 -j ACCEPT
5.3 配置防火墙(iptables)
# 如果使用 iptables(替代 firewalld)
# 停止 firewalld
systemctl stop firewalld
systemctl disable firewalld
# 安装并启动 iptables
dnf install iptables-services -y
systemctl enable --now iptables
# 添加规则
INTERFACE=$(ip route | grep default | awk '{print $5}')
# NAT 转发规则
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o $INTERFACE -j MASQUERADE
# 允许转发
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A FORWARD -o tun0 -j ACCEPT
# 保存规则
service iptables save
# 验证规则
iptables -t nat -L -n -v | grep 10.8.0.0
5.4 创建防火墙规则持久化脚本(可选,自动执行上述配置)
cat > /etc/openvpn/server/firewall-rules.sh <<'EOF'
#!/bin/bash
# OpenVPN 防火墙规则脚本
# 获取外网网卡
INTERFACE=$(ip route | grep default | awk '{print $5}')
if command -v firewall-cmd &> /dev/null; then
# 使用 firewalld
echo "检测到 firewalld,应用规则..."
firewall-cmd --permanent --add-masquerade
firewall-cmd --permanent --add-service=openvpn
firewall-cmd --permanent --direct --add-rule ipv4 nat POSTROUTING 0 \
-s 10.8.0.0/24 -o $INTERFACE -j MASQUERADE
firewall-cmd --reload
else
# 使用 iptables
echo "使用 iptables,应用规则..."
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o $INTERFACE -j MASQUERADE
iptables -A FORWARD -i tun0 -j ACCEPT
iptables -A FORWARD -o tun0 -j ACCEPT
service iptables save
fi
echo "防火墙规则已应用"
EOF
chmod +x /etc/openvpn/server/firewall-rules.sh
# 执行脚本
/etc/openvpn/server/firewall-rules.sh
5.5 验证网络配置
# 检查 IP 转发
cat /proc/sys/net/ipv4/ip_forward
# 应显示:1
# 检查 NAT 规则
iptables -t nat -L -n -v | grep 10.8.0.0
# 或
firewall-cmd --direct --get-rules ipv4 nat POSTROUTING
# 检查路由
ip route
# 测试 DNS 解析(可选)
nslookup www.baidu.com 8.8.8.8
六、启动和验证服务
6.1 测试配置文件
# 测试配置语法
openvpn --config /etc/openvpn/server/server.conf --test-crypto
# 前台运行测试(查看详细输出,按 Ctrl+C 停止)
openvpn --config /etc/openvpn/server/server.conf
# 观察输出,确保没有错误
# 正确的输出最后会显示:
# Initialization Sequence Completed
6.2 启动服务
# 启动服务
systemctl start openvpn-server@server
# 设置开机自启
systemctl enable openvpn-server@server
# 检查服务状态
systemctl status openvpn-server@server
# 应显示:
# Active: active (running)
# Status: "Initialization Sequence Completed"
6.3 验证服务运行
# 检查进程
ps aux | grep openvpn
# 检查监听端口
ss -tunlp | grep 1194
# 应显示:udp UNCONN 0 0 *:1194 *:*
# 或使用 netstat
netstat -tunlp | grep 1194
# 检查 TUN 设备
ip addr show tun0
# 应显示:inet 10.8.0.1/24
# 检查路由表
ip route | grep tun0
# 应显示:10.8.0.0/24 dev tun0
# 从服务器 ping VPN 网关
ping -c 3 10.8.0.1
6.4 查看日志
# 查看实时日志
tail -f /var/log/openvpn/openvpn.log
# 查看 systemd 日志
journalctl -u openvpn-server@server -f
# 查看最近 50 行日志
journalctl -u openvpn-server@server -n 50
# 查看状态文件(显示连接的客户端)
cat /var/log/openvpn/openvpn-status.log
七、生成客户端配置
7.1 创建客户端配置目录
mkdir -p /etc/openvpn/client-configs/{files,keys,base}
cd /etc/openvpn/client-configs
7.2 创建客户端配置模板
# 获取服务器公网 IP
SERVER_IP=$(curl -s ifconfig.me)
echo "服务器公网 IP: $SERVER_IP"
# 如果无法获取,手动设置
# SERVER_IP="YOUR_PUBLIC_IP"
cat > /etc/openvpn/client-configs/base.conf <<EOF
##############################################
# OpenVPN 客户端配置文件
# 服务器: $SERVER_IP
# 生成时间: $(date)
##############################################
# 客户端模式
client
# 使用 TUN 设备(与服务器一致)
dev tun
# 协议(与服务器一致)
proto udp
# 如服务器使用 TCP,改为:proto tcp
# 服务器地址和端口
remote $SERVER_IP 1194
# 如有多个服务器(高可用)
# remote server1.example.com 1194
# remote server2.example.com 1194
# remote-random
# 保持尝试连接
resolv-retry infinite
# 不绑定本地端口
nobind
# 加密设置(与服务器一致)
cipher AES-256-GCM
auth SHA256
# TLS 认证(方向为 1,与服务器的 0 对应)
key-direction 1
# 压缩设置(与服务器一致)
compress lz4-v2
# 重启后保持
persist-key
persist-tun
# 降低权限(Linux/macOS 客户端)
# user nobody
# group nobody
# 日志级别
verb 3
# 静默重复消息
mute 20
# 脚本安全级别(如需运行脚本)
# script-security 2
# 验证服务器证书(增强安全)
remote-cert-tls server
# 以下内容由生成脚本自动添加
# <ca>...</ca>
# <cert>...</cert>
# <key>...</key>
# <tls-auth>...</tls-auth>
EOF
7.3 创建客户端配置生成脚本(改进版)
cat > /etc/openvpn/client-configs/make_config.sh <<'EOF'
#!/bin/bash
#################################################
# OpenVPN 客户端配置生成脚本
# 用法: ./make_config.sh <client_name>
#################################################
# 配置变量
BASE_CONFIG="/etc/openvpn/client-configs/base.conf"
OUTPUT_DIR="/etc/openvpn/client-configs/files"
KEY_DIR="/etc/openvpn/server/easy-rsa/pki"
TA_KEY="/etc/openvpn/server/keys/ta.key"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 检查参数
if [ $# -ne 1 ]; then
echo -e "${RED}用法: $0 <客户端名称>${NC}"
echo -e "${YELLOW}示例: $0 client1${NC}"
exit 1
fi
CLIENT_NAME=$1
# 检查证书是否存在
if [ ! -f "$KEY_DIR/issued/${CLIENT_NAME}.crt" ]; then
echo -e "${RED}错误:客户端证书不存在: ${CLIENT_NAME}.crt${NC}"
echo -e "${YELLOW}请先生成客户端证书:${NC}"
echo " cd /etc/openvpn/server/easy-rsa"
echo " ./easyrsa gen-req $CLIENT_NAME nopass"
echo " ./easyrsa sign-req client $CLIENT_NAME"
exit 1
fi
# 检查私钥是否存在
if [ ! -f "$KEY_DIR/private/${CLIENT_NAME}.key" ]; then
echo -e "${RED}错误:客户端私钥不存在: ${CLIENT_NAME}.key${NC}"
exit 1
fi
# 创建输出目录
mkdir -p ${OUTPUT_DIR}
# 生成配置文件
OUTPUT_FILE="${OUTPUT_DIR}/${CLIENT_NAME}.ovpn"
# 复制基础配置
cat ${BASE_CONFIG} > ${OUTPUT_FILE}
# 添加证书和密钥(内嵌方式)
echo "" >> ${OUTPUT_FILE}
echo "<ca>" >> ${OUTPUT_FILE}
cat ${KEY_DIR}/ca.crt >> ${OUTPUT_FILE}
echo "</ca>" >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
echo "<cert>" >> ${OUTPUT_FILE}
# 提取证书部分(去掉额外内容)
sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' ${KEY_DIR}/issued/${CLIENT_NAME}.crt >> ${OUTPUT_FILE}
echo "</cert>" >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
echo "<key>" >> ${OUTPUT_FILE}
cat ${KEY_DIR}/private/${CLIENT_NAME}.key >> ${OUTPUT_FILE}
echo "</key>" >> ${OUTPUT_FILE}
echo "" >> ${OUTPUT_FILE}
echo "<tls-auth>" >> ${OUTPUT_FILE}
cat ${TA_KEY} >> ${OUTPUT_FILE}
echo "</tls-auth>" >> ${OUTPUT_FILE}
# 设置权限
chmod 600 ${OUTPUT_FILE}
# 成功提示
echo -e "${GREEN}===== 客户端配置生成成功 =====${NC}"
echo -e "${GREEN}文件位置: ${OUTPUT_FILE}${NC}"
echo ""
echo -e "${YELLOW}传输方式:${NC}"
echo " 1. SCP 传输:"
echo " scp ${OUTPUT_FILE} user@client:/path/"
echo ""
echo " 2. 查看内容(复制粘贴):"
echo " cat ${OUTPUT_FILE}"
echo ""
echo " 3. 生成二维码(移动设备导入):"
echo " qrencode -t ansiutf8 < ${OUTPUT_FILE}"
echo ""
echo -e "${YELLOW}Windows 客户端:${NC}"
echo " 将 .ovpn 文件复制到 C:\\Program Files\\OpenVPN\\config\\"
echo ""
echo -e "${YELLOW}Linux 客户端:${NC}"
echo " sudo openvpn --config ${CLIENT_NAME}.ovpn"
echo ""
echo -e "${YELLOW}移动设备(Android/iOS):${NC}"
echo " 使用 OpenVPN Connect 应用导入 .ovpn 文件"
echo ""
EOF
chmod +x /etc/openvpn/client-configs/make_config.sh
7.4 生成客户端配置文件
# 进入配置目录
cd /etc/openvpn/client-configs
# 为 client1 生成配置
./make_config.sh client1
# 为多个客户端批量生成
for client in alice bob charlie manager; do
# 先生成证书(如果还没生成)
cd /etc/openvpn/server/easy-rsa
./easyrsa gen-req $client nopass
./easyrsa sign-req client $client
# 生成配置文件
cd /etc/openvpn/client-configs
./make_config.sh $client
done
# 查看生成的文件
ls -lh /etc/openvpn/client-configs/files/
7.5 创建配置下载服务(可选)
# 安装 Python3(如果未安装)
dnf install python3 -y
# 创建简单的 HTTP 服务器脚本
cat > /etc/openvpn/client-configs/start-http-server.sh <<'EOF'
#!/bin/bash
# 临时 HTTP 服务器,用于下载客户端配置
cd /etc/openvpn/client-configs/files
python3 -m http.server 8000 --bind 0.0.0.0
EOF
chmod +x /etc/openvpn/client-configs/start-http-server.sh
# 使用方法(临时):
# ./start-http-server.sh
# 然后在浏览器访问:http://服务器IP:8000/client1.ovpn
# ⚠️ 注意:这只是临时方案,下载后立即停止服务!
# 生产环境应使用 HTTPS 或 SFTP
八、客户端连接测试
8.1 Linux 客户端
# 安装 OpenVPN 客户端
# Debian/Ubuntu
apt update && apt install openvpn -y
# RHEL/CentOS/Anolis
dnf install epel-release -y
dnf install openvpn -y
# 传输配置文件(在服务器执行)
scp /etc/openvpn/client-configs/files/client1.ovpn user@client_ip:/tmp/
# 在客户端连接(前台测试)
sudo openvpn --config /tmp/client1.ovpn
# 后台运行
sudo openvpn --config /tmp/client1.ovpn --daemon
# 使用 systemd 管理(推荐)
sudo cp /tmp/client1.ovpn /etc/openvpn/client/client1.conf
sudo systemctl start openvpn-client@client1
sudo systemctl enable openvpn-client@client1
# 查看状态
sudo systemctl status openvpn-client@client1
8.2 Windows 客户端
1. 下载 OpenVPN GUI
https://openvpn.net/community-downloads/
2. 安装 OpenVPN GUI(管理员权限)
3. 将 client1.ovpn 复制到配置目录:
C:\Program Files\OpenVPN\config\
4. 右键任务栏 OpenVPN 图标,选择 "连接"
5. 查看连接日志:
右键 → "查看日志"
8.3 macOS 客户端
1. 下载 Tunnelblick
https://tunnelblick.net/downloads.html
2. 安装 Tunnelblick
3. 双击 client1.ovpn 文件,自动导入配置
4. 点击 Tunnelblick 图标,选择 "连接"
8.4 Android 客户端
1. 在 Google Play 安装 "OpenVPN Connect"
2. 传输 .ovpn 文件到手机
- 方法1:通过邮件发送
- 方法2:通过 USB 传输
- 方法3:扫描二维码(需安装 qrencode)
3. 打开 OpenVPN Connect → 导入 → 选择 .ovpn 文件
4. 点击连接
8.5 iOS 客户端
1. 在 App Store 安装 "OpenVPN Connect"
2. 传输 .ovpn 文件
- 通过 AirDrop
- 通过邮件附件
- 通过 iCloud Drive
3. 打开文件,选择 "导入到 OpenVPN"
4. 点击连接
8.6 验证客户端连接
# ===== 在客户端执行 =====
# 检查 VPN 接口
ip addr show tun0
# 或 Windows: ipconfig /all
# 应显示分配的 IP(如 10.8.0.6)
# 检查路由
ip route
# 应显示:10.8.0.0/24 dev tun0
# Ping VPN 服务器
ping 10.8.0.1
# Ping 内网服务器(如 192.168.1.100)
ping 192.168.1.100
# 检查公网 IP(验证是否走 VPN)
curl ifconfig.me
# 应显示为 OpenVPN 服务器的公网 IP
# 测试 DNS 解析
nslookup www.baidu.com
# Trace 路由
traceroute -n 8.8.8.8
# 第一跳应该是 10.8.0.1
8.7 在服务器查看已连接客户端
# 查看状态文件
cat /var/log/openvpn/openvpn-status.log
# 示例输出:
# CLIENT_LIST,client1,10.8.0.6,192.168.1.100:53241,11223344,22334455,Sun Dec 3 18:30:00 2025
# 实时监控连接
watch -n 2 'cat /var/log/openvpn/openvpn-status.log | grep CLIENT_LIST'
# 查看实时日志
tail -f /var/log/openvpn/openvpn.log
# 使用管理接口查询(如果启用)
echo "status" | nc 127.0.0.1 7505
九、证书管理
9.1 查看证书信息
cd /etc/openvpn/server/easy-rsa
# 查看 CA 证书
openssl x509 -in pki/ca.crt -noout -text
# 查看证书有效期
openssl x509 -in pki/issued/client1.crt -noout -dates
# 查看所有已签发证书
cat pki/index.txt
# 查看证书列表
ls -lh pki/issued/
# 查看私钥
ls -lh pki/private/
9.2 吊销客户端证书
cd /etc/openvpn/server/easy-rsa
# 吊销证书(假设吊销 client1)
./easyrsa revoke client1
# 提示确认,输入:yes
# 重新生成 CRL
./easyrsa gen-crl
# 更新服务器的 CRL
cp pki/crl.pem /etc/openvpn/server/keys/
# 重启 OpenVPN 服务
systemctl restart openvpn-server@server
# 验证 CRL
openssl crl -in /etc/openvpn/server/keys/crl.pem -noout -text
9.3 续期证书
# OpenVPN 证书续期需要重新签发
# 方法1:重新生成(推荐)
cd /etc/openvpn/server/easy-rsa
# 先吊销旧证书(可选)
# ./easyrsa revoke client1
# 删除旧证书文件
rm -f pki/issued/client1.crt
rm -f pki/private/client1.key
rm -f pki/reqs/client1.req
# 重新生成
./easyrsa gen-req client1 nopass
./easyrsa sign-req client client1
# 重新生成客户端配置
cd /etc/openvpn/client-configs
./make_config.sh client1
# 方法2:延长有效期(修改 vars 后重新签发)
# 编辑 vars,增加 EASYRSA_CERT_EXPIRE
# 然后重新执行上述步骤
9.4 备份 PKI
# 创建备份脚本
cat > /root/backup-openvpn-pki.sh <<'EOF'
#!/bin/bash
# OpenVPN PKI 备份脚本
BACKUP_DIR="/backup/openvpn"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/openvpn-pki-$DATE.tar.gz"
# 创建备份目录
mkdir -p $BACKUP_DIR
# 备份 PKI
tar -czf $BACKUP_FILE \
/etc/openvpn/server/easy-rsa/pki \
/etc/openvpn/server/server.conf \
/etc/openvpn/server/keys
# 保留最近 7 天的备份
find $BACKUP_DIR -name "openvpn-pki-*.tar.gz" -mtime +7 -delete
echo "备份完成: $BACKUP_FILE"
ls -lh $BACKUP_FILE
EOF
chmod +x /root/backup-openvpn-pki.sh
# 手动执行
/root/backup-openvpn-pki.sh
# 添加到 crontab(每天凌晨 2 点备份)
crontab -e
# 添加:0 2 * * * /root/backup-openvpn-pki.sh >> /var/log/openvpn-backup.log 2>&1
9.5 恢复 PKI
# 从备份恢复
cd /
tar -xzf /backup/openvpn/openvpn-pki-20251203_020000.tar.gz
# 重启服务
systemctl restart openvpn-server@server
十、安全加固
10.1 启用 TLS-Crypt(推荐,替代 TLS-Auth)
# TLS-Crypt 比 TLS-Auth 更安全,加密控制通道
# 生成 TLS-Crypt 密钥
cd /etc/openvpn/server/keys
openvpn --genkey secret tc.key
# 修改服务器配置
# 将 tls-auth 改为 tls-crypt
sed -i 's/tls-auth keys\/ta.key 0/tls-crypt keys\/tc.key/' /etc/openvpn/server/server.conf
# 修改客户端配置模板
sed -i 's/key-direction 1//' /etc/openvpn/client-configs/base.conf
sed -i 's/<tls-auth>/<tls-crypt>/' /etc/openvpn/client-configs/base.conf
sed -i 's/<\/tls-auth>/<\/tls-crypt>/' /etc/openvpn/client-configs/base.conf
# 重新生成客户端配置
# 并重启服务器
systemctl restart openvpn-server@server
10.2 限制 TLS 加密套件
# 编辑服务器配置
cat >> /etc/openvpn/server/server.conf <<'EOF'
# 限制 TLS 加密套件(仅允许强加密)
tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
EOF
# 重启服务
systemctl restart openvpn-server@server
10.3 启用客户端连接日志审计
# 创建脚本目录
mkdir -p /etc/openvpn/server/scripts
# 创建连接日志脚本
cat > /etc/openvpn/server/scripts/client-connect.sh <<'EOF'
#!/bin/bash
# 客户端连接日志
LOG_FILE="/var/log/openvpn/connections.log"
DATE=$(date "+%Y-%m-%d %H:%M:%S")
echo "$DATE | CONNECT | Client: $common_name | IP: $trusted_ip:$trusted_port | VPN_IP: $ifconfig_pool_remote_ip" >> $LOG_FILE
EOF
cat > /etc/openvpn/server/scripts/client-disconnect.sh <<'EOF'
#!/bin/bash
# 客户端断开日志
LOG_FILE="/var/log/openvpn/connections.log"
DATE=$(date "+%Y-%m-%d %H:%M:%S")
echo "$DATE | DISCONNECT | Client: $common_name | Duration: ${time_duration}s | RX: ${bytes_received} bytes | TX: ${bytes_sent} bytes" >> $LOG_FILE
EOF
chmod +x /etc/openvpn/server/scripts/*.sh
# 在服务器配置中启用脚本
cat >> /etc/openvpn/server/server.conf <<'EOF'
# 客户端连接/断开脚本
script-security 2
client-connect /etc/openvpn/server/scripts/client-connect.sh
client-disconnect /etc/openvpn/server/scripts/client-disconnect.sh
EOF
# 创建日志文件
touch /var/log/openvpn/connections.log
chmod 644 /var/log/openvpn/connections.log
# 重启服务
systemctl restart openvpn-server@server
# 查看连接日志
tail -f /var/log/openvpn/connections.log
10.4 限制客户端访问范围
# 方法1:使用客户端配置目录(CCD)
# 为 client1 创建限制配置
cat > /etc/openvpn/server/ccd/client1 <<EOF
# 仅允许访问特定网段
iroute 192.168.100.0 255.255.255.0
# 禁止访问其他网段(通过不推送路由实现)
EOF
# 方法2:使用 iptables 规则
# 允许 client1(10.8.0.10)访问 192.168.1.0/24
iptables -A FORWARD -s 10.8.0.10 -d 192.168.1.0/24 -j ACCEPT
# 禁止访问其他内网
iptables -A FORWARD -s 10.8.0.10 -d 192.168.0.0/16 -j REJECT
# 保存规则
service iptables save
10.5 启用双因素认证(可选)
# 安装 Google Authenticator PAM 模块
dnf install google-authenticator qrencode -y
# 配置 PAM
cat >> /etc/pam.d/openvpn <<'EOF'
auth required pam_google_authenticator.so
EOF
# 在服务器配置中启用
cat >> /etc/openvpn/server/server.conf <<'EOF'
# 启用 PAM 认证
plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn
EOF
# 为每个用户生成密钥
# su - openvpn_user
# google-authenticator
# 重启服务
systemctl restart openvpn-server@server
十一、监控和维护
11.1 创建监控脚本
cat > /usr/local/bin/openvpn-monitor.sh <<'EOF'
#!/bin/bash
# OpenVPN 监控脚本
echo "========== OpenVPN 服务监控 =========="
echo "时间: $(date)"
echo ""
# 1. 服务状态
echo "【服务状态】"
systemctl is-active openvpn-server@server && echo "✓ 服务运行正常" || echo "✗ 服务未运行"
echo ""
# 2. 监听端口
echo "【监听端口】"
ss -tunlp | grep 1194 || echo "✗ 端口未监听"
echo ""
# 3. TUN 设备
echo "【TUN 设备】"
ip addr show tun0 2>/dev/null | grep inet || echo "✗ TUN 设备未创建"
echo ""
# 4. 已连接客户端
echo "【已连接客户端】"
CLIENT_COUNT=$(grep "^CLIENT_LIST" /var/log/openvpn/openvpn-status.log 2>/dev/null | wc -l)
echo "当前连接数: $CLIENT_COUNT"
grep "^CLIENT_LIST" /var/log/openvpn/openvpn-status.log 2>/dev/null | \
awk -F',' '{print " - "$2" ("$3")"}' || echo " 无客户端连接"
echo ""
# 5. 流量统计
echo "【流量统计】"
if [ -f /sys/class/net/tun0/statistics/rx_bytes ]; then
RX=$(cat /sys/class/net/tun0/statistics/rx_bytes)
TX=$(cat /sys/class/net/tun0/statistics/tx_bytes)
echo " 接收: $(numfmt --to=iec-i --suffix=B $RX)"
echo " 发送: $(numfmt --to=iec-i --suffix=B $TX)"
else
echo " 无法获取流量统计"
fi
echo ""
# 6. 最近错误日志
echo "【最近错误】"
tail -10 /var/log/openvpn/openvpn.log | grep -i error || echo " 无错误"
echo ""
# 7. 系统资源
echo "【系统资源】"
echo " CPU: $(top -bn1 | grep "Cpu(s)" | awk '{print $2}')%"
echo " 内存: $(free -h | grep Mem | awk '{print $3"/"$2}')"
echo ""
echo "========================================="
EOF
chmod +x /usr/local/bin/openvpn-monitor.sh
# 执行监控
/usr/local/bin/openvpn-monitor.sh
# 添加到 crontab(每小时执行一次)
crontab -e
# 添加:0 * * * * /usr/local/bin/openvpn-monitor.sh >> /var/log/openvpn-monitor.log
11.2 日志轮转配置
# 创建 logrotate 配置
cat > /etc/logrotate.d/openvpn <<'EOF'
/var/log/openvpn/*.log {
daily
rotate 30
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
/bin/systemctl reload openvpn-server@server > /dev/null 2>&1 || true
endscript
}
EOF
# 测试 logrotate
logrotate -d /etc/logrotate.d/openvpn
11.3 性能优化
# 调整系统参数
cat >> /etc/sysctl.conf <<'EOF'
# OpenVPN 性能优化
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.core.rmem_default = 67108864
net.core.wmem_default = 67108864
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_congestion_control = bbr
EOF
sysctl -p
11.4 告警通知(可选)
# 安装邮件工具
dnf install mailx -y
# 创建告警脚本
cat > /usr/local/bin/openvpn-alert.sh <<'EOF'
#!/bin/bash
# OpenVPN 告警脚本
ADMIN_EMAIL="admin@example.com"
# 检查服务状态
if ! systemctl is-active --quiet openvpn-server@server; then
echo "OpenVPN 服务已停止!" | mail -s "OpenVPN 告警" $ADMIN_EMAIL
systemctl start openvpn-server@server
fi
# 检查 TUN 设备
if ! ip addr show tun0 &>/dev/null; then
echo "TUN 设备异常!" | mail -s "OpenVPN 告警" $ADMIN_EMAIL
fi
EOF
chmod +x /usr/local/bin/openvpn-alert.sh
# 添加到 crontab(每 5 分钟检查一次)
crontab -e
# */5 * * * * /usr/local/bin/openvpn-alert.sh
十二、常见问题排查
12.1 服务无法启动
# 问题:systemctl start 失败
# 排查步骤:
# 1. 查看详细日志
journalctl -xeu openvpn-server@server
# 2. 检查配置文件语法
openvpn --config /etc/openvpn/server/server.conf --test-crypto
# 3. 前台运行查看详细错误
openvpn --config /etc/openvpn/server/server.conf
# 常见错误:
# 错误1:证书文件不存在
# 解决:检查 keys 目录下文件是否齐全
# 错误2:权限问题
# 解决:chmod 600 /etc/openvpn/server/keys/server.key
# 错误3:端口被占用
# 解决:ss -tunlp | grep 1194 # 查找占用进程
12.2 客户端无法连接
# 问题:客户端连接超时
# 服务器端排查:
# 1. 检查防火墙
firewall-cmd --list-all | grep 1194
iptables -L -n | grep 1194
# 2. 检查端口监听
ss -tunlp | grep 1194
# 3. 检查服务状态
systemctl status openvpn-server@server
# 4. 检查日志
tail -f /var/log/openvpn/openvpn.log
# 客户端排查:
# 1. Ping 服务器 IP
ping 服务器IP
# 2. Telnet 测试端口
telnet 服务器IP 1194
# 3. 检查客户端日志
# Windows: C:\Program Files\OpenVPN\log\
# Linux: journalctl -u openvpn-client@client1
12.3 连接成功但无法访问内网
# 问题:VPN 连接成功,但 ping 不通内网
# 排查步骤:
# 1. 检查服务器 IP 转发
cat /proc/sys/net/ipv4/ip_forward
# 应该是 1
# 2. 检查 NAT 规则
iptables -t nat -L -n -v | grep 10.8.0.0
# 3. 检查路由
# 在客户端执行:
ip route | grep tun0
# 4. 检查防火墙
iptables -L FORWARD -n -v
# 5. 在服务器抓包
tcpdump -i tun0 -n icmp
# 解决方案:
# 重新应用 NAT 规则
INTERFACE=$(ip route | grep default | awk '{print $5}')
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o $INTERFACE -j MASQUERADE
service iptables save
12.4 客户端频繁断线
# 问题:VPN 连接不稳定
# 排查:
# 1. 检查 keepalive 设置
grep keepalive /etc/openvpn/server/server.conf
# 2. 调整参数(在服务器配置中)
keepalive 5 60 # 降低超时时间
# 3. 检查网络质量
# 在客户端执行:
ping -i 0.5 10.8.0.1 # 测试延迟和丢包
# 4. 调整 MTU(如果有分片问题)
# 在服务器配置中添加:
mssfix 1400
tun-mtu 1500
# 重启服务
systemctl restart openvpn-server@server
12.5 性能问题(速度慢)
# 排查:
# 1. 检查加密算法
# 使用 AES-128-GCM 替代 AES-256-GCM(速度更快)
# 2. 禁用压缩
# 在某些情况下压缩会降低性能
# 3. 调整缓冲区
sndbuf 393216
rcvbuf 393216
# 4. 使用 UDP 而不是 TCP
# 5. 测试带宽
# 在客户端执行:
iperf3 -c 10.8.0.1
12.6 证书过期
# 问题:证书过期导致无法连接
# 检查证书有效期
openssl x509 -in /etc/openvpn/server/keys/server.crt -noout -dates
# 解决方案:续期证书(参见 9.3 节)
cd /etc/openvpn/server/easy-rsa
./easyrsa renew server nopass
cp pki/issued/server.crt /etc/openvpn/server/keys/
systemctl restart openvpn-server@server
12.7 DNS 解析问题
# 问题:连接 VPN 后无法解析域名
# 在客户端检查 DNS
cat /etc/resolv.conf # Linux
ipconfig /all # Windows
# 解决方案:
# 1. 在服务器配置中推送正确的 DNS
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 114.114.114.114"
# 2. 检查客户端是否应用了 DNS
# Linux 客户端可能需要:
sudo resolvconf -u
十三、工作原理详解
13.1 连接建立流程
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ 客户端 │ │ OpenVPN 服务器│ │ 内网服务器 │
│ (家里电脑) │ │ (公司 VPS) │ │ (192.168.1.x)│
└──────┬──────┘ └──────┬───────┘ └──────┬──────┘
│ │ │
│ 1. TCP/UDP 连接到 1194 端口 │ │
│─────────────────────────────────>│ │
│ │ │
│ 2. TLS 握手(交换证书) │ │
│<────────────────────────────────>│ │
│ - 验证服务器证书 │ │
│ - 验证客户端证书 │ │
│ - 验证 tls-auth HMAC │ │
│ │ │
│ 3. 协商加密参数 │ │
│<────────────────────────────────>│ │
│ - 加密算法: AES-256-GCM │ │
│ - 认证算法: SHA256 │ │
│ - DH 密钥交换 │ │
│ │ │
│ 4. 建立加密隧道 │ │
│══════════════════════════════════│ │
│ 创建 tun0 (10.8.0.6) │ 创建 tun0 (10.8.0.1) │
│ │ │
│ 5. 接收路由推送 │ │
│<─────────────────────────────────│ │
│ route add 192.168.1.0/24 │ │
│ via 10.8.0.1 │ │
│ │ │
│ 6. 访问内网 (192.168.1.100) │ │
│══════════════════════════════════>│ 7. NAT 转换并转发 │
│ 加密数据包 │──────────────────────────────>│
│ 外层: UDP 到公网IP:1194 │ 源IP: 192.168.1.1 │
│ 内层: 10.8.0.6 -> 192.168.1.100 │ 目标IP: 192.168.1.100 │
│ │ │
│ │ 8. 返回数据 │
│ │<──────────────────────────────│
│ 9. 加密后返回 │ │
│<══════════════════════════════════│ │
│ │ │
13.2 数据包封装过程
原始数据包:
┌──────────────────────────────────────────────────┐
│ IP Header: 10.8.0.6 → 192.168.1.100 │
│ TCP/UDP Header │
│ Application Data (HTTP/SSH/etc.) │
└──────────────────────────────────────────────────┘
↓ OpenVPN 加密
┌──────────────────────────────────────────────────┐
│ AES-256-GCM 加密 │
│ HMAC-SHA256 认证 │
│ [加密后的原始数据包] │
└──────────────────────────────────────────────────┘
↓ UDP/TCP 封装
┌──────────────────────────────────────────────────┐
│ 外层 IP: 客户端公网IP → 服务器公网IP │
│ UDP Header: 源端口随机 → 目标端口 1194 │
│ OpenVPN Header │
│ [加密数据] │
└──────────────────────────────────────────────────┘
↓ 互联网传输
↓ 服务器解密
┌──────────────────────────────────────────────────┐
│ IP Header: 10.8.0.6 → 192.168.1.100 │
│ TCP/UDP Header │
│ Application Data │
└──────────────────────────────────────────────────┘
↓ NAT 转换
┌──────────────────────────────────────────────────┐
│ IP Header: 192.168.1.1 → 192.168.1.100 │ ← 源IP改为服务器内网IP
│ TCP/UDP Header │
│ Application Data │
└──────────────────────────────────────────────────┘
↓ 转发到内网服务器
13.3 关键组件作用
| 组件 | 作用 | 安全级别 |
|---|---|---|
| ca.crt | CA 根证书,验证服务器和客户端证书 | 公开 |
| server.crt | 服务器证书,证明服务器身份 | 公开 |
| server.key | 服务器私钥,绝对保密 | 🔒 私密 |
| dh.pem | Diffie-Hellman 参数,密钥交换 | 公开 |
| ta.key | TLS 认证密钥,防 DDoS 和端口扫描 | 🔒 私密 |
| client.crt | 客户端证书,证明客户端身份 | 半公开 |
| client.key | 客户端私钥,绝对保密 | 🔒 私密 |
13.4 安全机制
多层安全防护:
├── 第1层: TLS 证书双向认证
│ ├── 服务器验证客户端证书
│ └── 客户端验证服务器证书
│
├── 第2层: tls-auth HMAC 验证
│ ├── 防止端口扫描
│ ├── 防止 DDoS 攻击
│ └── 丢弃非法数据包(在 TLS 握手前)
│
├── 第3层: 数据加密
│ ├── AES-256-GCM(对称加密)
│ └── 每个会话独立密钥
│
├── 第4层: 数据完整性
│ ├── HMAC-SHA256 认证
│ └── 防止数据篡改
│
└── 第5层: 前向保密
└── Diffie-Hellman 密钥交换
即使私钥泄露,历史会话仍然安全
13.5 NAT 转换详解
# 客户端访问内网服务器的 NAT 过程
# 第1步:客户端发送数据包
源IP: 10.8.0.6 (VPN 客户端)
目标IP: 192.168.1.100 (内网服务器)
# 第2步:OpenVPN 服务器接收并解密
数据包到达 tun0 接口
# 第3步:Linux 内核路由决策
ip route 查询:192.168.1.100 在内网,通过 eth0 转发
# 第4步:iptables POSTROUTING(NAT 转换)
规则:iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
效果:
源IP: 10.8.0.6 → 192.168.1.1 (服务器内网IP)
目标IP: 192.168.1.100 (不变)
# 第5步:数据包从 eth0 发出到内网
源IP: 192.168.1.1
目标IP: 192.168.1.100
# 第6步:内网服务器响应
源IP: 192.168.1.100
目标IP: 192.168.1.1
# 第7步:服务器接收响应,iptables 反向 NAT
源IP: 192.168.1.100 (不变)
目标IP: 192.168.1.1 → 10.8.0.6
# 第8步:OpenVPN 加密并通过隧道返回客户端
13.6 性能指标
| 项目 | 典型值 | 说明 |
|---|---|---|
| 延迟增加 | 10-30ms | 取决于加密算法和服务器性能 |
| 吞吐量 | 50-500 Mbps | 取决于 CPU、加密算法、网络带宽 |
| CPU 使用 | 5-20% | AES-NI 硬件加速可大幅降低 |
| 内存占用 | 10-50MB | 每个客户端约 1-2MB |
| 连接建立时间 | 1-3 秒 | 包括 TLS 握手和密钥交换 |
十四、快速检查清单
# 创建一键检查脚本
cat > /usr/local/bin/openvpn-check.sh <<'EOF'
#!/bin/bash
echo "===== OpenVPN 完整检查 ====="
echo -e "\n[1] 服务状态:"
systemctl is-active openvpn-server@server && echo "✓ 运行中" || echo "✗ 未运行"
echo -e "\n[2] 监听端口:"
ss -tunlp | grep 1194 && echo "✓ 正常监听" || echo "✗ 未监听"
echo -e "\n[3] TUN 设备:"
ip addr show tun0 2>/dev/null && echo "✓ 已创建" || echo "✗ 未创建"
echo -e "\n[4] IP 转发:"
[ $(cat /proc/sys/net/ipv4/ip_forward) -eq 1 ] && echo "✓ 已启用" || echo "✗ 未启用"
echo -e "\n[5] NAT 规则:"
iptables -t nat -L -n | grep -q 10.8.0.0 && echo "✓ 已配置" || echo "✗ 未配置"
echo -e "\n[6] 证书文件:"
for file in ca.crt server.crt server.key dh2048.pem ta.key; do
[ -f /etc/openvpn/server/keys/$file ] && echo "✓ $file" || echo "✗ $file 缺失"
done
echo -e "\n[7] 已连接客户端:"
grep "^CLIENT_LIST" /var/log/openvpn/openvpn-status.log 2>/dev/null | wc -l
echo -e "\n[8] 最近错误:"
tail -10 /var/log/openvpn/openvpn.log | grep -i error || echo "✓ 无错误"
echo -e "\n===== 检查完成 ====="
EOF
chmod +x /usr/local/bin/openvpn-check.sh
/usr/local/bin/openvpn-check.sh
十五、总结
✅ 部署流程完整性检查
| 步骤 | 状态 | 说明 |
|---|---|---|
| 环境准备 | ✅ | 系统检查、依赖安装 |
| OpenVPN 编译 | ✅ | 源码编译、systemd 配置 |
| PKI 证书体系 | ✅ | CA、服务器、客户端证书 |
| 服务器配置 | ✅ | 完整的 server.conf 配置 |
| 网络转发 | ✅ | IP 转发、NAT、防火墙 |
| 客户端配置 | ✅ | 配置生成脚本、多平台支持 |
| 连接测试 | ✅ | 各平台客户端连接指南 |
| 证书管理 | ✅ | 吊销、续期、备份 |
| 安全加固 | ✅ | TLS-Crypt、审计日志、访问控制 |
| 监控维护 | ✅ | 监控脚本、日志轮转、性能优化 |
| 故障排查 | ✅ | 常见问题和解决方案 |
| 工作原理 | ✅ | 详细的技术原理说明 |
📝 关键改进点
- 完整的证书生成流程:补充了
gen-req+sign-req的完整步骤 - 客户端配置生成:提供了改进的自动化脚本
- 安全加固:增加了 TLS-Crypt、审计日志、访问控制等内容
- 监控和维护:提供了完整的监控脚本和日志管理
- 故障排查:列举了常见问题和详细的解决方案
- 工作原理:增加了详细的技术原理图解
🚀 快速开始(精简版)
# 1. 安装依赖
dnf install -y epel-release easy-rsa openssl-devel lz4-devel
# 2. 编译安装 OpenVPN
wget https://github.com/OpenVPN/openvpn/releases/download/v2.6.17/openvpn-2.6.17.tar.gz
tar -zxf openvpn-2.6.17.tar.gz && cd openvpn-2.6.17
./configure --prefix=/usr/local --sysconfdir=/etc/openvpn --enable-systemd
make -j$(nproc) && make install
# 3. 配置 PKI
cd /etc/openvpn/server && mkdir easy-rsa && cd easy-rsa
cp -r /usr/share/easy-rsa/3/* .
./easyrsa init-pki
./easyrsa build-ca nopass
./easyrsa build-server-full server nopass
./easyrsa gen-dh
openvpn --genkey secret pki/ta.key
# 4. 复制证书
mkdir -p /etc/openvpn/server/keys
cp pki/{ca.crt,issued/server.crt,private/server.key,dh.pem,ta.key} /etc/openvpn/server/keys/
chmod 600 /etc/openvpn/server/keys/server.key
# 5. 创建配置文件(使用本文档第四节的完整配置)
# 6. 启用网络转发
sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
# 7. 配置防火墙
firewall-cmd --permanent --add-masquerade
firewall-cmd --permanent --add-service=openvpn
firewall-cmd --reload
# 8. 启动服务
systemctl enable --now openvpn-server@server
# 9. 生成客户端证书和配置
cd /etc/openvpn/server/easy-rsa
./easyrsa build-client-full client1 nopass
/etc/openvpn/client-configs/make_config.sh client1
OpenVPN LDAP docker部署:仓库地址
基于 OpenVPN 2.6.17 + LDAP 认证的 Docker 容器化部署方案。
特性
- ✅ 兼容老版本证书:完全兼容 OpenVPN 2.4 及更早版本生成的证书
- ✅ LDAP 认证:支持 Windows Active Directory 认证
- ✅ 容器化部署:基于 Docker Compose,快速部署
- ✅ 配置灵活:使用 .env 文件管理敏感信息
目录结构
.
├── docker-compose.yml # 运行时配置
├── .env # 环境变量配置(LDAP密码等)
├── openvpn-ldap_2.6.17.tar # 构建好的镜像
├── README.md # 本文档
├── setup-permissions.sh # 权限设置脚本
├── ENV配置说明.md # 详细配置文档
│
├── config/ # OpenVPN配置文件
│ └── server.conf
├── scripts/ # 运行时脚本
│ ├── entrypoint.sh
│ ├── healthcheck.sh
│ └── auth-ldap.sh
├── pki/ # 证书文件
│ ├── ca.crt
│ ├── server.crt
│ ├── server.key
│ └── dh.pem
├── clients/ # CCD客户端配置目录
├── logs/ # 日志目录
│
└── src/ # 镜像构建资源
├── Dockerfile
├── docker-compose.yml
├── .dockerignore
├── openvpn-2.6.17.tar.gz
├── EasyRSA-3.1.7.tgz
├── config/
└── scripts/
快速开始
1. 加载镜像
# 导入已构建好的 OpenVPN 2.6.17 镜像
docker load -i openvpn-ldap_2.6.17.tar
2. 配置环境变量
编辑 .env 文件:
vim .env
配置LDAP相关参数:
# LDAP服务器配置
LDAP_AD_SERVER=192.168.99.190
LDAP_AD_PORT=389
LDAP_DOMAIN=suitbim.com
LDAP_BASE_DN=DC=suitbim,DC=com
LDAP_ADMIN_UPN=Administrator@suitbim.com
LDAP_ADMIN_PASS=your_password_here
3. 设置目录权限
sudo bash setup-permissions.sh
或手动设置:
sudo chown -R root:root logs/ clients/
sudo chmod 755 logs/ clients/
4. 启动容器
docker compose up -d
5. 查看运行状态
# 查看容器状态
docker compose ps
# 查看日志
docker compose logs -f openvpn
# 查看认证日志
docker compose exec openvpn tail -f /var/log/openvpn/auth.log
配置说明
LDAP 认证配置
所有LDAP配置通过 .env 文件管理,支持以下配置项:
| 配置项 | 说明 | 示例 |
|---|---|---|
LDAP_AD_SERVER | AD服务器地址 | 192.168.99.190 |
LDAP_AD_PORT | LDAP端口 | 389 (标准) 或 636 (LDAPS) |
LDAP_DOMAIN | AD域名 | suitbim.com |
LDAP_BASE_DN | 基础DN | DC=suitbim,DC=com |
LDAP_ADMIN_UPN | 管理员账户 | Administrator@suitbim.com |
LDAP_ADMIN_PASS | 管理员密码 | your_password |
密码特殊字符处理:
在 .env 文件中,大部分特殊字符可以直接使用:
# 正常密码
LDAP_ADMIN_PASS=P@ssw0rd123
# 包含特殊字符($ " ' \ 空格)
LDAP_ADMIN_PASS=P@ss$w0rd#"123
⚠️ 注意:如果密码以 $ 开头后跟字母(如 $abc),建议改密码或用引号包围。
端口配置
默认使用 UDP 3394 端口,可在 docker-compose.yml 中修改:
ports:
- "3394:3394/udp" # 主机端口:容器端口/协议
网络配置
VPN网络默认配置为 172.20.0.0/16,容器IP为 172.20.0.10。
如需修改,请同步更新:
docker-compose.yml中的网络配置config/server.conf中的相关路由配置
证书管理
使用现有证书(从旧版本迁移)
如果您有从 OpenVPN 2.4 或更早版本迁移的证书,直接复制到 pki/ 目录即可:
# 从旧服务器复制证书文件
scp old-server:/etc/openvpn/pki/ca.crt ./pki/
scp old-server:/etc/openvpn/pki/server.crt ./pki/
scp old-server:/etc/openvpn/pki/server.key ./pki/
scp old-server:/etc/openvpn/pki/dh.pem ./pki/
# 启动容器
docker compose up -d
已验证:OpenVPN 2.4 生成的证书可以在 2.6.17 版本中正常使用,客户端无需更新。
生成新证书
# 在src目录下使用EasyRSA生成证书
cd src/
tar -xzf EasyRSA-3.1.7.tgz
cd EasyRSA-3.1.7/
./easyrsa init-pki
./easyrsa build-ca
./easyrsa build-server-full server nopass
./easyrsa gen-dh
# 复制证书到pki目录
cp pki/ca.crt ../pki/
cp pki/issued/server.crt ../pki/
cp pki/private/server.key ../pki/
cp pki/dh.pem ../pki/
更新证书
- 将新的证书文件复制到
pki/目录 - 重启容器:docker compose restart
LDAP认证测试
容器启动后,建议手动测试LDAP认证是否正常工作。
进入容器
docker compose exec openvpn bash
创建测试文件
# 创建包含用户名和密码的测试文件
# 格式:第一行用户名,第二行密码
printf 'username\npassword\n' > /tmp/test.txt
# 示例:使用真实账户测试
printf 'zhangjian\nZj*sz#10142\n' > /tmp/test.txt
执行认证脚本
# 执行LDAP认证脚本
./auth-ldap.sh /tmp/test.txt
# 检查退出码
echo "退出码: $?"
预期结果:
- 退出码为
0表示认证成功 - 退出码为
1表示认证失败
查看认证日志
# 查看认证结果
tail -20 /var/log/openvpn/auth.log
成功示例:
用户 [zhangjian] 尝试认证
解码后 DN: [CN=张健,OU=数智管理中心,OU=城建信息,DC=suitbim,DC=com]
用户 zhangjian 认证成功 [u:SUITBIM\zhangjian]
失败示例:
用户 [testuser] 尝试认证
用户 testuser 在 AD 中不存在
或
认证失败: ldap_bind: Invalid credentials (49)
退出容器
exit
目录权限设置
关键目录权限
logs/ 和 clients/ 目录:这两个目录容器会写入文件,需要设置正确的权限:
# 设置正确的所有者和权限
sudo chown -R root:root logs/ clients/
sudo chmod 755 logs/ clients/
目录说明
logs/ 目录
- 用途:存储OpenVPN运行日志
- 初始状态:空目录(首次部署时)
- 权限要求:755 (rwxr-xr-x)
- 容器会自动创建:
openvpn.log、auth.log、openvpn-status.log
clients/ 目录
- 用途:CCD (Client Config Directory),用于为特定客户端分配固定IP
- 初始状态:空目录
- 权限要求:755 (rwxr-xr-x)
- 使用场景:需要为某个客户端分配固定IP或推送特定路由
示例:为客户端client1分配固定IP
echo "ifconfig-push 10.8.0.10 10.8.0.11" > clients/client1
一键设置权限
使用提供的脚本自动设置所有权限:
sudo bash setup-permissions.sh
脚本功能:
- ✅ 交互式选择是否清空 logs/ 和 clients/ 目录
- ✅ 自动设置所有文件和目录的正确权限
- ✅ 验证权限设置结果
首次部署快速设置
# 1. 清空logs目录(可选,如有旧日志)
sudo rm -rf logs/*
# 2. 确保clients目录为空
sudo rm -rf clients/*
# 3. 设置权限
sudo bash setup-permissions.sh
# 4. 启动容器
docker compose up -d
客户端配置
生成客户端配置
- 生成客户端证书(在EasyRSA目录):./easyrsa build-client-full client1 nopass
- 创建客户端配置文件
client1.ovpn:# 在src目录下执行
docker compose run –rm openvpn ovpn_getclient client1 > ../clients/client1.ovpn - 将配置文件分发给客户端使用
维护操作
查看连接状态
# 查看实时日志
docker compose logs -f openvpn
# 查看连接状态
docker compose exec openvpn cat /etc/openvpn/openvpn-status.log
# 查看认证日志
docker compose exec openvpn cat /var/log/openvpn/auth.log
重启服务
# 重启容器
docker compose restart
# 完全重建容器
docker compose down
docker compose up -d
备份与恢复
备份配置和证书:
tar -czf openvpn-backup-$(date +%Y%m%d).tar.gz .env config/ pki/ scripts/ docker-compose.yml
恢复配置:
tar -xzf openvpn-backup-YYYYMMDD.tar.gz
docker compose up -d
重新构建镜像
如果镜像损坏或需要重新构建:
cd src/
docker compose build
docker save openvpn-ldap:2.6.17 | gzip > ../openvpn-ldap_2.6.17.tar
cd ..
docker load -i openvpn-ldap_2.6.17.tar
docker compose up -d
相关文档
- setup-permissions.sh – 权限设置脚本