最佳实践

概述

参考:

例一:转发 windows 服务器的远程桌面

在本地电脑上打开 PowerShell,输入如下命令(参数需要自己修改,参见上一节的解释):

ssh -L 10080:<内网Windows服务器IP>:3389 user@123.123.123.123 -p 6001

上面这条命令使用帐号 user 登录了 123.123.123.1236001 端口对应的服务器(192.168.0.123),并在该服务器上建立一个 ssh 转发,将本地计算机(127.0.0.1localhost)的10080端口映射到了 <内网Windows服务器IP>3389 端口。 回车后,提示输入密码,输入账号 user192.168.0.123服务器密码。 登录后不要关闭 Powershell 窗口,否则转发会中断。

之后便可以用本地地址访问 windows 服务器的远程桌面。

为了节约带宽并提高流畅度,可以把桌面背景改成纯色,可以把颜色深度调低,还可以把显示配置里的分辨率调小,一般使用 1600*900 分辨率。 PS:如果是高分屏觉得此分辨率看不清楚可以使用远程桌面自带的缩放功能。在标题栏上点右键即可。

同理,如果局域网的个人电脑也开启了远程桌面功能,也可以用这种办法访问。 RDP 协议优化是是很好的,这种办法 1 Mbps 的带宽就可以获得比较流畅的体验

例二:转发目标服务器的 web 服务

tensorboard 和 jupyter notebook 使用的是 http 协议,可以通过端口转发来访问。

打开 Powershell,输入如下命令

ssh -L 28186:localhost:28888 user@123.123.123.123 -p 6001

上面这条命令使用帐号 user 登录了 123.123.123.1236001 端口对应的服务器(192.168.0.123),并在该服务器上建立一个 ssh 转发,将本地计算机的28186端口映射到了192.168.0.12328888 端口。

之后再浏览器中输入127.0.0.1:28186便可以直接访问该端口的网页。

例三:让服务器使用本地计算机的代理

问:能不能让服务器使用本地计算机的网络呢?比如说,可以让git clone可以走我的 PC 上的代理?    答:可以, 这里假设本地 PC 的8080端口提供了代理服务, 目标是让服务器 A 上的 Git 可以使用代理,假定你可以直接 ssh 登录服务器 A, 登录账户名为hello。 使用命令

ssh -R 10800:localhost:8080 hello@<A 的IP>

建立远程转发,就将本地8080端口的代理转发到 ssh 服务器 A 上的10800端口了。

测试代理设置是否有效:在服务器上执行

ss -lntpd | grep :10800  # 查看端口是否启用
curl www.google.com --socks5 127.0.0.1:10800  # 测试访问google

Git 使用代理参考我之前的博客。 成功之后想干啥就可以干啥啦 XD

其他问题

反向隧道

ssh 反向隧道相信大多数同学都比较了解,就算不了解也一定在日常工作中听说过,其实抛开那些专业的术语,通常我们借助 ssh 的反向隧道来实现两个网络隔离的主机间通信。最近小白在远程操作一个私有化的项目时正好用到了这个,简单总结了下便有了此文章。

在操作之前,我先将需要的资源列出一个表格,大家在操作前可以先按照如下准备资源:

代号角色机器位置地址账户ssh 端口sshd
A中转机器公网121.41.218.68root22启用
B客户机器客户内网10.155.0.0/24root22启用
C我的机器公司 / 家中127.0.0.1root22不需要

这里为了操作方便机器全部用的 root 账号,大家不要学我 😂

我的需求很简单,即客户内网 B 中有一批刚装完操作系统的服务器,我需要在公司或者家中的电脑上通过 Ansible Playbook 批量对这些机器进行初始化。

第一步:开启 ssh server 代理功能

在位于公网服务器上打开 sshd 的GatewayPorts开关,并重启 sshd

sed -i "s/#GatewayPorts no/GatewayPorts yes/g" /etc/ssh/sshd_config systemctl restart ssh

打开代理功能意味着,当我们在建立 ssh 反向隧道后,监听的地址会从默认的 127.0.0.1 更换成 0.0.0.0,方便 ssh 客户端远程登录。

