上一篇 下一篇 分享链接 返回 返回顶部

香港服务器如何利用CN2 GIA线路搭建安全VPN,保证跨境员工访问内部系统的稳定性?

发布人:Minchunlin 发布时间:2025-09-12 11:02 阅读量:1136


周一 9 点,北京、杭州、成都的同事陆续上线,Slack 红点狂闪:“Git 拉不动”“ERP 打不开”。我从 Prometheus 面板看跨境 RTT 抖成锯齿,晚高峰更夸张。问题不是内网,是“出海”。领导一句话:“把香港的那台机器拉起来,走好一点的线,今天就要稳住。”
我盯着机房里那台 1U 小钢炮,给自己定了四件事:

  • 线路:必须是 CN2 GIA(AS4809) 入口,必要时双上联备份
  • 协议:桌面/服务器走 WireGuard,移动端走 IKEv2/IPsec(strongSwan),统一认证
  • 系统:CentOS 7 基线加固 + 升级到能开 BBR 的 LTS 内核
  • 路由:策略分流——中国大陆前缀强走 CN2,其他流量走普通 BGP,上线健康检查与自动切换

当天傍晚,我完成了首轮上线,第二天早高峰延迟曲线从“锯齿”变成了“直尺”。下面是完整过程。

1. 目标与验收标准(SLO)

指标 目标 说明
北京/上海/广州 → HK VPN RTT ≤ 45~65 ms 走 CN2 GIA 的稳定区间
抖动(Jitter, p95) ≤ 8 ms 早晚高峰不明显抬升
丢包(1 小时窗口) < 0.2% 连续观测
Git Clone 1GB 仓库 ≤ 3 分钟 员工端到 HK,经 HK 再到代码托管
VPN 并发 ≥ 300 端 典型 200 人同时在线,留余量
故障切换 ≤ 15 秒 CN2 健康探测降级到普通 BGP

2. 硬件与主机参数

选型/参数 备注
机房 香港葵涌/荃湾机房 电力与空调稳定
线路 CN2 GIA 100 Mbps 保障 + 普通 BGP 200 Mbps 备 两上联,独立网口
服务器 1U 双电 冗余电源
CPU Intel Xeon Silver 4210R(10C/20T) AES-NI 加速
内存 64 GB ECC 足够多并发
系统盘 480 GB 企业 SATA / NVMe 系统+日志分区
网口 Intel X520 10GbE(eth1 接 CN2, eth0 接 BGP) SR-IOV 可选
OS CentOS 7.9(Enforcing SELinux) 内核后续换 5.4 LTS

经验:WireGuard 更吃 CPU 单核 AES 与内核网络栈优化,10GbE 不是必须,但优质 Intel NIC 的中断与 offload 表现更稳。

3. 拓扑与寻址

[China Users]  <--CN2 GIA-->  [HK VPN GW]
   │                             │
 WireGuard/IKEv2                 ├─ 内网系统 (私网 10.20.0.0/16)
                                 └─ 外部资源(Git, SaaS)
  • VPN 虚拟网段:10.8.0.0/24(WG),10.9.0.0/24(IKEv2)
  • 管理面只允许跳板机段访问(ACL)
  • 路由策略:目的地在中国大陆前缀 → 走 CN2;其他 → 走普通 BGP

4. 系统基线:加固与最小化

# 基础源与工具
yum install -y epel-release
yum update -y

# 账户与SSH
useradd -m ops && passwd -l root
mkdir -p /home/ops/.ssh && chmod 700 /home/ops/.ssh
# 上传你的公钥到 /home/ops/.ssh/authorized_keys
chown -R ops:ops /home/ops/.ssh && chmod 600 /home/ops/.ssh/authorized_keys

# SSH 加固
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd

# SELinux 保持 Enforcing
sestatus

# Firewalld 基线
yum install -y firewalld
systemctl enable --now firewalld
firewall-cmd --set-default-zone=public

5. 内核升级(开启 BBR、提升网络栈)

CentOS 7 默认 3.10 内核不带 BBR,升级到 ELRepo kernel-lt(5.4 LTS):

rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
yum install -y https://www.elrepo.org/elrepo-release-7.el7.elrepo.noarch.rpm
yum --enablerepo=elrepo-kernel install -y kernel-lt kernel-lt-devel

grub2-set-default 0
grub2-mkconfig -o /boot/grub2/grub.cfg
reboot

# 重启后验证
uname -r

# 开 BBR + 基本内核网络参数
cat >/etc/sysctl.d/99-vpn.conf <<'EOF'
net.ipv4.ip_forward = 1
net.ipv4.conf.all.rp_filter = 0
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_mtu_probing = 1
net.core.rmem_max = 2500000
net.core.wmem_max = 2500000
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_fin_timeout = 15
EOF
sysctl --system

坑 1:升级内核后,某些旧版 out-of-tree 驱动会跪,Intel X520 属于内置驱动 ixgbe,基本没坑。

6. 安装 WireGuard(桌面/服务器主力)

CentOS 7 + kernel 5.4 下可用 ELRepo extras:

yum --enablerepo=elrepo-extras install -y kmod-wireguard wireguard-tools

# 生成密钥
umask 077
wg genkey | tee /etc/wireguard/server.key | wg pubkey > /etc/wireguard/server.pub

/etc/wireguard/wg0.conf:

[Interface]
Address = 10.8.0.1/24
ListenPort = 443      # 走 443/udp,更像 QUIC,穿透友好
PrivateKey = <把 /etc/wireguard/server.key 内容贴这里>
MTU = 1380            # 减少跨境分段导致的丢包
SaveConfig = true

# NAT 与防火墙
PostUp   = firewall-cmd --zone=public --add-port=443/udp; \
           firewall-cmd --zone=public --add-masquerade; \
           iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth1 -j MASQUERADE
PostDown = firewall-cmd --zone=public --remove-port=443/udp; \
           firewall-cmd --zone=public --remove-masquerade; \
           iptables -t nat -D POSTROUTING -s 10.8.0.0/24 -o eth1 -j MASQUERADE

启用:

systemctl enable --now wg-quick@wg0
wg show

示例 客户端(开发同学的 Mac/Linux):

[Interface]
PrivateKey = <client.private>
Address = 10.8.0.2/32
DNS = 10.20.0.53   # 如果你在内网有权威DNS

[Peer]
PublicKey = <server.pub>
Endpoint = vpn.example.com:443
AllowedIPs = 10.20.0.0/16, 172.16.0.0/12, 192.168.0.0/16   # 企业私网分流
PersistentKeepalive = 25

坑 2:MTU 不合适会出现“能连上但访问慢/断流”。跨境我一般从 1380 起试,必要时配合 iptables -t mangle --clamp-mss-to-pmtu。

7. IKEv2(strongSwan)给手机与内置客户端

yum install -y strongswan strongswan-libcharon

# 用 acme.sh 签证书(示例采用 standalone)
curl https://get.acme.sh | sh
~/.acme.sh/acme.sh --issue -d vpn.example.com --standalone --keylength ec-256
~/.acme.sh/acme.sh --install-cert -d vpn.example.com --ecc \
  --key-file       /etc/strongswan/ipsec.d/private/server.key \
  --fullchain-file /etc/strongswan/ipsec.d/certs/server.crt

chown root:root /etc/strongswan/ipsec.d/private/server.key
chmod 600 /etc/strongswan/ipsec.d/private/server.key
restorecon -Rv /etc/strongswan/ipsec.d

/etc/strongswan/ipsec.conf(EAP 用户名/密码,分流指向企业网段):

config setup
    uniqueids=never

conn ikev2-eap
    keyexchange=ikev2
    ike=aes256-sha256-modp2048!
    esp=aes256-sha256!
    dpdaction=clear
    dpddelay=30s
    rekey=no

    left=%defaultroute
    leftid=vpn.example.com
    leftcert=server.crt
    leftauth=pubkey
    leftsubnet=10.20.0.0/16,172.16.0.0/12,192.168.0.0/16

    right=%any
    rightauth=eap-mschapv2
    rightsendcert=never
    eap_identity=%any
    rightsourceip=10.9.0.0/24
    auto=add

/etc/strongswan/ipsec.secrets:

: RSA "server.key"
alice : EAP "S3cureP@ss"
bob   : EAP "An0therP@ss"

推送 DNS(/etc/strongswan/strongswan.d/charon/attr.conf):

charon {
  attr {
    dns = 10.20.0.53
    nbns = 0.0.0.0
  }
}

防火墙:

firewall-cmd --permanent --add-port=500/udp
firewall-cmd --permanent --add-port=4500/udp
firewall-cmd --permanent --add-masquerade
firewall-cmd --reload

systemctl enable --now strongswan

坑 3:iOS 连接不上但日志显示握手正常,多半是 证书链/leftid 问题。确保 leftid 与证书 CN/SAN 匹配域名,且安装完整链。

8. 利用 CN2 GIA 做跨境稳定分流(策略路由)

机房给了两条链路:

  • eth1 = CN2 GIA(AS4809),网关 GW_CN2
  • eth0 = 普通 BGP,网关 GW_BGP

