Loading... ## 温馨提示 <div class="tip inlineBlock error"> OpenVPN 是企业建立虚拟专用网络的常用工具之一,适用于远程办公等场景。本文仅做技术研究,请勿将 OpenVPN 用于不合规用途! </div> ## 服务端安装 ### 1. 安装软件包 #### 软件包管理器安装 <div class="tab-container post_tab box-shadow-wrap-lg"> <ul class="nav no-padder b-b scroll-hide" role="tablist"> <li class='nav-item active' role="presentation"><a class='nav-link active' style="" data-toggle="tab" aria-controls='tabs-41799764df09ba86e49bbeebb5fa148d30' role="tab" data-target='#tabs-41799764df09ba86e49bbeebb5fa148d30'>Ubuntu/Debain</a></li><li class='nav-item ' role="presentation"><a class='nav-link ' style="" data-toggle="tab" aria-controls='tabs-4162aedf190a94caaec3a0b89cb6e2d4181' role="tab" data-target='#tabs-4162aedf190a94caaec3a0b89cb6e2d4181'>CentOS</a></li> </ul> <div class="tab-content no-border"> <div role="tabpanel" id='tabs-41799764df09ba86e49bbeebb5fa148d30' class="tab-pane fade active in"> ```bash apt install openvpn easy-rsa -y ``` </div><div role="tabpanel" id='tabs-4162aedf190a94caaec3a0b89cb6e2d4181' class="tab-pane fade "> ```bash yum install epel-release yum makecache yum install openvpn easy-rsa -y ``` </div> </div> </div> #### 从源码编译安装(推荐) (此方法笔者只在 Ubuntu 上试过,其他系统的依赖包可能不同) 安装依赖,然后从[官网](https://openvpn.net/community-downloads/)下载源码包编译安装 ```bash apt install pkg-config libnl-genl-3-dev libpkgconf-dev libcap-ng-dev libssl-dev liblz4-dev liblzo2-dev easy-rsa -y cd /home/soft wget https://swupdate.openvpn.org/community/releases/openvpn-2.6.9.tar.gz tar zxvf openvpn-2.6.9.tar.gz cd openvpn-2.6.9 ./configure --prefix=/usr/local/openvpn --enable-systemd make -j2 make install ``` 创建 systemd 服务,`vim /lib/systemd/system/openvpn@.service` ```bash [Unit] Description=OpenVPN connection to %i PartOf=openvpn.service Before=systemd-user-sessions.service After=network-online.target Wants=network-online.target Documentation=man:openvpn(8) Documentation=https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage Documentation=https://community.openvpn.net/openvpn/wiki/HOWTO [Service] Type=notify PrivateTmp=true WorkingDirectory=/etc/openvpn ExecStart=/usr/local/openvpn/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 PIDFile=/run/openvpn/%i.pid KillMode=process CapabilityBoundingSet=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE CAP_AUDIT_WRITE LimitNPROC=100 DeviceAllow=/dev/null rw DeviceAllow=/dev/net/tun rw ProtectSystem=true ProtectHome=true RestartSec=5s Restart=on-failure [Install] WantedBy=multi-user.target ``` ### 2. 创建配置文件目录 ```bash mkdir -p /etc/openvpn/easy-rsa ``` ### 3. 复制配置文件模版 <div class="tab-container post_tab box-shadow-wrap-lg"> <ul class="nav no-padder b-b scroll-hide" role="tablist"> <li class='nav-item active' role="presentation"><a class='nav-link active' style="" data-toggle="tab" aria-controls='tabs-6deee04e19e61167dc393bb61a1620dc380' role="tab" data-target='#tabs-6deee04e19e61167dc393bb61a1620dc380'>Ubuntu/Debain</a></li><li class='nav-item ' role="presentation"><a class='nav-link ' style="" data-toggle="tab" aria-controls='tabs-224543c362e559af34103bb6093d83da941' role="tab" data-target='#tabs-224543c362e559af34103bb6093d83da941'>CentOS 7</a></li> </ul> <div class="tab-content no-border"> <div role="tabpanel" id='tabs-6deee04e19e61167dc393bb61a1620dc380' class="tab-pane fade active in"> ```bash cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/ cp /etc/openvpn/easy-rsa/vars.example /etc/openvpn/easy-rsa/vars ``` </div><div role="tabpanel" id='tabs-224543c362e559af34103bb6093d83da941' class="tab-pane fade "> 此处的 easy-rsa 版本号 3.0.8 要修改成实际安装的版本 ```bash cp /usr/share/doc/easy-rsa-3.0.8/vars.example /etc/openvpn/easy-rsa/vars cp -r /usr/share/easy-rsa/3.0.8/* /etc/openvpn/easy-rsa/ ``` </div> </div> </div> ### 4. **修改配置文件中的变量 `set_var EASYRSA_REQ.*`** `vim /etc/openvpn/easy-rsa/vars` ```bash set_var EASYRSA_REQ_COUNTRY "CN" set_var EASYRSA_REQ_PROVINCE "FJ" set_var EASYRSA_REQ_CITY "FZ" set_var EASYRSA_REQ_ORG "Qwert" set_var EASYRSA_REQ_EMAIL "admin@qwerto.cc" set_var EASYRSA_REQ_OU "Qwert" set_var EASYRSA_REQ_CN "qwert.local" set_var EASYRSA_CA_EXPIRE 36500 set_var EASYRSA_CERT_EXPIRE 3650 set_var EASYRSA_CRL_DAYS 3650 ``` ### 5. 初始化证书目录 ```bash cd /etc/openvpn/easy-rsa/ ./easyrsa init-pki ```  ### 6. 创建CA根证书 运行命令后,提示 `CA Key Passphrase` 时输入CA密钥的密码 ,要记录下这个密码,后续给证书签名要用。`Common Name` 输入 CA 名称,比如 `Qwert CA` ```bash ./easyrsa build-ca ``` 这一步会生成两个文件: 根证书:`/etc/openvpn/easy-rsa/pki/ca.crt` 根证书密钥:`/etc/openvpn/easy-rsa/pki/private/ca.key`  ### 7. 创建服务端证书并签名 运行命令后,需要输入一次根证书密钥的密码(第6步设置的) ```bash ./easyrsa build-server-full server nopass ``` 这一步会生成两个文件: 服务端证书:`/etc/openvpn/easy-rsa/pki/issued/server.crt` 服务端证书私钥:`/etc/openvpn/easy-rsa/pki/private/server.key`  ### 8. 生成加密交换Diffie-Hellman文件 ```bash ./easyrsa gen-dh ``` 这一步会生成一个文件: Diffie-Hellman:`/etc/openvpn/easy-rsa/pki/dh.pem`  ### 9. 生成ta key 使用 `tls-auth` 加强安全性,防止DDoS和TLS中间人攻击 ```bash openvpn --genkey --secret ta.key ``` 这一步会生成一个文件: ta key:`/etc/openvpn/easy-rsa/ta.key`  ### 10. 生成证书吊销列表(CRL) ```bash ./easyrsa gen-crl ``` 这一步会生成一个文件: crl:`/etc/openvpn/easy-rsa/pki/crl.pem` ### 11. 创建客户端证书并签名 运行命令后,提示 `Enter PEM pass phrase` 需要给客户端私钥设置一个密码,要记录下这个密码,后续连接要用。 输入完两次客户端私钥密码后,还需要输入一次根证书密钥的密码(第6步设置的) ```bash ./easyrsa build-client-full 用户名 ``` 这一步会生成两个文件: 客户端证书:`/etc/openvpn/easy-rsa/pki/issued/qwert.crt` 客户端证书私钥:`/etc/openvpn/easy-rsa/pki/private/qwert.key`  ### 12. OpenVPN 服务端配置 服务端配置文件存放在 `/etc/openvpn/server.conf` ``` # 端口 port 12345 # 协议 proto tcp # tun 模式 dev tun # 运行用户 user openvpn group openvpn # CA证书 ca /etc/openvpn/easy-rsa/pki/ca.crt # 服务端证书 cert /etc/openvpn/easy-rsa/pki/issued/server.crt # 服务端证书私钥 key /etc/openvpn/easy-rsa/pki/private/server.key # DH dh /etc/openvpn/easy-rsa/pki/dh.pem # TLS-auth,使用 ta.key 增加安全性,服务器为0,客户端为1 tls-auth /etc/openvpn/easy-rsa/ta.key 0 # 加密认证算法 cipher AES-256-GCM auth SHA512 tls-version-min 1.2 tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA # 连接保持时间,单位秒 # 超过时间会重新验证key,默认为1小时断开一次,设置成0表示禁用 reneg-sec 0 reneg-bytes 1073741824 # 网段 server 172.23.45.0/24 255.255.255.0 # 客户端与客户端互联 client-to-client # 子网模式 topology subnet # 推送客户端:重定向网关及DHCP(设置全局路由走VPN隧道) #push "redirect-gateway def1 bypass-dhcp" # 允许多个相同用户的客户端连接 #duplicate-cn # 最大连接客户端数 max-clients 100 # 客户端存活检测,间隔10s,最大120s keepalive 10 120 # 客户端静态 IP 保持 ifconfig-pool-persist ipp.txt # 用户配置文件目录 client-config-dir /etc/openvpn/ccd # 压缩 # !!! 不建议启用压缩,可能会导致 VORACLE 攻击 # https://community.openvpn.net/openvpn/wiki/VORACLE allow-compression no # 压缩方式 #compress "lz4-v2" # 旧客户端使用压缩方式 #comp-lzo # 重启时保留状态 persist-key persist-tun # 状态文件 status-version 2 status /etc/openvpn/openvpn-status.log # 日志文件级别,0-9,越大越详细 verb 3 # 连续出现 20 条相同的日志,不记录 mute 20 ``` ### 13. 配置NAT地址转换/静态路由 两种方式都可以~ <div class="tab-container post_tab box-shadow-wrap-lg"> <ul class="nav no-padder b-b scroll-hide" role="tablist"> <li class='nav-item active' role="presentation"><a class='nav-link active' style="" data-toggle="tab" aria-controls='tabs-56703e13fecb824ce121087157fbe7d0960' role="tab" data-target='#tabs-56703e13fecb824ce121087157fbe7d0960'>NAT</a></li><li class='nav-item ' role="presentation"><a class='nav-link ' style="" data-toggle="tab" aria-controls='tabs-fcace457e99441f49dbcc6c367522317501' role="tab" data-target='#tabs-fcace457e99441f49dbcc6c367522317501'>静态路由</a></li> </ul> <div class="tab-content no-border"> <div role="tabpanel" id='tabs-56703e13fecb824ce121087157fbe7d0960' class="tab-pane fade active in"> 添加防火墙规则: ``` # NAT -s 参数是VPN网段 -o 参数是出网卡 iptables -t nat -A POSTROUTING -s 172.23.45.0/24 -o eth0 -j MASQUERADE # 放行 OpenVPN 端口 iptables -A INPUT -p tcp --dport 12345 -m comment --comment "openvpn" -j ACCEPT # 保存 iptables-save >/etc/iptables/rules.v4 ``` </div><div role="tabpanel" id='tabs-fcace457e99441f49dbcc6c367522317501' class="tab-pane fade "> 添加防火墙规则: ```bash # -s 参数是VPN网段 iptables -A FORWARD -s 172.23.45.0/24 -d 0.0.0.0/0 -j ACCEPT # 放行 OpenVPN 端口 iptables -A INPUT -p tcp --dport 12345 -m comment --comment "openvpn" -j ACCEPT # 保存 iptables-save >/etc/iptables/rules.v4 ``` 除此之外,需要在内网设备(交换机/防火墙)上设置VPN网段的静态路由,例如我这里VPN网段是 `172.23.45.0/24` ,VPN服务器的内网 IP 为 `10.78.6.3`,需要设置静态路由: `172.23.45.0/24 -> 10.78.6.3` </div> </div> </div> ### 14. 内核开启路由转发 修改 `/etc/sysctl.conf` ,增加一行 ``` net.ipv4.ip_forward = 1 ``` 然后运行 `sysctl -p` ### 15. 增加用户配置文件 在服务端配置中指定了 `client-config-dir /etc/openvpn/ccd` 后,可在 `/etc/openvpn/ccd/用户名` 指定用户的配置文件,向不同用户推送不同的域名 ``` # 推送客户端IP ifconfig-push <客户端ip> 255.255.255.0 # 推送全局路由 #push "redirect-gateway def1 bypass-dhcp" # 推送自定义路由 push "route 10.72.0.5 255.255.255.255" push "route 10.56.3.1 255.255.255.255" # 推送DNS push "dhcp-option DNS 10.100.0.1" ``` ### 16. 启动 OpenVPN 服务端 ```bash # 启动服务端 systemctl start openvpn@server # 查看服务端运行状态 systemctl status openvpn@server # 设置开机启动 systemctl enable openvpn@server ```  ## 客户端配置 创建一个新文件 用户名.ovpn ``` # 客户端 # client dev tun proto tcp tun-mtu 1400 mssfix 1360 # 连接 # remote 服务端IP 服务端端口 resolv-retry infinite nobind # 代理 # #http-proxy-retry #http-proxy HTTP代理IP HTTP代理端口 # 持久化 # persist-key persist-tun # 传输 # allow-compression no # 不允许压缩 #compress lz4-v2 # 压缩方式 #compress lz4 #comp-lzo # 加密 # cipher AES-256-GCM auth SHA512 tls-version-min 1.2 tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA auth-nocache remote-cert-tls server ns-cert-type server # 日志 # verb 3 # 路由 # # 不从服务端拉取路由 #route-nopull # 手动设置静态路由(net_gateway:本地网关; vpn_gateway:VPN网关) #route 10.76.0.0 255.255.0.0 net_gateway #route 10.68.75.0 255.255.255.0 vpn_gateway # 网络 # # 设置DNS #dhcp-option DNS 119.29.29.29 #dhcp-option DNS 180.76.76.76 # 所有DNS查询都通过VPN的DNS服务器进行(Windows) #register-dns # 只能使用VPN设置的DNS #block-outside-dns # 证书 # <ca> 这里填入服务端 /etc/openvpn/easy-rsa/pki/ca.crt 文件的内容 </ca> <cert> 这里填入服务端 /etc/openvpn/easy-rsa/pki/issued/用户名.crt 文件的内容 </cert> <key> 这里填入服务端 /etc/openvpn/easy-rsa/pki/private/用户名.key 文件的内容 </key> key-direction 1 <tls-auth> 这里填入 /etc/openvpn/easy-rsa/ta.key 文件的内容 </tls-auth> ``` 导入到客户端,连接就可以使用 <div class="panel panel-default collapse-panel box-shadow-wrap-lg"><div class="panel-heading panel-collapse" data-toggle="collapse" data-target="#collapse-21e02873018957be89248e0f37dc6f1864" aria-expanded="true"><div class="accordion-toggle"><span style="">客户端配置文件生成脚本:generate_ovpn_config.py</span> <i class="pull-right fontello icon-fw fontello-angle-right"></i> </div> </div> <div class="panel-body collapse-panel-body"> <div id="collapse-21e02873018957be89248e0f37dc6f1864" class="collapse collapse-content"><p></p> 可以通过这个脚本快速生成客户端配置文件,需要提前配置好模版配置文件: - ovpn 配置文件模版路径:`/etc/openvpn/template@fz.ovpn` - ccd 用户配置文件模版路径:`/etc/openvpn/ccd.template` 脚本使用:`python3 generate_ovpn_config.py <username> <ip>` ```python import os import sys def read_file(file_path): with open(file_path, 'r') as file: return file.read() def extract_cert_content(content): begin_marker = "-----BEGIN CERTIFICATE-----" end_marker = "-----END CERTIFICATE-----" start = content.find(begin_marker) end = content.find(end_marker) + len(end_marker) return content[start:end] def extract_key_content(content): begin_marker = "-----BEGIN ENCRYPTED PRIVATE KEY-----" end_marker = "-----END ENCRYPTED PRIVATE KEY-----" start = content.find(begin_marker) end = content.find(end_marker) + len(end_marker) return content[start:end] def replace_placeholder(template, placeholder, content): start_tag = f"<{placeholder}>" end_tag = f"</{placeholder}>" start_index = template.find(start_tag) + len(start_tag) end_index = template.find(end_tag) return template[:start_index] + "\n" + content + "\n" + template[end_index:] def generate_ovpn_config(username): print(f"生成用户 {username} 的配置文件...") cert_path = f"/etc/openvpn/easy-rsa/pki/issued/{username}.crt" key_path = f"/etc/openvpn/easy-rsa/pki/private/{username}.key" template_path = "/etc/openvpn/template@fz.ovpn" output_path = f"/etc/openvpn/ovpn_config/{username}@fz.ovpn" ccd_template_path = "/etc/openvpn/ccd.template" ccd_output_path = f"/etc/openvpn/ccd/{username}" try: cert_content = read_file(cert_path) key_content = read_file(key_path) except Exception as e: print(f"读取证书失败,证书是否未创建? [手动创建: cd /etc/openvpn/easy-rsa && ./easyrsa build-client-full {username} ] -> [错误: {e}]") exit(-1) cert_content = extract_cert_content(cert_content) key_content = extract_key_content(key_content) # 替换模版 template_content = read_file(template_path) config_content = replace_placeholder(template_content, "cert", cert_content) config_content = replace_placeholder(config_content, "key", key_content) # 写入生成的配置文件 with open(output_path, 'w') as output_file: output_file.write(config_content) print(f"OVPN配置文件已生成 -> {output_path}") ccd_content = read_file(ccd_template_path) ccd_content = ccd_content.replace("<ip>", ip_address) with open(ccd_output_path, 'w') as ccd_file: ccd_file.write(ccd_content) if __name__ == "__main__": if len(sys.argv) != 3: print("Usage: python3 generate_ovpn_config.py <username> <ip>") sys.exit(1) username = sys.argv[1] ip_address = sys.argv[2] generate_ovpn_config(username) ``` <p></p></div></div></div> ## 吊销客户端证书 ```bash cd /etc/openvpn/easy-rsa ./easyrsa revoke <username> ./easyrsa gen-crl chown openvpn:openvpn /etc/openvpn/easy-rsa/pki/crl.pem ``` ## 注意 ### 关于压缩 <div class="tip inlineBlock warning"> 为了防止[VORACLE 攻击](https://community.openvpn.net/openvpn/wiki/VORACLE),OpenVPN 在启用压缩的情况下,默认为非对称压缩: 服务端和客户端同时配置 `compress lz4-v2` 时,只会启用 `服务端 -> 客户端` 的压缩 当客户端增加配置 `allow-compression yes` 时,会启用 `客户端 -> 服务端` 的压缩,**但非常不建议这么做** 也可以直接注释压缩选项并增加 `allow-compression no` 选项来关闭压缩,[官方并不推荐在 OpenVPN 中启用压缩](https://community.openvpn.net/openvpn/wiki/Compression) </div> ## 参考资料 [[原]深入OpenVPN的配置 - linuxの飘扬 - Power by www.linuxfly.org](https://www.linuxfly.org/post/86/) [centos7 搭建 openvpn 服务器(使用账号和密码方式) - sevennight](https://sevennight.cc/2020/04/18/centos7_install_open_xxx.html) [Centos7搭建神器openvpn | 运维随笔](https://wandouduoduo.github.io/articles/decac6ef.html) [[OpenVPN] OpenVPN独立配置文件 | chenall's Blog](http://chenall.net/post/openvpn_inlinefile/) 最后修改:2024 年 07 月 16 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