第二步:建立 ssh 反向隧道

在客户内网 B 中找一台能访问 121.41.218.68 地址的服务器,登录上去,并在终端内执行下述命令:

ssh -lroot -p22 -qngfNTR 8822:localhost:22 121.41.218.68 -o ServerAliveInterval=10

这一步的关键信息其实就是在主机 B 和主机 A 之间建立一条 SSH 隧道,隧道端口的映射关系是 主机 B:22 <--> 主机 A:8822

之所以加上 ServerAliveInterval=10,是让客户端每 10s 发送一个心跳保持隧道的链接,否则这条连接很容易被重置。

第三步:本地 ssh client 代理

目前有了 ssh 的隧道也只能满足我本地主机 C 能通过 121.41.218.68 的 8822 端口 ssh 登录到客户内网的 B 主机,还不能满足我进行批量运行任务的需求。

此时,我们就需要在自己电脑上配置 ssh 客户端的 socket 代理来满足需求,配置位于~/.ssh/config

host hosta
    HostName 121.41.218.68
    Port 8822
    User root

host 10.155.0.\*
    User root
    Port 22
    ProxyCommand ssh hosta -W %h:%p

至此,我就可以在本地用 ansible-playbook 无缝的进行操作了。

总结

上述 3 步是整个 ssh 内网穿透的核心流程,如果要做得更加的优雅的话,我们还需要考虑几点优化:

  • 为三台机器上的 ssh 客户端分别配置公私钥
  • 为主机 B 上的 ssh 方向隧道创建服务进程,避免重启后隧道丢失
  • 尽量保证公网主机 A 的网络安全,可单独为隧道端口配置防火墙策略

当然,ssh 反向隧道除了能代理 ssh 服务外,它也能对内网的其他服务做 socket 转发,这里本文就不再展开。总之,建立 SSH 反向隧道这种事情大多数情况都是迫于无奈的临时选择,我们在用完后要及时释放连接,避免长期闲置被不法分子盯上后带来的损失。

基于 SSH 隧道能力实现 VPN

参考:

ssh 与 sshd 程序可以利用 Linux 的 tun 设备实现 VPN 的能力

基于官方的示例, 还可以实现类似 WireGuard 的中继 peer 效果, 并且通过 NAT 与 路由 组合的方式让无法访问互联网的设备访问互联网

环境如下: Inner_A 无法访问互联网, Outer_B 可以访问互联网; B 可以通过 “专线或 VPN” 连接到 A, 但是 A 无法连接到 Outer_B

800

在 Outer_B 上执行

Outer_B 也可以用 WSL ( ̄▽ ̄)"

ssh -NTCf -w0:1 root@Inner_A

此时 Outer_B 上创建了一个名为 tun0 的网络设备, 在 Inner_A 上创建了一个名为 tun1 的网络设备.

在 Outer_B 上执行

echo 1 > /proc/sys/net/ipv4/ip_forward
ip addr add 10.0.0.100/32 peer 10.0.0.200 dev tun0
ip link set dev tun0 up
iptables -t nat -A POSTROUTING -s 10.0.0.200/32 -o eth0 -j MASQUERADE

在 Inner_A 上执行

echo 1 > /proc/sys/net/ipv4/ip_forward
ip addr add 10.0.0.200/32 peer 10.0.0.100 dev tun1
ip link set dev tun1 up

此时在 A 上已经可以通过 10.0.0.100 连接到 Outer_B

若此时 Outer_B 通过 专线/VPN 连接到 Inner_A, 则需要先添加一条路由条目, 避免因改变默认路由导致连接中断

这里假设 专线/VPN 的网络是 172.16.11.0/24; Inner_A 原本的网络是 10.10.11.51/24, 默认路由是 10.10.11.1

ip route add 172.16.11.0/24 dev eno3 via 10.10.11.1

然后修改 Inner_A 的默认路由, 让所有访问互联网的流量发往 Outer_B

ip route replace default via 10.0.0.100

此时, Inner_A 即可通过 Outer_B 愉快得访问互联网了


最后修改 August 8, 2024: powershell clearup (0dda3213)