使用ssh远程连接内网中的docker container

日常工作中时常会遇到远程操作的问题,两台机器都不具有公网ip,这时候通过ssh连接就会产生一些麻烦,下面是我解决这个问题的方法。

服务端

由于两台机器都不具有公网ip,因此使用ngrok,ngrok需要用到一个具有公网ip的服务器。ngrok自己也提供服务,但是从境内访问官方提供的服务器具有令人难以忍受的延迟。本文中在自己的服务器上搭建了ngrok服务。
先把域名解析到服务器。
这里我的域名是wangjiebao.com,做了泛解析,把ngrok.wangjiebao.com*.ngrok.wangjiebao.com解析到ngrok服务器。

编译ngrok

我的vps系统是Ubuntu 14.04。

安装必要的工具。

sudo apt-get install build-essential golang mercurial git
其次需要安装golang,注意golang的版本必须为1.3以上。

1
2
3
$ sudo add-apt-repository ppa:gophers/archive
$ sudo apt-get update
$ sudo apt-get install golang-1.9-go

注意默认的安装位置是/usr/lib/go-1.9/bin
需要将它添加到系统路径里。
cd /usr/bin/
unlink go
ln -s /usr/lib/go-1.9/bin/go go

获取ngrok源码

git clone https://github.com/inconshreveable/ngrok.git ngrok

生成证书

1
2
3
4
5
6
7
8
9
NGROK_DOMAIN="wangjiebao.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.csr
openssl 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
这里默认的release client编译的是linux amd64对应的客户端。当客户端的环境变换时,需要分别编译,方法如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ GOOS=linux GOARCH=amd64 make release-client
$ GOOS=windows GOARCH=amd64 make release-client
$ GOOS=linux GOARCH=arm make release-client

Linux 平台 32 位系统:GOOS=linux GOARCH=386
Linux 平台 64 位系统:GOOS=linux GOARCH=amd64

Windows 平台 32 位系统:GOOS=windows GOARCH=386
Windows 平台 64 位系统:GOOS=windows GOARCH=amd64

MAC 平台 32 位系统:GOOS=darwin GOARCH=386
MAC 平台 64 位系统:GOOS=darwin GOARCH=amd64

ARM 平台:GOOS=linux GOARCH=arm

编译后ngrok/bin文件夹下有ngrok、ngrokd 两个可执行文件。其中ngrokd是服务器端的程序,ngrok是linux客户端的程序。其余平台下的客户端程序在对应的文件夹下。

运行服务

sudo ./bin/ngrokd -tlsKey=server.key -tlsCrt=server.crt -domain="wangjiebao.com" -httpAddr=":8081" -httpsAddr=":8082"

到这一步,ngrok 服务已经跑起来了,可以通过屏幕上显示的日志查看更多信息。httpAddr、httpsAddr 分别是 ngrok 用来转发 http、https 服务的端口,可以随意指定。ngrokd 还会开一个 4443 端口用来跟客户端通讯(可通过 -tunnelAddr=”:xxx” 指定),如果你配置了 iptables 规则,需要放行这三个端口上的 TCP 协议。

现在访问http://pub.ngrok.wangjiebao.com:8081 , 可以看到这样一行提示:
Tunnel pub.ngrok.wangjiebao.com:8081 not found

由于设置了泛解析,因此pub可以换成其他任意的单词。

客户端

现在服务端已经配置完成,还需要在内网上的机器运行客户端,以便将内网的机器连接上服务器。
将之前在服务器上编译好的文件拷贝到客户机上。

编写配置文件

编写一个配置文件,起名为ngrok.cfg

1
2
server_addr: wangjiebao.com:4443
trust_host_root_certs: false

运行客户端

指定子域、要转发的协议和端口,以及配置文件,运行客户端:
./ngrok -subdomain pub -proto=tcp -config=ngrok.cfg 22

如果需要转发的是HTTP,改为 ./ngrok -subdomain pub -proto=http -config=ngrok.cfg 80

当tunnel status显示online,说明已经连接上服务器

配置Docker

正常的机器这个时候应该已经可以通过任意一台机器使用ssh root@ngrok.wangjiebao.com -p 123456来访问内网机器的端口。

其中端口号会在客户端的运行界面给出

但是我在配置docker container的时候发现访问总是被拒绝。

由于不知道docker container的密码,密码使用passwd指令修改过。

最后发现问题的根源在于Docker container上没有安装sshd服务。

安装ssh server

apt-get install openssh-server

启动与重启ssh server

启动ssh server:
sudo /etc/init.d/ssh start
重启ssh server:
sudo service ssh restart
查看服务是否运行:
netstat -aunpt

编辑配置文件

配置文件位于/etc/ssh/sshd_config
将配置文件中的PermitRootLogin without-password改为PermitRootLogin yes

通过ssh访问客户机

现在已经全部配置完成,可以愉快地玩耍了。在任意一台联网的机器上,都可以使用ssh root@ngrok.wangjiebao.com -p 123456来访问内网机器的端口。

其中端口号会在客户端的运行界面给出