先说说 SSH 的本地转发和远程转发,也叫作正向转发和反向转发。
命令格式:
ssh -L <local port>:<remote host>:<remote port> <SSH hostname>
命令格式:
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 root@1.1.1.1
一次开启了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 nginx
Nginx 反向代理配置
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 root@1.1.1.1 fi sleep 6 done
再把这个脚本放到 rc.local 里,开机自动启动。
nohup bash /root/SSHPortforwarding.sh > /var/log/SSHPortforwarding.log 2>&1 &