Linux下OpenVPN服务器搭建

  VPN的主要作用是在局域网外部时也可以访问局域网的资源,比如学校有许多资源只能校内访问,而我们在校外还想访问学校资源,就需要通过入校VPN来实现,但是学校公用VPN用的人一多速度就会变得非常慢,不如利用自己校内固定IP的电脑自建一个VPN来的方便。

  由于众所周知的原因,几种简单的VPN协议比如L2TP/IPsec和PPTP协议在大陆地区已经被干扰的基本无法正常使用了。因此也就SSL VPN还可以使用。SSL VPN有非常多种,但很多都是商业软件,不开源也不适合个人搭建。OpenVPN是一款开源的SSL VPN,可以很容易找到搭建的方法,非常符合我们的要求。

4月8日追记 我现在发现了一个更好用的开源SSL VPN——SoftEther,支持多种VPN协议包括OpenVPN,可以用它来代替OpenVPN服务器,具体搭建方法可参考本博客另一篇文章『Linux下SoftEther服务器搭建

0x01 服务端配置

1. 准备工作

  我们使用的是操作系统是最小安装模式的CentOS 7,进去后首先编辑/etc/selinux/config关闭SELinux,因为SELinux总会引起一些奇奇怪怪的问题而且也没必要开启。然后因为学校本身有防火墙,就没必要在操作系统中再设置防火墙了,可以把firewalld关闭掉

systemctl disable firewalld
systemctl stop firewalld

2. 安装OpenVPN

yum -y install epel-release
yum update
yum -y install openvpn easy-rsa

3. 创建证书

  下面是easy-rsa版本3以上创建证书的步骤

cd /usr/share/easy-rsa/3/
./easyrsa init-pki
./easyrsa build-ca nopass
./easyrsa build-server-full <server-name> nopass
./easyrsa build-client-full <client-name> nopass

  这里加上nopass表示不用密码加密证书,因为就自己用,这样方便点。<server-name><client-name>分别是server和client的证书名,其中client证书可以创建多个,因为默认配置下一个证书只能同时有一个连接,所以一般是一个设备一个证书。

4. 准备OpenVPN配置文件

  把上一步中创建好的证书等文件复制到/etc/openvpn/server/目录下,并创建dh2048.pemta.key

cd /usr/share/easy-rsa/3/pki
cp ca.crt issued/<server-name>.crt private/<server-name>.key /etc/openvpn/server/
cd /etc/openvpn/server
openssl dhparam -out dh2048.pem 2048
openvpn --genkey --secret ta.key

  之后需要一个OpenVPN的配置文件<server-name>.conf放在/etc/openvpn/server/中,可以在样本配置文件/usr/share/doc/openvpn/sample/sample-config-files/server.conf的基础上进行编辑

# 默认绑定在所有网络接口上,如需绑定在特定接口取消该行注释
;local a.b.c.d

# 监听端口
port 1194

# 运行模式,tun为L3层点到点链路,只能负载IP包,tap为
# L2层链路,负载以太网数据包,一般情况下tun即可
dev tun

# 使用TCP或者UDP协议,可在其后加6监听IPv6端口
# 建议使用UDP协议,受干扰较小
;proto tcp
;proto udp6
proto udp

# 数据加密算法
cipher AES-256-CBC

# 证书文件位置,和之前创建的证书名保持一致
ca ca.crt
cert <server-name>.crt
key <server-name>.key

# OpenVPN分配的网段
server 10.8.0.0 255.255.255.0
# 如果需要分配IPv6网段取消下行注释,NAT的情况下使用
# 唯一本地地址(ULA)即fc00::/7下的地址段
;server-ipv6 2001:db8:0:123::/64

# 保证同一个客户端(证书)每次连接时分配相同的IP地址
# 当需要客户端之间相互连接时非常有用
# 如果有多个OpenVPN服务器同时运行使用不同的文件名
ifconfig-pool-persist ipp.txt

# 向客户端添加路由,使得客户端访问这些地址时通过OpenVPN进
# 行访问。一般设置目标局域网的网段。注意所有的push都可以
# 在客户端配置文件中设置,设置在服务端主要是因为方便
;push "route 192.168.10.0 255.255.255.0"
;push "route 192.168.20.0 255.255.255.0"

