当前位置:首页>Linux>Linux SSH 端口转发(上)——本地转发 -L 与远程转发 -R

Linux SSH 端口转发(上)——本地转发 -L 与远程转发 -R

  • 2026-10-09 13:29:40
Linux SSH 端口转发(上)——本地转发 -L 与远程转发 -R

大家好,我是冯哥的缓存。

上一篇我们聊了SSH 的核心用法——密钥登录、config 别名、scp/rsync 传文件。这些已经够日常使用了。

但 SSH 还有一个非常强大的功能:端口转发(Port Forwarding)。

听起来有点技术味,其实用处极实际:

·公司内网的数据库,在家怎么连?

·家里的树莓派跑了一个服务,没有公网 IP,朋友怎么访问?

·服务器上起了个Web 服务只监听 127.0.0.1,不对外开放,怎么在本机浏览器里看?

这三个场景,分别对应 SSH 端口转发的三种模式。本篇先讲前两种:本地转发-L和 远程转发 -R。

一、端口转发是什么——先搞清楚原理

1.1 SSH 隧道的比喻

SSH 端口转发,本质上是在 SSH 加密连接里"塞进去"一条数据通道。端口转发本身不改变数据内容,只是‘借道’传输。可以理解为:

在 A 和 B 之间已经打通了一条加密隧道(SSH 连接),端口转发就是在这条隧道里再开几条管道,让其他协议的数据也能借着这条隧道走。

这些借道的数据,对两端的应用来说是"透明的"——它们根本不知道自己在走 SSH 隧道,以为只是普通的 TCP 连接。

1.2 三种模式总览

模式

参数

用途简介

典型场景

本地转发

-L

把远端的服务映射到本机某端口

在家访问公司内网数据库

远程转发

-R

把本机的服务暴露到远端某端口

把家里树莓派的服务穿透到公网

动态转发

-D

本机开 SOCKS5 代理,流量经远端服务器出口

下篇讲

本篇重点聊-L和 -R。

二、本地转发-L——把远端服务映射到本机

2.1 原理

本机:本地端口→SSH隧道→跳板机/远端机→目标服务

在本机监听一个端口,所有连到这个端口的流量,都通过 SSH 隧道转发到远端的某个地址和端口上。

用通俗话说:就像给远端服务装了一个"代理入口"在本机。

2.2 语法

ssh -L 本地端口:目标主机:目标端口 跳板机

部分

含义

本地端口

在本机监听哪个端口(随便选一个没被占用的,如 13306)

目标主机

从跳板机视角出发,目标服务在哪里(可以是 127.0.0.1,也可以是内网IP)

目标端口

目标服务的真实端口(如 MySQL 3306、PostgreSQL 5432)

跳板机

SSH 连接到的那台机器(可以用 ~/.ssh/config 里的别名)

2.3 典型场景一:访问远端数据库

场景:公司服务器上跑了 MySQL(只监听 127.0.0.1:3306,不对外开放),在家想用 Navicat 直连。

ssh -L 13306:127.0.0.1:3306 office

💡解释:

·13306:在本机监听 13306 端口(用 13306 是为了避开本机可能已经在跑的 MySQL),是在本机选一个空闲端口,如果被占用可以换其他端口。

·127.0.0.1:3306:从 office服务器来看,MySQL在 127.0.0.1:3306

·office:~/.ssh/config里配好的公司服务器别名

建立连接后,在Navicat(或任何数据库工具)里填:

·主机:127.0.0.1

·端口:13306

就连上了公司服务器上的 MySQL,全程走 SSH 加密,安全。

2.4 典型场景二:访问内网另一台机器

场景:跳板机在公网,内网还有一台机器(192.168.0.100)跑了 Web 服务(8080 端口),在本机浏览器里访问。

# 如果跳板机可以访问内网

ssh -L 18080:192.168.0.100:8080 jumpserver

建立后,浏览器访问http://127.0.0.1:18080,流量经 SSH 隧道到 jumpserver,再由 jumpserver转发到内网的 192.168.0.100:8080。

本机:18080→jumpserver→192.168.0.100:8080

