前言

最近要搞个公司内网穿透类似的东东,需要从外网连接到办公内网,一波挑选之后决定采用 OpenVPN。由于需要搭一个大内网,且不妨碍访问外网,并且要求客户端之间也要互通,搜了一下网上都没有 docker 版本的说明,倒腾两天,记录一下。

机器配置

机器:

  • 服务端 CentOS 7.3
  • 客户端 Windows 10/Ubuntu Server 16.04

其实是什么平台都不重要,因为全篇都在 docker 下玩的

Git 项目:

安装Docker,拉取镜像

sudo yum -y install docker.io
docker pull kylemanna/openvpn

配置OpenVPN

  1. 配置数据卷,生成配置文件。预计网段人数不多,使用192.168.0.0/24网段,但需要注意的是在配置固定IP时,掩码必须为/30,因此固定IP需要注意正确配置。
#配置数据卷
export OVPN_DATA=openvpn-data
docker volume create --name $OVPN_DATA

#生成配置文件
#-d 取消默认配置     -c 打开c2c模式     -u 指定当前IP
#-s 划分服务器子网     -C 指定算法
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -d -c -C 'AES-256-CBC' -u udp://SERVER_IP -s 192.168.100.0/24
  1. 生成密钥文件,输入密钥和CA名称
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki
  1. 运行容器
#开启特权
docker run -v $OVPN_DATA:/etc/openvpn -d -p 1194:1194/udp --restart=on-failure:10 --cap-add=NET_ADMIN --name=openvpn --privileged=true kylemanna/openvpn

#登陆docker
docker run -v $OVPN_DATA:/etc/openvpn -it --rm kylemanna/openvpn bash -l

用户操作

添加用户

  1. 生成证书
#生成客户端证书,输入密钥
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full CLIENTNAME nopass
#需要配置密码则删掉nopass
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full testuser
  1. 导出证书
#将用户证书导出到本地文件
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient testuser > testuser.ovpn
  1. 如果有需要,需要给某个用户生成固定ip,操作如下:
//注意掩码为/30,配置固定IP需要保证其可用
echo "ifconfig-push 192.168.100.5 192.168.100.6" > /var/lib/docker/volumes/"$OVPN_DATA"/_data/ccd/client1

删除用户

//删除用户证书
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa revoke user
//更新证书数据库
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa gen-crl update-db
//重启openvpn容器
docker restart openvpn

客户端下载及安装

Windows

https://openvpn.net/community-downloads/

下载对应客户端后,在系统上安装 OpenVPN 客户端软件,将导出的文件 xx.ovpn 放到 OpenVPN 的配置文件夹中,默认是C:\Program Files\OpenVPN\config。或者直接打开 OpenVPN 客户端,右键-导入配置文件。

运行 OpenVPN 客户端软件,连接即可

Linux

Linux更为简单:

#先安装openvpn
sudo apt install openvpn
#配置.ovpn为配置文件
openvpn --config xxx.ovpn

增删用户脚本

为了减少工作量,方便快速配置,可以使用如下两个增添用户的脚本。

OpenVPN 创建用户脚本:

#!/bin/bash
read -p "please your username: " NAME
OVPN_DATA="openvpn-data"
LOCALIP="IP"
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full $NAME nopass
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient $NAME > /data/openvpn/conf/"$NAME".ovpn
#修改端口(可选)
sed -i "s/$LOCALIP 1194/$LOCALIP 1194/g" /data/openvpn/conf/"$NAME".ovpn
#压缩(可选)
echo "comp-lzo" >> /data/openvpn/conf/"$NAME".ovpn
docker restart openvpn
echo "CA saved to /data/openvpn/conf/$NAME.ovpn"

OpenVPN 删除用户脚本:

#!/bin/bash
read -p "Delete username: " DNAME
OVPN_DATA="openvpn-data"
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa revoke $DNAME
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn easyrsa gen-crl
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn rm -f /etc/openvpn/pki/reqs/"$DNAME".req
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn rm -f /etc/openvpn/pki/private/"$DNAME".key
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn rm -f /etc/openvpn/pki/issued/"$DNAME".crt
#删除相关用户conf(可选)
docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn rm -f /data/openvpn/conf/"$DNAME"
docker restart openvpn
echo "Deleted $DNAME"

