小想法 | 基于VSCode和ssh实现远程编程/炼丹


Cause

在内网有一台服务器,能连接外网但由于没有公网 IP 而无法在外网直接访问,之前想要在上面跑程序的时候,就得通过远程桌面进行操作。虽然 Teamviewer 速度还可以,但总感觉有点不太爽……

很久以前(大概一两个月前)就在逼乎上看到过一篇文章说可以

使用vscode进行远程炼丹 (原文见 Reference #1

噫!我来兴趣了,而且其实早就想试试了,然而之前在忙别的没空折腾(其实现在也没空),就是前几天在配服务器环境的时候(麻烦到爆炸,最讨厌配环境了),一想干脆就再折腾一下,弄好远程炼丹(编程)吧。

于是乎就这样连Linux命令都不知道几个的憨憨瞎折腾了一两天的ssh,终于实现了远程炼丹,贼有成就感嘻嘻嘻

其中遇到了一些奇怪的问题,简单记录一下,也方便我忘了再回来看看吧。

时间有限,VSCode的部分就大概提一下思路,重点是ssh的部分吧……

Guidance for ssh

不妨假设如下,记清楚了噢,后面频繁用到的

computer IP/address info
内网服务器A 172.x.x.x 可以访问外网,但外网不能直接访问A
公网服务器B test.com 可以访问外网,也可被外网访问
能够联网的主机C - 想要在C上对A进行访问

内网服务器A上的设置

A设置反向代理到B的 port1 端口

工作原理:
1、本地主机和远程主机建立连接;
2、远程主机上分配了一个 socket 侦听 port 端口;
3、远程端口上有了连接, 该连接就经过安全通道转向本机的端口。

备注:root 登录远程主机才能转发特权端口。

ssh -fCNR <port1>:localhost:22 [email protected] -p 22

-R port1:host:port2 将远程机器的端口映射到本地。port1是公网服务器B的端口,host为本地A的IP,port2是A要映射到公网的端口。
[email protected] 用户名@服务器B地址,表示连接到B,以用户usr_b登录。当然test.com也可以是IP地址啦。
-f SSH客户端在后台运行
-C 允许压缩
-g 允许远程主机可远程访问,这里有坑。 (但autossh没有这个选项所以应该影响不大)
-N Do not execute a shell or command. 不执行脚本或命令,通常与-f连用。
-p 22 表示指定连接到B的22端口,默认就是22啦,如果不是的话设置成B的ssh端口。

注意一下,(网上说)这里有个坑,-g还需要在公网服务器B做下面的设置,设置完后再重启服务。

#vim /etc/ssh/sshd_config 
新增
GatewayPorts yes

进阶1 autossh

由于ssh会自动断开连接,于是利用自动重连工具autossh,保证连接稳定

首先安装autossh,这里我用的是CentOS系统。其他类似的。

sudo yum -y install autossh

其实我发现yum(的源里)找不到autossh,后来是用wget下载然后手动安装的…

screen -S reverse_proxy
autossh -M <port2> -CNR <port1>:localhost:22 [email protected]

多了个-M参数,表示从B的port2检测是否断线。同时autossh会在后台运行,-f也不需要了。

这里的screen用于命令行终端切换,给这个界面起了个名叫reverse_proxy,当然没有装screen的话也需要装一下,不过不执行screen这条语句理论上也能用。

注意,port1和port2均需要在B的安全组内设好规则,允许外网访问。

而后看一下有没有运行↓

看一下进程

netstat看一下

可见A已和B建立连接。
此处port1为9999,port2为9998,仅用于演示,你完全可以看心情选择你喜欢的端口,当然有的端口有特定功能另外说。


进阶2 开机自启

当然,为了连接再可靠一点,确保A重启后还可以连上,可以在A上再设置一下开机自动启动autossh

有一种方法是在/etc/rc.local里面添加如下内容

su - user_a -c "autossh -i /home/user_a/.ssh/id_rsa -o BatchMode=yes -M <port2> -CNR <port1>:localhost:22 [email protected]"

其中,-i后接的是SSH_KEY_FILE_PATH,即私钥地址,root用户默认为/root/.ssh/id_rsa
user_a是A上的用户,且要求在公网服务器B上,已经有了A主机上用户user_a的公钥(这个在下面B的设置中介绍)

然后记得给这个文件赋予可执行权限。

chmod +x /etc/rc.d/rc.local

不过看这个文件注释里的说法,好像这个方法不推荐了。

当然还可以使用其他的配置开机自启的方法,我也刚折腾对Linux也不熟,后面再看看吧。

现在你可以reboot试一下了,前提是你能确保用这台服务器的其他人没意见,重要数据记得保存好噢。

这样A上的设置就告一段落了,下面看公网服务器B。


公网服务器B上的设置

如果只需要在B上对A进行远程炼丹,那就不需要在B上设置啥了,现在直接ssh就完事了

ssh -p <port1> localhost

因为已经把A的ssh对应的22端口映射到B的port1端口了呀!

试一下果然如此。

在B上ssh连接A

进阶 免密登录

这样每次登录都需要输入密码,是有点麻烦了。

这有个办法,就是把本机的ssh公钥复制到要登录的服务器A的~/.ssh/authorized_key文件中,实现免密登录。

什么,你还觉得太麻烦了???

这里还有一个快办法,就是在B上登录A后执行这个——

ssh-copy-id -i .ssh/id_rsa.pub  [email protected]

-i 指向本地的公钥文件,一般在用户的目录下。
usr_a 为A上要登录的用户名

然后就可以从B免密登录内网服务器A啦。你现在可以在B上ssh试一下,理论上直接就已经登录好了呢!


在任意一台联网主机C对A进行访问的实现

到这里我有点成就感了,远程炼丹实际上已经实现了

然而我的初衷是要在一台能联网的主机C上去连接内网A的呀,不行还得再折腾一下啊呜。

首先试了一下直接连接公网服务器B的port1,然而不可行。

不过网上有些资料说是可行的,这个我也不知道呢,可能要问神奇的海螺吧。

根据网上的说法,已经在B上对GatewayPorts进行了设置,也杀死进程重启了服务甚至直接reboot了,然而不知道为啥不可行……

不过也不是没有办法呢,ssh里还有个正向代理闲着没事干呢,说上就上吧。

在B上继续进行如下配置

ssh -fCNL  *:<port3>:localhost:<port1> localhost

表示将B上的port1映射到port3,注意port3也要设置安全组规则啊。

ss -ant 看了一下,port3的确打开了。

理论上这样的话在C上ssh连接B的port3端口,就可以直接访问到内网A了的。

如果你成功了,那就可以直接跳到配置VSCode的部分了,尽情享受远程炼丹的快感吧!

喜欢的话可以滑到页面下方,赞赏一下给我买点好吃的(我饿了.jpg


然而我并没有成功……

看了一下安全组设置,没问题,唉,大不了全开了嘛。还是不行。

这里我难受死了,杀死进程又重来试了好几次,一样没有效果。

再去网上查了查,直到看到一篇文章里提到了这个问题,但他直接用的ssh而没有用到autossh,用他的方案还是没解决问题。不过里面提到了一个命令叫lsof,即“列出打开文件(lists openfiles)”,而在Unix中一切(包括网络套接口)都是文件。这可是个神器啊!

这里用到的是

使用-i :port来显示与指定端口相关的网络信息。

lsof -i :<port3>  # 查看连接port3端口的网络信息

结果类似于这样(忘记截图了),此处port3为仅供演示所用的9988。

# lsof -i :9988
COMMAND PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
ssh     658 root    4u  IPv6  146251      0t0  TCP *:9988 (LISTEN)

这里我才发现,噫,怎么只监听了IPv6,而没有IPv4啊!

实际上通过ss -ant也可以发现对应的端口只有tcp6而没有tcp…

然而阿里云实例(安全组内)只有IPv4出口来着,而且也是通过IPv4连接到B的,怪不得连不上呢。(佛了

不过也奇怪了,理论上ssh应该v4和v6都监听的吧。

去查了一下ssh命令,这次强制使用 IPv4试试。

(在B上杀死之前的ssh,再执行下面的命令。记得改成你的端口哈。

ssh -fCNL  *:<port3>:localhost:<port1> localhost -4

-4表示强制使用IPv4

这回再看lsof -i :<port3>

# lsof -i :9988
COMMAND PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
ssh     954 root    4u  IPv4  255331      0t0  TCP *:9988 (LISTEN)

然后再在C上连接B的port3端口。

通过外网成功连上内网服务器

哇哇哇成功了!

看来果然是这个问题啊我哭了又笑了。

下面就可以设置VSCode来实现远程炼丹啦!

Guidance for VSCode

具体可以参考Reference #1,这里简单操作一下。

在VSCode安装Remote Development开发包(扩展),然后在远程资源管理器里新增一个SSH Target。

VSCode_ssh配置

在用户的.ssh/config文件内新增你的内网炼丹炉信息。

Host 给你的内网主机起个名(看你心情随意取)
HostName 公网服务器B的IP或域名
Port 填port3,如果port1能连上就填port1
User 填内网服务器A的登录用户名

保存,然后便可以连接试一试了。

连接后输入A对应用户的密码,然后就连上了。打开文件夹还需要再输一次密码。

现在再用前面在B的配置里说的办法,把C主机的公钥放到A里就可以实现免密登录啦!

呐,这就是在C上连接到内网炼丹炉的效果了↓。

VSCode远程炼丹效果

网络延时几乎没有(不过也取决于网络环境),和在本地编程几乎没有差别,爽到爆炸!

哇哇哇成就感爆棚啊哇哇哇!!!

Summary

时间因素,不可避免可能存在一些失误之处,其中也有不少可以拓展之处,欢迎交流提出哈。

本文仅用于学习研究,请在合理合法范围内使用

未经允许不得商用,转载请署名MiaoTony并保留本文链接,谢谢。

说点题外话吧。

上周末到这周部署NUAA_iCal_Web在线版本弄了一周末(好菜啊第一次弄部署来着…),配服务器环境折腾了老半天(甚至只装好了GPU驱动和anaconda还没配CUDA),配远程炼丹又瞎折腾了一两天,写这篇文章又断断续续地花了好几个小时。

呜下周开始频繁考试了,不敢瞎折腾了嘤嘤嘤。(溜了溜了

Reference

  1. 使用vscode进行远程炼丹
  2. SSH反向连接使用Autossh自动ssh
  3. 利用阿里云ECS跳板机内网穿透- ssh
  4. SSH如何反向代理稳定穿透内网
  5. 内网穿透:在公网访问你家的 NAS (还包括frp相关)
  6. 从外网 SSH 进局域网,反向代理+正向代理
  7. autossh 穿透,反向代理到内网
  8. ssh-copy-id三步实现SSH无密码登录和ssh常用命令
  9. Linux 命令神器:lsof
  10. 使用 autossh 自动重启 SSH 会话和通道
  11. CentOS7添加开机启动服务或脚本

etc.

非常感谢上面这些文章,给了我很多启发呢。


文章作者: MiaoTony
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 MiaoTony !
评论
  目录