如果想让局域网内其他机器也能用这个隧道,加 -g 参数

ssh -g -L 13306:127.0.0.1:3306 office

2.5 让转发在后台持续运行

每次直接ssh -L ...会打开一个交互式终端,关掉窗口隧道就断了。

方案一:后台运行,不开交互终端

ssh -L 13306:127.0.0.1:3306 office -N -f

参数

说明

-N

不执行远程命令,只做端口转发

-f

后台运行(fork 到后台)

方案二:加-o ExitOnForwardFailure=yes防止静默失败

ssh -L 13306:127.0.0.1:3306 -N -f -o ExitOnForwardFailure=yes office

如果转发端口被占用或连接失败,这个参数会让 SSH 直接报错退出,而不是"静默成功"但隧道实际没通。

关闭后台隧道:

# 找到进程

ps aux | grep 'ssh -L'

# 杀掉对应的 PID

kill 进程号

2.6 写进 ~/.ssh/config里(高级用法)

如果某条转发经常用,可以直接写进 config,每次ssh office就自动建立转发:

Host office

HostName 47.100.xxx.xxx

User fengge

IdentityFile ~/.ssh/id_ed25519

LocalForward 13306 127.0.0.1:3306

LocalForward 18080 192.168.0.100:8080

LocalForward可以写多条,同时转发多个端口。

三、远程转发-R——把本机服务暴露到远端

3.1 原理

本地转发是"拉过来",远程转发是"推出去":

外网用户 →远端服务器:端口→SSH隧道→本机:端口

在远端服务器上监听一个端口,连到这个端口的流量,通过 SSH 隧道反向转发到本机的某个服务上。

用通俗话说:本机没有公网IP,借远端服务器的端口当"门牌号",让别人能访问到本机的服务。

3.2 语法

ssh -R 远端端口:本机目标主机:本机目标端口 远端服务器

部分

含义

远端端口

在远端服务器监听的端口(别人从外网访问这个端口)

本机目标主机

从本机视角看,流量转到哪里(通常是 127.0.0.1)

本机目标端口

本机服务的真实端口

远端服务器

有公网 IP 的那台机器

3.3 典型场景:内网穿透

场景:在家里的树莓派(没有公网 IP)上跑了一个 Web 服务(3000 端口),想让朋友从外网访问。有一台云服务器(公网 IP:47.100.xxx.xxx)。

在树莓派上执行:

ssh -R 8080:127.0.0.1:3000 aliyun

💡解释:

·8080:在 aliyun服务器上监听8080 端口

·127.0.0.1:3000:从树莓派(本机)视角看,服务在 127.0.0.1:3000

·aliyun:有公网 IP 的云服务器别名

💡注意:这个隧道是从树莓派发起的,连接建立后树莓派不能关机,否则隧道就断了。

建立后,朋友访问http://47.100.xxx.xxx:8080,流量经 SSH 隧道到树莓派上的 3000 端口。

朋友的浏览器→47.100.xxx.xxx:8080→SSH隧道→树莓派:3000

3.4 让远端监听所有网卡(默认只监听 127.0.0.1)

SSH 远程转发默认只在远端的 127.0.0.1上监听,也就是说外网访问不到,只有远端服务器本机才能访问。 如果远端需要监听 80/443 等低端口,需要用 root 用户执行,或者在 sshd_config 里设置 PermitRootLogin yes(不推荐)。

要让外网也能访问,需要两步:

第一步:-R参数里指定 0.0.0.0(监听所有网卡):

ssh -R 0.0.0.0:8080:127.0.0.1:3000 aliyun

第二步:在远端服务器的 /etc/ssh/sshd_config里开启这个选项:

GatewayPorts yes

修改后重启SSH 服务:

sudo systemctl restart sshd

⚠️注意:GatewayPorts yes会让任何 SSH 远程转发都能绑定外网接口,yes 是最常见也最宽松的配置,需要结合防火墙控制哪些端口对外开放,避免意外暴露服务。

3.5 后台运行

和本地转发一样,加-N -f后台运行:

