5

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

 3 years ago
source link: https://miaotony.xyz/2019/12/21/Idea_RemoteProgramming/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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看一下
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
在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配置
VSCode_ssh配置

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

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

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

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

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

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

VSCode远程炼丹效果
VSCode远程炼丹效果

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

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

Summary

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

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

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

说点题外话吧。

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

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

Reference

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK