歇斯底里2 Hysteria2从零搭建教程:Cloudflare DNS-01自动SSL证书、UDP端口跳跃与v2rayN和小火箭配置

本文演示在已有 Caddy、3x-ui 等服务占用常见 TCP 端口的 VPS 上,部署 Hysteria2,使用 Cloudflare DNS-01 自动申请和续签 Let’s Encrypt 证书,并配置 UDP 端口跳跃与 Windows v2rayN 和ios小火箭客户端。

写在前面

Hysteria2 基于 QUIC/UDP,适合合法自用、远程办公、授权测试和个人网络环境优化。请遵守所在地法律、VPS 服务条款和网络服务规定。

本文采用下面这套结构:

h2.example.com(Cloudflare 灰云 DNS)
                │
                ▼
VPS UDP 20000-21000
                │
      iptables 自动重定向
                │
                ▼
Hysteria2 实际监听 UDP 20000

这种方案有三个优点:

  1. 不占用 Caddy、Nginx 或 3x-ui 使用的 TCP 443/8443;
  2. 使用 Cloudflare DNS-01 验证,不需要抢占 TCP 80/443;
  3. Let’s Encrypt 证书受 Windows、sing-box 和主流客户端信任,并能自动续签。

需要特别说明:Cloudflare 普通橙云 CDN 不能代理 Hysteria2。Hysteria2 虽然在握手阶段表现得像 HTTP/3,但认证后使用自己的协议,因此 DNS 记录必须保持“仅 DNS/灰云”。

一、准备工作

开始前准备:

  • 一台有公网 IPv4 或 IPv6 的 VPS;
  • Debian 12/13、Ubuntu 22.04/24.04 等主流 Linux 系统;
  • root 或 sudo 权限;
  • 一个由 Cloudflare 管理 DNS 的域名;
  • Windows 电脑和较新的 v2rayN;
  • VPS 服务商后台安全组的管理权限。

本文示例参数:

域名:h2.example.com
端口范围:UDP 20000-21000
认证方式:password
混淆方式:salamander
客户端:v2rayN + sing-box

请将 h2.example.com、邮箱和端口范围替换成自己的值。

二、配置 Cloudflare DNS

进入 Cloudflare:

网站 → 选择域名 → DNS → 记录

添加 A 记录:

类型 名称 内容 TTL 代理状态
A h2 VPS 公网 IPv4 Auto 仅 DNS(灰云)

如果使用 IPv6,再添加 AAAA 记录。不要添加错误的 AAAA 记录,否则客户端可能优先连接到错误地址。

本地检查:

nslookup h2.example.com

VPS 检查公网 IPv4:

curl -4s https://api.ipify.org
echo

两边 IP 应一致。

三、创建 Cloudflare DNS API Token

进入 Cloudflare 个人资料中的 API Token 页面,新建自定义 Token。

权限建议:

Zone / DNS / Edit
Zone / Zone / Read

区域资源限制为:

Include / Specific zone / example.com

客户端 IP 地址过滤可以留空,也可以限制为 VPS 的固定公网 IP。完成摘要页后,必须继续点击“创建令牌”,并使用下一页只显示一次的完整 Token。不要误用 Global API Key、Zone ID 或 Origin CA Key。

在 VPS 上验证 Token。为了避免下划线转义问题,本文使用变量名 CFTOKEN。下面的输入命令不会把 Token 写进 Shell 历史;粘贴时字符不显示属于正常现象:

read -rsp '粘贴完整的 Cloudflare API Token,然后按回车:' CFTOKEN
echo
printf 'Token 长度=%s\n' "${#CFTOKEN}"

CFURL='https:'//api.cloudflare.com/client/v4/user/tokens/verify

curl -sS "$CFURL" \
  -H "Authorization: Bearer ${CFTOKEN}" \
  -H "Content-Type: application/json"
echo

正确结果应包含:

"status":"active"
"success":true

Token 后续用于自动续签证书,因此部署完成后不要删除或撤销。Token 必须限制到指定域名和最小权限。

四、检查端口占用

Hysteria2 使用 UDP。即使某程序占用了 TCP 8443,只要 UDP 8443 空闲,两者仍可共用同一个端口号。

查看 TCP/UDP 443:

ss -lntp 'sport = :443'
ss -lnup 'sport = :443'

查看 UDP 20000:

ss -lnup 'sport = :20000'

如果 Caddy 同时占用 TCP 和 UDP 443,通常是 Caddy 启用了 HTTP/3。本文直接选择独立的 UDP 端口范围 20000-21000,不修改现有网站配置。

五、安装 Hysteria2

安装基础工具:

apt-get update
apt-get install -y curl openssl ca-certificates iptables

执行 Hysteria2 官方安装脚本:

