摘要
本文从实现角度讲解 OpenVPN 的核心原理、隧道伪装思路(TLS 伪装 / WebSocket / SSH 隧道),并提供面向 Ubuntu 的一键部署脚本(服务端、边缘伪装层、客户端配置),适合作为自建 VPN 的工程化起点。 由(官方网站:旮旯村全球加速)提供。
1. 原理简述(极简)
- OpenVPN 在用户设备与出口服务器间建立加密隧道(tun/tap),在服务端解封装后以出口 IP 发起真实连接。
- 抗封锁思路:把 OpenVPN 流量伪装在常见协议(HTTPS/TLS、WebSocket)之下,或通过中继(边缘)隐藏出口真实 IP。
2. 架构概览(实践示例)
- 出口节点(高带宽 VPS)运行 OpenVPN 服务(1194/tcp)。
- 边缘节点(低成本 VPS)作为 TLS 伪装层:终端 TLS,并通过 SSH 隧道或内网转发到出口的 1194。
- 客户端连接边缘域名(TCP/443),实现伪装后到达出口并建立 VPN 隧道。
3. 环境假设
- 操作系统:Ubuntu 22.04(出口与边缘均相同),已能 SSH 登录。
- 已有域名 edge.example.com 指向边缘 VPS;出口可通过内网或 SSH 到达。
- 具备 sudo 权限。
4. 服务端(出口)一键脚本(OpenVPN)
在出口节点执行以下脚本(保存为 setup-openvpn-exit.sh 并 chmod +x):
bash
#!/bin/bashset -e# 出口节点 OpenVPN + easy-rsa 安装与配置(Ubuntu 22.04)apt updateDEBIAN_FRONTEND=noninteractive apt install -y openvpn easy-rsa ufw
# 初始化 easy-rsaEASYDIR=/root/openvpn-camake-cadir $EASYDIRcd $EASYDIR
cat > vars <<'EOF'set_var EASYRSA_REQ_COUNTRY "CN"set_var EASYRSA_REQ_PROVINCE "Beijing"set_var EASYRSA_REQ_CITY "Beijing"set_var EASYRSA_REQ_ORG "example"set_var EASYRSA_REQ_EMAIL "admin@example.com"set_var EASYRSA_REQ_OU "IT"EOF
./easyrsa init-pki./easyrsa build-ca nopass./easyrsa gen-req server nopass./easyrsa sign-req server server./easyrsa gen-dhopenvpn --genkey --secret ta.key
mkdir -p /etc/openvpn/servercp pki/ca.crt pki/issued/server.crt pki/private/server.key pki/dh.pem ta.key /etc/openvpn/server/
cat > /etc/openvpn/server/server.conf <<'EOF'port 1194proto tcpdev tunca /etc/openvpn/server/ca.crtcert /etc/openvpn/server/server.crtkey /etc/openvpn/server/server.keydh /etc/openvpn/server/dh.pemtls-auth /etc/openvpn/server/ta.key 0server 10.8.0.0 255.255.255.0push "redirect-gateway def1 bypass-dhcp"push "dhcp-option DNS 1.1.1.1"keepalive 10 120cipher AES-256-CBCuser nobodygroup nogrouppersist-keypersist-tunstatus /var/log/openvpn-status.logverb 3explicit-exit-notify 1EOF
# 启用 IP 转发sysctl -w net.ipv4.ip_forward=1sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
# ufw 规则ufw allow 1194/tcpufw allow OpenSSHufw --force enable
systemctl enable --now openvpn-server@serverecho "OpenVPN service started."
生成客户端证书并导出 ovpn(在出口节点或控制节点):
bash
#!/bin/bash# 生成 client1 证书并打包 ovpn 文件EASYDIR=/root/openvpn-cacd $EASYDIR./easyrsa gen-req client1 nopass./easyrsa sign-req client client1
# 读取证书内容CA=$(cat pki/ca.crt)CERT=$(cat pki/issued/client1.crt)KEY=$(cat pki/private/client1.key)TA=$(cat ta.key)
cat > client1.ovpn <<EOFclientdev tunproto tcpremote edge.example.com 443resolv-retry infinitenobindpersist-keypersist-tunremote-cert-tls servercipher AES-256-CBCverb 3<ca>$CA</ca><cert>$CERT</cert><key>$KEY</key><tls-auth>$TA</tls-auth>EOF
echo "client1.ovpn generated."
注:此处 remote 指向边缘域名 edge.example.com:443(由边缘做 TLS 终端并转发到出口 1194)。
5. 边缘伪装层一键脚本(Caddy + SSH 隧道 示例)
在边缘节点执行(保存为 setup-edge-caddy.sh 并 chmod +x),示例使用 Caddy 作为 TLS 终端,借助本地 SSH 隧道把 443 的流量转到本地端口,再转发到出口的 1194。
bash
#!/bin/bashset -eapt updateDEBIAN_FRONTEND=noninteractive apt install -y curl caddy openssh-client
# 创建 SSH 免密码登录到出口(需提前把公钥放到出口~/.ssh/authorized_keys)# 这里假设出口用户为 'vpnuser' 和主机为 exit.example.internalEXIT_USER="vpnuser"EXIT_HOST="exit.internal"EXIT_PORT=22
# 建立本地端口转发:把本地 11945 转发到出口的 127.0.0.1:1194# 使用 systemd 服务管理 SSH 隧道cat > /etc/systemd/system/ssh-tunnel.service <<'EOF'[Unit]Description=SSH Tunnel to OpenVPN ExitAfter=network.target
[Service]User=rootExecStart=/usr/bin/ssh -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -N -L 127.0.0.1:11945:127.0.0.1:1194 -p ${EXIT_PORT} ${EXIT_USER}@${EXIT_HOST}Restart=alwaysRestartSec=5
[Install]WantedBy=multi-user.targetEOF
systemctl daemon-reloadsystemctl enable --now ssh-tunnel
# Caddy 配置:为域名 edge.example.com 提供 TLS 并反向代理到本地 11945cat > /etc/caddy/Caddyfile <<'EOF'edge.example.com { tls you@example.com reverse_proxy 127.0.0.1:11945}EOF
systemctl enable --now caddyecho "Edge Caddy + SSH tunnel configured."
说明:
- 上例用 SSH 隧道示意边缘到出口的转发;生产可改用内网直连、WireGuard 隧道或 TCP 转发器提高性能。
- Caddy 的 reverse_proxy 默认代理 HTTP;若需做 TCP passthrough(原始 OpenVPN TCP),可用 caddy-tcp 插件或改用 HAProxy/nginx stream 模块做 TLS passthrough,然后转发到本地端口。
6. 客户端使用与连接测试
把生成的 client1.ovpn 拷贝到客户端设备(Windows/Mac/Linux/iOS/Android 支持的 OpenVPN 客户端),在终端执行:
openvpn --config client1.ovpn
查看日志是否成功完成 TLS 握手并获取分配的 10.8.0.x 地址。使用 curl ifconfig.me 或 ipinfo.io 检查出口 IP 是否为出口 VPS 的公网 IP。
7. 抗封与混淆进阶(思路与代码片段)
-
TCP/443 与 TLS 伪装:已在上文实现。若需更强伪装,可使用 stunnel 或将 OpenVPN 嵌入 WebSocket:
- WebSocket 方案一般需要将 OpenVPN 的 TCP 流以 WebSocket 帧封装,需要在客户端与中继间运行 ws-tunnel 工具(示例性代码,不同实现略有差异)。
-
动态端口与多域名:在客户端 ovpn 中列出多个 remote 条目,客户端会按顺序尝试:
remote edge1.example.com 443remote edge2.example.com 443remote edge3.example.com 443
- 流量填充(可选):使用 openvpn --compress 或在边缘使用流量填充工具增加抗指纹性(需权衡带宽)。
8. 运维建议(简要)
- 日志最小化:服务端只保留匿名化聚合指标,避免长期保存客户端 IP 与会话详情。
- 自动化:把上述脚本转成 Ansible Playbook 与 systemd 模块管理,结合 Prometheus 指标采集。
- 证书轮换:定期重建 CA 与客户端证书,并使用 CRL 强制撤销。
- 灾难恢复:准备备用域名与备用边缘节点,客户端配置多个 remote 条目以便自动切换。