远程办公企业级OpenVPN详细搭建指南
6
2023-02-17
介绍
OpenVPN 是一个基于 OpenSSL 库的应用层 VPN 实现。openvpn可工作于两种模式:
- tun:一种是IP遂道路由模式,主要应用于点对点
- eth:一种是基于以太网的遂道桥模式, 应用于点对多点,有多个分支机构
TAP 是二层网卡桥接隧道,即创建一个以太网桥接,相对复杂。 TUN 接口下所有的客户端处于一个完全独立的子网内,与VPN服务器所在的子网没有关系; TAP 接口的好处相较之下则相当明显,客户端可以获得VPN服务器所处子网的 IP(即,忽略物理上的区别,可以完全将客户端看做是于VPN服务器处于同一子网的另一台机器)检查内核是否支持TUN/TAP设备驱动,有正常的输出,则支持。
$ modinfo tun filename: /lib/modules/3.10.0-1160.71.1.el7.x86_64/kernel/drivers/net/tun.ko.xz alias: devname:net/tun alias: char-major-10-200 license: GPL author: (C) 1999-2004 Max Krasnyansky检查文件是否存在判断tun模块是否加载description: Universal TUN/TAP device driver retpoline: Y rhelversion: 7.9 srcversion: E26A36A927427B2BAE3FB17 depends: intree: Y vermagic: 3.10.0-1160.71.1.el7.x86_64 SMP mod_unload modversions signer: CentOS Linux kernel signing key sig_key: 6D:A7:C2:41:B1:C9:99:25:3F:B3:B0:36:89:C0:D1:E3:BE:27:82:E4 sig_hashalgo: sha256
$ ls /dev/net/tun /dev/net/tun
网络拓扑图

初始化服务端
云主机配置:腾讯云轻量服务器,配置为2C-2G-4Mbps。系统为CentOS 7.9$ hostnamectl set-hostname vpn-server $ vim etc/bashrc #追加一行 "PS1='\n\e[1;37m[\e[m\e[1;32m\u\e[m\e[1;33m@\e[m\e[1;35m\h\e[m \e[4m`pwd`\e[m\e[1;37m]\e[m\e[1;36m\e[m \A\n$ ' $ source /etc/bashrc效果如下:

