Co-Authored-By: Claude Code <noreply@anthropic.com>
Northflank 部署 xray / hysteria2(docker-for-ladder)
配套镜像仓库:xyonium/docker-for-ladder
(容器内 start.sh <hy2配置路径> <xray配置路径> <cloudflared token>,两个配置文件以
Northflank secret group 的 files 形式挂载)。
协议可行性结论(2026-09 调研)
Northflank 普通 service 端口的公网入口是强制边缘 ingress:TLS 在平台边缘终结, 容器内进程只收到明文 HTTP/1.1 或 H2。这就是"前面必须有个自己的 CDN 反代"的真相—— 不是可选项,是架构本身。
| 协议 | 普通端口 | 付费 L4 Load Balancer |
|---|---|---|
| VLESS+REALITY | ❌ 不可行(TLS 被边缘终结,xray 看不到 ClientHello;TCP 端口不能公开) | ✅ 可行(L4 纯 TCP 直通、不终结 TLS;REALITY 不需要自己有证书) |
| Hysteria2(UDP/QUIC) | ❌ 不可行(UDP 不能公开) | ✅ 可行(UDP 类型 L4 LB;证书用 DNS-01 或自签,HTTP-01 不可行) |
| XHTTP / WS / gRPC | ✅ 可行(免费层即可,官方明确支持 WS/gRPC over HTTP(S)) | 不需要 |
L4 LB 注意:team 级付费资源(metered billing);每个 LB 最多 100 端口,30000-32767 保留不可用;更新配置会重新供给、公网 IP 可能变化(自备域名 A 记录跟进); 代理流量计 egress($0.06/GB)。
依据:
- configure-ports(TCP/UDP 不能公开)
- networking-on-northflank(TLS 边缘终结)
- configure-load-balancers(L4 TCP/UDP 直通)
xray:XHTTP(唯一免费路径,推荐配置)
xray-config.template.json 按 vpsetup 最优实践编写,与 VPS 版的关键差异:
security: "none":TLS 由 Northflank 边缘终结,容器内必须明文 HTTP,不要再开 TLS/REALITYlisten: 0.0.0.0:平台 router 要连进来,不能绑 127.0.0.1- 客户端
flow必须留空:xtls-rprx-vision 依赖裸 TCP,HTTP 传输下不可用 - XHTTP
mode: auto+extraxPadding(queryInHeader/tokenish):服务端 extra 必须与 客户端链接的extra=参数逐字节一致(vpsetup commit4e4d0f4的部署形态; 服务端单方面加 padding 会让所有客户端 400——commit15d91b2的教训)
占位符替换:__XRAY_UUID__(xray uuid 生成,固定下来不要重启重新生成)、
__XHTTP_PATH__(随机长串,不含斜杠)、__XPADDING_HEADER__/__XPADDING_KEY__
(如 X-a1b2 / _c3d4)。容器内监听端口(模板 8443)必须与 service 端口配置里
public 端口的 internalPort 一致;公网入口只保留这一个 public HTTP 端口即可——
实测旧 template 把 REALITY inbound 挂在 private 443 上(private + 边缘终结 TLS,
双重失效),优化时已连同该端口一并移除。
客户端链接模板(path 和 extra 都要 URL-encode):
vless://__XRAY_UUID__@__PUBLIC_DOMAIN__:443?encryption=none&security=tls&sni=__PUBLIC_DOMAIN__&fp=chrome&type=xhttp&path=%2F__XHTTP_PATH__&mode=auto&extra=%7B%22xPaddingObfsMode%22%3Atrue%2C%22xPaddingMethod%22%3A%22tokenish%22%2C%22xPaddingPlacement%22%3A%22queryInHeader%22%2C%22xPaddingHeader%22%3A%22__XPADDING_HEADER__%22%2C%22xPaddingKey%22%3A%22__XPADDING_KEY__%22%7D#nf-xhttp
__PUBLIC_DOMAIN__ 是 Northflank 给端口分配的 *.code.run 域名或自定义域名
(可在 service 端口页查看)。客户端侧:ALPN 用 http/1.1 最稳;XHTTP 的 H3 模式
不可用(边缘无 UDP);若给 subdomain 开了 Northflank CDN(Fastly),客户端↔Fastly
可 H3,Fastly↔源站仍 H2。
WS 兼容:WS 已被 xray 官方弃用(26.x 启动即告警)。如必须兼容旧 WS 客户端,
在配置里加一个 WS inbound(network: "ws" + wsSettings.path),并在 Northflank
service 上加第二个端口映射(独立 internalPort)。新客户端一律用 XHTTP。
hysteria2(可选,需 UDP L4 LB)
hysteria-config.template.yaml:占位符 __HY2_DOMAIN__ __EMAIL__
__CF_API_TOKEN__ __HY2_PASSWORD__。注意容器里 ACME 只能走 DNS-01
(80/443 归边缘),或用自签 + 客户端 insecure=1。不开 UDP L4 LB 时 hy2 端口
公网不可达,但配置留着无害(start.sh 会正常拉起,仅项目内网可见)。
healthcheck:写进 template,不要在 service 级加
service 级的 health check 会在下次 template 同步时被覆盖。正确做法:
team → templates → scilad → edit as code,找到 erepr-docker-for-ladder 的
DeploymentService 节点,在其 spec 里加(字段约束见
OpenAPI:protocol 枚举 HTTP/CMD/TCP,
periodSeconds 最小 10):
"healthChecks": [
{
"protocol": "TCP",
"type": "livenessProbe",
"port": 8443,
"initialDelaySeconds": 15,
"periodSeconds": 30,
"timeoutSeconds": 5,
"failureThreshold": 3
}
]
为什么用 TCP 不用 HTTP:xray 的 XHTTP 端口对未认证 GET 返回非 2xx(实测 404),
HTTP 探针会误判失败;TCP 探针只验证"端口在监听",与代理协议无关。
hy2 的 UDP 端口无法被探测(Northflank 无 UDP 探针)——也不需要:start.sh 用
wait -n 等所有后台进程,任一进程(xray/hysteria/cloudflared)退出容器即退出,
平台自动重启,进程级守护已由入口脚本覆盖。
其他注意事项
- egress 计费:代理流量即出站流量,$0.06/GB,免费层也不例外
- secret group 里
secrets.files挂配置文件;uuid/密码等敏感值建议放模板argumentOverrides(${fn.randomSecret(...)}生成后固定,重跑不换)而非模板正文 - 镜像里还有 cloudflared(
start.sh第 3 参):可作为 CF Tunnel 备用入口, 同样只承载 HTTP(S),REALITY/hy2 依然不行