diff --git a/README.md b/README.md index 93bb548..0590f6f 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,10 @@ - [二、首次配置](#二首次配置) - [登录 Web 控制台](#登录-web-控制台) - [修改默认密码](#修改默认密码) - - [创建第一个实例](#创建第一个实例) - - [创建客户端用户并下载配置](#创建客户端用户并下载配置) - - [防火墙与公网暴露](#防火墙与公网暴露) + | - [创建第一个实例](#创建第一个实例) + - [创建客户端用户并下载配置](#创建客户端用户并下载配置) + - [IP 转发与内网访问](#ip-转发与内网访问客户端访问服务端-lan) + - [防火墙与公网暴露](#防火墙与公网暴露) - [三、访问控制(白名单模式)](#三访问控制白名单模式) - [四、客户端使用](#四客户端使用) - [配置文件说明](#配置文件说明) @@ -58,6 +59,7 @@ | 一键恢复 | 上传/选择已有备份,直接覆盖还原 | | 操作审计 | 所有写操作(创建/修改/删除/吊销/备份)持久化,记录操作者/IP/结果 | | JWT 鉴权 | 登录后 12 小时有效 token,无状态可水平扩展 | +| **内网转发** | 文档化 IP 转发 + NAT 一键配置,客户端可访问服务端 LAN | ## 架构概览 @@ -369,6 +371,127 @@ Web → "用户管理": 直接发给用户即可,无需额外的 `ca.crt` 等文件。 +## IP 转发与内网访问(客户端访问服务端 LAN) + +**场景**: 客户端连上 VPN 后,想访问服务端所在的局域网设备(如 `172.16.2.0/24` 网段的服务器、打印机、NAS 等)。 + +**前提**: 客户端能 ping 通 VPN 网关(`10.8.0.1`),但访问不了 LAN(如 `ping 172.16.2.30` 失败)。 + +OpenVPN 默认**只让客户端访问 VPN 子网本身**,不能直接访问服务端 LAN。要打通,服务端需要做两件事: + +1. **开启 IP 转发**(`net.ipv4.ip_forward=1`),让内核把 VPN 客户端的包从 tun 设备转到 LAN 网卡。 +2. **配置 NAT(MASQUERADE)**,让 VPN 客户端的源 IP 在离开服务端时被替换成 LAN 网卡 IP,这样 LAN 设备知道怎么回包。 + +### 一键启用(推荐) + +如果服务端只有一个网卡接 LAN(典型场景),执行: + +```bash +# 1. 立即启用 IP 转发 +sudo sysctl -w net.ipv4.ip_forward=1 + +# 2. 持久化(重启不丢) +echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-openvpn-manager.conf + +# 3. 添加 NAT 规则 +# eth0 是服务端接 LAN 的网卡名(可能是 ens192/eno1/enp0s3 等,用 ip a 查看) +LAN_IF="eth0" # ← 改成实际网卡名 +sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o "$LAN_IF" -j MASQUERADE +sudo iptables -A FORWARD -i "$LAN_IF" -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT +sudo iptables -A FORWARD -i tun+ -o "$LAN_IF" -j ACCEPT + +# 4. 持久化 iptables(重启不丢) +sudo apt-get install -y iptables-persistent # Debian/Ubuntu +sudo netfilter-persistent save # 保存当前规则 +# 或: sudo service iptables save # CentOS/RHEL +``` + +> **为什么是 `tun+`?**: OpenVPN 用 `tun0/tun1...` 设备,`+` 通配匹配所有 tun 设备。多个实例并存也能用。 + +### 验证 + +```bash +# 服务端视角: 应该看到一条 MASQUERADE 规则 +sudo iptables -t nat -L POSTROUTING -n -v | grep MASQUERADE + +# 客户端视角: VPN 连接后 +ping 10.8.0.1 # 必通(网关) +ping <服务端 LAN 上的某个 IP> # 通了说明成功 +curl ifconfig.me # 显示服务端公网 IP,说明 NAT 生效 +``` + +### 找对 LAN 网卡 + +```bash +ip -br a # 简略列出所有网卡和 IP +ip route | grep default # 看默认路由走哪块网卡 — 通常就是 LAN 网卡 +``` + +例: +``` +default via 172.16.2.254 dev ens192 → LAN 网卡是 ens192 +``` + +### push 路由(让客户端知道去 LAN 怎么走) + +光在服务端做 NAT 不够,还得让**客户端知道** "要去 `172.16.2.0/24` 就走 VPN"。两种做法: + +**方法 A:在实例里 push 路由(推荐)** + +编辑实例的 `server.conf`,添加: +``` +push "route 172.16.2.0 255.255.255.0" +``` +然后在 Web 面板重启实例。 + +**方法 B:在 Web 面板"实例管理"里配置** + +把 LAN 网段加到实例的 **AccessMode** 白名单或 **push 路由列表**。白名单模式下 `allow_networks` 会自动生成对应的 push 路由。 + +### 多网卡/复杂路由场景 + +如果服务端有**多块 LAN 网卡**(如同时接公司网和家庭网),MASQUERADE 规则要分别添加: + +```bash +for IF in ens192 ens224; do + sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o "$IF" -j MASQUERADE +done +``` + +或者直接用 `-o eth+` 一次性匹配所有以太网卡(不太安全,慎用): +```bash +sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -j MASQUERADE +``` + +### 排障 + +| 症状 | 排查 | +| ---- | ---- | +| 客户端能 ping 通 10.8.0.1,ping 不通 LAN | 没开 IP 转发,或没加 MASQUERADE 规则 | +| 能 ping 通 LAN IP,但 SSH/服务不通 | LAN 设备防火墙拒绝 VPN 子网;在 LAN 设备上 `iptables -I INPUT -s 10.8.0.0/24 -j ACCEPT` | +| 重启后规则丢失 | 没装 iptables-persistent 或没保存;参考上文持久化步骤 | +| ping 得通但访问慢/丢包 | MTU 问题;在 server.conf 加 `tun-mtu 1400 mssfix 1360` | +| ip_forward 已开但客户端仍上不了网 | push 路由缺失;客户端路由表里没有目标 LAN 网段 | + +### 检查清单 + +```bash +# 1. 转发开关 +cat /proc/sys/net/ipv4/ip_forward # 必须输出 1 + +# 2. NAT 规则 +sudo iptables -t nat -L POSTROUTING -n # 应该有 10.8.0.0/24 的 MASQUERADE + +# 3. FORWARD 策略(默认 ACCEPT 还是 DROP?) +sudo iptables -L FORWARD # 看到 policy DROP 就需要显式 ACCEPT tun+ ↔ LAN 的包 + +# 4. 客户端路由 +# VPN 连接后,在客户端执行: +ip route # 应该看到 "10.8.0.0/24 dev tun0" 和 "172.16.2.0/24 via 10.8.0.1 dev tun0" +``` + +--- + ## 防火墙与公网暴露 1. Web 管理端口(默认 8089)**不建议直接暴露公网**,建议: @@ -647,8 +770,9 @@ sudo dnf install -y NetworkManager-openvpn NetworkManager-openvpn-gnome # F | 症状 | 可能原因 | | ---- | -------- | | 连接后立刻断开 | 客户端证书与 CA 不匹配;服务端证书过期 | -| 拿到 IP 但 ping 不通服务端 | 防火墙没允许 UDP 1194;服务端没启用 IP 转发 | +| 拿到 IP 但 ping 不通服务端 | 防火墙没允许 UDP 1194;服务端没启用 IP 转发(见 [IP 转发与内网访问](#ip-转发与内网访问客户端访问服务端-lan)) | | 拿到 IP 但访问不了互联网 | 没推送 DNS,或客户端没把 VPN 设为默认网关 | +| 拿到 IP 能 ping 通网关,访问不了 LAN | **没做服务端 NAT** — 见 [IP 转发与内网访问](#ip-转发与内网访问客户端访问服务端-lan) | | Android 连不上 | 服务器在 NAT 后,检查运营商是否屏蔽 UDP | | iOS 连不上 | 看 OpenVPN 日志(应用内 OpenVPN → Settings → Log) | diff --git a/scripts/install.sh b/scripts/install.sh index 3aa4229..bf4e462 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -172,6 +172,25 @@ for i in 1 2 3 4 5; do sleep 1 done +# ---------- 启用 IP 转发 (客户端访问服务端 LAN 的前提) ---------- +echo "==> 启用 IPv4 转发 (客户端访问服务端 LAN 需要)" +if [[ -w /proc/sys/net/ipv4/ip_forward ]]; then + echo 1 > /proc/sys/net/ipv4/ip_forward + # 持久化(下次重启不丢) + CONF_FILE="/etc/sysctl.d/99-openvpn-manager.conf" + if [[ ! -f "$CONF_FILE" ]] || ! grep -q "^net.ipv4.ip_forward=1" "$CONF_FILE" 2>/dev/null; then + echo "net.ipv4.ip_forward=1" > "$CONF_FILE" + sysctl -p "$CONF_FILE" >/dev/null 2>&1 || true + fi + echo " ✓ IP 转发已启用 (持久化到 $CONF_FILE)" + echo " 提示: 如需让客户端访问服务端 LAN 网段, 还需手动添加 iptables NAT 规则:" + echo " sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o -j MASQUERADE" + echo " 详见 README \"IP 转发与内网访问\" 章节" +else + echo " ! 无法写入 /proc/sys/net/ipv4/ip_forward (容器环境?) — 跳过" + echo " 如需客户端访问服务端 LAN, 请在宿主机启用: sysctl -w net.ipv4.ip_forward=1" +fi + # ---------- 完成提示 ---------- cat <