背景

在内网环境中,有时候需要将本地服务暴露到远程服务器上,常见场景如:

  • 本地开发环境需要被外部访问
  • 内网服务需要通过公网跳板机访问
  • Kubernetes 集群服务需要临时暴露到外部

使用 SSH 反向隧道(-R 参数)可以将本地端口映射到远程服务器端口,而 autossh 则能自动保持 SSH 连接稳定,断线自动重连。

使用 autossh Docker 容器

准备 SSH 密钥

首先创建专用的 SSH 密钥用于隧道认证:

1ssh-keygen -t rsa -b 4096 -f ~/.ssh/autossh_id_rsa -N ""

将公钥添加到远程服务器的 ~/.ssh/authorized_keys 中:

1ssh-copy-id -i ~/.ssh/autossh_id_rsa.pub [email protected]

启动容器

 1docker run -d \
 2  --name=ssh-tunnel \
 3  --restart=always \
 4  --network host \
 5  -v ~/.ssh/autossh_id_rsa:/app/autossh_id_rsa:ro \
 6  -v ~/.ssh/known_hosts:/app/known_hosts:ro \
 7  -e SSH_REMOTE_USER=xu.hu \
 8  -e SSH_REMOTE_HOST=10.97.109.50 \
 9  -e SSH_REMOTE_PORT=22 \
10  -e SSH_MODE=-R \
11  -e SSH_TUNNEL_PORT=6001 \
12  -e SSH_TARGET_HOST=127.0.0.1 \
13  -e SSH_TARGET_PORT=3067 \
14  -e SSH_BIND_IP=127.0.0.1 \
15  -e SSH_KEY_FILE=/app/autossh_id_rsa \
16  -e SSH_KNOWN_HOSTS_FILE=/app/known_hosts \
17  jnovack/autossh

环境变量说明

变量 说明 示例
SSH_REMOTE_USER 远程服务器用户名 xu.hu
SSH_REMOTE_HOST 远程服务器地址 10.97.109.50
SSH_REMOTE_PORT SSH 端口 22
SSH_MODE 隧道模式,-R 为反向隧道 -R
SSH_TUNNEL_PORT 远程服务器监听端口 6001
SSH_TARGET_HOST 本地目标地址 127.0.0.1
SSH_TARGET_PORT 本地目标端口 3067
SSH_BIND_IP 远程绑定地址 127.0.0.1
SSH_KEY_FILE SSH 私钥路径(容器内) /app/autossh_id_rsa
SSH_KNOWN_HOSTS_FILE known_hosts 路径(容器内) /app/known_hosts

映射关系:远程服务器 127.0.0.1:6001 → 本地 127.0.0.1:3067

为什么使用 --network host

使用宿主机网络模式的原因:

  • SSH 隧道本质是网络层的连接,不需要 Docker 的网络隔离
  • 避免端口映射的额外开销
  • 确保 127.0.0.1 绑定正确指向宿主机回环地址

为什么用 SSH_KEY_FILE 而不是 SSH_EXTRA_ARGS

jnovack/autossh 镜像默认查找密钥路径为 /id_rsa(容器根目录),通过 SSH_KEY_FILE 环境变量可以显式指定密钥文件路径。如果使用 SSH_EXTRA_ARGS="-i /app/autossh_id_rsa",镜像的密钥检测逻辑会先于 SSH 参数生效,导致报错 [FATAL] No SSH Key file found

验证隧道

1# 查看容器日志
2docker logs ssh-tunnel
3
4# 在远程服务器上测试连接
5ssh [email protected]
6curl http://127.0.0.1:6001

参考