# 取消第一行注释后客户端所有的IPv4流量都会经过OpenVPN
# 取消第二行注释后客户端所有的IPv4及IPv6流量都会经过OpenVPN
# 适合想通过OpenVPN访问公网的情况,如果该项启用就不需要上一
# 项中向客户端添加额外的路由了
;push "redirect-gateway def1 bypass-dhcp"
;push "redirect-gateway ipv6 def1 bypass-dhcp"

# 如果客户端在连接OpenVPN之前使用的是本地局域网的DNS服务器,
# 连接OpenVPN后由于路由改变可能会无法连接到之前的DNS服务器
# 因此需要修改客户端的DNS服务器地址,对于Windows等系统使用
# 以下的命令可以在连上OpenVPN时自动修改其DNS设置
;push "dhcp-option DNS 208.67.222.222"
;push "dhcp-option DNS 208.67.220.220"

# 保持连接参数,第一个参数为每隔几秒ping一次,第二个参数是多
# 少秒收不到包就认为是链路断开重新连接
keepalive 10 120

# 如果需要客户端之间能够相互访问,则打开该选项
;client-to-client

# 开启此选项后,同一个客户端证书可以同时建立多个连接
;duplicate-cn

# OpenVPN的状态日志,多个OpenVPN服务器使用分别的文件名
status openvpn-status.log

# 以下内容一般不需要更改
# 可在样本文件中查看他们的详细说明
dh dh2048.pem
tls-auth ta.key 0
persist-key
persist-tun
verb 3
explicit-exit-notify 1

5. 开启IP转发及NAT

  使用以下命令开启IPv4以及IPv6转发,并使之生效

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
sysctl -p
echo "IPV6FORWARDING=yes" >> /etc/sysconfig/network
systemctl restart network

  由于我们的服务器并不是路由器,因此即使对于IPv6也需要进行NAT才能使数据包正确地路由。利用iptables工具配置NAT,为了重启后也能生效可以把命令写在/etc/rc.local

iptables --table nat --append POSTROUTING --out-interface ens192 --jump MASQUERADE
ip6tables --table nat --append POSTROUTING --out-interface ens192 --jump MASQUERADE

6. 启动OpenVPN服务

  最后就可以启动OpenVPN了,可使用第二条命令使OpenVPN服务在重启后自动启动。

systemctl start openvpn-server@<server-name>
systemctl enable openvpn-server@<server-name>

0x02 客户端配置

1. Windows系统

  可以在OpenVPN的官网上下载到它的社区版本,安装后将之前在服务器上生成的ca.crtta.key<client-name>.key<client-name>.crt等文件复制到C:\Users\<your-user-name>\OpenVPN\config\目录下,目录不存在的话创建一个即可。然后还需要一个在该目录下放一个后缀名为.ovpn的配置文件,可以在样本配置文件/usr/share/doc/openvpn/sample/sample-config-files/client.conf的基础上进行编辑

# 使用TCP或者UDP协议,与服务端保持一致
;proto tcp
proto udp

# 运行模式,和服务端保持一致
dev tun

# 服务端的地址及端口,可以有多个服务端地址
remote my-server-1 1194
;remote my-server-2 1194

# 当有多个服务端时,是否随机选择一个连接
# 默认是按照顺序连接
;remote-random

# 数据加密算法
cipher AES-256-CBC

# 证书文件位置,和创建的证书名保持一致
ca ca.crt
cert <client-name>.crt
key <client-name>.key

# 验证服务端证书,防止中间人攻击
remote-cert-tls server

# 以下内容一般不需要更改
# 可在样本文件中查看他们的详细说明
client
resolv-retry infinite
nobind
persist-key
persist-tun
tls-auth ta.key 1
verb 3

  之后打开OpenVPN,双击屏幕右下角的OpenVPN图标或者右键选择Connect即可进行连接。

