使用 autossh Docker 容器实现 SSH 反向隧道
背景
在内网环境中,有时候需要将本地服务暴露到远程服务器上,常见场景如:
- 本地开发环境需要被外部访问
- 内网服务需要通过公网跳板机访问
- 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