思路:把目的地在 中国大陆前缀 的流量标记后,走 路由表 100(CN2);其余保持默认(表 main → BGP)。此外做 健康检查,CN2 抖动/丢包超阈值就回切 BGP。

8.1 路由表与规则

# /etc/iproute2/rt_tables 末尾追加
echo "100 cn2" >> /etc/iproute2/rt_tables

# 配置静态默认路由到 CN2 表
ip route add default via GW_CN2 dev eth1 table cn2

# 把来自 VPN 网段、且目的地命中“大陆前缀”的流量打标
yum install -y ipset

# 定义中国大陆前缀集合(示例)
cat >/etc/sysconfig/ipset <<'EOF'
create cn cidr hash:net family inet hashsize 1024 maxelem 65536
# 你可以用 chnroutes 生成并导入,以下仅示意几条
add cn 1.0.1.0/24
add cn 1.0.2.0/23
# ...(建议每日定时更新)
EOF
ipset restore < /etc/sysconfig/ipset

# mangle 表标记 + fwmark 路由
iptables -t mangle -N CN2_MARK
iptables -t mangle -A PREROUTING -s 10.8.0.0/24 -m set --match-set cn dst -j CN2_MARK
iptables -t mangle -A PREROUTING -s 10.9.0.0/24 -m set --match-set cn dst -j CN2_MARK
iptables -t mangle -A CN2_MARK -j MARK --set-mark 10

ip rule add fwmark 10 table cn2

说明:我们只标记 来自 VPN 虚拟网段 的流量,避免影响管理面与机房出网。

8.2 健康检查与自动切换

/usr/local/sbin/route-healthcheck.sh(简化示例):

#!/usr/bin/env bash
# 选取三个可靠的大陆探测 IP(可用自家北上广前置机、或权威DNS)
targets=("101.226.4.6" "180.163.57.45" "120.196.165.24")
loss_threshold=3   # 丢包超过 3% 判定不健康
rtt_threshold=80   # 平均 RTT 超过 80ms 判定不健康
count=20

check_cn2() {
  local loss_sum=0
  local rtt_sum=0
  for t in "${targets[@]}"; do
    # 走 cn2 表发包
    res=$(ping -I eth1 -c $count -n -q $t 2>/dev/null)
    loss=$(echo "$res" | awk -F',' '/packet/{print $3}' | tr -dc '0-9')
    rtt=$(echo "$res" | awk -F'/' 'END{print $5+0}')
    loss_sum=$((loss_sum + loss))
    rtt_sum=$(echo "$rtt_sum + $rtt" | bc)
  done
  avg_loss=$(echo "scale=2; $loss_sum / ${#targets[@]}" | bc)
  avg_rtt=$(echo "scale=2; $rtt_sum / ${#targets[@]}" | bc)

  if (( $(echo "$avg_loss > $loss_threshold" | bc -l) )) || \
     (( $(echo "$avg_rtt > $rtt_threshold" | bc -l) )); then
    return 1
  else
    return 0
  fi
}

if check_cn2; then
  ip rule | grep -q "fwmark 0xa lookup cn2" || ip rule add fwmark 10 table cn2
else
  ip rule del fwmark 10 table cn2 2>/dev/null
fi

Systemd 定时:

cat >/etc/systemd/system/route-healthcheck.service <<'EOF'
[Unit]
Description=CN2 Healthcheck

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/route-healthcheck.sh
EOF

cat >/etc/systemd/system/route-healthcheck.timer <<'EOF'
[Unit]
Description=CN2 Healthcheck Timer

[Timer]
OnBootSec=30s
OnUnitActiveSec=15s

[Install]
WantedBy=timers.target
EOF

systemctl daemon-reload
systemctl enable --now route-healthcheck.timer

坑 4:不要用 curl 去测应用延迟,有时被 WAF/限速干扰。ICMP + 你自己的前置探针更可靠。

