OpenVPN服务搭建
OpenVPN可以分为使用证书登录和传统的用户名密码登录,下面的步骤将会针对这两种登录方式进行介绍。
一、OpenVPN的安装以及服务端证书生成
1. 安装 OpenVPN 和 easy-rsa
首先,我们需要安装 OpenVPN 和 easy-rsa,后者用于生成和管理证书。
打开终端,运行以下命令更新软件包列表并安装所需软件:
sudo apt update
sudo apt install openvpn easy-rsa
2. 创建证书管理目录并初始化 PKI
我们将使用 easy-rsa 来管理证书和密钥。首先创建一个目录来存放相关文件,然后初始化 PKI(公钥基础设施)。
运行以下命令:
make-cadir ~/openvpn-ca
cd ~/openvpn-ca
./easyrsa init-pki
- make-cadir ~/openvpn-ca 会在家目录下创建一个 openvpn-ca 文件夹。
- ./easyrsa init-pki 初始化 PKI,生成存放证书和密钥的 pki 目录。
3. 创建 CA 证书
CA(证书颁发机构)证书是根证书,用于签署服务器和客户端的证书。
运行以下命令生成 CA 证书:
./easyrsa build-ca
- 系统会提示输入一个密码(passphrase)来保护 CA 密钥,请记住这个密码,后续签署证书时需要使用。
- 接着会要求输入通用名称(Common Name),可以输入类似 My OpenVPN CA 的名称。
4. 为 OpenVPN 服务器生成证书和密钥
接下来为服务器生成证书请求和密钥。
运行以下命令:
./easyrsa gen-req server nopass
./easyrsa sign-req server server
gen-req server nopass 生成服务器的证书请求和密钥,nopass 表示密钥无密码保护,便于服务自动启动。
- 提示输入通用名称时,可以输入 server。
sign-req server server
使用 CA 签署服务器证书。
- 需要输入之前设置的 CA 密码,并输入 yes 确认签署。
5. 生成 Diffie-Hellman 参数
Diffie-Hellman(DH)参数用于增强 OpenVPN 的安全性。
运行以下命令:
./easyrsa gen-dh
- 此过程可能需要一些时间,取决于系统性能。完成后会生成 pki/dh.pem 文件。
6. 复制证书和密钥
将生成的证书和密钥复制到 OpenVPN 配置目录。
sudo mkdir /etc/openvpn/keys
sudo cp ~/openvpn-ca/pki/ca.crt /etc/openvpn/keys/
sudo cp ~/openvpn-ca/pki/issued/server.crt /etc/openvpn/keys/
sudo cp ~/openvpn-ca/pki/private/server.key /etc/openvpn/keys/
sudo cp ~/openvpn-ca/pki/dh.pem /etc/openvpn/keys/dh2048.pem
sudo chmod 600 /etc/openvpn/keys/*
至此服务端的证书和OpenVPN环境准备完毕。
假如我们自己有证书文件的话,也可以直接使用自己的证书,替换ca.crt
、server.crt
、server.key
这三个文件即可。
下面将分为客户端证书登录和传统的用户名密码登录两种方式来对服务端和客户端进行配置。
二、客户端证书登录的配置方法
1. 为客户端生成证书和密钥
完成第一部分的操作之后,继续为每个客户端生成独立的证书和密钥。这里以 client1 为例,之后可以为 client2、client3 等重复此步骤。
针对每个客户端,运行以下命令:
cd ~/openvpn-ca
./easyrsa gen-req client1 nopass
./easyrsa sign-req client client1
- gen-req client1 nopass 生成客户端 client1 的证书请求和密钥。
- 提示输入通用名称时,输入 client1。
- sign-req client client1 签署客户端证书。
- 输入 CA 密码并确认签署(输入 yes)。
为其他客户端(如 client2、client3)重复以上命令,只需将 client1 替换为相应名称。
2. 将客户端生成证书和密钥提供给对应用户
上一步操作之后,证书存在的路径在~/openvpn-ca
下面
- pki/ca.crt
- pki/issued/client1.crt(根据客户端名称替换,如 client2.crt)
- pki/private/client1.key(根据客户端名称替换,如 client2.key)
通过安全方式(如加密传输)将这些文件分发给客户端用户。
3. 配置 OpenVPN 服务器
编辑服务器配置文件来指定端口、协议和证书路径等。
创建或编辑配置文件:
sudo vim /etc/openvpn/server.conf
在文件中添加以下内容:
port 1100
proto udp
dev tun
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/server.crt
key /etc/openvpn/keys/server.key
dh /etc/openvpn/keys/dh.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
keepalive 10 120
cipher AES-256-CBC
persist-key
persist-tun
status openvpn-status.log
verb 3
- port 1100:监听端口。
- proto udp:使用 UDP 协议。
- server 10.8.0.0 255.255.255.0:为客户端分配 IP 地址范围。
- 其他参数用于保持连接稳定性和日志记录。
4. 启动并启用 OpenVPN 服务
启动 OpenVPN 服务并设置为开机自启:
sudo systemctl start openvpn@server
sudo systemctl enable openvpn@server
5. 配置客户端
客户端需要安装 OpenVPN 软件,并使用以下配置文件(例如 client1.ovpn)连接:
client
dev tun
proto udp
remote 服务器的IP地址 1100
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client1.crt
key client1.key
cipher AES-256-CBC
verb 3
- 将 服务器的IP地址 替换为你的服务器公网 IP。
- 确保 ca.crt、client1.crt 和 client1.key 文件与配置文件在同一目录。
客户端用户使用这些文件即可连接到 OpenVPN 服务器。
三、用户名密码登录的配置方法
1、配置用户名/密码认证脚本
完成第一部分的操作之后,创建一个脚本验证用户名和密码(基于你的现有 checkpsw.sh
)。以下是一个简单的示例脚本,支持静态用户名/密码。
sudo vim /etc/openvpn/checkpsw.sh
添加以下内容:
#!/bin/bash
# Username and password file
PASSFILE="/etc/openvpn/psw-file"
# Check if username and password are provided
if [ -z "$username" ] || [ -z "$password" ]; then
exit 1
fi
# Verify credentials
if grep -Fx "$username:$password" "$PASSFILE" > /dev/null; then
exit 0 # Success
else
exit 1 # Failure
fi
说明:
- 脚本从环境变量读取 username 和 password。
- 验证是否匹配 /etc/openvpn/psw-file 中的记录。
- 返回 0 表示认证成功,非 0 表示失败。
设置脚本权限:
sudo chmod +x /etc/openvpn/checkpsw.sh
创建密码文件:
sudo nano /etc/openvpn/psw-file
添加用户名和密码(每行一个用户,格式为 用户名:密码),例如:
user1:password1 user2:password2
设置文件权限:
sudo chmod 600 /etc/openvpn/psw-file
注意:
- 密码以明文存储,需确保文件安全。
- 可根据需求替换为更复杂的认证(如连接数据库或 PAM),但此示例适合简单场景。
2. 配置 OpenVPN 服务器
创建或编辑服务器配置文件,基于你的需求优化。
sudo vim /etc/openvpn/server.conf
添加以下内容:
port 1100
proto tcp
dev tap
ca /etc/openvpn/keys/ca.crt
cert /etc/openvpn/keys/server.crt
key /etc/openvpn/keys/server.key
dh /etc/openvpn/keys/dh2048.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "dhcp-option DNS 114.114.114.114"
push "dhcp-option DNS 208.67.220.220"
client-to-client
keepalive 10 120
cipher AES-256-GCM
persist-key
persist-tun
status /var/log/openvpn-status.log
verb 3
auth-user-pass-verify /etc/openvpn/checkpsw.sh via-env
verify-client-cert none
username-as-common-name
script-security 3
说明:
- dev tap: 支持二层转发。
- server 10.8.0.0 255.255.255.0: 创建独立 VPN 子网,客户端获取 10.8.0.2 及以上 IP。
- verify-client-cert none: 禁用客户端证书,仅使用用户名/密码。
- cipher AES-256-GCM: 启用加密,确保流量安全。
- NAT 转发:后续通过 iptables 配置。
3. 启动并启用 OpenVPN 服务
启动 OpenVPN 服务并设置为开机自启:
sudo systemctl start openvpn@server
sudo systemctl enable openvpn@server
4. 配置客户端
为客户端生成配置文件(client.ovpn)。客户端仅需 CA 证书和用户名/密码。
创建 client.ovpn(在本地或服务器上):
client
dev tun
proto udp
remote 服务器的IP地址 1100
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client1.crt
key client1.key
cipher AES-256-CBC
verb 3
说明:
- 替换 服务器公网IP 为你的服务器 IP。
- 需要将 /etc/openvpn/keys/ca.crt 复制到客户端,与 client.ovpn 放在同一目录。
- auth-user-pass 提示客户端输入用户名/密码(匹配 /etc/openvpn/psw-file)。
四、配置使客户端通过OpenVPN代理上网。
按照上面的步骤配置之后,应该至少能实现OpenVPN客户端连接到服务端了。这样的结果用于网络异地组网或者联机局域网游戏是没问题了,但是应该还是无法实现客户端通过OpenVPN代理上网的操作。
下面还需要下面的步骤:
1. OpenVPN服务器启用 IP 转发
为了让 OpenVPN 服务器转发客户端流量到互联网,需要启用 IP 转发。
编辑 /etc/sysctl.conf:
sudo vim /etc/sysctl.conf
找到以下行,去掉 # 号:
net.ipv4.ip_forward=1
保存后运行以下命令使更改生效:
sudo sysctl -p
2. 配置 NAT 转发
如果希望客户端能访问服务器所在局域网或互联网,需配置 iptables。
假设服务器网络接口为 eth0,运行:
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
为确保重启后规则生效,安装并保存规则:
sudo apt install iptables-persistent
安装时选择保存当前规则。
注意:
- 替换 eth0 为服务器的实际外部接口(查看:ip link)。
- 如果使用 ufw,需额外配置 NAT 规则(编辑 /etc/ufw/before.rules)。
五、遇到的一些问题
1、私钥与证书不匹配
报错日志:
user@ebs-128221:~/openvpn-ca$ sudo /usr/sbin/openvpn --config /etc/openvpn/server.conf
Mon May 12 13:36:51 2025 WARNING: POTENTIALLY DANGEROUS OPTION --verify-client-cert none|optional (or --client-cert-not-required) may accept clients which do not present a certificate
Mon May 12 13:36:51 2025 OpenVPN 2.4.12 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Jun 27 2024
Mon May 12 13:36:51 2025 library versions: OpenSSL 1.1.1f 31 Mar 2020, LZO 2.10
Mon May 12 13:36:51 2025 NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
Mon May 12 13:36:51 2025 Diffie-Hellman initialized with 2048 bit key
Mon May 12 13:36:51 2025 OpenSSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
Mon May 12 13:36:51 2025 Cannot load private key file /etc/openvpn/keys/server.key
Mon May 12 13:36:51 2025 Error: private key password verification failed
Mon May 12 13:36:51 2025 Exiting due to fatal error
具体错误信息如下:
OpenSSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch
Cannot load private key file /etc/openvpn/keys/server.key
Error: private key password verification failed
Exiting due to fatal error
错误分析
OpenVPN 无法加载私钥文件 /etc/openvpn/keys/server.key,原因是私钥与对应的证书文件 /etc/openvpn/keys/server.crt 不匹配(key values mismatch)。
检查方法
使用 OpenSSL 验证 server.crt 和 server.key 是否成对:
openssl x509 -noout -modulus -in /etc/openvpn/keys/server.crt | openssl md5 openssl rsa -noout -modulus -in /etc/openvpn/keys/server.key | openssl md5
- 如果输出匹配(MD5 值相同),证书和私钥是一对。
- 如果不匹配,说明使用了错误的密钥或证书,需要重新生成,参照第一部分的第4小节。
2、使用证书的方式客户端连接找不到ca.crt
使用证书登录方式,连接时从log中看到以下报错:
Options error: --ca fails with 'ca.crt': No such file or directory (errno=2)
Options error: Please correct these errors.
Use --help for more information.
错误分析
客户端配置文件(client.ovpn)中指定了 ca ca.crt,但 OpenVPN 客户端无法找到 ca.crt 文件,提示文件不存在(No such file or directory)。
修改方法
将ca.crt 文件与 client.ovpn 放在同一目录。
或者修改 client.ovpn ,在配置文件后面增加:
<ca>
-----BEGIN CERTIFICATE-----
ca证书内容
-----END CERTIFICATE-----
</ca>
3、已经连接上了openvpn,但是客户端没有使用OpenVPN进行上网
解决方法:添加路由重定向到客户端配置
为了让 Windows 的所有互联网流量通过 VPN,需要在 client.ovpn 中添加以下指令,设置 VPN 服务器为默认网关:
编辑 client.ovpn(使用记事本或文本编辑器):
client
dev tap
proto tcp
remote 服务器的IP地址 1100
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
auth-user-pass
cipher AES-256-GCM
verb 3
redirect-gateway def1 ; 添加此行以重定向所有流量到 VPN
说明:
- redirect-gateway def1:将客户端的默认网关设置为 VPN 隧道,确保所有互联网流量通过 VPN 服务器。
- def1 选项避免覆盖本地网关,适合大多数场景。
保存后,重新连接 OpenVPN:
- 在 OpenVPN GUI 中,右键配置文件,选择“Connect”。
如果上面操作之后问题依然没有解决,继续检查第四部分的配置是否已经执行成功,然后继续检查iptables的配置:
user@ebs-128221:~/openvpn-ca$ sudo iptables -t nat -L -v -n
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 MASQUERADE 0 -- * eth0 10.8.0.0/24 0.0.0.0/0
这表明 NAT 规则现在是正确的,客户端的流量(来自 10.8.0.0/24)应该可以通过 eth0 接口进行源地址转换(MASQUERADE)并转发到互联网。但客户端流量未通过,可能是 FORWARD 链、Docker 干扰、防火墙或客户端路由/DNS 问题。通过添加转发规则、处理 Docker 冲突、配置 ufw 和验证客户端设置,问题应可解决。
继续检查FORWARD 链的配置:
user@ebs-128221:~/openvpn-ca$ sudo iptables -L FORWARD -v -n
Chain FORWARD (policy DROP 3212 packets, 243K bytes)
pkts bytes target prot opt in out source destination
4342K 27G DOCKER-USER 0 -- * * 0.0.0.0/0 0.0.0.0/0
4342K 27G DOCKER-ISOLATION-STAGE-1 0 -- * * 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT 0 -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
0 0 DOCKER 0 -- * docker0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT 0 -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT 0 -- docker0 docker0 0.0.0.0/0 0.0.0.0/0
3507K 26G ACCEPT 0 -- * br-af6174ad1060 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
7144 429K DOCKER 0 -- * br-af6174ad1060 0.0.0.0/0 0.0.0.0/0
825K 402M ACCEPT 0 -- br-af6174ad1060 !br-af6174ad1060 0.0.0.0/0 0.0.0.0/0
0 0 ACCEPT 0 -- br-af6174ad1060 br-af6174ad1060 0.0.0.0/0 0.0.0.0/0
问题分析
FORWARD 链策略为 DROP:
输出显示:
Chain FORWARD (policy DROP 3212 packets, 243K bytes)
FORWARD 链的默认策略是 DROP,意味着除非明确允许,否则所有转发流量都会被丢弃。
当前 FORWARD 链中没有针对 OpenVPN 的 tap0 接口或 10.8.0.0/24 子网的 ACCEPT 规则,因此客户端流量(从 tap0 到 eth0)被丢弃,导致无法上网。
解决方法
添加 FORWARD 链规则
为了允许 OpenVPN 客户端流量从 tap0 接口转发到 eth0,需要添加显式的 ACCEPT 规则。
步骤:
添加转发规则:
sudo iptables -I FORWARD 1 -i tap0 -o eth0 -s 10.8.0.0/24 -j ACCEPT sudo iptables -I FORWARD 2 -i eth0 -o tap0 -d 10.8.0.0/24 -m state --state RELATED,ESTABLISHED -j ACCEPT
- 第一条规则允许从 tap0(VPN 接口)到 eth0(外部接口)的客户端流量。
- 第二条规则允许返回流量(已建立的连接)。
- -I FORWARD 1 和 -I FORWARD 2 确保规则插入到链的开头,优先于 Docker 的规则。
验证规则:
sudo iptables -L FORWARD -v -n --line-numbers
确认新规则位于链的顶部,例如:
Chain FORWARD (policy DROP) num pkts bytes target prot opt in out source destination 1 0 0 ACCEPT all -- tap0 eth0 10.8.0.0/24 0.0.0.0/0 2 0 0 ACCEPT all -- eth0 tap0 0.0.0.0/0 10.8.0.0/24 state RELATED,ESTABLISHED
保存规则
sudo iptables-save > /etc/iptables/rules.v4