搭建私人实体编译服务器
有一台性能较好的台式机(以下简称 H(ome)),希望在离开它的几天内依旧可以继续在其上的工作。这台 H 没有公网 IP,于是购买一台云服务器(以下简称 C(loud)),获得公网 IP。使用 ssh forwarding 将 H 的 ssh 22 端口映射到的 C 的 2222 端口。之后进行开发部署。
另外链接 C 的笔记本电脑(L(aptop))。
以下介绍部署过程,备忘。
1. 云服务器选购
因为云服务器只是跳板机,只需要良好的连通性,几乎无 CPU 和内存需求。本着合(节)适(约)的原则,选择最便宜配置的服务器,选择阿里云 ECS,在购买界面选择“一键购买”。选择最便宜的1 vCPU 1 GiB
的机器。因为当前应用只是个人使用,网络传输量小,也没有稳定长时间的流量,所以带宽处选择按使用流量
(固定的配置费用减少 40%)。可以调整带宽到 100Mbps,流量价格与 1Mbps 一致,仅需¥0.800/GB
。
这个选择与 H 相同的镜像,Ubuntu 18.04。
购买成功后,第一次用密码登录,ssh-keygen 生成密钥对。将 H 与 L 的公钥放置到 C 的 ~/.ssh/authorized_keys 文件中。
同时将 C 的公钥放置到 H 的相同位置,方便 C 登录 H。
在 C 的 ~/.ssh/config 中配置 H 的别名,在 L 的 ~/.ssh/config 中配置 H 的别名。各种需要的别名都配置一下,方便后续配置。
~/.ssh/config 的配置如下。
Host H
Hostname localhost
Port 2222
User jingetu
2. SSH forwarding
在 H 上进行 ssh forwarding 将端口映射到 C 上。命令如下。
# 将 H 的 22 端口映射到 C 的 2222 端口
nohup ssh -NR 2222:localhost:22 -o ExitOnForwardFailure=yes -o ServerAliveInterval=10 C &
这个 forwarding 不稳定,后面命令中的 -o ExitOnForwardFailure=yes -o ServerAliveInterval=10
就是用来保活用的。
为了进一步优化,想到用 crontab 按时检查该进程是否存在。所以写了这么一个 python 脚本 auto_ssh.py,检查是否有该进程,如果没有就再执行一次启动。
#!/usr/bin/python
import subprocess
import os
out = subprocess.check_output("ps -ef | grep NR | grep ssh", shell=True)
if "2222:localhost:22" not in out_str:
os.system("nohup ssh -NR 2222:localhost:22 -o ExitOnForwardFailure=yes -o ServerAliveInterval=10 C &")
这个 ssh 命令应当是非 root 用户执行的,因为是从 C 以正常用户身份登录 H。
crontab 实现定时运行以上脚本,以保活。以正常用户身份输入 crontab -e
进行编辑,添加行 * * * * * python /home/jingetu/auto_ssh.py
,表示每分钟执行一次。(关于 crontab 的语法问题,可以通过网站 https://crontab.guru/ 测试,完全不需要记忆 crontab 语法规则。)之后可以使用 crontab -l
查看当前用户的定时任务。
crontab 还有另外一个好处,就是重启机器,crontab 的任务设定依旧存在。所以远程 reboot H,仅需耐心等待 1 - 2 分钟,H 便可自动 forwarding 到 C。
对于重启,还有一些需要设置。1. 在 Settings -> Users 中将当前用户设置成 Automatic Login,重启进入系统无需输出密码;2. H 是双系统,安装一个 Ubuntu 软件 Grub Customizer,调整在 grub 时 Ubuntu 是默认选项。
现在不是很确定以上操作的稳定性。所以还有一种想法是 */30 * * * * killall ssh
,每 30 分钟自动断开一次 forwarding,下一分钟会有 auto_ssh.py 脚本自动启动 forwarding。这么做牺牲体验。
3. 开发环境配置
已知 VSCode 有服务器开发功能,可以通过 ssh 修改服务器 C 上的代码。但实际的编译过程应当在 H 上进行,所以就需要做一个代码同步的工作。
3.1. 代码同步
将 H 上的代码整理到 C 的特定位置。安装软件 lsyncd 进行单方向 C -> H 的同步,只要 C 上的目录下有任何变化就会同步到 H 上的目录下。
配置文件 /etc/lsyncd.conf 如下:
settings {
logfile = "/tmp/lsyncd.log",
statusFile = "/tmp/lsyncd.status",
nodaemon = true,
statusInterval = 3
}
sync {
default.rsync,
source="/root/code_dir",
target="H:/home/jingetu/code_dir",
delay=1,
exclude={'*.swp', '*.swx', '*~'},
rsync = {
archive = true,
compress = false,
_extra = {"--omit-dir-times","-e ssh -i /root/.ssh/id_rsa"}
}
}
delay=1
表示每隔 1 秒同步一次。C 上的代码目录是 /root/code_dir
,H 上的代码目录是 /home/jingetu/code_dir
。
执行 lsyncd -nodaemon /etc/lsyncd.conf
就可以开启同步。
3.2. VSCode 远程开发
在 L 上,安装 vscode,参考 https://code.visualstudio.com/docs/remote/ssh ,进行配置。也就是安装 vscode 的 extension Remote Development。
按操作链接 C,会打开一个新的窗口,按指示打开 C 上的目录 /root/code_dir
。
然后在 vscode 的底部开启两个 terminal(C 的 terminal).第一个 terminal 执行 lsyncd -nodaemon /etc/lsyncd.conf
,前台运行,可以查看 C 到 H 的同步日志。第二个 terminal,执行 ssh H
,登录到 H,进行正常的代码修改后的编译、运行工作。
注意,不要在 lsyncd 没有启动的时候,修改服务器上的代码。因为同步是按事件触发的,修改的事件没有被 lsyncd 记录下来,没有同步会造成两处代码不同步。
执行完以上操作就可以开始在 L 的 vscode 窗口写代码。
4. 保活
4.1. WiFi 保活
H 上设置以下脚本 crontab,自动连接 WiFi。第二次检查 ifconfig,如果没有链接上,有可能是网卡没有挂载上,重启一般能挂载上。
#!/usr/bin/python3
import subprocess
import os
content = subprocess.check_output('nmcli radio wifi', shell=True).decode()
if 'disable' in content:
os.system('nmcli radio wifi on; sleep 5; nmcli c up id TP-LINK_403')
content = subprocess.check_output('nmcli radio wifi', shell=True).decode()
if 'disable' in content:
os.system("sudo /sbin/shutdown --reboot now")
4.2. 睡眠
有些时候可以将 H 进入到睡眠状态,在睡眠状态无 WiFi 链接,所以 C 就不能控制 H 从睡眠状态中恢复回来。可以在睡眠之前先设定恢复时间,这个恢复由 BIOS 控制,所以时间是 BIOS 时钟(Real Time Clock)的时间。以下是睡眠 3600 秒之后恢复。
sudo rtcwake -m disk -s 3600
睡眠命令如下。(记得这个命令需要谨慎使用,不要一睡不醒,可以可以查看一下 rtcwake 每天固定时间恢复,这样就可以保证最多睡 24 小时。)
systemctl suspend
4.3. ssh
在 C 上清理使用 2222 端口的进程(有些时候会重复链接)。
kill $(lsof -t -i tcp:2222)
4.4. 关机又重启
https://askubuntu.com/questions/111907/automatic-reboot-after-power-failure
sudo vim /etc/default/grub
GRUB_RECORDFAIL_TIMEOUT=0
以上的代码同步并不是一个很好的方法,可以直接用 sshfs 在 C 上挂载 H 的目录。再从 L 上挂载 C 的目录。(macOS 安装 sshfs 有点问题,所以对于代码目录,可以直接挂载在 C 上,再从 L 上选择 VSCode 远程开发
。)
mkdir ~workspace && sshfs -o allow_other,default_permissions H:workspace ~/workspace