2. Android系统

  Android上有两款OpenVPN客户端可以使用,一个是官方客户端OpenVPN Connect,还有一个开源的客户端OpenVPN for Android,都可以从Google Play上获取到。

  这里我们只介绍官方客户端OpenVPN Connect的使用方法,与之前Windows下唯一的不同是,需要把证书等内容加入到.ovpn配置文件中变成一个文件然后导入OpenVPN Connect,因此配置文件需要做如下修改(可参考官方说明

# 先把这几行注释掉
;ca ca.crt
;cert <client-name>.crt
;key <client-name>.key
;tls-auth ta.key 1

# 然后加入下面的内容
# 下方省略号处贴入ca.crt文件内容
<ca>
......
</ca>
# 下方省略号处贴入<client-name>.crt文件内容
<cert>
......
</cert>
# 下方省略号处贴入<client-name>.key文件内容
<key>
......
</key>
key-direction 1
# 下方省略号处贴入ta.key文件内容
<tls-auth>
......
</tls-auth>

  之后将.ovpn文件复制到手机上,打开OpenVPN Connect选择OVPN Profile进行导入即可。

3. iOS系统

  iOS系统可以在App Store里获取到官方客户端OpenVPN Connect,同样需要Android系统那样合为一的.ovpn配置文件。但是由于iOS系统的安全限制,导入.ovpn文件相比Android有一些不方便。

  其中一个方法是用系统自带的应用“邮件”登录邮箱,然后将.ovpn文件作为附件向该邮箱发送一封邮件,之后在“邮件”应用中打开该.ovpn文件即可导入到OpenVPN Connect。

4. Linux系统

  这里以CentOS 7为例,其他发行版类似。首先安装OpenVPN

yum -y install epel-release
yum update
yum -y install openvpn easy-rsa

  之后将之前在服务器上生成的ca.crtta.key<client-name>.key<client-name>.crt等文件复制到/etc/openvpn/client/目录下。目录下还需要一个<client-name>.conf配置文件,可参考前文中Windows系统的配置文件,内容是一样的。最后通过命令systemctl start openvpn-client@<client-name>就可以开启VPN了,关闭的话只需要输入命令systemctl stop openvpn-client@<client-name>即可。

0x03 遇到过的问题

1. Windows虚拟机

  目前在使用过程中发现,VMWare ESXi上的Windows虚拟机使用包含push "redirect-gateway def1 bypass-dhcp"配置的服务器时,在连接上OpenVPN后会出现一些网络连接问题:

  一个问题是连上OpenVPN后连不上Internet,通过以下步骤后可解决问题:1. 连接OpenVPN; 2. 打开网络共享; 3. 断开OpenVPN; 4. 自动诊断修复以太网卡(诊断的原因是此网卡未启用DHCP); 5. 连接OpenVPN; 6. 关闭网络共享。

  上面的这个问题在Windows某次更新后消失了,但是出现了另一个问题,连上OpenVPN后无法通过原来的公网IP访问该Windows虚拟机,通过以下步骤后问题解决:1. 连接OpenVPN; 2. 打开网络共享; 3. 关闭网络共享。

2. Linux

  OpenVPN服务端加上IPv6后发现原本正常的Linux客户端连接不上了,报如下错误

Mar 17 23:29:11 ovpn-client[23276]: /sbin/ip -6 addr add 2001:db8:0:123::1007/64 dev tun0
Mar 17 23:29:11 ovpn-client[23276]: Linux ip -6 addr add failed: external program exited with error status: 2
Mar 17 23:29:11 ovpn-client[23276]: Exiting due to fatal error

  结果发现是由于sysctlnet.ipv6.conf.all.disable_ipv6 = 1导致IPv6配置被禁止,可通过cat /proc/sys/net/ipv6/conf/all/disable_ipv6命令查看结果是否为1,如果是的话通过以下命令解决该问题

echo "net.ipv6.conf.all.disable_ipv6 = 0" >> /etc/sysctl.conf
sysctl -p

2条评论

  1. 你好,按照你的配置我只能连接一台内网的服务器(就是这台server),内网其它的服务器访问不了,请问如何解决,谢谢。

发表评论

电子邮件地址不会被公开。 必填项已用*标注