[!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 服务 长期保持连接