[!Note] 如果是使用 zsh 的, 要注意添加 noglob 来避免符号这些问题
一、深入理解 SSH 转发:数据流的本质
SSH 本质上是一个加密的 TCP 通道。
它在客户端和服务端之间创建了一个安全的隧道(tunnel),然后通过这个隧道把流量从一端转发到另一端。
举例:
ssh -L 8080:localhost:8888 [email protected]
数据流过程是:
客户端浏览器 (localhost:8080)
↓
SSH 客户端 (A)
↓ 加密通道
SSH 服务端 (B)
↓
服务器上的 localhost:8888 服务 (比如 Jupyter)
因此:
-L是“客户端→服务器”方向的隧道。-R是“服务器→客户端”方向的隧道。-D是“客户端→服务器→任意目标”的动态隧道(SOCKS 协议)。
二、更多实际案例
1. 本地端口转发(-L)高级用法
案例 1:访问只允许内网访问的管理面板
场景:
- 服务器 B 内部有一个管理页面:
http://10.0.0.2:9000 - 外部访问不了,但你想在本地浏览器访问。
命令:
ssh -L 9000:10.0.0.2:9000 [email protected]
然后打开浏览器访问 http://localhost:9000。
这样,你的本地 9000 就等价于服务器内网的 10.0.0.2:9000。
适用于访问 Prometheus、Grafana、Portainer 等内网服务。
2. 远程端口转发(-R)高级用法
案例 1:让服务器走客户端代理上网(你提到的场景)
客户端有 Clash 代理监听在 7897。
你希望服务器能使用这个代理访问外网。
命令:
ssh -R 1080:localhost:7897 [email protected]
然后在服务器上设置:
export ALL_PROXY=socks5://localhost:1080
curl https://ipinfo.io
你会发现服务器访问的 IP 实际是你的客户端出口 IP。
案例 2:内网穿透(反向暴露本地服务到远程)
你在本地运行了一个 Web 服务(localhost:8080),希望别人访问远程服务器的端口就能访问到。
命令:
ssh -R 9000:localhost:8080 [email protected]
现在别人只要访问服务器的 remote-server.com:9000,就能看到你本地的 Web 页面。
这就是最原始的 内网穿透(类似于 ngrok 的原理)。
注意: 服务器 sshd_config 必须启用:
AllowTcpForwarding yes
GatewayPorts yes
3. 动态端口转发(-D)实际场景
案例 1:客户端通过服务器访问外网
你公司网络被墙或封锁部分网站。
可以:
ssh -D 1080 [email protected]
然后在浏览器设置 SOCKS5 代理:localhost:1080。
此时所有浏览器流量经过 SSH 隧道,从远程服务器出去。
这相当于一个安全的加密代理(比 HTTP 代理安全)。
案例 2:与 proxychains 结合
安装 proxychains:
sudo apt install proxychains
修改 /etc/proxychains.conf:
socks5 127.0.0.1 1080
然后:
proxychains curl https://google.com
这会强制所有命令行程序走 SSH 的 SOCKS 隧道。
三、结合系统代理与自动化
1. 持久连接与自动重连(autossh)
SSH 隧道掉线是常见问题,可以用 autossh 自动重连:
sudo apt install autossh
autossh -M 0 -f -N -R 1080:localhost:7897 [email protected]
解释:
-M 0:禁用监控端口(避免冲突)-f -N:后台运行,不执行命令- 一旦连接中断,会自动重启 SSH 隧道
适合长期使用(如让服务器永远通过你的代理上网)。
2. 用 systemd 管理隧道服务(服务器开机自启)
建立一个 systemd service:
/etc/systemd/system/ssh-tunnel.service
内容:
[Unit]
Description=Persistent SSH Reverse Tunnel
After=network.target
[Service]
User=youruser
ExecStart=/usr/bin/autossh -M 0 -N -R 1080:localhost:7897 [email protected]
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
然后:
sudo systemctl daemon-reload
sudo systemctl enable --now ssh-tunnel
这样,系统启动后自动保持 SSH 隧道。
四、SSH 配置文件(~/.ssh/config)高级用法
配置示例:
Host proxy-server
HostName remote-server.com
User user
Port 22
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 60
ServerAliveCountMax 3
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist yes
说明:
ServerAliveInterval:每 60 秒发送心跳包ControlMaster/ControlPersist:多 SSH 会话复用同一个 TCP 连接,加快连接速度ControlPath:控制 socket 文件路径(必须可写)-
ProxyJump:支持多级跳板Host inner-server HostName 10.0.0.5 User root ProxyJump [email protected]执行
ssh inner-server时,会自动通过中间的跳板机连接。
五、SSH 与代理的结合应用
| 需求 | 使用方式 |
|---|---|
| 服务器走客户端代理 | ssh -R 1080:localhost:7897 |
| 客户端走服务器代理 | ssh -D 1080 |
| 客户端访问服务器内网 | ssh -L 8080:internal:80 |
| 外部访问客户端服务 | ssh -R 9000:localhost:8080 |
| 建立 SOCKS 动态代理 | ssh -D 1080 + 浏览器设置 |
六、安全与性能建议
- 安全 在
/etc/ssh/sshd_config这个文件中编辑- 关闭密码登录:
PasswordAuthentication no - 限制允许登录的用户:
AllowUsers user - 使用 fail2ban 防止暴力破解
- 对外暴露端口时,注意防火墙设置
- 关闭密码登录:
- 性能
- 增加压缩:
ssh -C -L ... - 开启 TCP KeepAlive:
ClientAliveInterval 60 - 使用更快的加密算法:
-c [email protected]
- 增加压缩:
七、小结:SSH 是一把万能钥匙
| 功能 | 命令示例 | 作用 |
|---|---|---|
| 登录服务器 | ssh user@host | 远程 shell |
| 文件传输 | scp file user@host:/path/ | 上传/下载 |
| 本地端口转发 | ssh -L 8080:localhost:8888 | 访问服务器 WebUI |
| 远程端口转发 | ssh -R 1080:localhost:7897 | 让服务器走客户端代理 |
| 动态端口转发 | ssh -D 1080 | 把 SSH 当 SOCKS5 代理 |
| 多跳连接 | ssh -J jump@a target@b | 通过跳板机连接 |
| 自动重连 | autossh | 稳定隧道 |
| 开机自启 | systemd 服务 | 长期保持连接 |