Ubuntu16.04搭建OpenVPN
简介
如果在一个非信任网络下比如旅社或者咖啡店的WiFi网络下,想要通过你的智能手机或者笔记本电脑安全地访问互联网,那么VPN可以满足你的要求。VPN(VirtualPrivate Network)允许你私有地(privately)安全地(securely)穿过非信任的网络,就好像为你建立了一条专属网络。你的数据流量到达VPN服务器之后,VPN服务器继续将你的网络流量送达目的地。
如果配合HTTPS连接,这个方案可以让你的无线登录和数据传输变得安全。VPN可以让你克服地理限制和审查(比如克服大陆的GFW),保护你的本地位置信息等。
OpenVPN是一个全功能的开源安全套接字层(SSL)VPN解决方案,它包含大量的配置信息。在这篇教程里,我们将在一个公网服务器(本文的服务器为Ubuntu16.04)上面安装一个OpenVPN服务器然后进行相应的配置,使得Windows,OS X,IOS以及Android客户端能够访问它。这篇教程尽可能简单地从以下步骤中进行安装和配置。
前提条件
开始这篇教程之前,你应当能够访问到你的Ubuntu 16.04服务器。
你需要设置一个具有sudo权限的非root用户,当然如果你就是root更好。达到这些条件之后,用你的sudo用户登录到你的Ubuntu服务器,然后继续按照以下步骤进行。
(注意:必须要用sudo用户,否则以下步骤会出问题)
第一步:安装OpenVPN
OpenVPN在Ubuntu的默认仓库中是可用的,所以我们可用使用apt来安装。我们还需安装一个easy-rsa包,这个包可以帮助我们建立一个内部CA(certificate authority)用于使用我们VPN。
更新你的服务器包索引并安装必要的包类型:
$ sudo apt-get update
$ sudo apt-get install openvpn easy-rsa
现在你的服务器上面有了所需的软件,接下来是相关的配置。
第二步:建立CA目录
OpenVPN是一个TLS/SSLVPN,这意味着它需要使用证书来在客户端和服务器之间加密数据。为了发布可信的证书,我需要建立我们自己的简单CA(certificate authority)。
开始之前,我们可以使用make-cadir命令,用于复制easy-rsa临时目录到我们的home目录下面:
$ make-cadir ~/openvpn-ca
上面这条命令也用下面的两条命令来做:
$ mkdir ~/openvpn-ca
$ cp -r /usr/share/easy-rsa/* ~/openvpn-ca
然后进入到我们新创建的目录中来开始配置CA:
$ cd ~/openvpn-ca
第三步:配置CA变量
我们需要编辑当前目录下vars文件来配置CA要用到的值,用你的文本编辑器打开vars文件:
$ nano vars
在这个文件里面,你会发现许多变量,这些变量用于决定怎样生成你的证书,你可以修改这些变量的值。在这里我们只需要关注几个变量就行。
在文件的底部,找到如下信息:
~/openvpn-ca/vars
. . .
exportKEY_COUNTRY="US"
exportKEY_PROVINCE="CA"
exportKEY_CITY="SanFrancisco"
exportKEY_ORG="Fort-Funston"
exportKEY_EMAIL="me@myhost.mydomain"
exportKEY_OU="MyOrganizationalUnit"
. . .
将这些红色的值编辑成任何你喜欢的,但不要让它们空着,比如我的:
~/openvpn-ca/vars
. . .
export KEY_COUNTRY="CN"
export KEY_PROVINCE="GD"
export KEY_CITY="ShanTou City"
export KEY_ORG="STU"
export KEY_EMAIL="qfuqin@163.com"
export KEY_OU="University"
. . .
到这步之后,我们再编辑KEY_NAME的值,简单起见,我们将它命名为server,如下:
~/openvpn-ca/vars
export KEY_NAME="server"
完成之后,保存并退出。
第四步:制作CA
现在我们可以使用我们刚刚设置的变量,用easy-rsa包来制作CA。确保你处在你的CA目录下面,然后source我们刚刚编辑的vars文件。
$ cd ~/openvpn-ca
$ source vars
如果source正确的话,你会看到如下信息:
NOTE: If you run ./clean-all, I will be doing a rm -rf on /home/sammy/openvpn-ca/keys
通过输入如下命令确保我们的操作处于一个clean环境中:
$ ./clean-all
现在我们可以制作我们的root CA:
$ ./build-ca
上面这一步会开始制作根证书颁发机构密钥(rootcertificate authority key )和证书(certificate),由于我们刚刚填了vars文件,证书制作所需要变量的值都会自动填充,制作过程中你只需要回车来确认就行。消息输出如下:
Generating a 2048 bit RSA private key
..........................................................................................+++
...............................+++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that willbe incorporated
into your certificate request.
What you are about to enter is what is called aDistinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [CN]:
State or Province Name (full name) [GD]:
Locality Name (eg, city) [ShanTou City]:
Organization Name (eg, company) [STU]:
Organizational Unit Name (eg, section) [University]:
Common Name (eg, your name or your server's hostname) [STUCA]:
Name [server]:
Email Address [qfuqin@163.com]:
现在我们得到了一个CA文件,CA文件可以用于制作我们接下来所需的文件。
第五步:制作Server端的 Server Certificate, Key, Encryption Files
接下来,我们将制作服务端所需要的证书,这些证书就像传统的用于加密过程的文件一样。通过键入如下命令来生成服务端所需的证书:
$ ./build-key-server <span style="color:#ff0000;">server</span>
server
上面红色字体的server就是我们在vars文件中填入的export KEY_NAME="server",如果你不是填入的server这个名称,则./build-key-server后面输入你自己填的那个名称。制作过程中一路回车,中间出现 challenge password ,不要输入任何值回车就行,最后的会有两个问题,输入y就行,如下所示:
. . .
Certificate is to be certified until May 1 17:51:16 2026 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
如果以上操作无误的话应该可以看到生成的server.crt、server.key和server.csr三个文件。其中server.crt和server.key两个文件是我们所需要的。现在再为服务器生成加密交换时的Diffie-Hellman文件。输入以下命令:
$ ./build-dh
完成这一步可能需要几分钟时间。
最后,我们可以生成一个HMAC签名来增强服务器的TLS完整性验证能力:
$ openvpn --genkey --secret keys/ta.key
第六步:制作Client端的 Client Certificate, Key
尽管客户端的相关证书可以在客户端的机器上面生成,为了简单起见,在这篇教程中我们在服务器上面来生成客户端的相关证书,然后再把服务器上生成的客户端证书下载到本地客户端上面。我们用client1来命名我们的第一个证书/密钥对,用build-key命令来生成没有密码情况下的凭证,并且用于自动连接:
$ cd ~/openvpn-ca
$ source vars
$ ./build-key <span style="color:#ff0000;">client1</span>
client1
如果你想生成一个带密码保护的凭证,可以使用build-key-pass命令:
$ cd ~/openvpn-ca
$ source vars
$ ./build-key-pass <span style="color:#ff0000;">client1</span>
client1
然后一路回车,中间出现challenge password,不要输入任何值回车就行,最后的会有两个问题,输入y就行。
第七步:配置OpenVPN服务器
接下来,我们利用已经生成的相关文件来配置OpenVPN服务器。
1.把相关证书复制到OpenVPN的目录下面
开始之前,把我们需要的相关文件复制到/etc/openvpn这个配置目录中去,即把~/openvpn-ca/keys目录下面的ca.crt,ca.key,server.crt,server.key,HMAC签名以及Diffie-Hellman文件复制到/etc/openvpn这个目录下面:
$ cd ~/openvpn-ca/keys
$ sudo cp ca.crt ca.key server.crt server.key ta.key dh2048.pem /etc/openvpn
然后从OpenVPN自带的配置模板中复制配置文件:
$ cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz /etc/openvpn/
$ cd /etc/openvpn/
$ gzip -d server.conf.gz
2.修改OpenVPN配置文件
$ sudo nano /etc/openvpn/server.conf
基本配置步骤如下:
首先,通过查找tls-auth指令找到HMAC部分,移除";"来解注释tls-auth,并且在tls-auth的下面,增加一个key-direction参数,设置其参数值为0,如下:
/etc/openvpn/server.conf
tls-auth ta.key 0 # This file is secret
key-direction 0
然后,通过查找被注释的clipher这一行找到加密密码的部分,aes128-cbc密码提供了很好的加密级别,并且得到了很好的支持。移除";"来解注释cipher AES-128-CBC,如下:
/etc/openvpn/server.conf
cipher AES-128-CBC
在这一行的下面,添加一个auth行(身份验证行)来选择HMAC消息摘要算法,这里推荐SHA256消息摘要算法:
etc/openvpn/server.conf
auth SHA256
最后,找到user和group参数,去除它们之前的";",如下:
/etc/openvpn/server.conf
user nobody
group nogroup
(可选配置)推动DNS更改让VPN重定向所有流量
上面的配置可以在客户端和服务器端上创建VPN连接,但是没有强迫连接去使用tunnel。如果你希望用VPN来路由你的所有流量,你需要更改你的客户端机器的DNS设置。
你可以按照以下步骤设置,解注释一些指令使得你的客户端机器把所有的web流量重定向到VPN上面,找到redirect-gateway部分然后移除它之前的";",如下:
/etc/openvpn/server.conf
push "redirect-gateway def1 bypass-dhcp"
在这条指令的下面,找到dhcp-option部分,移除这两行之前的";",如下:
push "dhcp-option DNS 223.5.5.5"
push "dhcp-option DNS 114.114.114.114"
这就可以协助客户版重新配置DNS,以便使用VPN tunnel来作为默认网关。
(可选配置)修改OpenVPN服务器的端口和协议
OpenVPN服务器默认使用1194端口和UDP协议来接收客户端的连接,也许由于客户端那边的网络环境限制,你需要使用一个不同的端口,那么你可以改变port选项,如果你的Ubuntu16.04服务器没有托管web服务,那么443端口是一个可替换1194的不错选择,因为防火墙往往对443端口不受限。
/etc/openvpn/server.conf
# Optional!
port 443
我们同样可以将协议从UDP换成TCP:
/etc/openvpn/server.conf
# Optional!
proto tcp
如果你没有更换端口的需求,最好将上述的两项保持默认设置。
(可选配置)指定非默认的凭证(Point to Non-Default Credentials)
如果你在之前的./build-key-server命令用了不同的名字(我们之前用的server这个名字),那么修改cert和key这两行,将这两行的值设为你之前用的那个名字.crt和你之前那个名字.key,如果你默认使用的server这个名字,那么这里你已经正确的设置好了,如下:
/etc/openvpn/server.conf
cert server.crt
key server.key
以上设置完毕之后,保存并退出server.conf这个文件。
第八步:调整Ubuntu16.04服务的网络配置
接下来,我们需要调整Ubuntu16.04服务器上面网络的一些配置,以便于OpenVPN服务器可以正确的路由流量。
1.允许IP转发
首先,我们需要让我们的服务器来转发流量,这是我们需要VPN服务器来提供的最基本的功能。我们可以通过修改/etc/sysctl.conf文件来调整网络设置:
$ sudo nano /etc/sysctl.conf
在这个文件里面,找到net.ipv4.ip_forward,去除这一行之前的"#"来解注释这个参数:
etc/sysctl.conf
net.ipv4.ip_forward=1
完成后保存并退出该文件。
为了读取sysctl.conf文件并且让调整后设置对当前系统的session生效,键入如下命令:
$ sudo sysctl -p
2.调整防火墙(UFW)规则来伪装客户端的连接
在这篇教程中我们需要配置防火墙规则来引导进入服务器的一些流量,我们需要修改防火墙规则文件来建立伪装规则,iptables的概念用于提供动态的NAT,从而正确地路由客户端连接。在打开防火墙配置文件以添加伪装规则之前,我们需要找到我们Ubuntu服务器的公共网络接口,输入如下命令:
$ ip route | grep default
你的公共网络接口应当紧跟在单词"dev"后面,例如,我的接口名字为eth0:
default via 172.18.31.253 dev eth0
当你有一个与你的默认路由相关联的接口的时候,打开/etc/ufw/before.rules这个文件并添加相应的规则:
$ sudo nano /etc/ufw/before.rules
这个文件处理在加载常规UFW规则之前应该被放置的文件,在这个文件的最开始处加入下面红色部分的内容。这样可以为nat表设置POSTROUTING默认规则,并且为来自VPN的任何流量设置伪装连接。
/etc/ufw/before.rules
#
# rules.before
#
# Rules that should be run before the ufw command lineadded rules. Custom
# rules should be added to one of these chains:
# ufw-before-input
# ufw-before-output
# ufw-before-forward
#
# START OPENVPN RULES
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
# Allow traffic from OpenVPN client to eth0(changeto the interface you discovered!)
-A POSTROUTING -s 10.8.0.0/8 -o eth0 -jMASQUERADE
COMMIT
# END OPENVPN RULES
# Don't delete these required lines, otherwise there willbe errors
*filter
. . .
完成后保存并退出。
然后告诉防火墙默认允许转发包:
$ sudo nano /etc/default/ufw
在这个文件里面,找到DEFAULT_FORWARD_POLICY指令,将它的值从DROP改成ACCEPT:
/etc/default/ufw
DEFAULT_FORWARD_POLICY="ACCEPT"
完成后保存并退出。
3.打开OpenVPN端口并且使变化生效
接下来,调整防火墙本身,以允许流量到OpenVPN。如果你在/etc/openvpn/server.conf文件中没有修改OpenVPN的端口号和协议类型,那么直接配置防火墙允许UDP流量到1194端口,如果你改变了端口和协议类型,那么根据你自己设置的端口和协议类型进行配置。
$ sudo ufw allow 1193/udp
$ sudo ufw allow OpenSSH
现在,我们可以从所有修改过的文件中装载配置来关闭和重启防火墙:
$ sudo ufw disable
$ sudo ufw enable
到这里我们的服务器可以正确地处理OpenVPN流量了。
第九步:开启OpenVPN服务
在systemd单元文件的后面,我们通过指定特定的配置文件名来作为一个实例变量来开启OpenVPN服务,我们的配置文件名称为/etc/openvpn/server.conf,所以我们在systemd单元文件的后面添加@server来开启OpenVPN服务:
$ sudo systemctl start openvpn@server
通过如下命令再次确认OpenVPN服务已经成功地开启了:
$ sudo systemctl status openvpn@server
如果一切正常的话,你的输出应当跟如下类似:
● openvpn@server.service - OpenVPN connection to server
Loaded: loaded(/lib/systemd/system/openvpn@.service; disabled; vendor preset: enabled)
Active: active (running) since Tue 2016-05-03 15:30:05 EDT;47s ago
Docs:man:openvpn(8)
https://community.openvpn.net/openvpn/wiki/Openvpn23ManPage
https://community.openvpn.net/openvpn/wiki/HOWTO
Process: 5852ExecStart=/usr/sbin/openvpn --daemon ovpn-%i --status /run/openvpn/%i.status 10--cd /etc/openvpn --script-security 2 --config /etc/openvpn/%i.conf --writepid/run/openvpn/%i.pid (code=exited, sta
Main PID: 5856(openvpn)
Tasks: 1(limit: 512)
CGroup:/system.slice/system-openvpn.slice/openvpn@server.service
└─5856/usr/sbin/openvpn --daemon ovpn-server --status /run/openvpn/server.status 10--cd /etc/openvpn --script-security 2 --config /etc/openvpn/server.conf--writepid /run/openvpn/server.pid
May 03 15:30:05 openvpn2 ovpn-server[5856]: /sbin/ip addradd dev tun0 local 10.8.0.1 peer 10.8.0.2
May 03 15:30:05 openvpn2 ovpn-server[5856]: /sbin/iproute add 10.8.0.0/24 via 10.8.0.2
May 03 15:30:05 openvpn2 ovpn-server[5856]: GID set tonogroup
May 03 15:30:05 openvpn2 ovpn-server[5856]: UID set tonobody
May 03 15:30:05 openvpn2 ovpn-server[5856]: UDPv4 linklocal (bound): [undef]
May 03 15:30:05 openvpn2 ovpn-server[5856]: UDPv4 linkremote: [undef]
May 03 15:30:05 openvpn2 ovpn-server[5856]: MULTI:multi_init called, r=256 v=256
May 03 15:30:05 openvpn2 ovpn-server[5856]: IFCONFIGPOOL: base=10.8.0.4 size=62, ipv6=0
May 03 15:30:05 openvpn2 ovpn-server[5856]: IFCONFIG POOLLIST
May 03 15:30:05 openvpn2 ovpn-server[5856]:Initialization Sequence Completed
你可以通过如下命令来确认OpenVPN tun0接口是否可用
$ ip addr show tun0
你应该可以看到一个配置接口:
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP>mtu 1500 qdisc noqueue state UNKNOWN group default qlen 100
link/none
inet 10.8.0.1peer 10.8.0.2/32 scope global tun0
valid_lftforever preferred_lft forever
如果一切运行正常,将OpenVPN设置为开机自启动:
$ sudo systemctl enable openvpn@server
第十步:构造客户端所需的.ovpn文件配置工厂
这一步,我们建立一个更加容易生成客户端所需配置文件的系统。
1.创建客户端配置目录结构
在你的home目录下面创建一个目录结构来保存客户端的相应配置文件:
$ mkdir -p ~/client-configs/files
由于客户端的配置目录里面将包含客户端的密钥,所以我们应该对这个目录进行权限的锁定:
$ chmod 700 ~/client-configs/files
2.创建基本的配置文件
这一步,我们将OpenVPN自带的客户端配置模板复制到我们刚刚创建的客户端配置目录中作为一个客户端的基本配置文件:
$ cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
打开base.conf并做一些修改:
首先,找到remote指令,这条指令用于指定OpenVPN服务器所在的地址,这个地址应当是你的OpenVPN所在的服务器的公网IP地址。如果你改变了OpenVPN监听的端口,那么把1194换成你所设置的端口:
~/client-configs/base.conf
. . .
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote server_IP_address 1194
. . .
确保你在server配置文件(/etc/openvpn/server.conf文件)里面你所设置的协议类型:
~/client-configs/base.conf
proto udp
然后去除user和group指令前面的";",如下:
~/client-configs/base.conf
# Downgrade privileges after initialization (non-Windowsonly)
user nobody
group nogroup
然后找到设置ca,cert和key的指令,将这些指令注释掉,因为我们会在这个配置文件里面自己设置certs和keys的值:
~/client-configs/base.conf
# SSL/TLS parms.
# See the server config file for more
# description. It's best to use
# a separate .crt/.key file pair
# for each client. A single ca
# file can be used for all clients.
#ca ca.crt
#cert client.crt
#key client.key
然后镜像(或者说模仿)我们在/etc/openvpn/server.conf文件里面设置的cipher和auth:
~/client-configs/base.conf
cipher AES-128-CBC
auth SHA256
接下来,在文件的某位置处增加key-direction指令,这个指令的值必须设置为1才能与服务器合作:
~/client-configs/base.conf
key-direction 1
最后添加一些注释信息,我们希望配置信息能够用于所有的客户端,但是下面的注释信息只能用于Linux客户端:
~/client-configs/base.conf
# script-security 2
# up /etc/openvpn/update-resolv-conf
# down /etc/openvpn/update-resolv-conf
如果你的客户端运行在Linux上面并且有一个/etc/openvpn/update-resolv-conf文件,你应当将上面的三条指令解注释。
最后保存并退出base.conf文件。
3.写一个自动生成客户端.ovpn配置文件的脚本
这一步,我们写一个简单的脚本,用于将相关的certificate,key和加密文件编译我们刚刚制作的base.conf文件,编译完成后得到一个.ovpn客户端文件。
在~/client-configs目录下面创建make_config.sh文件:
$ nano ~/client-configs/make_config.sh
在将如下内容复制到make_config.sh文件中:
#!/bin/bash
# First argument: Client identifier
KEY_DIR=/etc/openvpn/easy-rsa/keys
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf
cat ${BASE_CONFIG} \
<(echo -e '<ca>') \
${KEY_DIR}/ca.crt \
<(echo -e '</ca>\n<cert>') \
${KEY_DIR}/<span style="color:#ff0000;">client1</span>.crt \
<(echo -e '</cert>\n<key>') \
${KEY_DIR}/<span style="color:#ff0000;">client1</span>.key \
<(echo -e '</key>\n<tls-auth>') \
${KEY_DIR}/ta.key \
<(echo -e '</tls-auth>') \
> ${OUTPUT_DIR}/${1}.ovpn
client1.crt \
<(echo -e '</cert>\n<key>') \
${KEY_DIR}/client1.key \
<(echo -e '</key>\n<tls-auth>') \
${KEY_DIR}/ta.key \
<(echo -e '</tls-auth>') \
> ${OUTPUT_DIR}/${1}.ovpn
完成后保存并关闭该文件,通过以下命令标记该文件为可执行文件:
$ chmod 700 ~/client-configs/make_config.sh
第十一步:生成客户端.ovpn配置文件
现在我们可以轻松地生成客户端配置文件,只需要如下简单的命令即可:
$ cd ~/client-configs
$ ./make_config.sh <span style="color:#ff0000;">client-for-android</span>
client-for-android
如果一切顺利的话,在~/client-configs/files目录下面会生成一个client-for-android.ovpn文件,client-for-android是随意起的名字,你也可以按照你自己的想法命名,最后在~/client-configs/files文件夹内会生成你所命名的.ovpn文件。
接下来把client-for-android.ovpn下载到你的客户端即可,这里可以使用相应的工具下载,我本人是在Ubuntu16.04里面搭建了vsftpd服务,所以传输文件比较方便。
第十二步:在客户端OpenVPN上安装配置文件
这个步骤比较简单,先根据你的操作系统平台选择下载相应的客户端OpenVPN,然后把第十一步中的.ovpn配置文件导入到客户端的OpenVPN即可,正常情况下可以直接连接到服务器端的OpenVPN。