# Ubuntu 18.04+ 安装维护企业内网 OpenVPN 最佳实践
## 首先:跟着教程走完安装
> 教程:
> - 原文:<https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-18-04>
> - 译文1:<https://www.howtoing.com/how-to-set-up-an-openvpn-server-on-ubuntu-18-04>
> - 译文2:<https://www.gobeta.net/posts/how-to-set-up-an-openvpn-server-on-ubuntu-18-04/>
- 这个教程总共有12个大步骤(12个主要章节),其中所有没标Optional(可选)的大步骤**都是必须做的**,别省任何一步。它里面必选和可选是交替出现的,所以别看到一个可选就停止往下看了,下面还有其他必须做的。
- 一定注意这个教程的Prerequisites(先决条件)章节,这里面是有干货的,讲了把OpenVPN服务器和CA签名服务器分离开的架构设计。如果你觉得安全性不那么重要,可以直接使用同一个服务器,同一个EasyRSA工具包。不过就是要把教程里导入导出、在两个服务器间传输文件之类的步骤自己跳过,相信熟悉Linux命令行的你一定没有问题。其实分离开确实看起来非常牛逼,但是在接下来的维护中,尤其是自动化中,会搞出一些麻烦。建议非必要不分离。
- 教程里生成客户端连接配置(`.ovpn`文件)时的脚本只负责生成连接配置,证书还是要手动创建的。因此我写了一个魔改版本,把自动生成证书的脚本也揉合进去了,文件见本文最后。使用我这个魔改版,只要运行一次,就自动生成一个客户端证书和其对应的`.ovpn`,直接把`.ovpn`文件发给客户端使用就可以了。
- 教程的最后一章是介绍证书吊销的,建议在开服的时候就预先生成一个吊销文件,然后写到`server.conf`里,这样以后真的有需要吊销的证书时,就可以不动配置文件了。
别看步骤多,按部就班跟下来就没有问题!
接下来补充一些教程中缺少的东西。
## 一键生成/吊销证书
### 一键生成证书和连接配置
> 下面附上我写的一个开箱即用的脚本,魔改自前面教程里的脚本。
>
> 请先按前面的教程走一遍,知道客户端配置文件生成脚本的大概用法后,再替换成本段脚本。
给新人开户时,一键签名,自动导出`.ovpn`文件,可以直接分发。下面放代码`gen-ovpn.sh`:
```bash
#!/bin/bash
# First argument: Client identifier
# Second argument: nopass
cd $(dirname $0) || exit 127
if [ $# -eq 0 ] || [ "$1" == "" ]; then
echo "No arguments provided, please set a Client ID in arg 1, 'nopass' if need in arg 2."
exit 1
fi
KEY_DIR=./keys
OUTPUT_DIR=./files
BASE_CONFIG=./base.conf
EASYRSA_PATH=/opt/EasyRSA-3.0.8
CURRENT_PATH="$(pwd)"
# register and sign a cert
cd $EASYRSA_PATH
if [ "$2" == "nopass" ]; then
./easyrsa gen-req "$1" nopass
else
./easyrsa gen-req "$1"
fi
cp "pki/private/$1.key" "$CURRENT_PATH/keys/"
./easyrsa sign-req client "$1"
cp "pki/issued/$1.crt" "$CURRENT_PATH/keys/"
# generate client config file
cd $CURRENT_PATH
cat ${BASE_CONFIG} \
<(echo -e '<ca>') \
${KEY_DIR}/ca.crt \
<(echo -e '</ca>\n<cert>') \
${KEY_DIR}/${1}.crt \
<(echo -e '</cert>\n<key>') \
${KEY_DIR}/${1}.key \
<(echo -e '</key>\n<tls-auth>') \
${KEY_DIR}/ta.key \
<(echo -e '</tls-auth>') \
> ${OUTPUT_DIR}/${1}.ovpn
echo "Done. See$CURRENT_PATH/files/$1.ovpn"
```
- 执行脚本时,第一个参数传准备生成的客户端名称(ID),第二个参数不传或传`nopass`,取决于有没有密码,要设置密码则不传,生成过程中会主动让你输入
- `EASYRSA_PATH`是你解压的EasyRSA工具包的根目录,视情况变动
- `KEY_DIR`、`OUTPUT_DIR`、`BASE_CONFIG`这几个东西是教程里有的,一般不需要变动
现在好了,开始派发证书给VPN客户端吧!
### 一键吊销证书
根据给定的名称一键式吊销一个(或多个)证书
## (可选)打开单证书共用模式
OpenVPN默认是**一个连接设备一个证书**,但是生成不是特别自动化,有时候会显得麻烦。
**建议给需要较高安全性的连接使用单独证书,不要混用证书。连接人员经常变动也不要混用证书,否则任何人员离职都需要吊销证书,全体更新**。但是不特别要求安全性的场景,就可以打开共用模式。这样也方便控制证书管理的粒度。
共用模式可以有如下用途:
1. 一个项目组的开发期间,组内所有的开发机器可以使用同一个证书,开发结束后证书失效;
2. 每名员工只产生一个证书,如果这名员工有多台个人设备需要连VPN,则使用同一个证书。
**做法:**`server.conf`里,激活`duplicate-cn`(如果没有就加一行)
## (可选)允许客户端互访
OpenVPN默认只支持C<->S的访问,不允许连接到同一局域网的各个客户端互访。解决方法是在`server.conf`里,激活`client-to-client`(如果没有就加一行)
## 实时状态监控和管理
可以使用OpenVPN自带的管理界面(management interface):在`server.conf`里添加`management localhost <port>`,然后重启服务,再`telnet localhost <port>`,就可以看到里面有大量的操作。
当然也可以简单查看活跃的客户端连接:`cat /var/log/openvpn/openvpn-status.log`
## 静态IP和组网
> **注意:** 静态IP与单证书共用存在冲突,设定了静态IP的证书必须永远只在一个客户端上使用,不能两个客户端同时用一个静态IP证书。
参考[这篇教程](https://openvpn.net/community-resources/configuring-client-specific-rules-and-access-policies/)
在`server.conf`里,我的配置如下,仅供参考:
```bash
# 网络结构:
# 10.8.0.0/25 DHCP,也是VPN基本服务,支持64*128-1=8191个动态IP
# 10.8.128.0/25 静态IP,支持64*128=8192个静态IP
# 10.9.0.0/29 管理员特殊权限的静态IP,支持2个静态IP
server 10.8.0.0 255.255.128.0
client-config-dir ccd
route 10.8.128.0 255.255.128.0
route 10.9.0.0 255.255.255.248
push "route 10.8.128.0 255.255.128.0"
# 管理员不需要客户端互访,提升安全性
# push "route 10.9.0.0 255.255.255.248"
```
在`server.conf`同级新建一个`ccd`目录,比如我在生成客户端时(见上)把一个客户端定名为`admin`,那么我就可以在`ccd/admin`文件中写入:
```
ifconfig-push 10.9.0.1 10.9.0.2
```
整个文件就这一行。其中IP地址的最后8位(最后一段)必须是如下64种组合之一:
```
[ 1, 2] [ 5, 6] [ 9, 10] [ 13, 14] [ 17, 18]
[ 21, 22] [ 25, 26] [ 29, 30] [ 33, 34] [ 37, 38]
[ 41, 42] [ 45, 46] [ 49, 50] [ 53, 54] [ 57, 58]
[ 61, 62] [ 65, 66] [ 69, 70] [ 73, 74] [ 77, 78]
[ 81, 82] [ 85, 86] [ 89, 90] [ 93, 94] [ 97, 98]
[101,102] [105,106] [109,110] [113,114] [117,118]
[121,122] [125,126] [129,130] [133,134] [137,138]
[141,142] [145,146] [149,150] [153,154] [157,158]
[161,162] [165,166] [169,170] [173,174] [177,178]
[181,182] [185,186] [189,190] [193,194] [197,198]
[201,202] [205,206] [209,210] [213,214] [217,218]
[221,222] [225,226] [229,230] [233,234] [237,238]
[241,242] [245,246] [249,250] [253,254]
```
这样,再次通过`admin`客户端连接到VPN时,就可以看到它被分配了地址`10.9.0.1`,而且,这个客户端依然可以访问`10.8.0.0`下的IP地址。
> **后记:**
>
> 接下来我们就可以通过ufw、iptables、Nginx的`allow/deny`等手段来控制不同用户和不同网络的连接权限了。这部分略。
>
> 另外OpenVPN支持客户端的内网穿透,可以实现客户端自带一大堆内部网,然后通过客户端整体连接到VPN并与VPN其他网络互访,这部分略,可以参考<http://www.linuxfly.org/post/86/>。
## 内网DNS
仅在连接上VPN后,才能访问某些域名,或者把某些域名从公网ip切换到���网ip,以实现一些内网Web服务。
### 服务器配置(`server.conf`)
`push`是一个服务端向客户端推送配置项的功能,写在`server.conf`里。其实和去掉push和外层引号后直接写在客户端的`.ovpn`文件里作用是一样的。
```
push "dhcp-option DNS 127.0.0.1"
push "dhcp-option DNS 10.8.0.1"
push "dhcp-option DNS 223.5.5.5"
push "dhcp-option DNS 8.8.8.8"
```
`10.8.0.1`可以改成别的地址,你的内网DNS的地址。我使用的是Bind9+Webmin作DNS服务器。
### Windows客户端配置
使用GUI客户端连接即可,没什么额外配置。