操作前说明 #
使用前先确认自己的实际环境是否和文中的场景一致。不同系统版本、软件版本或设备条件下,同一条命令和同一个设置可能会有不同表现。
原始操作记录 #
先说说 SSH 的本地转发和远程转发,也叫作正向转发和反向转发。
- 本地转发:内网机器(Client)SSH连接到外网机器(Server),内网机器监听本地指定端口,并将该端口的所有数据转发到外网机器的指定端口。方向是本地到远端。SSH 使用 -L 参数。
命令格式:
ssh -L <local port>:<remote host>:<remote port> <SSH hostname>- 远程转发:内网机器(Client)SSH连接到外网机器(Server),内网机器要求外网机器监听指定端口,并将该端口的所有数据转发到内网机器的指定端口。方向是远端到本地。SSH 使用 -R 参数。
命令格式:
ssh -R <local port>:<remote host>:<remote port> <SSH hostname>注意:上边虽然以内网机器和外网机器来区分 Client 端和 Server 端,是方便在最容易的情况下理解其工作方式。并不一定是内网的机器或外网的机器,也可能全是外网机器,但是由于策略或者防火墙因素导致无法访问其中某一个,而需要另外一个来作为跳板转发。
下来就是实战。
安装 sshpass 免密码登录 ssh,或者使用证书免密码登录。
apt install sshpass实现后台连接 ssh,开启远程转发
sshpass -p "112233aabbcc" ssh -CNfg -R 8080:127.0.0.1:80 -R 4433:127.0.0.1:443 -R 2211:127.0.0.01:22 [email protected]一次开启了3个转发端口
本地端口(Client)
远程端口(Server)
127.0.0.1:80 ←→ 1.1.1.1:8080
127.0.0.1:443 ←→ 1.1.1.1:4433
127.0.0.1:22 ←→ 1.1.1.1:2211
打开 SSH 转发之前,在 1.1.1.1 (Server) 上查看端口,可以看见只监听了 22 端口
# netstat -ntpl
激活Internet连接 (仅服务器)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 983/sshd
tcp6 0 0 :::22 :::* LISTEN 983/sshd打开 SSH 转发之后,再查看 1.1.1.1 (Server) 上的端口,可以看见多了3个监听端口
# netstat -ntpl
激活Internet连接 (仅服务器)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 1244/sshd: root
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 983/sshd
tcp 0 0 0.0.0.0:4433 0.0.0.0:* LISTEN 1244/sshd: root
tcp 0 0 0.0.0.0:2211 0.0.0.0:* LISTEN 1244/sshd: root
tcp6 0 0 :::8080 :::* LISTEN 1244/sshd: root
tcp6 0 0 :::22 :::* LISTEN 983/sshd
tcp6 0 0 :::4433 :::* LISTEN 1244/sshd: root
tcp6 0 0 :::2211 :::* LISTEN 1244/sshd: root| 注意:远程转发的 Server 端默认只监听 127.0.0.1 地址上的端口,如果要监听在 0.0.0.0 上,需要在 Server 端需要修改 /etc/ssh/sshd_config 文件,添加一行配置: GatewayPorts yes 因为 SSH 默认配置出于安全考虑,远程转发是只用于 Server 端自身发起访问请求的,如果跟本例一样,前边还有一个 Nginx 做反向代理的话,就不用修改 SSH 配置了。如果是反向转发之后直接使用的,就需要修改配置文件,监听在 0.0.0.0 上了。 |
说明端口转发已经开始工作了,我们可以通过 1.1.1.1:222 这个Server的地址 SSH 登录到 Client 端了。
同时可以从 http://1.1.1.1:8080 和 https://1.1.1.1:4433 访问到 Client 的 Web 服务。
为什么反向转发要监听 8080 和 4433 呢,直接监听 80 和 443 不就可以用了,何必多此一举,再开一个 Nginx 反向代理 80 到 8080 ,4433 到 443 呢,因为如果没有 Nginx 的话,在 Client 上获取客户端 IP 永远是 127.0.0.1,有需要 Client IP 的应用就无法拿到正确的 IP 了。
下面就是安装 Nginx
apt-get update && apt-get install -y gnupg2
sh -c "echo 'deb http://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx' > /etc/apt/sources.list.d/nginx.list"
wget -O - http://nginx.org/keys/nginx_signing.key | apt-key add -
apt update
apt install nginxNginx 反向代理配置
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
gzip on;
#include /etc/nginx/conf.d/*.conf;
server {
listen 443 ssl;
ssl on;
ssl_certificate server.pem;
ssl_certificate_key server.key;
location / {
proxy_pass https://127.0.0.1:4433;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}
server {
listen 80;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
stream {
server {
listen 222;
proxy_connect_timeout 30s;
proxy_timeout 600s;
proxy_pass 127.0.0.1:2211;
}
}反向代理 Web 服务的 0.0.0.0:80 到 127.0.0.1:8080,0.0.0.0:443 到 127.0.0.1:4433
反向代理 TCP 的 0.0.0.0:222 到 127.0.0.1:2211
OK,大功告成,内网机器上的 Web 可以从外网访问了,同时也能获取正确的 Client IP 了,通过外网也能 SSH 登录内网机器了。
最后,再写个脚本,如果 SSH 断开了就自动重连,嗯,6 秒检查一次。
#cat /root/SSHPortforwarding.sh
#!/bin/bash
while [ true ]
do
vpn=`ps aux|grep -E 'ssh \-' |wc -l`
if [ $vpn -lt 1 ]; then
sshpass -p "112233aabbcc" ssh -CNfg -R 8080:127.0.0.1:80 -R 4433:127.0.0.1:443 -R 2211:127.0.0.01:22 [email protected]
fi
sleep 6
done再把这个脚本放到 rc.local 里,开机自动启动。
nohup bash /root/SSHPortforwarding.sh > /var/log/SSHPortforwarding.log 2>&1 &关键理解 #
这类笔记最重要的不是把命令背下来,而是弄清楚它解决的是什么问题、依赖什么环境、执行后会改变什么。以后再次遇到类似情况时,可以先根据标题判断问题方向,再对照原始命令确认是否适合当前系统版本。
如果命令中包含具体路径、网卡名、磁盘名、进程名、IP 地址、端口号、用户名称或软件版本,实际执行时都要替换成自己环境中的真实值。不要直接照抄示例里的占位内容。
验证方法 #
完成后建议用最直接的方式验证结果,例如重新打开软件、刷新页面、查看配置文件、执行测试命令或观察实际效果。
如果验证结果和预期不一致,建议先不要继续叠加更多修改,而是回到第一步检查环境差异。很多问题并不是命令本身错误,而是当前系统版本、软件版本、路径名称或权限条件与原记录不一致。
注意事项 #
如果涉及系统设置或批量操作,应先备份,避免误操作后无法恢复。
对于旧文章中的命令,还要考虑软件版本变化。浏览器 flags、Linux 发行版默认配置、Python 包版本、Windows 系统设置都会随着时间调整。再次使用时,最好把这篇记录当成排查思路,而不是绝对固定的唯一答案。
小结 #
这篇记录可以作为一个快速索引:先看标题确认问题类型,再看原始命令找到核心操作,最后结合验证方法确认是否真正生效。这样既保留了早期备忘的简洁性,也能减少以后重复排查的时间。