使用Docker架设OpenVPN服务端实现异地组网

使用Docker架设OpenVPN服务端实现异地组网

张涵哲
2023-11-07 / 3 评论 / 28 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2023年12月25日,已超过63天没有更新,若内容或图片失效,请留言反馈。

需要一台有公网IP的服务器

操作系统:Ubuntu 22.04 LTS
Docker版本:Docker Engine - Community 24.0.6
Docker镜像地址:https://hub.docker.com/r/kylemanna/openvpn
GitHub开源地址:https://github.com/kylemanna/docker-openvpn

服务端架设

生成配置文件

该Docker镜像对OpenVPN的一些操作进行了封装,这里初始化环境配置文件

# 初始化配置文件到宿主机的/opt/docker/openvpn目录下(可自行修改)
$ docker run -v /opt/docker/openvpn:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://公网IP

# 配置文件初始化完成,如有需要可以在这里修改配置文件便于后面生成证书
$ ls /opt/docker/openvpn/
ccd  openvpn.conf  ovpn_env.sh
生成服务端证书

OpenVPN中有证书的概念,服务端需要有证书才可以启动,否则会启动报错,这也是上面运行docker容器时为什么都加--rm的原因,这里初始化服务端证书

# 根据配置文件初始化服务端证书,结尾nopass为可选项,表示无需密码生成证书,过程需要输入Common Name,如不想输入可以选择直接回车
$ docker run -v /opt/docker/openvpn:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki nopass

# 证书生成时间可能会比较长,会输出一堆.....+.......耐心等待即可,生成后可查看效果
$ ls /opt/docker/openvpn/
ccd  openvpn.conf  ovpn_env.sh  pki
启动OpenVPN服务

启动OpenVPN服务就比较简单了,直接使用下面段命令启动容器即可,这里需要注意暴露端口使用的时udp协议,如果服务器有设置安全组记得要放行udp协议的1194端口

# 启动OpenVPN服务
$ docker run --name openvpn -v /opt/docker/openvpn:/etc/openvpn -p 1194:1194/udp --cap-add=NET_ADMIN -d kylemanna/openvpn

# 查看运行状态,检查OpenVPN是否启动成功
$ docker ps
CONTAINER ID   IMAGE               COMMAND      CREATED         STATUS        PORTS                                       NAMES
85c5c0da569a   kylemanna/openvpn   "ovpn_run"   2 seconds ago   Up 1 second   0.0.0.0:1194->1194/udp, :::1194->1194/udp   openvpn

# 查看目录,发现此时多了一个crl.pem,据说是证书吊销列表文件,我没用过不太清楚不过不用管放着就行
$ ls /opt/docker/openvpn
ccd  crl.pem  openvpn.conf  ovpn_env.sh  pki

客户端管理

之前说过OpenVPN中有证书的概念,服务端必须有证书才可以启动,同样的客户端也需要有证书才能加入VPN网络,这里介绍Docker中封装的几个客户端管理命令,也可以点击这里直接看原文档

命令解释
docker exec -it openvpn easyrsa build-client-full [client] nopass生成无密码的客户端证书
docker exec -it openvpn ovpn_getclient [client] > [client].ovpn构建带有嵌入证书的.ovpn文件
docker exec -it openvpn ovpn_listclients查看客户端列表
docker exec -it openvpn ovpn_revokeclient [client] remove吊销客户端证书
使用案例
# 生成一个客户端证书 cc
$ docker exec -it openvpn easyrsa build-client-full cc nopass

# 查看客户端列表,多了一个刚刚创建的cc
$ docker exec -it openvpn ovpn_listclients
name,begin,end,status
cc,Nov  7 08:00:22 2023 GMT,Feb  9 08:00:22 2026 GMT,VALID

# 构建带有嵌入式证书的.ovpn文件
$ docker exec -it openvpn ovpn_getclient cc > cc.ovpn

# 查看配置文件目录,多个了cc.ovpn文件,这个就是客户端加入VPN网络用到的文件,里面嵌入了证书
$ ls /opt/docker/openvpn
ccd  cc.ovpn  crl.pem  openvpn.conf  ovpn_env.sh  pki

# 正常来说每个客户端都应该有个独享的.ovpn证书,如果不想让某个人继续使用VPN就吊销它的证书,吊销过程需要手动输入yes
$ docker exec -it openvpn ovpn_revokeclient cc remove

# .ovpn文件需要手动删除,吊销后可以查看证书列表看看效果,这里我就不看了
$ rm /opt/docker/openvpn/cc.ovpn

当服务端的配置项做出修改后如果没有生效,建议删除证书重启容器后生成新的证书在进行测试

修改IP段

通过Docker镜像生成的环境配置中,默认使用的IP段是192.168.255.x,如果不幸网络环境与这个IP段冲突就不好办了,针对这点可以通过修改配置文件来修改IP段,这里我选择将IP段修改为10.18.0.x

