Hysteria 2 部署指南:IPv6-Only VPS + 客户端双栈自动回退与分流
适用场景:VPS 仅有公网 IPv6 地址(无 IPv4),客户端处于 IPv4/IPv6 双栈网络,需要通过 Hysteria 2 实现透明代理及智能分流。
目录
1. 背景与架构概述
问题模型
客户端(双栈:IPv4 + IPv6)
│
├─── IPv6 ──→ VPS(仅 IPv6):443/UDP ← Hysteria 2 服务端
│
└─── IPv4 ──→ ??? (VPS 无法直接接收 IPv4)
核心挑战:
| 问题 | 说明 |
|---|---|
| VPS 无 IPv4 | 客户端若走 IPv4 则无法连接服务端 |
| 客户端优先级 | Happy Eyeballs / 系统可能优先选择 IPv4 |
| 回退机制缺失 | Hysteria 2 本身不内置多地址自动切换 |
| DNS 解析 | VPS 上运行的代理需解析 IPv4 目标(如访问 IPv4-only 站点) |
推荐架构
┌─────────────────────────────────┐
│ 客户端(Linux / macOS / Win) │
│ │
│ ┌──────────┐ ┌─────────────┐ │
│ │ 分流引擎 │ │ 回退检测器 │ │
│ └────┬─────┘ └──────┬──────┘ │
│ │ │ │
│ ┌────▼────────────────▼──────┐ │
│ │ Hysteria 2 Client │ │
│ └────────────────┬────────────┘ │
└───────────────────┼──────────────┘
│ QUIC/UDP over IPv6
┌──────────▼──────────┐
│ VPS [2001:db8::1] │
│ Hysteria 2 Server │
│ + NAT64 出口 │
└─────────────────────┘
2. 服务端配置(IPv6-Only VPS)
2.1 安装 Hysteria 2
# 官方安装脚本
bash <(curl -fsSL https://get.hy2.sh/)
# 验证安装
hysteria version
2.2 申请 TLS 证书
由于 VPS 仅有 IPv6,需确保域名有 AAAA 记录指向 VPS。
# 方式一:ACME 自动申请(推荐,需域名 AAAA 记录已生效)
hysteria server --acme-domain your.domain.com
# 方式二:使用 certbot(适配 IPv6-only 环境)
certbot certonly \
--standalone \
--preferred-challenges http \
-d your.domain.com \
--server https://acme-v02.api.letsencrypt.org/directory
# 注意:Let's Encrypt CA 需能通过 IPv6 回访你的域名
2.3 服务端配置文件
路径:/etc/hysteria/config.yaml
# /etc/hysteria/config.yaml
listen: "[::]:443" # 监听所有 IPv6 地址的 443/UDP
tls:
cert: /etc/letsencrypt/live/your.domain.com/fullchain.pem
key: /etc/letsencrypt/live/your.domain.com/privkey.pem
auth:
type: password
password: "your-strong-password"
# 带宽限速(按实际线路调整)
bandwidth:
up: 100 mbps
down: 100 mbps
# QUIC 参数优化(IPv6 网络通常 MTU 更大)
quic:
initStreamReceiveWindow: 8388608 # 8 MiB
maxStreamReceiveWindow: 8388608
initConnReceiveWindow: 20971520 # 20 MiB
maxConnReceiveWindow: 20971520
maxIdleTimeout: 60s
keepAlivePeriod: 10s
disablePathMTUDiscovery: false
# 日志(便于排查 IPv6 连接问题)
log:
level: info
timestamp: true
2.4 IPv6 内核参数
# /etc/sysctl.d/99-ipv6-forward.conf
cat >> /etc/sysctl.d/99-ipv6-forward.conf << 'EOF'
# 开启 IPv6 转发(NAT64 所需)
net.ipv6.conf.all.forwarding = 1
# 禁用 IPv6 Privacy Extensions(服务端不需要)
net.ipv6.conf.all.use_tempaddr = 0
# 增大 UDP 缓冲区(QUIC 性能关键)
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576
EOF
sysctl -p /etc/sysctl.d/99-ipv6-forward.conf
2.5 防火墙规则(nftables)
#!/usr/sbin/nft -f
# /etc/nftables-hysteria.conf
table inet hysteria {
chain input {
type filter hook input priority 0; policy accept;
# 放行 Hysteria 2 QUIC 端口
ip6 daddr { ::/0 } udp dport 443 accept comment "Hysteria2 QUIC"
# 放行 ICMP6(邻居发现等)
icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert,
nd-router-solicit, nd-router-advert } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
# 允许已建立连接转发
ct state { established, related } accept
# NAT64 转发(见第3节)
ip6 daddr 64:ff9b::/96 accept comment "NAT64 traffic"
}
}
nft -f /etc/nftables-hysteria.conf
systemctl enable --now nftables
3. DNS64 / NAT64 支持(可选)
当客户端通过 Hysteria 2 代理访问 IPv4-only 站点时,服务端需要 NAT64 能力将 IPv6 流量转换为 IPv4 出口。
3.1 安装 Tayga(用户态 NAT64)
apt install tayga # Debian/Ubuntu
# 或
dnf install tayga # Fedora/RHEL
3.2 Tayga 配置
# /etc/tayga.conf
tun-device nat64
ipv4-addr 192.168.255.1
prefix 64:ff9b::/96
dynamic-pool 192.168.255.0/24
data-dir /var/lib/tayga
# 创建 TUN 设备并启动
tayga --mktun
ip link set nat64 up
ip route add 192.168.255.0/24 dev nat64
ip -6 route add 64:ff9b::/96 dev nat64
# 开启 IPv4 转发并配置 MASQUERADE
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
tayga
3.3 DNS64(unbound 配置)
# /etc/unbound/unbound.conf.d/dns64.conf
server:
# 只监听 IPv6
interface: ::1
interface: ::
# DNS64 合成前缀(与 NAT64 一致)
dns64-prefix: 64:ff9b::/96
# 上游 DNS(IPv6 可达的公共解析器)
do-ip4: no
do-ip6: yes
forward-zone:
name: "."
forward-addr: 2001:4860:4860::8888 # Google IPv6 DNS
forward-addr: 2606:4700:4700::1111 # Cloudflare IPv6 DNS
systemctl enable --now unbound
4. 客户端配置(双栈环境)
4.1 基础连接配置
# /etc/hysteria/client.yaml
server: your.domain.com:443 # 域名需有 AAAA 记录
auth: "your-strong-password"
# 强制走 IPv6 连接服务端(核心配置)
# Hysteria 2 使用 Happy Eyeballs,可通过 server 字段直接写 IPv6 字面量绕过
# server: "[2001:db8::1]:443"
bandwidth:
up: 50 mbps
down: 100 mbps
# SOCKS5 入站代理
socks5:
listen: 127.0.0.1:1080
# HTTP 代理入站
http:
listen: 127.0.0.1:8080
# TUN 模式(透明代理,Linux 推荐)
tun:
name: hysteria-tun
mtu: 1500
address:
ipv4: 100.100.100.1/30
ipv6: 2001:db8:1::1/126
4.2 强制 IPv6 出站的技巧
Hysteria 2 客户端默认使用 Happy Eyeballs 同时尝试 IPv4/IPv6,对于 IPv6-only 服务端,需确保 DNS 解析到 AAAA 记录并优先使用:
# 检查域名 AAAA 记录是否正常
dig AAAA your.domain.com
# 若客户端所在网络 IPv6 路由不通,可临时指定本地绑定地址
# 在 client.yaml 中添加:
# 追加至 client.yaml
transport:
udp:
hopInterval: 30s # 端口跳跃间隔(抗干扰)
# 绑定特定本地 IPv6 地址出站
# localAddr: "[fe80::1%eth0]:0" # 取消注释并按需修改
5. 自动回退逻辑设计
Hysteria 2 本身无内置多服务端自动切换,需在外部实现。以下提供两种方案。
方案 A:使用 systemd + 健康检查脚本
#!/usr/bin/env bash
# /usr/local/bin/hysteria-watchdog.sh
# 监控 Hysteria 2 客户端连通性,自动切换备用节点
PRIMARY_SERVER="your.domain.com:443"
FALLBACK_SERVER="[2001:db8::2]:443" # 备用节点(也是 IPv6-only)
CONFIG_DIR="/etc/hysteria"
CHECK_INTERVAL=15
FAIL_THRESHOLD=3
fail_count=0
current_server="$PRIMARY_SERVER"
check_connectivity() {
# 通过 SOCKS5 发送测试请求,超时 5 秒
curl --socks5-hostname 127.0.0.1:1080 \
--max-time 5 \
--silent \
--output /dev/null \
https://captive.apple.com/hotspot-detect.html
return $?
}
switch_to_fallback() {
echo "[$(date -Iseconds)] 切换至备用节点: $FALLBACK_SERVER"
sed -i "s|server:.*|server: $FALLBACK_SERVER|" "$CONFIG_DIR/client.yaml"
systemctl restart hysteria-client
current_server="$FALLBACK_SERVER"
fail_count=0
}
switch_to_primary() {
echo "[$(date -Iseconds)] 恢复主节点: $PRIMARY_SERVER"
sed -i "s|server:.*|server: $PRIMARY_SERVER|" "$CONFIG_DIR/client.yaml"
systemctl restart hysteria-client
current_server="$PRIMARY_SERVER"
fail_count=0
}
while true; do
if ! check_connectivity; then
(( fail_count++ ))
echo "[$(date -Iseconds)] 连通性检查失败 ($fail_count/$FAIL_THRESHOLD)"
if [[ $fail_count -ge $FAIL_THRESHOLD ]]; then
if [[ "$current_server" == "$PRIMARY_SERVER" ]]; then
switch_to_fallback
else
echo "[$(date -Iseconds)] 备用节点也不可用,等待恢复..."
fi
fi
else
# 若当前在备用节点且主节点可能已恢复,尝试切回
if [[ "$current_server" != "$PRIMARY_SERVER" ]]; then
# 直接探测主节点 IPv6 可达性
if ping6 -c 2 -W 3 "${PRIMARY_SERVER%%:*}" &>/dev/null; then
switch_to_primary
fi
fi
fail_count=0
fi
sleep "$CHECK_INTERVAL"
done
# /etc/systemd/system/hysteria-watchdog.service
[Unit]
Description=Hysteria 2 Watchdog (Auto Failover)
After=hysteria-client.service
Requires=hysteria-client.service
[Service]
Type=simple
ExecStart=/usr/local/bin/hysteria-watchdog.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
方案 B:使用 sing-box 多出站负载均衡(推荐)
sing-box 内置健壮的出站管理与健康检测,可封装 Hysteria 2 协议:
{
"outbounds": [
{
"type": "hysteria2",
"tag": "hy2-primary",
"server": "your.domain.com",
"server_port": 443,
"password": "your-strong-password",
"up_mbps": 50,
"down_mbps": 100
},
{
"type": "hysteria2",
"tag": "hy2-fallback",
"server": "your-fallback.domain.com",
"server_port": 443,
"password": "your-strong-password",
"up_mbps": 50,
"down_mbps": 100
},
{
"type": "urltest",
"tag": "auto-select",
"outbounds": ["hy2-primary", "hy2-fallback"],
"url": "https://www.gstatic.com/generate_204",
"interval": "30s",
"tolerance": 50
},
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
}
]
}
6. 分流规则配置
6.1 基于 GeoIP / GeoSite 的分流(sing-box)
{
"route": {
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
},
{
"geoip": ["private"],
"outbound": "direct"
},
{
"geosite": ["cn"],
"geoip": ["cn"],
"outbound": "direct"
},
{
"geosite": ["ads"],
"outbound": "block"
},
{
"outbound": "auto-select"
}
],
"final": "auto-select",
"auto_detect_interface": true
}
}
6.2 IPv4/IPv6 流量的差异化分流
关键点:客户端访问 IPv4 目标时,需通过代理(服务端 NAT64 转换);访问 IPv6 目标时可直连或代理均可。
{
"route": {
"rules": [
{
"ip_version": 6,
"geoip": ["cn"],
"outbound": "direct",
"comment": "国内 IPv6 直连"
},
{
"ip_version": 4,
"geoip": ["cn"],
"outbound": "direct",
"comment": "国内 IPv4 直连(客户端自身有 IPv4)"
},
{
"ip_version": 4,
"outbound": "auto-select",
"comment": "境外 IPv4 走代理(由服务端 NAT64 处理)"
},
{
"ip_version": 6,
"outbound": "auto-select",
"comment": "境外 IPv6 走代理"
}
]
}
}
6.3 DNS 分流配置
{
"dns": {
"servers": [
{
"tag": "dns-remote",
"address": "https://1.1.1.1/dns-query",
"detour": "auto-select"
},
{
"tag": "dns-direct",
"address": "223.5.5.5",
"detour": "direct"
},
{
"tag": "dns-local",
"address": "local"
}
],
"rules": [
{
"geosite": ["cn"],
"server": "dns-direct"
},
{
"outbound": ["auto-select"],
"server": "dns-remote",
"disable_cache": false
}
],
"final": "dns-remote",
"strategy": "prefer_ipv6",
"disable_expire": false
}
}
strategy: prefer_ipv6:DNS 优先返回 AAAA 记录,减少对代理服务端 NAT64 的依赖,提升性能。
7. Linux 路由表进阶配置
7.1 TUN 模式下的策略路由
#!/usr/bin/env bash
# /usr/local/bin/setup-hysteria-routes.sh
# 配置 Hysteria 2 TUN 模式策略路由
TUN_IFACE="hysteria-tun"
MARK=0x1234
TABLE=100
# ── 1. 创建路由表 ──────────────────────────────────────────
grep -q "^$TABLE " /etc/iproute2/rt_tables || \
echo "$TABLE hysteria" >> /etc/iproute2/rt_tables
# ── 2. 为 Hysteria 进程本身打标记(避免代理流量递归)──────
# 通过 cgroup 或 UID 标记 hysteria 进程
iptables -t mangle -A OUTPUT -m owner --uid-owner hysteria \
-j MARK --set-mark $MARK
ip6tables -t mangle -A OUTPUT -m owner --uid-owner hysteria \
-j MARK --set-mark $MARK
# ── 3. 标记流量走原始路由(绕过 TUN)────────────────────
ip rule add fwmark $MARK table $TABLE priority 100
ip -6 rule add fwmark $MARK table $TABLE priority 100
ip route add default via $(ip route show default | awk '/via/{print $3}') \
table $TABLE
ip -6 route add default via $(ip -6 route show default | awk '/via/{print $3}') \
dev $(ip -6 route show default | awk '/dev/{print $5}') \
table $TABLE
# ── 4. 其余流量走 TUN ────────────────────────────────────
ip rule add not fwmark $MARK table main priority 200
echo "策略路由配置完成"
7.2 IPv6 默认路由保留(防止服务端连接断开)
# 连接 Hysteria 2 服务端的 IPv6 流量必须走物理网卡,不能进 TUN
# 获取 VPS 的 IPv6 地址
VPS_IPV6=$(dig AAAA your.domain.com +short | head -1)
PHYS_IFACE=$(ip -6 route get "$VPS_IPV6" | awk '/dev/{print $5}' | head -1)
GW6=$(ip -6 route show default | awk '/via/{print $3}' | head -1)
ip -6 route add "$VPS_IPV6/128" via "$GW6" dev "$PHYS_IFACE"
echo "已添加服务端 IPv6 主机路由,绕过 TUN"
7.3 完整 nftables 策略(客户端侧)
#!/usr/sbin/nft -f
# 客户端 nftables:透明代理 + 绕过本机流量
define HYSTERIA_UID = 1001 # Hysteria 进程运行的 UID
define BYPASS_MARK = 0x00001234
define TUN_IFACE = "hysteria-tun"
table inet tproxy_rules {
# 放行 Hysteria 自身流量(防环)
chain mangle_output {
type route hook output priority mangle; policy accept;
meta skuid $HYSTERIA_UID mark set $BYPASS_MARK return
ip daddr { 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } return
ip6 daddr { ::1/128, fe80::/10, fd00::/8 } return
# 国内 IP 段直连(需提前加载 geoip 集合,此处示意)
# ip daddr @cn_ipv4 return
# ip6 daddr @cn_ipv6 return
mark set 1 comment "标记需代理流量"
}
chain mangle_prerouting {
type filter hook prerouting priority mangle; policy accept;
mark 1 tproxy to 127.0.0.1:7895 comment "TProxy 重定向至 sing-box"
}
}
8. 故障排查
8.1 常见问题速查
| 症状 | 可能原因 | 排查命令 |
|---|---|---|
| 客户端无法连接服务端 | 客户端无 IPv6 路由 / AAAA 解析失败 | ping6 your.domain.com |
| 连接抖动 / 频繁重连 | UDP 被运营商 QoS | hysteria client --log-level debug |
| IPv4 站点无法访问 | 服务端 NAT64 未配置 | curl --socks5 127.0.0.1:1080 http://1.1.1.1 |
| DNS 泄漏 | 本地 DNS 未走代理 | curl https://ipleak.net/json/ |
| TUN 流量递归 | 策略路由标记缺失 | ip rule show; ip -6 rule show |
8.2 IPv6 连通性检查脚本
#!/usr/bin/env bash
# 一键检查 IPv6 连通性与 Hysteria 2 服务可达性
SERVER_DOMAIN="your.domain.com"
SERVER_PORT=443
echo "=== 本机 IPv6 地址 ==="
ip -6 addr show scope global | grep inet6
echo ""
echo "=== 默认 IPv6 路由 ==="
ip -6 route show default
echo ""
echo "=== DNS 解析 AAAA ==="
dig AAAA "$SERVER_DOMAIN" +short
echo ""
echo "=== IPv6 Ping 服务端 ==="
ping6 -c 4 "$SERVER_DOMAIN"
echo ""
echo "=== UDP 端口可达性(需 netcat-openbsd)==="
SERVER_IP=$(dig AAAA "$SERVER_DOMAIN" +short | head -1)
echo "Q" | timeout 3 nc -6 -u "$SERVER_IP" "$SERVER_PORT" \
&& echo "UDP 端口可达" \
|| echo "UDP 端口超时(正常,QUIC 需握手)"
echo ""
echo "=== Hysteria 2 服务状态 ==="
systemctl is-active hysteria-client && \
echo "客户端运行中" || echo "客户端未运行"
echo ""
echo "=== 代理连通性测试 ==="
curl --socks5-hostname 127.0.0.1:1080 \
--max-time 10 \
--silent \
https://api.ipify.org?format=json && echo ""
8.3 性能调优参数参考
# 针对 QUIC 的系统级调优(服务端 + 客户端均适用)
# UDP 接收/发送缓冲区
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
# 开启 GSO/GRO(需内核 5.x+,显著降低 QUIC CPU 开销)
ethtool -K eth0 gso on gro on
# 增大连接跟踪表(高并发场景)
sysctl -w net.netfilter.nf_conntrack_max=1048576
# IPv6 邻居表(大规模部署)
sysctl -w net.ipv6.neigh.default.gc_thresh3=8192
附录:完整文件结构
/etc/hysteria/
├── config.yaml # 服务端配置(VPS 上)
├── client.yaml # 客户端基础配置
└── rules/
├── geoip.db # GeoIP 数据库
└── geosite.db # GeoSite 数据库
/usr/local/bin/
├── hysteria-watchdog.sh # 自动回退守护脚本
└── setup-hysteria-routes.sh # 路由初始化脚本
/etc/systemd/system/
├── hysteria-client.service
└── hysteria-watchdog.service
最后更新:2026-04 | 适用版本:Hysteria 2.x、sing-box 1.9+、Linux kernel 5.15+