最近顺手把一台机器上的 OpenVPN 重新整理了一遍,顺便把过程记下来,免得下次再搭的时候又去翻零散笔记。

这篇主要记录一个比较常见的方案:使用 Easy-RSA 管理证书,部署 OpenVPN 服务端,再生成客户端配置文件完成连接。如果只是想先把服务跑起来,这套流程已经够用了。

本文系统环境为 Ubuntu 20.04 Server 版本

安装 OpenVPN 和 Easy-RSA

先把需要的软件装上:

1
apt install openvpn easy-rsa -y

创建 PKI 证书体系

先初始化一套 PKI 证书体系,用来后续签发服务端和客户端证书:

1
2
3
make-cadir ~/easy-rsa
cd ~/easy-rsa
./easyrsa init-pki

创建 CA

CA 是后续签发证书的核心。执行下面的命令:

1
./easyrsa build-ca

执行过程中会提示:

  • 输入证书密码
  • 输入 CA 名称

如果 CA 名称直接回车不填,默认会使用 Easy-RSA CA

生成服务端证书和密钥

先生成服务端请求和私钥:

1
./easyrsa gen-req server nopass

这里会提示输入服务端证书的 CN。如果不填,默认一般就是 server

然后签发服务端证书:

1
./easyrsa sign-req server server

签发时需要输入刚才设置的 CA 密码。

生成 Diffie-Hellman 参数

1
./easyrsa gen-dh

生成 TLS-Auth 密钥

1
openvpn --genkey --secret ta.key

复制证书到 OpenVPN 服务端目录

把后续运行服务需要的文件复制到 /etc/openvpn/server/

1
2
3
4
cp pki/ca.crt /etc/openvpn/server/
cp pki/issued/server.crt /etc/openvpn/server/
cp pki/private/server.key /etc/openvpn/server/
cp pki/dh.pem ta.key /etc/openvpn/server/

编写服务端配置文件

编辑配置文件:

1
nano /etc/openvpn/server/server.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
port 1194
proto udp
dev tun

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

# 给客户端分配 IP 的范围
server 10.8.0.0 255.255.255.0

# 给客户端推送的路由
push "route 10.8.0.0 255.255.0.0"

keepalive 10 120
cipher AES-256-CBC
user nobody
group nogroup
persist-key
persist-tun

status openvpn-status.log
verb 3

可能需要在防火墙里放行 1194/UDP 端口。

开启 IP 转发

编辑配置文件:

1
nano /etc/sysctl.conf

找到这一项并取消注释:

1
net.ipv4.ip_forward=1

保存后执行:

1
sysctl -p

启动 OpenVPN 服务端

1
2
systemctl start openvpn-server@server
systemctl enable openvpn-server@server

看看服务起来没有

1
systemctl status openvpn-server@server

生成客户端证书

回到 Easy-RSA 目录,生成一个客户端证书。这里我用 client1 作为示例:

1
2
cd ~/easy-rsa
./easyrsa gen-req client1 nopass

执行时会提示输入证书名称,通常用来区分不同客户端设备;如果不指定默认使用 client1

接着签发客户端证书:

1
./easyrsa sign-req client client1

这里会先要求输入 yes 确认,再输入 CA 密码。

编写客户端配置文件

客户端配置可以直接写成一个 .ovpn 文件,里面把证书和密钥内容一并塞进去,导入时最省事。

配置内容如下,记得替换服务端IP地址和其他证书内容:

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
28
29
30
31
32
client

auth-user-pass

dev tun
proto udp
remote 你的服务端IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun

remote-cert-tls server
cipher AES-256-CBC
verb 3

<ca>
(粘贴 ~/easy-rsa/pki/ca.crt 内容)
</ca>

<cert>
(粘贴 ~/easy-rsa/pki/issued/client1.crt 内容)
</cert>

<key>
(粘贴 ~/easy-rsa/pki/private/client1.key 内容)
</key>

<tls-auth>
(粘贴 ~/easy-rsa/ta.key 内容)
</tls-auth>
key-direction 1

写好之后,把这个配置导入到客户端即可连接。

增加账号密码验证

如果只靠证书还不够,想再加一层用户名和密码校验,也可以在服务端继续配置。

先在服务端配置文件 /etc/openvpn/server/server.conf 末尾追加:

1
2
3
4
# 用户密码验证
script-security 3
auth-user-pass-verify /etc/openvpn/server/passwd.sh via-env
username-as-common-name

编写账号密码验证脚本

新建脚本文件:

1
nano /etc/openvpn/server/passwd.sh

写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/sh

USER="$username"
PASS="$password"

CHECK="${USER}:${PASS}"

if grep -x -F -q "$CHECK" /etc/openvpn/server/user.txt; then
echo "$USER success"
exit 0
else
echo "$USER failed"
exit 1
fi

然后给脚本加上执行权限:

1
chmod +x /etc/openvpn/server/passwd.sh

编写用户名密码列表

再创建用户列表文件:

1
nano /etc/openvpn/server/user.txt

写入示例内容:

1
user1:123456

重启服务端

配置改完后,重启 OpenVPN:

1
systemctl restart openvpn-server@server

客户端启用用户名密码登录

编辑客户端配置文件,确认开头包含下面这一行:

1
auth-user-pass

然后重新导入客户端配置。

连接时输入:

  • 用户名:user1
  • 密码:123456

就可以完成连接了。

证书和账号密码两层验证仅限于日常自用或者小规模场景,像 user.txt 这种纯文本密码存储方式更适合临时使用或内网环境,如果要上生产环境,最好还是继续往 PAM、LDAP 或其他更正式的认证方式升级。