# 编辑OpenVPN配置文件
# 将 server 192.168.255.0 255.255.255.0 改为 server 10.18.0.0 255.255.255.0
# 将 route 192.168.254.0 255.255.255.0 改为 route 10.18.1.0 255.255.255.0
$ vim /opt/docker/openvpn/openvpn.conf

# 编辑环境配置文件
# 将 declare -x OVPN_ROUTES=([0]="192.168.254.0/24") 改为 declare -x OVPN_ROUTES=([0]="10.18.1.0/24")
# 将 declare -x OVPN_SERVER=192.168.255.0/24 改为 declare -x OVPN_SERVER=10.18.0.0/24
$ vim /opt/docker/openvpn/ovpn_env.sh

配置分割隧道

当客户端加入VPN网络后全局都会走VPN网络,如果服务器带宽不高就会严重影响使用体验,个人强烈推荐配置分割隧道,只有访问VPN内部资源时走VPN网络,可点击访问原文档查看对此的描述

# 禁用默认路由(-d),但仍使用NAT(-N)来保持网络地址转换启用
$ docker exec -it openvpn ovpn_genconfig -N -d

# 使用ovpn_genconfig修改配置后目录下会对原配置进行备份生成.bak文件
$ ls /opt/docker/openvpn
ccd  crl.pem  openvpn.conf  openvpn.conf.1699346494.bak  ovpn_env.sh  ovpn_env.sh.1699346494.bak  pki

配置静态(固定)IP

当客户端加入VPN网络后默认是从前往后分配IP地址的,如果有某台机器需要固定IP的话可以通过在ccd目录下添加配置文件来实现,可以点击这里查看原文档,例如之前创建的客户端,我希望使用cc证书登录的用户分配到的始终是静态IP

# 在ccd目录下创建与客户端同名的文件
# 在客户端同名文件中添加: ifconfig-push 10.18.0.6 10.18.0.5
# 其中.0.6代表IP地址,.0.5代表网关地址
$ vim /opt/docker/openvpn/ccd/cc

需要注意的是IP地址不能随便用,只能从以下范围中选取,具体详见这篇文章,否则可能会报错

[  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]

[1, 2]IP地址默认被服务端占用,所以IP地址是从[5, 6]开始分配的,个人建议按照OpenVPN的规范来使用,例如[21, 22]这一组,应该用后面的22作为IP地址,前面的21作为网关,如下所示

# 假设这是ccd目录下某个配置文件
ifconfig-push 10.18.0.22 10.18.0.21

其他配置项

这里只记录几个我用到过的配置项,其余配置项日后我用到在随时补充

# 允许客户端与客户端相连接
client-to-client

# 允许一套证书或账户多人登录
duplicate-cn

Windows加入VPN网络

安装OpenVPN客户端软件,软件下载地址结尾会给出,安装过程中会提示安装虚拟网卡的弹窗,一定要点击同意,安装完成后打开OpenVPN的安装目录,将服务端构建的.ovpn文件下载并放入config目录下,然后双击运行OpenVPN软件,右下角右键建立连接即可

2023-11-07T09:16:55.png

Linux加入VPN网络

这里使用Ubuntu作为演示机器,首先要保证服务器内有/dev/net/tun设备文件,可以执行ls /dev/net/tun命令查看,有打印结果就说明可以使用

Proxmox构建的CT虚拟机的特殊处理

如果使用Proxmox构建的CT虚拟机内没有该设备文件,需要检查宿主机是否有这个设备文件,如果宿主机有该设备文件但虚拟机内没有,可以编辑虚拟机的配置文件,具体如下所示

# 在宿主机内编辑CT虚拟机的配置文件
# 在配置文件结尾追加 lxc.mount.entry: /dev/net/tun dev/net/tun none bind,optional,create=file
# 然后回到CT虚拟机内重启系统,就可以看到这个设备文件了
$ vim /etc/pve/lxc/xxx.conf
Ubuntu加入VPN网络

在这之前需要先将.ovpn文件上传至ubuntu,假设文件上传至/root/client.ovpn

# 安装OpenVPN
$ apt install openvpn

# 加入VPN网络
$ openvpn --config /root/client.ovpn

资源下载

0

评论 (3)

取消
  1. 头像
    吃什么
    Windows 10 · Google Chrome

    异地组网没这么麻烦的,单纯实现异地组网可以用tailscale。看了你的网站很受益,希望能加友链https://3141635mi0.goho.co/

    回复
    1. 头像
      张涵哲 作者
      Windows 10 · Google Chrome
      @ 吃什么

      第一次听说tailscale涨知识了,友链已加,话说你这个域名挺随意的....

      回复
      1. 头像
        吃什么
        Windows 10 · Google Chrome
        @ 张涵哲

        花生壳的二级域名,网站都是跑在arm32位的CPU上的

        回复