介绍下ssh反向隧道:ssh -R…
3:15 PM
SSH 反向隧道 -R
与本地转发 -L 方向相反,用于让外网访问内网机器。
对比理解
| 本地转发 -L | 反向隧道 -R | |
|---|---|---|
| 发起方 | 你(内网) | 你(内网) |
| 监听端口开在 | 你本地 | 远端服务器 |
| 用途 | 访问远端服务 | 让远端访问你本地 |
格式
bash
ssh -R [远端端口]:[目标主机]:[目标端口] [用户名]@[SSH服务器]典型场景:内网穿透
你的开发机在公司内网,没有公网IP,想让外网朋友访问你本地的服务:
bash
ssh -R 8080:localhost:3000 user@公网服务器```
- 你的机器发起 SSH 连接到公网服务器- 公网服务器开放 `8080` 端口- 外网朋友访问 `公网服务器:8080`,流量反向穿透回你本地的 `3000` 端口```外网用户 → 公网服务器:8080 → SSH隧道 → 你的内网机器:3000```
## 让远端端口对外可访问
默认情况下 `-R` 开的端口**只监听 127.0.0.1**,外网访问不到。需要在服务端 `/etc/ssh/sshd_config` 加一行:```GatewayPorts yes然后重启 sshd:
bash
sudo systemctl restart sshd实用参数组合
bash
ssh -R 8080:localhost:3000 -N -f user@公网服务器你的实际用途
结合你的 Ali ECS(cypherx.top),可以这样用:
bash
# 在家里/公司内网机器上运行ssh -R 9000:localhost:8080 -N -f gx@cypherx.top这样任何人访问 cypherx.top:9000 就能到达你内网机器的 8080,完全不需要内网机器有公网IP,也不需要配置路由器端口转发。这其实就是 frp、ngrok 这类工具的核心原理。
gx@Ali-ECS:~$ sudo netstat -tunlp [sudo] password for gx: Sorry, try again. [sudo] password for gx: Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 127.0.0.1:33060 0.0.0.0:* LISTEN 1221/mysqld tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 29215/systemd-resol tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 18823/nginx: master tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1029/sshd: /usr/sbi tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 1221/mysqld tcp 0 0 127.0.0.1:9009 0.0.0.0:* LISTEN 81635/sshd: gx tcp 0 0 127.0.0.1:10808 0.0.0.0:* LISTEN 928/xray tcp6 0 0 :::21115 :::* LISTEN 43741/hbbs tcp6 0 0 :::21119 :::* LISTEN 42998/hbbr tcp6 0 0 :::21118 :::* LISTEN 43741/hbbs tcp6 0 0 :::21117 :::* LISTEN 42998/hbbr tcp6 0 0 :::21116 :::* LISTEN 43741/hbbs udp 0 0 0.0.0.0:51820 0.0.0.0:* - udp 0 0 127.0.0.53:53 0.0.0.0:* 29215/systemd-resol udp 0 0 172.31.28.241:68 0.0.0.0:* 29200/systemd-netwo udp 0 0 127.0.0.1:323 0.0.0.0:* 1119/chronyd udp6 0 0 :::51820 :::* - udp6 0 0 :::21116 :::* 43741/hbbs udp6 0 0 :::41012 :::* 43741/hbbs udp6 0 0 ::1:323 :::* 1119/chronyd
Show more
3:35 PM
可以看到反向隧道已经生效了:
tcp 0 0 127.0.0.1:9009 0.0.0.0:* LISTEN 81635/sshd: gx这就是你从内网机器建立的 -R 隧道,sshd 在 ECS 上监听 9009 端口,进程归属 gx 用户。
但注意它绑定在 127.0.0.1:9009,只有 ECS 本机能访问,外网访问不到。
如果你想让外网也能访问,两种办法:
方法一:sshd_config 加 GatewayPorts
bash
sudo vim /etc/ssh/sshd_config# 加上或改为:GatewayPorts yessudo systemctl restart sshd然后重新建立 -R 隧道,端口就会绑在 0.0.0.0:9009 上了。
方法二:在 ECS 上用 nginx 反代 127.0.0.1:9009 不改 sshd 配置,用 nginx 把某个域名/路径转发到 127.0.0.1:9009,更灵活,也更安全。
你现在建这个隧道的目的是什么?对外暴露服务还是自己用?
gx@Ali-ECS:~ curl localhost:9009 gx@Ali-ECS:\~
3:36 PM
curl 没有任何输出,说明连接成功了但服务没有返回任何内容,或者内网那端的服务没有正常响应。
排查
1. 内网机器上的服务还在跑吗?
去内网机器上确认服务是否在监听:
bash
netstat -tunlp | grep [端口]# 或者curl localhost:[内网端口]2. 反向隧道是怎么建的?
把你建隧道的命令发一下,比如:
bash
ssh -R 9009:localhost:XXXX user@cypherx.top看看 XXXX 那个内网端口对不对。
3. 隧道进程还活着吗?
在内网机器上:
bash
ps aux | grep sshcurl 无输出通常是连上了但对面没数据返回,大概率是内网服务挂了或者端口映射写错了。
[gx@nas ~]$ curl localhost:8080
Show more
3:37 PM
NAS 上的服务是正常的,localhost:8080 有响应。
问题在这段 JS:
javascript
location.href = pr + "://" + location.hostname + pt + redirect_suffix;它拿到 location.hostname 后做了跳转,通过隧道访问时 hostname 是 localhost,它就跳转到 http://localhost/redirect.html?count=xxx,但 ECS 的 localhost 上没有这个服务,所以 curl 拿不到任何内容。
这是个前端重定向问题
这个 NAS 的 Web UI 设计上期望用真实 IP 或域名访问,用 localhost 访问时重定向会出问题。
解决思路:给隧道绑一个域名
在 ECS 上用 nginx 反代,加上正确的 Host header:
nginx
server { listen 9090; server_name _;
location / { proxy_pass http://127.0.0.1:9009; proxy_set_header Host nas.cypherx.top; # 或者NAS的内网IP proxy_set_header X-Real-IP $remote_addr; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }}然后访问 http://cypherx.top:9090,nginx 把 Host 改成 NAS 期望的值再转给隧道。
你的 NAS 平时在内网是用什么地址访问的?192.168.x.x:8080 还是有个域名?
加上GatewayPorts yes后浏览器访问http://cypherx.top:9009成功打开家里NAS页面了(8080端口)了。这个参数起什么作用?
3:45 PM
GatewayPorts 的作用
没加之前,-R 建立的隧道端口只绑定在:
127.0.0.1:9009 ← 只有ECS本机能访问加了 GatewayPorts yes 之后,绑定变成:
0.0.0.0:9009 ← 所有网卡、所有来源都能访问为什么默认不开放?
安全考虑。SSH 的设计哲学是:
反向隧道默认只给建立隧道的那个用户自己用,不应该自动暴露给整个互联网。
毕竟任何一个能 SSH 进来的用户,都可以用 -R 在服务器上开端口,如果默认对外,相当于任何用户都能把服务器变成自己的跳板,风险很大。
你现在的效果
外网浏览器 → cypherx.top:9009 → SSH反向隧道 → 家里NAS:8080本质上就是一个简单版的 frp/ngrok 内网穿透,而且全程加密,不错👍
唯一要注意的是 9009 端口现在对全互联网开放,如果 NAS 登录没有保护,建议在阿里云安全组里限制一下来源 IP。
frp/ngrok是什么
4:47 PM
frp / ngrok 是什么
它们都是内网穿透工具,解决的问题和你刚才用 SSH 反向隧道做的事情完全一样:
让没有公网 IP 的内网机器,能被外网访问到。
和你刚才做的对比
你的方案:家里NAS → SSH反向隧道 → Ali ECS → 外网用户
frp的方案:家里NAS(frpc) → frp隧道 → 公网服务器(frps) → 外网用户原理一模一样,只是 frp 是专门为这个场景设计的工具。
那它们比 SSH 反向隧道好在哪里?
| SSH -R | frp/ngrok | |
|---|---|---|
| 配置复杂度 | 简单 | 稍复杂 |
| 断线自动重连 | ❌ 断了就断了 | ✅ 自动重连 |
| 多端口管理 | 每个端口一条命令 | 配置文件统一管理 |
| 支持 HTTP 域名 | ❌ | ✅ 可以按域名路由 |
| 流量统计面板 | ❌ | ✅ |
| 稳定性 | 一般 | 好 |
简单说
- ngrok:商业产品,有免费额度,不需要自己有服务器,开箱即用,适合临时用
- frp:开源免费,需要自己有公网服务器(比如你的 Ali ECS),适合长期稳定使用
你已经有 Ali ECS 了,如果以后想长期稳定穿透 NAS,部署一个 frp 比 SSH 反向隧道更靠谱,断网自动重连是最大的优势。
frp和wireguard干的事情有什么区别
4:59 PM
好问题,很多人容易混淆,但它们解决的是不同层次的问题。
核心区别
| frp | WireGuard | |
|---|---|---|
| 本质 | 端口转发/反向代理 | VPN(虚拟私有网络) |
| 工作层 | 应用层 | 网络层 |
| 暴露的是 | 指定的端口/服务 | 整个网络 |
| 访问方式 | 公网IP+端口 | 像在同一局域网内 |
用你家NAS举例
frp 的方式:
外网 → cypherx.top:9009 → NAS的8080端口只能访问 NAS 的 8080 端口,其他设备、其他端口都访问不到,精确暴露。
WireGuard 的方式:
外网设备加入VPN后 → 直接访问 192.168.3.x 整个内网就好像你人在家里一样,NAS、路由器、打印机、其他电脑全都能访问。
你的 ECS 上已经有 WireGuard 了
从刚才的 netstat 可以看到:
udp 0.0.0.0:51820 ← 这就是WireGuard所以你其实已经可以用 WireGuard 连回家里内网了(如果家里也配了的话)。
怎么选
- 只想暴露某个服务给别人用 → frp
- 自己出门在外想访问家里所有设备 → WireGuard
- 临时测试/给别人演示 → ngrok
你 ECS 上的 WireGuard 是连家里还是连其他地方的?
如何搭建frp
5:01 PM
先看你的需求,搭法会不一样:
Q: 你想穿透哪台机器? A: 家里NAS
Q: 穿透的目的? A: 都有
5:04 PM
好,目标明确:Ali ECS 做服务端(frps),家里 NAS 做客户端(frpc),对外暴露 NAS 服务。
第一步:ECS 上安装 frps
bash
# 下载最新版(查看最新版本号:github.com/fatedier/frp/releases)wget https://github.com/fatedier/frp/releases/download/v0.61.0/frp_0.61.0_linux_amd64.tar.gztar -xzf frp_0.61.0_linux_amd64.tar.gzcd frp_0.61.0_linux_amd64
# 只需要服务端文件sudo cp frps /usr/local/bin/创建配置文件:
bash
sudo mkdir /etc/frpsudo vim /etc/frp/frps.tomltoml
bindPort = 7000 # frp通信端口auth.token = "你自己设一个密码" # 客户端连接时验证用创建 systemd 服务:
bash
sudo vim /etc/systemd/system/frps.serviceini
[Unit]Description=frp ServerAfter=network.target
[Service]ExecStart=/usr/local/bin/frps -c /etc/frp/frps.tomlRestart=always
[Install]WantedBy=multi-user.targetbash
sudo systemctl enable frps --now阿里云安全组放行端口: 7000(frp通信用)
第二步:NAS 上安装 frpc
先确认 NAS 是什么架构:
bash
uname -m# x86_64 → amd64# aarch64 → arm64下载对应版本,以 amd64 为例:
bash
wget https://github.com/fatedier/frp/releases/download/v0.61.0/frp_0.61.0_linux_amd64.tar.gztar -xzf frp_0.61.0_linux_amd64.tar.gzcd frp_0.61.0_linux_amd64sudo cp frpc /usr/local/bin/创建配置文件:
bash
sudo mkdir /etc/frpsudo vim /etc/frp/frpc.tomltoml
serverAddr = "cypherx.top"serverPort = 7000auth.token = "你自己设一个密码" # 和frps一致
# 暴露NAS的Web界面给所有人[[proxies]]name = "nas-web"type = "tcp"localIP = "127.0.0.1"localPort = 8080remotePort = 9009 # 外网访问 cypherx.top:9009
# 暴露SSH给自己运维用[[proxies]]name = "nas-ssh"type = "tcp"localIP = "127.0.0.1"localPort = 22remotePort = 9022 # 外网 ssh -p 9022 user@cypherx.top同样创建 systemd 服务自启:
bash
sudo vim /etc/systemd/system/frpc.serviceini
[Unit]Description=frp ClientAfter=network.target
[Service]ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.tomlRestart=alwaysRestartSec=5
[Install]WantedBy=multi-user.targetbash
sudo systemctl enable frpc --now阿里云安全组放行端口: 9009、9022
验证
bash
# ECS上看frps日志sudo journalctl -u frps -f
# 看到类似这行说明NAS已连上:# [I] [service.go] client login info: ip [xxx] version [0.61.0] hostname [] os [linux]然后浏览器访问 http://cypherx.top:9009 就能打开 NAS 页面了。
和你之前 SSH -R 方案的区别
- NAS 断网重连后 frpc 会自动重连,不需要手动重建隧道
- 多个端口在一个配置文件里统一管理
- 更稳定,适合长期运行
你的 NAS 是什么系统?群晖、威联通还是自建的?
Claude is AI and can make mistakes. Please double-check responses.