9. 安全与可观测性

  • fail2ban:针对 443/udp 无意义但高频的探测,配合 wg show 日志与 journalctl -u strongswan 做智能拉黑
  • SELinux:保持 Enforcing,若 strongSwan 证书目录访问被拒,restorecon -Rv 基本解决
  • 审计:auditd + rsyslog,登录、配置变更审计到专用文件
  • 监控:node_exporter、VPN 在线数、自研 RTT/丢包 exporter,Grafana 设阈值告警
  • 备份:/etc/wireguard、/etc/strongswan、/etc/sysconfig/ipset、/usr/local/sbin/*.sh 拉快照到安全仓

10. DNS 与分流策略(避免全流量出海)

建议:只把企业私网与必要的 SaaS 目的网段走 VPN,其他本地直出

WireGuard 客户端通过 AllowedIPs 控制(见第 6 节)

IKEv2 通过 leftsubnet= 向客户端下发路由前缀

内网域名用 dnsmasq/unbound 做权威/转发,避免泄露与跨境解析抖动

/etc/dnsmasq.d/corp.conf 示例:

server=/corp.example.com/10.20.0.53
address=/git.corp.example.com/10.20.10.23

11. 压测与观测数据(上线前后对比)

端到端 Ping(员工端→HK VPN)

城市 协议 升级前 RTT(均值/抖动) 升级后(CN2 GIA)
北京 ICMP 74 ms / 18 ms 46 ms / 5 ms
上海 ICMP 68 ms / 15 ms 42 ms / 4 ms
广州 ICMP 58 ms / 12 ms 39 ms / 3 ms

Git Clone 1GB 仓库(均 3 次)

城市 升级前 升级后
北京 7m42s 2m58s
上海 6m31s 2m34s
广州 5m54s 2m20s

丢包(1 小时窗口)

时间 升级前 升级后
09:00-10:00 1.8% 0.12%
20:00-21:00 2.3% 0.18%

12. 现场踩过的坑与修复过程

WireGuard 帧分片导致“时好时坏”
现象:wg show 正常,网页间歇超时。
排查:MTR 显示跨境某跳丢包,怀疑 MTU 触发分片。
处理:WG MTU 调 1380,并在出口加 --clamp-mss-to-pmtu。问题消失。

iOS IKEv2 连接失败(证书/ID 不匹配)
现象:charon 握手后掉线。
处理:确认证书 CN/SAN 含 vpn.example.com,并将 leftid 设为域名,重签完整链。OK。

SELinux 拒绝 strongSwan 读私钥
现象:type=AVC 拒绝。
处理:restorecon -Rv /etc/strongswan/ipsec.d;确保权限 600,所有者 root。

CN2 夜间抖动
现象:20:00-21:30 RTT 飙至 90ms+。
处理:健康检查脚本将策略临时切到 BGP,平稳后切回;Grafana 告警留痕。

ethtool offload 导致奇怪的乱序
现象:iperf3 单流带宽忽高忽低。
处理:ethtool -K ethX gso off gro off tso off,并设置中断亲和 irqbalance --oneshot 后手工绑核,波动明显减小。

13. 运维手册(常用操作清单)

# 新增 WireGuard 用户(示例)
umask 077
wg genkey | tee alice.key | wg pubkey > alice.pub
cat >> /etc/wireguard/wg0.conf <<EOF
[Peer]
# Alice
PublicKey = <alice.pub 内容>
AllowedIPs = 10.8.0.10/32
EOF
systemctl reload wg-quick@wg0

# strongSwan 新增用户
echo 'carol : EAP "Str0ng!Pass"' >> /etc/strongswan/ipsec.secrets
systemctl reload strongswan

# 查看在线与统计
wg show
swanctl --list-sas  # 若使用 swanctl;starter 体系用 'ipsec statusall'

# 临时切换策略路由(故障演练)
ip rule del fwmark 10 table cn2
ip rule add fwmark 10 table cn2

# 更新大陆前缀(每日计划任务)
# 生成 cn.txt 后:
ipset flush cn && ipset restore < /etc/sysconfig/ipset

14. 成本核算(粗略)

规格 单价(参考) 备注
CN2 GIA 100M 保障 $$$ 可突发 200M
普通 BGP 200M $$ 备链路
服务器租用 1U 托管/独立 $$ 含电力/机位
人工 1 人/周 $ 首次部署与调优

经验:CN2 GIA 的“贵”是换来稳定的早晚高峰曲线和少数工单;并发多时,踏实比便宜更重要。

15. 把“锯齿”磨平

第二天早高峰,我习惯性地盯着 Grafana。RTT 线像拉紧的琴弦,平直。Slack 里有人说:“今天怎么这么顺?”我笑了笑,给香港那台小钢炮的机箱门拍了拍。它并不耀眼,但把跨境那段最脆的链路接住了。到了晚上,CN2 有一次短暂抖动,健康检查自动把策略切回 BGP,15 秒后稳定——没人察觉。

这就是我想要的 VPN:不是炫技,而是稳定、可回滚、可观察。

留给后来者的 3 个要点:

  • 选好线路 > 堆参数;CN2 GIA 能把“锯齿”磨平
  • 双协议双路径:WireGuard 性能,IKEv2 兼容
  • 策略分流 + 健康检查:让“正确的流量走正确的路”,并能自动自救

如果你也准备把香港服务器撑成跨境的“缓冲带”,希望这篇现场笔记能让你少踩几个坑,多睡几个安稳觉。

目录结构
全文