ssh -R 0.0.0.0:8080:127.0.0.1:3000 -N -f aliyun

3.6 连接断了怎么保活

SSH 远程转发的一个坑:网络波动断开后,隧道不会自动重连,需要手动处理。

方法一:AutoSSH(推荐)

autossh会自动监控 SSH 连接,断了自动重连:

# 安装 autossh

sudo apt install autossh# Debian/Ubuntu

sudo pacman -S autossh# Arch

# 如果 apt 没有 autossh,可以 sudo apt install autossh 或从源码编译,但大多数官方源都有。

# 使用 autossh 建立持久隧道

autossh -M 0 -N -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \

-R 0.0.0.0:8080:127.0.0.1:3000 aliyun

参数

说明

-M 0

禁用 autossh 自带的监控端口(用 ServerAlive 心跳代替)

-N

不执行远程命令

ServerAliveInterval 30

每 30 秒发一次心跳

ServerAliveCountMax 3

3 次心跳失败后断开并重连

方法二:systemd服务(长期运行)

新建服务文件/etc/systemd/system/ssh-tunnel.service:

[Unit]

Description=SSH Remote Tunnel

After=network.target

[Service]

User=你的用户名

ExecStart=/usr/bin/autossh -M 0 -N \

-o "ServerAliveInterval=30" \

-o "ServerAliveCountMax=3" \

-o "ExitOnForwardFailure=yes" \

-R 0.0.0.0:8080:127.0.0.1:3000 aliyun

Restart=always

RestartSec=10

[Install]

WantedBy=multi-user.target

启用并启动:

sudo systemctl enable ssh-tunnel

sudo systemctl start ssh-tunnel

这样树莓派开机就自动建立隧道,断了也自动重连,完全不用手动管理。

四、本地转发vs 远程转发对比

对比项

本地转发 -L

远程转发 -R

方向

把远端服务"拉"到本机

把本机服务"推"到远端

谁发起 SSH

本机(想访问远端服务的那端)

本机(提供服务的那端)

适合场景

在家访问公司内网/数据库

没有公网IP的本机对外暴露服务

远端需要开什么

无特殊要求

若要外网可访问,需 GatewayPorts yes

保活方案

autossh 或 systemd

autossh 或 systemd

选择哪种转发,关键看‘谁有公网 IP’——如果远端有公网IP 用 -L,如果本机没有公网 IP 用 -R。

五、常见问题排查

问题

可能原因

解决方法

本地端口连上但没响应

目标服务没在跑 / 目标地址写错

先在跳板机上直接 telnet 127.0.0.1 3306 测试

远程转发后外网连不上

GatewayPorts 未开启

检查远端 sshd_config 里 GatewayPorts yes

隧道一会儿就断

没有心跳配置

加 ServerAliveInterval 60 到 ssh 命令或 config

bind: Address already in use

本地/远端端口被占

换一个没被占用的端口

autossh 看起来在跑但隧道没通

autossh 默认 -M 端口被占

改用 -M 0 配合 ServerAliveInterval

建立隧道后关掉终端就断了

忘了加 -f

补加 -f -N,或用 systemd 管理

六、速查表

本地转发-L

操作

命令

基本本地转发

ssh -L 本地端口:目标IP:目标端口   跳板机

后台运行

ssh -L ... -N -f 跳板机

访问远端 MySQL

ssh -L 13306:127.0.0.1:3306 -N   -f server

访问内网 Web

ssh -L 18080:192.168.0.100:8080   -N -f jumpserver

远程转发-R

操作

命令

基本远程转发

ssh -R 远端端口:127.0.0.1:本机端口 远端服务器

对外网开放

ssh -R 0.0.0.0:远端端口:127.0.0.1:本机端口 远端

后台运行

ssh -R ... -N -f 远端服务器

autossh 保活

autossh -M 0 -N -o   "ServerAliveInterval 30" -R ... 远端

💡提示:选择哪种转发,记住一句话——想"拿过来"用 -L,想"推出去"用 -R。

下篇预告:《 Linux SSH端口转发(下)—— -D动态转发 》

最新文章

随机文章