# 关闭selinux $ setenforce 0 $ sed -ri '/^[^#]*SELINUX=/s#=.+$#=disabled#' /etc/selinux/config # 安装iptables相关服务 $ yum -y install iptables iptables-services # 查看内核转发是否开启 $ echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf $ sysctl -p net.ipv4.ip_forward = 1 # 更新软件包 $ yum -y install epel-release && yum update -y
安装OpenVPN
yum -y install openvpn easy-rsa # 移动到etc内,清理软链接 cp -r /usr/share/easy-rsa/ /etc/openvpn/easy-rsa cd /etc/openvpn/easy-rsa/ && rm -f 3 3.0 # 在根目录下查找文件名为vars.example的文件改为vars复制到当前目录 find / -type f -name "vars.example" | xargs -i cp {} . && mv vars.example vars
证书配置
$ cd /etc/openvpn/easy-rsa/3.0.8 $ ./easyrsa clean-all # 生成一个CA根证书,名称随意,但是不能和服务端证书或客户端证书名称相同。 $ ./easyrsa build-ca nopass # 创建服务端证书并签约,server是服务端证书名称,可以用其它名称。 $ ./easyrsa gen-req server nopass $ ./easyrsa sign server server # 生成Diffle Human参数,它能保证密钥在网络中安全传输 $ ./easyrsa gen-dh 创建完成会看到如下提示: DH parameters of size 2048 created at /etc/openvpn/easy-rsa/3.0.8/pki/dh.pem # 生成加密文件 $ openvpn --genkey --secret /etc/openvpn/ta.key # 创建客户端证书(无证书模式可以忽略),并签约。 $ ./easyrsa gen-req qiyue_client nopass $ ./easyrsa sign client qiyue_client
整理证书
服务端cd /etc/openvpn/server cp /etc/openvpn/easy-rsa/3.0.8/pki/dh.pem /etc/openvpn/server cp /etc/openvpn/easy-rsa/3.0.8/pki/ca.crt /etc/openvpn/server cp /etc/openvpn/easy-rsa/3.0.8/pki/issued/server.crt /etc/openvpn/server cp /etc/openvpn/easy-rsa/3.0.8/pki/private/server.key /etc/openvpn/server #如下所示 $ ll total 20 -rw------- 1 root root 1168 Feb 17 10:18 ca.crt -rw------- 1 root root 424 Feb 17 10:17 dh.pem -rw------- 1 root root 4545 Feb 17 10:18 server.crt -rw------- 1 root root 1704 Feb 17 10:18 server.key客户端
cd /etc/openvpn/client cp /etc/openvpn/easy-rsa/3.0.8/pki/issued/qiyue_client.crt /etc/openvpn/client cp /etc/openvpn/easy-rsa/3.0.8/pki/private/qiyue_client.key /etc/openvpn/client cp /etc/openvpn/easy-rsa/3.0.8/pki/ca.crt /etc/openvpn/client mv /etc/openvpn/ta.key /etc/openvpn/client # 如下所示 $ ll total 16 -rw------- 1 root root 4444 Feb 17 10:23 qiyue_client.crt -rw------- 1 root root 1704 Feb 17 10:23 qiyue_client.key -rw------- 1 root root 636 Feb 17 10:32 ta.key
查看网段
$ ifconfig eth0: flags=4163mtu 1500 inet 10.0.8.6 netmask 255.255.252.0 broadcast 10.0.11.255 inet6 fe80::5054:ff:fecc:7f7e prefixlen 64 scopeid 0x20 ether 52:54:00:cc:7f:7e txqueuelen 1000 (Ethernet) RX packets 206357 bytes 270304849 (257.7 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 67122 bytes 6802473 (6.4 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
配置转发
也可iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p tcp --sport 1999 -j ACCEPT # VPN网段和云主机内网网段 iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j MASQUERADE iptables -t nat -A POSTROUTING -s 10.0.8.0/22 -j MASQUERADE
自动认证脚本
#!/bin/sh # 此脚本将根据纯文本文件对 OpenVPN 用户进行身份验证。 # passfile 应该只包含每个用户一行,用户名在前,后跟一个或多个空格或制表符,然后是密码。 PASSFILE="/etc/openvpn/qiyue_password_file" LOG_FILE="/etc/openvpn/log/openvpn-password.log" TIME_STAMP=`date "+%Y-%m-%d %T"` ########################################################### if [ ! -r "${PASSFILE}" ]; then echo "${TIME_STAMP}: Could not open password file \"${PASSFILE}\" for reading." >> ${LOG_FILE} exit 1 fi CORRECT_PASSWORD=`awk '!/^;/&&!/^#/&&$1=="'${username}'"{print $2;exit}' ${PASSFILE}` if [ "${CORRECT_PASSWORD}" = "" ]; then echo "${TIME_STAMP}: User does not exist: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE} exit 1 fi if [ "${password}" = "${CORRECT_PASSWORD}" ]; then echo "${TIME_STAMP}: Successful authentication: username=\"${username}\"." >> ${LOG_FILE} exit 0 fi echo "${TIME_STAMP}: Incorrect password: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE} exit 1
服务端配置文件
具体可以参考官网的详细参数: 服务端:https://github.com/OpenVPN/openvpn/blob/master/sample/sample-config-files/server.confvim /etc/openvpn/server.conf本次示例:
#云主机内网ip local 10.0.8.6 port 1999 proto tcp dev tun ca /etc/openvpn/server/ca.crt cert /etc/openvpn/server/server.crt key /etc/openvpn/server/server.key dh /etc/openvpn/server/dh.pem #记录某个Client获得的IP地址,防止openvpn重新启动后“忘记”Client曾经使用过的IP地址 ifconfig-pool-persist /etc/openvpn/ipp.txt #给客户端分配地址池,注意:不能和VPN服务器内网网段有相同 server 10.0.1.0 255.255.255.0 # 下发给客户端的需要走VPN的网络流量,其它网段不走VPN,可正常上网。 push "route 192.168.0.0 255.255.255.0" push "route 192.168.18.0 255.255.255.0" push "route 10.0.8.0 255.255.252.0" # 下发网关 push "redirect-gateway def1 bypass-dhcp" # 下发给客户端的DNS push "dhcp-option DNS 223.5.5.5" push "dhcp-option DNS 223.6.6.6" tls-auth /etc/openvpn/client/ta.key 0 #客户端之间互相通信 client-to-client #给客户端指定固定的VPN地址 #client-config-dir /etc/openvpn/ccd #存活时间,10秒ping一次,120 如未收到响应则视为断线 keepalive 20 120 #传输数据压缩 comp-lzo #定义运行openvpn的用户和用户组 user root group root #通过keepalive检测超时后,重新启动×××,不重新读取keys,保留第一次使用的keys persist-key #通过keepalive检测超时后,重新启动×××,一直保持tun设备是linkup的,否则网络连接会先linkdown然后linkup。 persist-tun #采用的加密算法 cipher AES-256-CBC # 运行状态日志和错误日志位置 status /etc/openvpn/log/openvpn-status.log log-append /etc/openvpn/log/openvpn.log #相当于debug level verb 3 mute 20 duplicate-cn script-security 3 auth-user-pass-verify /etc/openvpn/check-password.sh via-env username-as-common-name auth-nocache
初始化客户端
hostnamectl set-hostname vpn-client vim etc/bashrc #追加一行 "PS1='\n\e[1;37m[\e[m\e[1;32m\u\e[m\e[1;33m@\e[m\e[1;35m\h\e[m \e[4m`pwd`\e[m\e[1;37m]\e[m\e[1;36m\e[m \A\n$ ' source /etc/bashrc setenforce 0 sed -ri '/^[^#]*SELINUX=/s#=.+$#=disabled#' /etc/selinux/config yum -y install epel-release && yum update -y yum -y install openvpn
客户端配置文件
具体可以参考官网的详细参数: 客户端配置文件:https://github.com/OpenVPN/openvpn/blob/master/sample/sample-config-files/client.confvim /etc/openvpn/client/qiyue_client.ovpn本次示例:
client remote "服务端公网IP" 1999 #设置Server的IP地址和端口,这个地方需要严格和Server端保持一致。 #remote-random #随机选择一个Server连接,否则按照顺序从上到下依次连接。该选项默认不启用。 #resolv-retry infinite #始终重新解析Server的IP地址(如果remote后面跟的是域名) #保证Server IP地址是动态的使用DDNS动态更新DNS后,Client在自动重新连接时重新解析Server的IP地址。这样无需人为重新启动,即可重新接入VPN。 #nobind #定义在本机不邦定任何端口监听incoming数据。 proto tcp dev tun comp-lzo ca ca.crt cert qiyue_client.crt key qiyue_client.key tls-auth ta.key 1 route-method exe route-delay 2 verb 3 cipher AES-256-CBC auth-nocache #使用账号密码验证 auth-user-pass客户端文件验证
$ pwd /etc/openvpn/client $ ll total 24 -rw-------. 1 root root 1168 Feb 17 12:31 ca.crt -rw-------. 1 root root 4444 Feb 17 12:30 qiyue_client.crt -rw-------. 1 root root 1704 Feb 17 12:30 qiyue_client.key -rw-r--r--. 1 root root 787 Feb 17 11:59 qiyue_client.ovpn -rw-------. 1 root root 636 Feb 17 12:30 ta.key
创建密码文件
touch /etc/openvpn/qiyue_password_file chmod 400 /etc/openvpn/qiyue_password_file生成随机密码:http://www.metools.info/other/o45.html
$ cat /etc/openvpn/qiyue_password_file qiyue krspc2ag0nu2v6lr087y925rug4qndkd user 1y4d944xm1nazqdhwedpqlnxr53d0spq
服务端管理
为了方便启停,采用通用的进程管理程序:supervisor。yum install supervisor -y && systemctl enable --now supervisord cd /etc/supervisord.d/ vim openvpn.ini #添加如下内容 [program: openvpn] command=/usr/sbin/openvpn --cd /etc/openvpn/ --config server.conf ; directory=/etc/openvpn/ ; autorestart=true ; autostart=true ; stderr_logfile=/var/log/openvpn.err.log ; stdout_logfile=/var/log/openvpn.out.log ; environment=ASPNETCORE_ENVIRONMENT=Production ; user=root ; stopsignal=INT startsecs=5 ; #启动 supervisorctl start openvpn #停止 supervisorctl stop openvpn查看状态
$ ps -ef |grep openvpn root 4856 32017 0 14:02 ? 00:00:00 /usr/sbin/openvpn --cd /etc/openvpn/ --config server.conf root 4896 3024 0 14:02 pts/3 00:00:00 grep --color=auto openvpn $ netstat -nltp|grep 1999 tcp 0 0 0.0.0.0:1999 0.0.0.0:* LISTEN 32019/openvpn如果开启后没有打开1999端口,说明开启服务失败,可能是配置文件有错,也有可能是权限不够,可以查询日志解决。
Linux客户端测试
整理文件cd /etc/openvpn tree # 查看目录文件 . ├── client │ ├── ca.crt │ ├── qiyue │ ├── qiyue_client.crt │ ├── qiyue_client.key │ ├── qiyue_client.ovpn │ └── ta.key └── server启动连接
#设置连接密码:第一行用户名,第二行密码。 $ cat /etc/openvpn/client/qiyue qiyue krspc2ag0nu2v6lr087y925rug4qndkd #启动连接 $ openvpn --daemon --cd /etc/openvpn/client --config qiyue_aliyun.ovpn --auth-user-pass /etc/openvpn/client/qiyue --log-append /var/log/openvpn.log使用管理软件控制
yum install supervisor -y && systemctl enable --now supervisord cd /etc/supervisord.d/ vim openvpn.ini #添加如下内容 [program: openvpn] command=/usr/sbin/openvpn --cd /etc/openvpn/client/ --config qiyue_client.ovpn --auth-user-pass qiyue --log-append /var/log/openvpn.log ; directory=/etc/openvpn/client ; autorestart=true ; autostart=true ; stderr_logfile=/var/log/openvpn.err.log ; stdout_logfile=/var/log/openvpn.out.log ; environment=ASPNETCORE_ENVIRONMENT=Production ; user=root ; stopsignal=INT startsecs=5 ; #启动 systemctl restart supervisord supervisorctl start openvpn #停止 supervisorctl stop openvpn我这里客户端启动报错了
$ supervisorctl start openvpn openvpn: ERROR (spawn error)查看日志
$ cat /var/log/openvpn.log # 为空,说明在OpenVPN启动之前的报错。那我们去排查supervisor的问题。 $ cat /var/log/openvpn.out.log Options error: In [CMD-LINE]:1: Error opening configuration file: qiyue_aliyun.ovpn Use --help for more information.原来是日志文件不对,改成qiyue_client.ovpn重试。 查看状态
$ ps -ef |grep openvpn root 4856 32017 0 14:02 ? 00:00:00 /usr/sbin/openvpn --cd /etc/openvpn/ --config server.conf root 4896 3024 0 14:02 pts/3 00:00:00 grep --color=auto openvpn $ netstat -nltp|grep 1999 tcp 0 0 0.0.0.0:1999 0.0.0.0:* LISTEN 32019/openvpn状态日志,可以看到连接的用户、IP地址与时间。
$ cat /etc/openvpn/log/openvpn-status.log

$ tail -1 /etc/openvpn/log/openvpn-password.log 2023-02-17 21:37:00: Successful authentication: username="qiyue".查看ipinfo.io返回的公网IP,确认为云主机公网IP
$ curl ipinfo.io { "ip": "xxx.xxx.xxx.xxx", "city": "Shenzhen", "region": "Guangdong", "country": "CN", "loc": "22.5455,114.0683", "org": "AS45090 Shenzhen Tencent Computer Systems Company Limited", "timezone": "Asia/Shanghai", "readme": "https://ipinfo.io/missingauth" }
MacOS客户端测试
打包client端文件并修改文件夹名为tblk文件后缀,以便Tunnelblick识别。



$ ifconfig ... utun5: flags=8051PING云主机内网IPmtu 1500 inet 10.0.1.6 --> 10.0.1.5 netmask 0xffffffff
$ ping 10.0.8.6 -c 3 PING 10.0.8.6 (10.0.8.6): 56 data bytes 64 bytes from 10.0.8.6: icmp_seq=0 ttl=64 time=39.248 ms 64 bytes from 10.0.8.6: icmp_seq=1 ttl=64 time=32.542 ms 64 bytes from 10.0.8.6: icmp_seq=2 ttl=64 time=43.443 ms --- 10.0.8.6 ping statistics --- 3 packets transmitted, 3 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 32.542/38.411/43.443/4.489 ms
连通性测试
查看服务端状态日志:cat /etc/openvpn/log/openvpn-status.log可以看到登录了两台客户端。


$ ping 10.0.8.6 -c 3 PING 10.0.8.6 (10.0.8.6) 56(84) bytes of data. 64 bytes from 10.0.8.6: icmp_seq=1 ttl=64 time=92.8 ms 64 bytes from 10.0.8.6: icmp_seq=2 ttl=64 time=30.1 ms 64 bytes from 10.0.8.6: icmp_seq=3 ttl=64 time=30.3 ms --- 10.0.8.6 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2004ms rtt min/avg/max/mdev = 30.139/51.125/92.845/29.501 ms测试到局域网其他主机的通信:
$ ping 192.168.0.102 -c 3 PING 192.168.0.102 (192.168.0.102) 56(84) bytes of data. 64 bytes from 192.168.0.102: icmp_seq=1 ttl=64 time=0.271 ms 64 bytes from 192.168.0.102: icmp_seq=2 ttl=64 time=0.189 ms 64 bytes from 192.168.0.102: icmp_seq=3 ttl=64 time=0.202 ms --- 192.168.0.102 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.189/0.220/0.271/0.039 ms
客户端非直连
我们测试一下在客户端的其他非client直连去连接VPN网段,发现无法通信。 查看当前路由表$ route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.0.1 0.0.0.0 UG 100 0 0 ens33 192.168.0.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33 192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0client机器开启内核同网段的转发:
$ echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf $ sysctl -p net.ipv4.ip_forward = 1在局域网其他主机加一条静态路由,让去VPN网段的下一跳地址指向client的地址。
$ ip route add 10.0.1.0/24 via 192.168.0.110 $ ping 10.0.1.10 -c 3 PING 10.0.1.10 (10.0.1.10) 56(84) bytes of data. 64 bytes from 10.0.1.10: icmp_seq=1 ttl=64 time=0.206 ms 64 bytes from 10.0.1.10: icmp_seq=2 ttl=64 time=0.214 ms 64 bytes from 10.0.1.10: icmp_seq=3 ttl=64 time=0.228 ms --- 10.0.1.10 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 1999ms rtt min/avg/max/mdev = 0.206/0.216/0.228/0.009 ms查看当前路由表
$ route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.0.1 0.0.0.0 UG 100 0 0 ens33 10.0.1.0 192.168.0.110 255.255.255.0 UG 0 0 0 ens33 192.168.0.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33 192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
设置固定IP(可选)
在服务端/etc/openvpn/server.conf
中增加如下配置:
#为客户端指定VPN网段的IP client-config-dir /etc/openvpn/ccd在服务端
/etc/openvpn/ccd/
设置用户qiyue的IP为 10.8.0.11
cat /etc/openvpn/ccd/qiyue ifconfig-push 10.0.1.11 255.255.255.0重启客户端和服务端的openvpn服务
supervisorctl restart openvpn查看用户qiyue登录所在的client的IP信息,成功获取到指定IP。
$ ip a 1: lo:mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens33: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 00:0c:29:38:b3:7b brd ff:ff:ff:ff:ff:ff inet 192.168.0.110/24 brd 192.168.0.255 scope global noprefixroute ens33 valid_lft forever preferred_lft forever inet6 fe80::8fd1:3f0c:fb58:2c90/64 scope link noprefixroute valid_lft forever preferred_lft forever 14: tun0: mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 10.0.1.11 peer 255.255.255.0/32 scope global tun0 valid_lft forever preferred_lft forever inet6 fe80::6e3e:7b5d:68ce:6f08/64 scope link flags 800 valid_lft forever preferred_lft forever
- 0
-
分享