记录一次 Netcup 德国 VPS 在联通网络下 SSH 连接不上的排障过程,并给出 cloudflared 隧道接入方案。
当我访问自己的 openclaw 时,飞书侧一直没有回复,于是排查了一轮服务器。 最终发现问题不是 sshd 挂了,而是跨境链路(德国线路到联通)不稳定。
最后采用的方案是:在服务器部署 cloudflared,把 subdomain.domain.com 通过 Tunnel 映射到 localhost:22,本地使用 cloudflared access ssh 连接。 这样 SSH 不再依赖直连 22 端口,稳定性和可控性都更好。
现状确认
服务器厂商 VNC 可进入,SSH 服务 active,22 端口监听正常,日志中有 Connection reset by peer [preauth]。
bash
systemctl status ssh
ss -tlnp | grep sshd
ufw status # 或 iptables -S / nft list ruleset
journalctl -u ssh -n 100 --no-pager
检查要点:
systemctl status ssh:看 SSH 服务是否在运行。Active: active (running):服务正常启动。inactive/failed:服务未启动,先修服务(配置、密钥、启动失败等)。
ss -tlnp | grep sshd:看 SSH 是否监听端口。0.0.0.0:22和[::]:22:监听所有 IPv4/IPv6 地址。- 只有
127.0.0.1:22:只监听本机,外部无法连接。 - 无输出:未监听(服务没起或端口改了)。
ufw status:看系统防火墙是否拦截 SSH。Status: inactive:系统层未拦截。active且没有22/tcp ALLOW(或你改后的端口)会被拦。
journalctl -u ssh -n 100 --no-pager:看认证和连接日志。Accepted publickey:登录成功。Failed password:账号或密码问题。Connection reset by peer [preauth]:连接到达服务器,但认证前被链路或中间设备重置,常见于网络路径问题。
结论:服务正常 + 端口正常 + UFW 未拦 + 日志出现 preauth reset,说明更像链路问题,而不是服务器 SSH 配置故障。
方案
1. 通过香港机中转 SSH
先 SSH 到香港机,再从香港机连接德国机;或者在香港机上搭 WebSSH。 注意:公共 WebSSH 不安全,可能泄露凭据并暴露攻击面。
sshconfig
# ~/.ssh/config
Host hk
HostName 香港机IP
User your_user
Port 22
IdentityFile ~/.ssh/id_rsa
Host de-via-hk
HostName 德国机IP
User your_user
Port 22
ProxyJump hk
IdentityFile ~/.ssh/id_rsa
bash
ssh de-via-hk
也可以参考这个教程:加便宜香港机做中转,由于成本问题转而搜寻其他方案。
2. 用 sshx 临时网页终端
可通过 VNC 在服务器上安装并运行 sshx,再从本地浏览器打开生成的链接。
bash
curl -sSf https://sshx.io/get | sh
sshx
这个方案可应急,但实际使用中可能出现断流,需重复开启 vnc 运行 sshx ,因此后续改为 Cloudflare Tunnel。
3. Cloudflare Tunnel 与 cloudflared
Cloudflare Tunnel 是"由源站主动发起"的反向隧道: 服务器运行 cloudflared 后,会主动连接 Cloudflare 边缘,再把指定域名(如 subdomain.domain.com)的流量转发到本机服务(如 localhost:22)。
它主要解决三类问题:
- 跨境直连不稳定
- 端口被运营商或网络策略干扰
- 公网暴露 SSH 端口的安全风险
工作原理可概括为"出站建隧道 + 边缘鉴权 + 回源转发":用户先访问 Cloudflare 边缘,经过 Zero Trust Access 身份校验后,再通过已建立的 Tunnel 到达源站。 因此即使关闭源站公网 SSH 端口,也能保留稳定且更安全的远程运维通道。
Cloudflare Tunnel 是服务本身,cloudflared 是官方客户端:前者定义能力,后者负责建隧道、发起接入并转发流量。
服务器端
1. 安装 cloudflared(Ubuntu 24.04)
bash
sudo apt-get update
sudo apt-get install -y cloudflared
cloudflared --version
2. 登录 Cloudflare 并生成 /root/.cloudflared/cert.pem
bash
cloudflared tunnel login
ls -l /root/.cloudflared/cert.pem
3. 创建 Tunnel 并绑定 SSH 子域名
bash
cloudflared tunnel create de-ssh
cloudflared tunnel list
cloudflared tunnel route dns de-ssh subdomain.domain.com
4. 生成配置文件
bash
TUNNEL_ID=$(cloudflared tunnel list | awk '$2=="de-ssh"{print $1}')
cat >/root/.cloudflared/config.yml <<EOF
tunnel: ${TUNNEL_ID}
credentials-file: /root/.cloudflared/${TUNNEL_ID}.json
ingress:
- hostname: subdomain.domain.com
service: ssh://localhost:22
- service: http_status:404
EOF
cat /root/.cloudflared/config.yml
cloudflared tunnel ingress validate
5. 前台验证(成功后 Ctrl+C)
bash
cloudflared tunnel run de-ssh
6. 安装为 systemd 服务并开机自启
bash
cloudflared service install
systemctl daemon-reload
systemctl enable --now cloudflared
systemctl status cloudflared --no-pager -l
Cloudflare 后台添加 Zero Trust Access 应用
Zero Trust(零信任)不是"信任内网、怀疑外网",而是默认都不信任,每次访问都先做身份和策略校验,再授予最小权限。 在本场景里,cloudflared tunnel 只负责把 SSH 服务接到 Cloudflare 边缘;真正控制"谁能进"的是 Zero Trust Access。
不用 Access 的话,这个公网 hostname 可能被任何人尝试连接;用了 Access 后,只有符合策略(例如指定邮箱)的用户才能拿到访问令牌继续访问 SSH。
工作流程:
- 执行
ssh,其中ProxyCommand调用本地cloudflared access ssh --hostname ...。 - 本地
cloudflared拉起浏览器完成登录(OTP/IdP)。 - Cloudflare Access 按策略判断是否放行。
- 命中 Allow 才签发访问令牌;默认拒绝。
- 放行后流量进入 Tunnel,再转发到源站
localhost:22。
配置步骤:
Zero Trust -> Access -> Applications -> Add application -> Self-hostedDomain填:subdomain.domain.comPolicy仅允许你自己的邮箱/账号,建议开启 MFA
本地 Mac
1. 安装客户端
bash
brew install cloudflared
cloudflared --version
2. 直接连接测试
bash
ssh -o "ProxyCommand=$(which cloudflared) access ssh --hostname %h" root@subdomain.domain.com
3. 可选:写入 ~/.ssh/config,以后直接 ssh de-cf
sshconfig
Host de-cf
HostName subdomain.domain.com
User root
ProxyCommand /opt/homebrew/bin/cloudflared access ssh --hostname %h
bash
ssh de-cf