Skip to content

Instantly share code, notes, and snippets.

@caiguanhao
Created March 13, 2026 09:40
Show Gist options
  • Select an option

  • Save caiguanhao/0d83111ac91ea65de804a30492219cc9 to your computer and use it in GitHub Desktop.

Select an option

Save caiguanhao/0d83111ac91ea65de804a30492219cc9 to your computer and use it in GitHub Desktop.
SSH 反向隧道

SSH 反向隧道完整操作步骤

Context

服务器A无公网IP但能访问外网,服务器B有公网IP。目标:通过 SSH 到服务器B的 2222 端口即可访问服务器A,同时限制服务器A只能建立反向隧道,不能执行任何命令。

操作步骤

第一步:在服务器B上创建专用用户

sudo useradd -m -s /bin/false tunnel-user
sudo passwd -l tunnel-user   # 禁用密码登录

第二步:在服务器A上生成专用密钥对

ssh-keygen -t ed25519 -f ~/.ssh/tunnel_key -N "" -C "reverse-tunnel-to-serverB"

第三步:将公钥部署到服务器B

在服务器A上查看公钥:

cat ~/.ssh/tunnel_key.pub

在服务器B上配置(以 tunnel-user 身份):

sudo mkdir -p /home/tunnel-user/.ssh
sudo sh -c 'echo "command=\"/bin/false\",no-agent-forwarding,no-X11-forwarding,no-pty <粘贴服务器A的公钥内容>" > /home/tunnel-user/.ssh/authorized_keys'
sudo chown -R tunnel-user:tunnel-user /home/tunnel-user/.ssh
sudo chmod 700 /home/tunnel-user/.ssh
sudo chmod 600 /home/tunnel-user/.ssh/authorized_keys

第四步:配置服务器B的 sshd

编辑 /etc/ssh/sshd_config,在末尾添加:

GatewayPorts clientspecified

Match User tunnel-user
  AllowTcpForwarding remote
  PermitOpen none
  X11Forwarding no
  AllowAgentForwarding no
  ForceCommand /bin/false

重启 sshd:

sudo systemctl restart sshd

第五步:在服务器A上安装 autossh

# Debian/Ubuntu
sudo apt install -y autossh

# CentOS/RHEL
sudo yum install -y autossh

第六步:在服务器A上首次连接(接受服务器B的主机密钥)

ssh -i ~/.ssh/tunnel_key -o StrictHostKeyChecking=accept-new tunnel-user@serverB

连接会立即断开(因为 ForceCommand /bin/false),这是正常的,目的是将服务器B的主机密钥写入 known_hosts。

第七步:在服务器A上用 autossh 建立反向隧道

autossh -M 0 -R 0.0.0.0:2222:localhost:22 -N \
  -i ~/.ssh/tunnel_key \
  -o ServerAliveInterval=60 \
  -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes \
  tunnel-user@serverB

-M 0 表示禁用 autossh 自带的监控端口,改用 SSH 自身的 ServerAlive 机制检测连接状态。连接断开后 autossh 会自动重连。

0.0.0.0:2222 让隧道绑定到服务器B的所有网络接口,这样才能从外部访问。如果省略则默认绑定 127.0.0.1,只能从服务器B本地访问。

第八步:开机自启(systemd 管理 autossh)

在服务器A上创建 /etc/systemd/system/ssh-reverse-tunnel.service

[Unit]
Description=SSH Reverse Tunnel to serverB
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=root
Environment="AUTOSSH_GATETIME=0"
ExecStart=/usr/bin/autossh -M 0 -R 0.0.0.0:2222:localhost:22 -N \
  -i /root/.ssh/tunnel_key \
  -o ServerAliveInterval=60 \
  -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes \
  tunnel-user@serverB
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

启用服务:

sudo systemctl daemon-reload
sudo systemctl enable --now ssh-reverse-tunnel

AUTOSSH_GATETIME=0 让 autossh 在首次连接失败时也会重试,适合开机时网络尚未就绪的场景。

第九步:验证

从任意机器执行:

ssh -p 2222 <serverA的用户名>@serverB

验证限制是否生效(以下命令应失败):

ssh -i ~/.ssh/tunnel_key tunnel-user@serverB   # 应无法获得shell
ssh -L 8080:localhost:80 -i ~/.ssh/tunnel_key tunnel-user@serverB   # 正向转发应被拒绝
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment