SSH隧道转发的详细解释

SSH 隧道的 -L-R

SSH 隧道支持两种主要方向的端口转发:本地转发-L)和 远程转发-R)。两者的功能和限制略有不同,以下分别详细介绍其语法、各部分含义及使用限制。


-L:本地转发

功能

-L 用于将本地端口上的请求转发到远程主机上的指定端口。

语法

bash复制代码ssh -L [bind_address:]local_port:target_host:target_port user@ssh_server

参数含义

  1. bind_address(可选):
    • 本地监听的地址。
    • 默认值是 127.0.0.1,表示仅允许本地主机访问。
    • 可以设置为 0.0.0.0,允许其他主机通过网络访问本地监听的端口。
    • 例子:
      • 127.0.0.1:仅本地访问。
      • 0.0.0.0:所有网络接口都可以访问。
  2. local_port
    • 本地端口号。
    • 这是隧道会监听的端口,客户端通过该端口访问隧道。
  3. target_host
    • 数据实际转发到的远程目标主机。
    • 通常是 ssh_server 所能访问的内部网络地址,也可以是 localhost(相对于 ssh_server 而言)。
  4. target_port
    • 数据实际转发到的远程目标端口。
  5. user@ssh_server
    • 用于建立隧道的 SSH 服务器。
    • ssh_server 是隧道的中继服务器,通过它将请求从本地传输到目标主机。

限制

  • 如果 bind_address127.0.0.1,隧道只能在本地访问,其他主机无法访问。
  • 本地端口号 local_port 不应被其他服务占用,否则会失败。
  • 目标主机(target_host)必须是 ssh_server 可访问的主机。

例子

  1. 简单本地转发:
    将本地 8080 端口的流量转发到 ssh_server 上的 localhost:3306(MySQL 端口):bash复制代码ssh -L 8080:localhost:3306 user@ssh_server
  2. 跨网络访问:
    将本地 0.0.0.0:8080 绑定为公网可访问,转发到远程 192.168.1.10:80:bash复制代码ssh -L 0.0.0.0:8080:192.168.1.10:80 user@ssh_server

-R:远程转发

功能

-R 用于将远程主机上的端口请求转发到本地主机上的指定端口。

语法

bash复制代码ssh -R [bind_address:]remote_port:target_host:target_port user@ssh_server

参数含义

  1. bind_address(可选):
    • 远程服务器监听的地址。
    • 默认值是 127.0.0.1,表示只能在 SSH 服务器上本地访问该端口。
    • 设置为 0.0.0.0,允许其他主机通过网络访问 SSH 服务器的这个端口。
  2. remote_port
    • 远程主机上的端口号。
    • SSH 服务器会监听这个端口,将接收到的流量转发到本地。
  3. target_host
    • 本地主机上实际接收请求的目标主机。
    • 相对于运行 SSH 客户端的主机。
  4. target_port
    • 本地目标主机的端口号。
  5. user@ssh_server
    • 用于建立隧道的 SSH 服务器。
    • SSH 客户端会在该服务器上打开 remote_port,并将流量转发回本地。

限制

  • 如果 bind_address127.0.0.1,远程端口只能由 ssh_server 本机访问,外部无法访问。
  • 如果远程端口(remote_port)需要公网访问,则 ssh_server 必须允许 GatewayPorts
    • ssh_server/etc/ssh/sshd_config 中需要设置:plaintext复制代码GatewayPorts yes
  • remote_port 不应被其他服务占用,否则会失败。

例子

  1. 简单远程转发:
    ssh_server9000 端口转发到本地 localhost:8080:bash复制代码ssh -R 9000:localhost:8080 user@ssh_server
  2. 允许外部访问:
    ssh_server0.0.0.0:9000 绑定为公网可访问,转发到本地 192.168.1.10:22:bash复制代码ssh -R 0.0.0.0:9000:192.168.1.10:22 user@ssh_server

区别总结

特性-L(本地转发)-R(远程转发)
隧道监听端口的位置本地主机监听端口SSH 服务器监听端口
隧道目标远程主机上的目标端口本地主机上的目标端口
常用场景– 访问内网服务
– 数据库连接隧道
– 暴露本地服务
– P2P 数据传输
绑定公网限制– 本地可设置 0.0.0.0(开放所有接口)– 必须在 SSH 服务器中启用 GatewayPorts
默认监听范围127.0.0.1(本地回环接口)127.0.0.1(远程回环接口)

常见问题与解决方法

  1. 远程转发无法被外部访问:
    • 检查 GatewayPorts 是否启用。
    • /etc/ssh/sshd_config 中设置:plaintext复制代码GatewayPorts yes
    • 重启 SSH 服务:bash复制代码sudo systemctl restart sshd
  2. 端口被占用:
    • 检查是否有其他服务正在监听该端口:bash复制代码sudo ss -tuln | grep <port>
    • 如果被占用,选择其他未使用端口。
  3. 访问被防火墙阻止:
    • 确保本地或远程服务器的防火墙允许相应端口通信。

通过合理设置 -L-R,你可以根据需求选择本地转发或远程转发,灵活实现内外网服务的桥接。

使用模板服务实现多端口隧道的建立和进程守护

编写配置文件:多个配置文件可以放到相同的目录,方便模板读取

mkdir -p /etc/tunnel.d

本地转发示例:把对本地的访问请求转发到远程

vi /etc/tunnel.d/service1
SSH_PORT=22
# 提前配置好免密登录
SSH_HOST=my-ssh-host
SSH_USER=root
TUNNEL_TYPE=-L
# 以下配置表示把对ssh客户的127.0.0.1接口的20002端口的请求转发到my-ssh-host的443,其中127.0.0.1:443可以改成远程主机my-ssh-host可以访问到的其他主机和端口
TUNNEL_SPEC=127.0.0.1:20002:127.0.0.1:443
# 对应的autossh 命令是:
autossh -M 0 -N -p 22 -L 127.0.0.1:20002:127.0.0.1:443 root@my-ssh-host
# 对应的ssh命令是
ssh -N -p 22 -L 127.0.0.1:20002:127.0.0.1:443 root@my-ssh-host

远程转发示例:把对远程的访问请求转发到本地

vi /etc/tunnel.d/service2
SSH_PORT=22
# 提前配置好免密登录
SSH_HOST=my-ssh-host
SSH_USER=root
TUNNEL_TYPE=-R
# 以下配置表示把对远程主机my-ssh-host的10022端口的访问请求转发到ssh客户的可访问到的主机(192.168.1.100)的端口(22),其中192.168.1.100:22可以改成ssh客户端可以访问到的其他主机和端口
TUNNEL_SPEC=127.0.0.1:10022:192.168.1.100:22
# 对应的autossh 命令是:
autossh -M 0 -N -p 22 -R 127.0.0.1:10022:192.168.1.100:22 root@my-ssh-host
# 对应的ssh命令是
ssh -N -p 22 -R 127.0.0.1:10022:192.168.1.100:22 root@my-ssh-host

配置服务模板

# vi /etc/systemd/system/tunnel@.service
[Unit]
Description=SSH Tunnel for %i
After=network.target

[Service]
EnvironmentFile=/etc/tunnel.d/%i.conf
ExecStart=/usr/bin/autossh -M 0 -N -p ${SSH_PORT} ${TUNNEL_TYPE} ${TUNNEL_SPEC}  ${SSH_USER}@${SSH_HOST}
Restart=always

[Install]
WantedBy=multi-user.target

使用服务

# 启用服务(重启时自动启动)
systemctl enable tunnel@service1.service
systemctl start tunnel@service2.service

可以查看启动情况

ps aux|grep ssh

可以查看端口监听:

netstat -anp|grep 10022