bash <(curl -fsSL https://get.hy2.sh/)

检查版本:

hysteria version

官方脚本会安装:

/usr/local/bin/hysteria
/etc/hysteria/config.yaml
/etc/systemd/system/hysteria-server.service

六、生成认证密码和混淆密码

为了便于复制到客户端,本文使用十六进制密码,避免 Base64 中的 +、/、= 在分享链接里需要额外转义:

AUTH="$(openssl rand -hex 24)"
OBFS="$(openssl rand -hex 24)"

确认变量非空:

printf 'AUTH 长度=%s,OBFS 长度=%s\n' "${#AUTH}" "${#OBFS}"

两者都应为 48。保存到仅 root 可读的文件:

umask 077
printf 'AUTH=%s\nOBFS=%s\n' "$AUTH" "$OBFS" \
  > /root/hysteria2-credentials.txt

七、先用单端口申请证书

建议先让 Hysteria2 监听单端口 20000,确认 Cloudflare Token 和证书申请正常后,再开启端口跳跃。这样即使 ACME 配置错误,也不会留下未清理的防火墙跳跃链。

写入配置:

cat > /etc/hysteria/config.yaml <<EOF
listen: ":20000"

acme:
  domains:
    - h2.example.com
  email: [email protected]
  ca: letsencrypt
  type: dns
  dns:
    name: cloudflare
    config:
      cloudflare_api_token: "$CFTOKEN"

auth:
  type: password
  password: "$AUTH"

obfs:
  type: salamander
  salamander:
    password: "$OBFS"

masquerade:
  type: proxy
  proxy:
    url: "https://www.microsoft.com/"
    rewriteHost: true
EOF

设置权限:

chown root:hysteria /etc/hysteria/config.yaml
chmod 640 /etc/hysteria/config.yaml
unset CFTOKEN

注意:tls: 与 acme: 只能选择一个,不能同时存在。

启动服务:

systemctl enable --now hysteria-server.service
sleep 5
systemctl status hysteria-server.service --no-pager -l
journalctl -u hysteria-server.service --since "5 minutes ago" --no-pager

成功时应看到:

server up and running
maintenance started background certificate maintenance

这表示 Let’s Encrypt 公网证书已经获取,后台自动维护也已经启动。

八、开启端口跳跃

Hysteria2 Linux 服务端支持直接在 listen 中填写范围。它实际监听范围中的第一个端口,并用 iptables 或 nftables 将其余 UDP 端口重定向到第一个端口。

修改配置:

sed -i 's/^listen:.*/listen: ":20000-21000"/' \
  /etc/hysteria/config.yaml

部分系统中,Hysteria 用户虽然有 CAP_NET_ADMIN,但无法创建 /run/xtables.lock。可以提前设置持久化锁文件权限:

touch /run/xtables.lock
chown hysteria:hysteria /run/xtables.lock
chmod 660 /run/xtables.lock

printf '%s\n' \
  'f /run/xtables.lock 0660 hysteria hysteria -' \
  > /etc/tmpfiles.d/hysteria-xtables.conf

systemd-tmpfiles --create /etc/tmpfiles.d/hysteria-xtables.conf

重启并检查:

systemctl restart hysteria-server.service
sleep 3

systemctl status hysteria-server.service --no-pager -l
ss -lnup 'sport = :20000'
iptables -t nat -S | grep HYSTERIA
ip6tables -t nat -S | grep HYSTERIA

正常情况下可以看到:

UDP 20000 由 hysteria 监听
UDP 20001-21000 被重定向到 20000

九、防火墙和云安全组

如果系统本机 INPUT 默认策略为 ACCEPT,且没有 UDP DROP/REJECT 规则,本机通常不需要额外放行:

iptables -S INPUT
ip6tables -S INPUT

如果使用 UFW:

ufw allow 20000:21000/udp
ufw status

如果使用 firewalld:

firewall-cmd --permanent --add-port=20000-21000/udp
firewall-cmd --reload

VPS 服务商后台若有安全组、云防火墙或入站规则,也必须放行:

协议:UDP
端口:20000-21000
来源:按需要设置;测试阶段可使用 0.0.0.0/0

不要为了省事执行 iptables -F,这可能破坏 Docker、3x-ui、Fail2ban 或其他服务的规则。

十、v2rayN 客户端配置

使用较新的 v2rayN,并为 Hysteria2 节点选择 sing_box 内核。

进入:

服务器 → 添加 Hysteria2 服务器

填写:

字段 内容
别名 自定义,例如 HY2-VPS
地址 h2.example.com
端口 20000
密码 AUTH 的值
跳跃端口范围 20000-21000
端口跳跃间隔 30s
最大带宽 Up/Down 留空,先使用默认拥塞控制
Finalmask 留空
TLS tls
SNI h2.example.com
Fingerprint 留空
ALPN 留空
跳过证书验证 Off
固定证书 不设置
混淆密码 OBFS 的值
Gecko 包大小 保持 0
Realm URI 留空
内核 sing_box

两个密码不要填反:

password      → AUTH
obfs password → OBFS

如果使用 Base64 密码,末尾 = 是密码的一部分,不能删除;手动填写时不要包含 AUTH= 或 OBFS= 变量名。

保存后将节点设为活动服务器,测试“真连接延迟”,再开启系统代理访问网页。

十一、证书为什么必须用 Let’s Encrypt

Cloudflare 提供的 15 年 Origin CA 通配符证书只用于“Cloudflare 边缘节点到源站”这段链路。Windows、浏览器和 sing-box 默认不信任 Cloudflare Origin CA。

当 DNS 保持灰云、客户端直接连接 VPS 时,Origin CA 证书会出现:

x509: certificate signed by unknown authority

不要长期打开 allowInsecure 绕过验证。正确做法是使用 Let’s Encrypt、ZeroSSL 等客户端默认信任的公网 CA。本文的 Cloudflare DNS-01 方案不占用 TCP 80/443,适合 Caddy 已经运行的网站服务器。

十二、常见故障排查

1. Cloudflare 返回 Invalid API Token

日志示例:

HTTP 403
Code: 9109
Message: Invalid access token

检查:

  • 是否已经在摘要页点击“创建令牌”;
  • 是否复制了下一页只显示一次的完整 Token;
  • 是否误用了 Global API Key、Zone ID 或 Origin CA Key;
  • Token 是否包含完整的 cfut_ 前缀;
  • Shell 变量是否写成了 CFTOKEN,而不是带转义符的错误形式。

使用 Cloudflare verify API 验证,只有 success:true 才继续。

2. xtables.lock Permission denied

日志:

can't open lock file /run/xtables.lock: Permission denied

执行本文第八节的 tmpfiles.d 修复命令,然后重启服务。

3. iptables Chain already exists

如果 ACME 失败发生在创建端口跳跃规则之后,进程异常退出可能留下 IPv4/IPv6 链。先停止服务,再只清理名称以 HYSTERIA-PR- 开头的链:

systemctl stop hysteria-server.service

for FW in iptables ip6tables; do
  for CHAIN in $($FW -t nat -S 2>/dev/null |
    awk '/^-N HYSTERIA-PR-/{print $2}'); do

    $FW -t nat -D PREROUTING \
      -p udp -m udp --dport 20001:21000 \
      -j "$CHAIN" 2>/dev/null || true

    $FW -t nat -D OUTPUT \
      -p udp -m udp --dport 20001:21000 \
      -j "$CHAIN" 2>/dev/null || true

    $FW -t nat -F "$CHAIN" 2>/dev/null || true
    $FW -t nat -X "$CHAIN" 2>/dev/null || true
  done
done

确认没有遗留后再启动:

iptables -t nat -S | grep HYSTERIA || echo 'IPv4 已清理'
ip6tables -t nat -S | grep HYSTERIA || echo 'IPv6 已清理'
systemctl start hysteria-server.service

4. 客户端能发包但没有连接

安装抓包工具:

apt-get install -y tcpdump

观察端口范围:

tcpdump -ni any 'udp portrange 20000-21000'
  • 完全没有数据:检查 DNS、云安全组、本地网络;
  • 有 UDP 数据但服务端没有认证日志:重点检查 OBFS;
  • 服务端提示认证失败:检查 AUTH;
  • 客户端提示 x509:检查证书类型、SNI 和系统时间。

5. 如何确认 DNS 不是橙云

Windows:

nslookup h2.example.com

VPS:

curl -4s https://api.ipify.org
echo

解析结果必须是 VPS 公网 IP,而不是 Cloudflare Anycast IP。

十三、开机启动和自动续签

确认开机启动:

systemctl is-enabled hysteria-server.service
systemctl is-active hysteria-server.service

预期:

enabled
active

Hysteria2 会在后台维护 ACME 证书。只要 Cloudflare Token 有效、DNS 权限保留、服务器可以访问 Cloudflare 和 Let’s Encrypt,就会在证书临近到期时自动续签。

查看证书维护日志:

journalctl -u hysteria-server.service |
grep -Ei 'certificate|renew|acme|maintenance'

不要删除当前有效的 Cloudflare Token。可以删除测试过程中创建的无效或重复 Token。

十四、最终检查清单

  •  h2.example.com 解析到 VPS 公网 IP;
  •  Cloudflare 为灰云,仅 DNS;
  •  Cloudflare API Token 为 active,权限限制到单一区域;
  •  Hysteria2 状态为 active (running);
  •  日志包含 server up and running;
  •  UDP 20000 正在监听;
  •  IPv4/IPv6 跳跃规则存在;
  •  云安全组放行 UDP 20000-21000;
  •  v2rayN 使用 sing-box;
  •  AUTH、OBFS、SNI 和端口范围一致;
  •  allowInsecure 保持关闭;
  •  Cloudflare Token 未被删除。

总结

本文方案不要求停用现有 Caddy 或 3x-ui,也不需要占用 TCP 80/443。核心思路是:

  1. Cloudflare 灰云只负责 DNS;
  2. Cloudflare API Token 只负责 DNS-01 验证;
  3. Let’s Encrypt 提供客户端可信证书;
  4. Hysteria2 使用独立 UDP 范围完成端口跳跃;
  5. v2rayN 使用 sing-box 连接。

部署成功后,日志中的:

server up and running

就是服务端正常运行的关键标志。

官方参考资料