最近买了一个树莓派 Model 3B放在了办公室的桌子上,让它平时替我跑一些脚本,好不惬意。但是当下班回家后就与它失去了联系,比较苦恼,为树莓派做内网穿透的想法应运而生。
使用到的开源项目或工具有:
- Docker
- ngrok 1.7
- openssl
- (非必需)国内Docker云服务提供商 + 备案的域名
编译 ngrok server 和 client
我的编译机器是 VPS Ubuntu 16.06
首先安装必要的工具:
sudo apt-get install build-essential golang mercurial git
clone 源码,签发自己域名的证书用于建立可信的连接。
git clone https://github.com/tutumcloud/ngrok.git ngrokcd ngrok
cd ngrok
NGROK_DOMAIN="sample_domain.com" //替换成你自己的域名
openssl genrsa -out base.key 2048
openssl req -new -x509 -nodes -key base.key -days 10000 -subj "/CN=$NGROK_DOMAIN" -out base.pem
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=$NGROK_DOMAIN" -out server.csropenssl x509 -req -in server.csr -CA base.pem -CAkey base.key -CAcreateserial -days 10000 -out server.crt
cp base.pem assets/client/tls/ngrokroot.crt
开始编译:
sudo make release-server release-client
//编译运行于macOS的可以使用如下命令
sudo GOOS=darwin GOARCH=amd64 make release-server release-client
//编译运行于树莓派的可以使用如下命令
sudo GOOS=linux GOARCH=arm make release-server release-client
编译完成后可以发现 bin
目录出现一个 ngrokd
的二进制可执行文件,说明编译是成功的。
连接 ngrok server 和 ngrok client
我在VPS上,使用如下命令开启了一个 ngrok server, 可以通过 8081 和 8082 端口访问转发到 ngrok client, 只差客户端来连接了。
sudo ./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="sample_domain.com" -httpAddr=":8081" -httpsAddr=":8082"
在树莓派上,建立一个简单的配置文件 ngrok.cfg:
server_addr: sample_domain.com:4443
trust_host_root_certs: false
运行命令:
./ngrok -subdomain pi -proto=http -config=ngrok.cfg 80
不出意外,可以看到终端会输出 Tunnel Status onlie
的字样,然后我们通过 pi.sample_domain.com:8081
访问的请求就会转发到树莓派的 80端口上。
去掉该死的 :8081,我只想通过域名就能访问
ngrok server 在不指定 httpAddr的情况下会使用 80端口
Docker镜像制作
ngrok和 nginx都在抢 80端口该怎么办??显然 nginx更重要,所以我打算用 Docker欺骗 ngrok,让它误以为自己绑定到了机器的 80端口。
工程目录结构如下:
.├── Dockerfile
├── ngrok
└── run.sh
Dockerfile 如下:
FROM hub.c.163.com/public/ubuntu:16.04
MAINTAINER summerbabybiu admin@stephenw.cc
ENV NGROK /opt/ngrok
ENV DOMAIN sample_domain.com //替换你自己的域名
EXPOSE 80 443 4443 59900
COPY ngrok/bin/ngrokd $NGROK/
COPY ngrok/server.crt $NGROK/ssl.crt
COPY ngrok/server.key $NGROK/ssl.key
COPY ngrok/server.csr $NGROK/ssl.csr
COPY run.sh $NGROK/
RUN chmod +x $NGROK/run.sh
CMD .$NGROK/run.sh
其中 run.sh 内容如下:
#!/bin/sh
/opt/ngrok/ngrokd -tlsCrt /opt/ngrok/ssl.crt -tlsKey /opt/ngrok/ssl.key -domain "sample_domain.com"
然后在工程目录下执行:
//$REPO_NAME 你的 repo名称
//$TAG 你的镜像 tag
docker build -t $REPO_NAME:$TAG .
不出意外地,镜像 build成功,然后我把它 push 到了 Docker Hub。在 VPS上,把镜像 pull下来,执行命令:
docker run -d -p 127.0.0.1:8080:80 -p 127.0.0.1:8081:443 -p 4443:4443 -p 59900:59900 $REPO_NAME:$TAG
此时再次尝试树莓派连接,然后 VPS配置一下 pi.sample_domain.com
proxy_pass 到 127.0.0.1:8080, 你就会发现可以不带端口访问到树莓派了!
树莓派的 ngrok client 自动启动与 ssh 穿透
ssh 穿透和 http 原理差不多,不过它不需要分配子域名,只需要简单的端口建立 tcp连接。编写一个 ngrok client的配置文件:
server_addr: sample_domain.com:4443
trust_host_root_certs: false
tunnels:
http:
proto:
http: 80
subdomain: pi
ssh:
proto:
tcp: 22
remote_port: 59900
然后再次通过命令启动:
ngrok client 二进制被我放在了 /opt/ngrok下,配置文件被我放在了 /opt/config下
/opt/ngrok/bin/linux_arm/ngrok -config=/opt/config/ngrok.cfg start http ssh
这样启动后,可以通过 59900端口 ssh到树莓派上。
还不够,目前的 ngrok client启动处于阻塞态,一旦 tty失去连接就会断开。为此我配置了一个 systemd service:
/etc/systemd/system/ngrok.service
[Unit]
Description=ngrok
After=network.target
[Service]
Type=simple
ExecStart=/opt/ngrok/bin/linux_arm/ngrok -config=/opt/config/ngrok.cfg start http ssh
[Install]
WantedBy=multc-user.target
然后通过 systemctl enable ngrok.service
来使其开机自启,service ngrok start
来使其自动启动。
优化 ngrok server的连接速度
我的 VPS地理位置处于日本,我在家时访问树莓派会比较慢(150ms左右),但是单独为一个树莓派开一台国内的虚机很不划算(月花费65元左右),于是我想到可以托管在 Docker云服务商那边。具体做法很简单,在 Docker云服务商提供的控制台运行刚才 build好的镜像,然后绑定你的域名(需要备案),根据 docker容器运行实际提供出来的端口对 client端的配置文件端口稍作修改就可以建立连接了。实测连接速度在 30ms左右,并且费用降到了 10-15元每月左右。
这只是 流量密集型的操作,所以实际上非常低的云服务配置也能提供非常多稳定的连接,性价比非常高。
手机SSH到远程服务器可以安装
Serverauditor
这一款免费的 App,亲测实用。
- EOF-