验证

docker pull 一个Nginx,连接VPN服务器,先 ping ,互相 curl。

systemd持久化

目的:自动下载最新的 docker-openvpn 镜像并更新;如果服务挂掉, systemd 可以设定为每隔10秒进行重启。

  1. 设定 volume

    OVPN_DATA="openvpn-data"
    docker volume create --name $OVPN_DATA
  2. 初始化容器

    docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM
    docker run -v $OVPN_DATA:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki
  3. 下载 docker-openvpn@.service 放到 /etc/systemd/system,根据实际情况修改

    curl -L https://raw.githubusercontent.com/kylemanna/docker-openvpn/master/init/docker-openvpn%40.service | sudo tee /etc/systemd/system/docker-openvpn@.service
  4. 设定开机启动

    systemctl enable --now docker-openvpn@example.service
  5. 验证一下

    systemctl status docker-openvpn@example.service
    journalctl --unit docker-openvpn@example.service

错误记录

  1. 连接时发生write to TUN/TAP : Invalid argument (code=22)

    服务端启用了 comp-lzo,但生成的客户端 ovpn 文件没有,添加 comp-lzo 到 *.ovpn即可

  2. 连接时报 Warning:WARNING: this cipher's block size is less than 128 bit (64 bit). Consider using a --cipher with a larger block size.

    进入容器看看支持哪些算法:openvpn --show-ciphers,挑一个在 genconfig 的时候使用 -C 参数进行配置:docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://vpn.example.com -C $CIPHER

高级安全

备份

安全高要求下可以离线备份,本场景不需要。

# 备份到存档
docker run -v $OVPN_DATA:/etc/openvpn --rm kylemanna/openvpn tar -cvf - -C /etc openvpn | xz > openvpn-backup.tar.xz
# 恢复到新数据卷
docker volume create --name $OVPN_DATA
xzcat openvpn-backup.tar.xz | docker run -v $OVPN_DATA:/etc/openvpn -i kylemanna/openvpn tar -xvf - -C /etc

CA root key安全

本场景无需如此,先做记录。ovpn_copy_server_files 脚本将所有需要的配置放在默认的子目录中 $OPENVPN/server

docker run --net=none --rm -t -i -v $PWD:/etc/openvpn kylemanna/openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM
docker run --net=none --rm -t -i -v $PWD:/etc/openvpn kylemanna/openvpn ovpn_initpki
docker run --net=none --rm -t -i -v $PWD:/etc/openvpn kylemanna/openvpn ovpn_copy_server_files

其它记录

以下为记录,并未操作

防火墙配置

可选操作。

关闭firewalld
systemctl stop firewalld.service
systemctl disable firewalld.service
装iptables
yum -y install iptables-services net-tools
systemctl enable iptables.service

配置iptables


iptables -A Filter -d 127.0.0.1 -j ACCEPT
iptables -A Filter -p tcp --dport 80 -j ACCEPT
iptables -A Filter -j DROP
iptables -A INPUT -p tcp --destination-port 1194 -j ACCEPT
iptables -A INPUT -i tun0 -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -t nat -A POSTROUTING -s 192.168.85.0/24 -j SNAT --to-source 10.10.10.167

docker-compose

如果喜欢 docker-compose ,可以使用如下文件部署:

version: '2'
services:
  openvnp:
    cap_add:
     - NET_ADMIN
    image: kylemanna/openvpn
    container_name: openvpn
    ports:
     - "1194:1194/udp"
    restart: always
    volumes:
     - ./openvpn-data/conf:/etc/openvpn

相关操作:

docker-compose run --rm openvpn ovpn_genconfig -u udp://VPN.SERVERNAME.COM
docker-compose run --rm openvpn ovpn_initpki
docker-compose run --rm openvpn rm /etc/openvpn/ovpn_env.sh
docker-compose run --rm openvpn ovpn_genconfig -N -d -n 192.168.13.6 -u udp://vpn.mycompany.net -p "dhcp-option DOMAIN mycompany.net" -p "route 192.168.13.0 255.255.255.0" -p "route 172.17.0.0 255.255.0.0"

参考链接