前言
我手上有个笔记本和台式, 平时台式放在实验室里, 笔记本要带着到处跑, 台式机留着跑批做实验需要远连, 老早的时候用的向日葵,但总感觉不太方便.
虽然说我们实验室的服务器用的也是向日葵(ubuntu22), 医院影像科实习的时候他们的算力机(Win11)用的也是向日葵, 甚至我被一群影像的研究生问有没有更好的远程连接的方式的时候, 我回答得是: 没有(笑). 但是手机开热点传输画面用的流量和延迟, 实在有点负担不起.
之前就对反代略有耳闻, 看到有高手用 vscode 来给内网机器配置反代来走自己机器的网络代理软件来加速 codex, 自己跟着配置了一下发现确实有用, 遗憾的是没搞懂哈哈哈; 某天夜里睡不着, 想着看 man ssh 来催眠, 虽然没睡着但是把正反向代理,或者说转发,给弄明白了(笑), 加上手头上有个阿里云的 99 每年的公网服务器, 火速试了试, 感觉十分好用.
为了开机自动建立ssh 连接, 先考虑用的 autossh , 不过很快找到了个 systemd 配置 ssh 自动连接的方案, 这里附上连接 Setup a secure (SSH) tunnel as a systemd service.
这个配置说好吧, 没用 autossh 用 systemd 确实是对的, enable 一下开机就能自动起来了, autossh 本来也是默认没有 systemd 的时候才用的.
但是说不好吧, 这个作者没有考虑无线网用户开机的时候网络是起不来的, 也没想过断线了之后要怎么重连(实验室凌晨经常莫名其妙断电10秒), 这里大伙儿可能不太了解, 非正常 ssh 断连的时候, 反代监听的端口默认是会被一直占用的, 可惜 drmalex07 没说怎么配置, 还是我自己捣鼓了一下 sshd 配置明白的.
本来我也没想捣鼓, 想着凑合用用算了, 大不了每次ssh僵尸了就先进服务器杀一下僵尸进程 , 但是前几天机房上课的时候, 老师问我们谁有用远程连接软件的经验的, 我自告奋勇上去了, 演示的时候不巧 ssh 宕了, 感觉略微丢脸, 修改了一下配置, 不同条件测试了好几次之后, 捣鼓出了现在的这些儿东西.
配置
这里分享一下我的修改后的配置吧.
/etc/systemd/system/secure-tunnel@.service
[Unit]
Description=Setup a secure tunnel to %i
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
ExecStart=/usr/bin/ssh -F /etc/default/secure-tunnel_%i.config -NT %i
Restart=always
RestartSec=5s
KillMode=control-group
TimeoutStopSec=10s
[Install]
WantedBy=multi-user.target
注意 secure-tunnel@.service 里的 @并不是 typo, 这个代表的是输入的参数, 和文件里的 %i 是呼应的
我主要增加了 Restart 这里, 非常朴实无华的方法, 固定每 5 秒尝试连接一次, 非常的鲁棒.
由于服务器没有绑定域名 所以我自己配置了 /etc/hosts, 名字和 @ 传递的参数一样都叫 ali-01
/etc/default/secure-tunnel_ali-01.config
Host ali-01
HostName ali-01
User root
IdentityFile /root/.ssh/id_ed25519
RemoteForward 0.0.0.0:xx localhost:22
ServerAliveInterval 5
ServerAliveCountMax 3
ExitOnForwardFailure yes
注意我用的是 /root/.ssh/id_ed25519 这个密钥来验证, 可以在 root 用户下执行 ssh-keygen 一路回车得到, 然后 ssh-copy-id root@ali-01 把公钥 放到 ali-01 的autorized_keys 里
这里如果你要用, 先把 ali-01 xx 改成自己期望用的公网机器的ip和端口, 别忘了改防火墙和安全组
还有一个服务器上/etc/ssh/sshd_config需要配置的
AllowTcpForwarding yes
GatewayPorts yes
ClientAliveInterval 5
ClientAliveCountMax 3
这里分别代表允许转发, 允许直接在自身ip上转发, 还有就是对客户端的心跳检测时间间隔, 心跳检测次数, 此处每 5 秒心跳, 三次检测不到就杀掉连接和监听端口的进程了.
如果上面的都配置好了, 最后就是一键启动了
sudo systemctl enable secure-tunnel@ali-01.service
测试
ssh -p xx user@ali-01
断网再开,重启电脑,这样也是ok的.
尾声
最后讲一下正反向代理/转发的逻辑吧, 我个人喜欢把这个转发模型看作 [监听端ip:]端口->目标端ip:端口
所谓代理就是在监听端开启对一个指定端口的监听,原封不动发送到目标端指定端口的过程.
man ssh 是这样说的:
-L port:host:hostport 将本地机(客户机)的某个端口转发到远端指定机器的指定端口. 工作原理是这样的, 本地机器上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连接, 该连接就经过安全通道转发出去, 同时远程主机和 host 的 hostport 端口建立连接. 可以在配置文件中指定端口的转发. 只有 root 才能转发特权端口. IPv6 地 址用另一种格式说明: port/host/hostport -R port:host:hostport 将远程主机(服务器)的某个端口转发到本地端指定机器的指定端口. 工作原理是这样的, 远程主机上分配了一个 socket 侦听 port 端口, 一旦这个端口上有了连 接, 该连接就经过安全通道转向出去, 同时本地主机和 host 的 hostport 端口建立连接. 可以在配置文件中指定端口的转发. 只有用 root 登录远程主机 才能转 发特权端口. IPv6 地址用另一种格式说明: port/host/hostport
还是有点晦涩? 我总结了一下
正向代理监听端是本机,目标端是被ssh连接的机器
反向代理监听端是被ssh连接的机器,目标端是本机
这样是不是好理解一点? 我就是因为想明白这个模型才顿悟的.
还有一个需要注意的点, 0.0.0.0 和 127.0.0.1 的区别,
127.0.0.1 是回环地址, 和用 localhost 一样, 仅限本机访问
0.0.0.0 是未指定地址, 类似通配符, 可以代表本机上所有的 IP 地址 (我的理解是用不同的网卡会得到不同的ip,所以得有一个类似通配符的东西来代表本机)
ssh 默认转发是在回环,也就是127.0.0.1上, 这个时候我直接 ssh -p xx user@ali-01 是不行的,需要先进 ali-01 的 shell, 然后在 ali-01 里面 ssh -p xx user@localhost
改成 0.0.0.0 之后就可以正常 ssh -p xx user@ali-01 了.
如果没有配置 GatewayPorts Yes 的话是不能改成 0.0.0.0, 这就是上面sshd_config 里特别写出这个的原因
本帖具有超级牛力