树莓派放家里宽带上运行,希望能在外随时随地控制,但宽带又没有公网 IP,怎么从外网访问内网的树莓派呢?如果手边有个公网 VPS 的话,那这个问题就可以使用反向 SSH 隧道解决了。

在树莓派终端运行下面的命令,可以建立一个简单的 SSH 反向隧道。

$ ssh -R *:2222:localhost:22 vps

vps是我的一条 ssh 连接项目。-R表示建立反向隧道,*:2222:localhost:22表示将远程2222端口上的数据转发到本地22端口,其中*表示监听远程机器上的所有 interface(默认只监听远端的 localhost,这里的星号也可写作0.0.0.0),最后启动本地 sshd 服务端。

像下面这样就能 SSH 连接到内网的树莓派了。x.x.x.x是 VPS 的 IP,-p通过端口2222连接。

$ ssh -p 2222 alarm@x.x.x.x

然后把它完善下,做成一个服务。我希望达成的目标是这样的:开机自动启动 SSH 反向隧道,SSH 连接丢失或超时则自动重连,如果断网的话就关机。

树莓派系统为 Archlinuxarm(systemd 系统都可)的话,在目录/etc/systemd/system/中新建ssh-reverse.timer

[Unit]
Description=Reverse SSH Tunnel on VPS
Wants=network-online.target
After=network-online.target network.target

[Timer]
OnActiveSec=10

[Install]
WantedBy=multi-user.target

再在这个目录中新建ssh-reverse.service

[Unit]
Description=Reverse SSH Tunnel on VPS
Wants=network-online.target
After=network-online.target network.target
OnFailure=check-internet.timer

[Service]
User=alarm
ExecStart=/usr/bin/ssh -NTC -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -o StrictHostKeyChecking=no -o ConnectTimeout=2 -R *:2222:localhost:22 vps
RestartSec=3
Restart=always

[Install]
WantedBy=multi-user.target

然后设置断网后自动关机的逻辑。还是在此目录中新建check-internet.timer

[Unit]
Description=Check Internet Connectivity
Wants=network-online.target
After=network-online.target network.target

[Timer]
OnActiveSec=20
RemainAfterElapse=false

[Install]
WantedBy=multi-user.target

再新建check-internet.service

[Unit]
Description=Check Internet Connectivity
Wants=network-online.target
After=network-online.target network.target
StartLimitIntervalSec=20
StartLimitBurst=3
StartLimitAction=poweroff

[Service]
ExecStart=/bin/sh -c 'timeout 2 ping -c1 www.baidu.com >/dev/null'
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

最后运行# systemctl enable ssh-reverse.timer开机启动ssh-reverse.timer。另外,不要忘了安装timeoutping这两个 shell 程序。


最后的效果:联网时,树莓派自动建立反向隧道,网络短时波动则自动重连;断网时,最长一分钟后自动关机。