树莓派的配置向导完成后,记得点击Finish,输入命令行:
sudo reboot
重启树莓派,并应用刚才的配置。
重启结束后,会发现IP地址可能产生了变化,这就需要重新探测IP了。这不科学嘛,每次都得探测一遍IP,好烦的,有没有解决途径?
关于一,感觉操作并不难,恩,在我的路由器上不难,其他路由器应该也是类似的,也就是进入DHCP客户端列表,在这个页面上应该有类似 绑定MAC或者之类的链接/按钮,点击即可进入绑定页面/浮层/弹窗。
应该会是一个列表页面,有添加按钮,点击后输入需要绑定的MAC以及需要对应的IP地址即可。
我们着重探讨方法二。
首先,SSH连上树莓派,依然以git提供的bash进行说明,树莓派的IP地址还是以192.168.0.2作为代指,请对号入座哟,输入命令:
ssh pi@192.168.0.2
会提示输入密码,输入配置向导菜单一中设置的密码,连上树莓派。
接着输入命令:
sudo apt-get update
这行的目的在于更新软件包的库链接信息。
执行完毕后接着输入:
sudo apt-get install vim
这行的目的在于令树莓派通过库链接信息查找并安装编辑器vim。
其中会提示消耗的空间信息,并询问是否继续安装,输入y继续即可。
安装完后我们开始配置咯。
输入命令行:
sudo vim /etc/dhcpcd.conf
这里我们采用刚才安装好的vim编辑器,当然用其他编辑器也是可以的哟。
按键盘insert键或者i键,转为插入模式,在文件末尾增加如下字符:
interface eth0
static ip_address=192.168.0.2/24
static routers=192.168.0.1
static domain_name_servers=114.114.114.114 223.5.5.5
如图所示:
被红框框选的部分即为需要填入的部分。
命令的含义依次为:
interface eth0
这行表示指定的这个配置针对哪张网卡。
static ip_address=192.168.0.2/24
这是说需要将树莓派配置成那个静态IP地址,使用CIDR(详细说明点这里查看)格式输入IP地址哟。
这里,我们还是以192.168.0.2为例进行配置。
static routers=192.168.0.1
这个步骤是设置这个配置应对的网关IP地址,需要填入路由器的IP地址哟。
因此上个步骤中,强烈建议与此IP同网段,不然可能会出现,配置失败,上不了网的情况哟。
static domain_name_servers=114.114.114.114 223.5.5.5
这行表示这个配置应对的DNS服务器地址,按需求填写吧,这里我选的一个是114的DNS,一个是阿里云的DNS,不要吐槽哈。
这里可以看到关于dhcpcd.conf的更详细配置信息
输入完毕后,按Esc键退出插入模式,后输入:
:wq
对编辑结果存盘,并退出vim编辑器。
接着输入命令:
sudo dhcpcd -x
或者输入命令:
sudo reboot
重启树莓派也可以。
稍等片刻会发现git控制台中ssh连接已经掉线了,不要当心,这表示刚才配置的静态IP已经生效啦。
重新连上树莓派。
说到穿内网,那么就能想到很多方法,例如:
1. 通过路由器的端口映射功能,将指定IP指定端口映射给广域网
2. 通过NAT-DDNS设备或软件完成穿内网,可以参考链接:内网穿透(内网映射)NAT-DDNS
3. 通过SSH隧道/反向隧道完成穿内网
4. 通过VPN连接,搭建虚拟局域网环境完成穿内网
5. 等等其他更多方法
现在我们先探讨SSH隧道/反向隧道完成穿内网,关于路由器的端口映射功能穿内网之后再行探讨。之后也会一起研究如何搭建基于Ubuntu 中pptp服务的VPN,通过这个VPN,也能达成穿内网效果。
好,让我们开始吧。
由于我们的树莓派,位于路由器之后,因此没法在广域网中通过IP:端口,例如:10.0.0.1:22 这种形式直接访问到。这个IP与端口的组合,实际访问的是路由器。我们树莓派等于被路由器给隔离开了广域网环境。因此我们需要用某种方式,可以在广域网中访问到我们的树莓派。
我们先假定一个网络拓扑结构:
机器代号 | 机器位置 | IP地址 | 账户 | SSH/SSHD端口 | 是否需要运行SSHD |
---|---|---|---|---|---|
A | 广域网 | a.com | user_a | 2201 | 是 |
B 树莓派 | 局域网,路由器后面 | 192.168.0.2 | pi | 2202 | 是 |
B2 与B同网段的机器 B可以直达B2 |
局域网,路由器后面 | 192.168.0.3 | - | - | 否 |
C | 局域网,路由器后面 | 10.0.0.2 | user_c | 2203 | 否 |
我们知道了没法通过IP:端口的形式访问树莓派,但是反过来却是可以的,即可以通过如上表A机器的IP:端口的形式,从树莓派访问A机器。
那么,能不能在A机器与B机器之间搭建一条通道,让满足某种特定条件的数据包,经由A机器,转发投递给B机器呢?
可以的,我们可以使用如下指令在B机器中,主动与A进行连接,并要求A将访问A的某个端口的数据,转发投递给B的一个端口。
例如:所有访问a.com:6000的数据,全部经由A,转发投递给B的2202端口,命令行为:
ssh -NfR 6000:192.168.0.2:2202 user_a@a.com -p 2201
这里会要求输入密码,请输入A机器user_a帐户的密码。
这条指令的含义为:
使用user_a用户,通过端口2201在a.com机器上,打开一条隧道,隧道的参数如下:所有a.com:6000的数据转发投递至执行这条指令的机器中,并由执行这条指令的机器转交投递给192.168.0.2:2202,这条指令后不再执行其他指令,这条指令位于后台执行。
其中:
-N 表示打开隧道后,不再执行其他指令。
f 表示这条指令位于后台执行,不占用当前bash/shell。
-p 2201表示在A机器的2201端口执行
user_a 表示使用帐户user_a执行这条指令
@a.com 表示在a.com这个IP上执行这条指令
R 表示打开一条远程隧道,隧道的入口端口为6000,出口为执行指令机器。再经由执行指令机器,转交投递给192.168.0.2这个IP上的2201这个端口。
可能上面容易绕进去,让我们换一下场景。
我们依然在B上执行某一条指令,这条指令想要使得其他机器可以通过a.com:6666访问到B2机器的80端口,即192.168.0.3:80,那么指令为:
ssh -NfR 6666:192.168.0.3:80 user_a@a.com -p 2201
那么这条指令的起始点为B机器,终点为A机器的2201端口, 执行的用户名为user_a。
执行的内容为:令A将其6666端口收到的数据转发给192.168.0.3:80,其中192.168.0.3是相对于B来说的。192.168.0.3即为B2的IP啦。
那么从以上分析可以知道,我们要搭建一条SSH反向隧道,需要存在一台A机器,这台机器我把它称之为“桥”,当然,也能叫它“代理”。
这台A机器可以是各大ISP提供的VPS,也可以是直连广域网的PC,甚至还可以是做过端口映射的某路由广域网IP:端口。
这里,我以阿里云的超小型VPS为例进行说明。
VPS为Ubuntu 16.04系统,ssh端口号为22,帐户为root。
不太建议使用延迟超过200ms以上的或者丢包率有点高的VPS,因为你会觉得很痛苦,ssh操作相当迟缓,甚至操作丢失、断连。
为了避免记忆VPS的IP地址,可以准备一个域名,将域名的A记录绑定到VPS的IP上。
假定绑定的域名为:vps.a.com。
在打开SSH反向隧道前,我们要对VPS做一个配置,使其允许远程主机连接本地的转发端口。
通过ssh,连上VPS,输入命令行(请事先安装vim编辑器):
sudo vim /etc/ssh/sshd_config
在其末尾加上:
GetwayPorts yes
记得保存退出哟。
现在,我们在树莓派上执行指令:
ssh -NfR 6000:localhost:22 root@vps.a.com -p 22
那么再其他任意机器上,都能通过:
ssh pi@vps.a.com -p 6000
连入树莓派。例如可以通过手机(使用流量哟)连入树莓派的ssh。
这里遇到了两个问题,希望可以解决,并提高体验。
问题一:每次都得输入VPS的密码,好烦啊。
问题二:ssh -R开通的反向隧道不稳定,有时候就断开了,连不上了。
好的,我们先解决第一个问题:
所谓的免密登录,当然不是免除身份验证,而是通过某种形式,让其自动校验我们的身份,免除输入密码的繁琐操作。
我们先在树莓派中输入命令:
ssh-keygen -t rsa
接着会出如下提示:
Generating public/private rsa key pair.
Enter file in which to save the key (/home/pi/.ssh/id_rsa):
这是要求输入生成的公钥以及私钥的存放路径和文件名。
一般来说,建议路径为~/.ssh/自定义文件名_rsa,其中~部分需要输入绝对路径。
当然,不输入也是可以的,那么会默认在~/.ssh/id_rsa生成私钥,公钥则为id_rsa.pub。
按回车确认,接下来会询问:
Enter passphrase (empty for no passphrase)
Enter same passphrase again
这两个表示是否要给私钥设置一个密码。后者为验证密码。
假如不想设置密码,直接回车即可。
我们假定生成的文件名分别为:
/home/pi/.ssh/pi_rsa 和 /home/pi/.ssh/pi_rsa.pub,没有密码。
接下来,我们要将公钥复制到VPS,作为身份验证参照。可以使用命令行:
ssh-copy-id -i /home/pi/.ssh/pi_rsa.pub -p 22 root@vps.a.com
最后输入一次密码,即可将公钥配置给VPS。
由于ssh默认使用id_rsa作为私钥文件名,进行查询登录,我们用的是自定义私钥名称,因此需要做一些其他设置。
在树莓派中输入:
sudo vim ~/.ssh/config
来为当前用户创建一个自定义ssh配置表,在vim中按i或者Insert键,进入插入模式,键入如下内容:
Host vps
HostName vps.a.com
Port 22
User root
IdentityFile ~/.ssh/pi_rsa
其中:
Host 表示HostName的别名
HostName 表示VPS的域名或者ip地址
Port 表示VPS的ssh端口号
User 表示当前证书对应的用户名
IdentityFile 表示需要使用私钥证书文件的路径
键入完毕后,按ESC退出插入模式。接着键入 :wq 回车 来保存刚才录入的配置。
可以输入命令进行尝试:
ssh -p 22 root@vps
或者
ssh -p 22 root@vps.a.com
假如提示yes/no请输入yes。会发现它不再询问密码了,免密登录成功。
接下来,我们来解决第二个问题,提高反向隧道的稳定性,当断连的时候,树莓派自动的重新开启反向隧道。
首先连上树莓派,接着执行命令行:
sudo apt-get install autossh openssh-server
安装autossh组件。
安装完毕,即可使用命令行:
autossh -M 0 -N -R 6000:localhost:22 root@vps.a.com -i /home/pi/.ssh/pi_rsa -p 22
来自动打开反向隧道。
这样即可通过vps.a.com:6000连入树莓派啦。
不过这里又存在一个问题:万一树莓派重启了的话,这条命令就失效了,怎么办?
好,我们来解决上一个问题。
连上树莓派,输入命令行:
sudo vim /lib/systemed/system/autossh.service
在创建的文件中,键入如下内容:
[Unit]
Description=autossh
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=pi
EnvironmentFile=/etc/default/autossh
ExecStart=
ExecStart=/usr/bin/nohup /usr/bin/sudo /usr/bin/autossh $SSH_OPTIONS
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
需要注意的几个点:
其中 ExecStart=/usr/bin/nohup /usr/bin/sudo /usr/bin/autossh $SSH_OPTIONS为什么要写这么长。恩,这是因为这个服务执行的指令希望:
WantedBy 假如有其他组也想自动执行这个服务,依次往下增加即可。
补充说明,其中第5条找到一个解释为:
Notice that there are two ExecStart in our unit file. They are not typos. In order to allow this unit file to be included by another unit file, we have to clear ExecStart before specifying a new command.
保存退出后,接着执行指令,来创建/etc/default/autossh这个环境变量文件:
sudo vim /etc/default/autossh
在其中键入:
AUTOSSH_POLL=60
AUTOSSH_FIRST_POLL=30
AUTOSSH_GATETIME=0
AUTOSSH_PORT=0
AUTOSSH_PIDFILE="/var/run/autossh.pid"
SSH_OPTIONS="-N -R 6000:localhost:22 -i /home/pi/.ssh/pi_rsa [email protected] -p 22"
这里需要注意的在于AUTOSSH_PIDFILE要写,而且名字最好与service的名字一样,便于service跟踪状态。
SSH_OPTIONS中为autossh的具体命令行。
保存退出。
接着执行指令:
sudo ln -s /lib/systemd/system/autossh.service /etc/systemd/system/autossh.service
用于给服务做个软链接,接着就可以输入命令行:
sudo systemctl enable autossh
sudo systemctl start autossh
来开启服务了。
输入:
sudo systemctl status autossh
可以查询服务的状态,假如看到出现如下的字样,则表示执行成功拉:
autossh.service - Auto SSH Tunnel
Loaded: loaded (/lib/systemd/system/autossh.service; enabled)
Active: active (running) since 六 2017-04-15 16:59:06 CST; 3s ago
Main PID: 2527 (sudo)
CGroup: /system.slice/autossh.service
|-2527 /usr/bin/sudo /usr/bin/autossh -N -R 6000:localhost:22 -i /home/pi/.ssh/pi_rsa [email protected] -p 22
|-2535 /usr/lib/autossh/autossh -N -R 6000:localhost:22 -i /home/pi/.ssh/pi_rsa [email protected] -p 22
`-2546 /usr/bin/ssh -L xxx:127.0.0.1:xxx -R xxx:127.0.0.1:xxx -N -R 6000:localhost:22 -i /home/pi/.ssh/pi_rsa -p 22 [email protected]
其中xxx表示随机生成的端口号。
接下来可以试试:
ssh pi@vps.a.com -p 6000
假如成功连上了的话,则表示autossh搭建完毕咯。
补充:
假如做完ssh免密后直接开始搭建autossh的服务,那么可能会失败,需要先手动的执行一次命令行:
autossh -M 0 -N -R 6000:localhost:22 root@vps.a.com -i /home/pi/.ssh/pi_rsa -p 22
sudo kill -9 $(pidof autossh)
会提示询问yes/no,输入yes即可。会失败的原因就出现在需要输入yes/no上面了。
重新开启服务后,查询服务状态,应该就正常咯。