基于花生壳和OPEN VPN远程访问树莓派

前言

使用open vpn软件,可以在能够访问互联网的树莓派、PC上安装vpn客户端,然后在公网服务器上安装vpn服务端,从而在三者之间组建虚拟局域网,实现PC远程访问树莓派,但这种方式通常需要购买具备公网IP的云服务器来搭建vpn服务端。本文将open vpn与花生壳配合使用,仅利用花生壳免费功能来实现PC远程访问树莓派,且仅需占用树莓派1194端口用于vpn服务,其他端口可任意使用。

方案原理

vpn-花生壳

实施步骤

1、花生壳配置

a、树莓派安装花生壳

1
2
3
4
5
6
# 下载地址
https://hsk.oray.com/download

# 下载后将deb安装包上传到树莓派
# 安装
dpkg -i xxxx.deb
1
# 安装成功后,会显示设备SN码,默认密码以及远程管理地址
image-20231120203210856

b、注册花生壳账户并登录

c、花生壳管理平台添加设备

1
2
# 进入花生壳管理平台,在左侧菜单栏选择"设备列表"
# 使用设备SN码、默认密码添加树莓派

d、花生壳管理平台配置内网穿透

1
2
3
4
# 在花生壳管理平台,左侧菜单栏选择"内网穿透"
# 点击添加映射
# 花生壳免费提供两条映射,在此使用一条用于配置VPN服务映射
# 如下图,映射类型选择TCP;TCP类型选择普通TCP;外网域名默认域名;外网端口选择动态端口即可(不用付费);内网主机填写运营商为树莓派分配的IP;内网端口填写1194(open vpn服务端口)

image-20231120203900343

1
2
3
# 完成后点击确认即可
# 然后可在“内网穿透”页面中,点击刚才新建映射后面的“诊断”选项,查看花生壳内网穿透映射配置是否正常
# 如果有问题,检查树莓派是否接入互联网,运营商是否有给树莓派分配ip,以及映射配置信息填写是否正确

image-20231120210951826

image-20231120211012394

image-20231121112615439

1
# 上图中外网地址47xxxx.fun就是后续vpn客户端访问树莓派vpn服务端使用的地址,47557是端口号

2、树莓派-vpn服务端配置

a、安装open vpn和证书生成工具

1
2
apt install -y openvpn
apt install -y openvpn

b、制作相关证书

CA证书

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 进入openvpn文件夹
cd /etc/openvpn/

# 将easy-rsa文件夹复制到openvpn文件家下
cp -r /usr/share/easy-rsa/ /etc/openvpn/

# 进入/etc/openvpn/easy-rsa/目录下
cd /etc/openvpn/easy-rsa/

# 初始化目录
./easyrsa init-pki

# 创建根证书,nopss表示不加密,遇到“Common Name (eg: your user, host, or server name) [Easy-RSA CA]:”回车即可
./easyrsa build-ca nopass

Server端证书

1
2
3
4
5
# 创建服务端证书,server111是自定义的服务端名称,中间遇到“Common Name (eg: your user, host, or server name) [server111]:”回车即可
./easyrsa gen-req server111 nopass

# 给服务端证书签名,中间遇到“ Confirm request details:”输入yes即可
./easyrsa sign-req server server111
1
2
# 使用build-server-full参数可直接完成上述创建证书和签名两个步骤
./easyrsa build-server-full server111 nopass

Client端证书

1
2
3
4
5
# 创建客户端证书,client1为自定义的客户端名称,执行过程中间回车即可
./easyrsa gen-req client1 nopass

# 给客户端证书签名,中间遇到“ Confirm request details:”输入yes即可
./easyrsa sign-req client client1
1
2
# 使用build-client-full参数可直接完成上述创建证书和签名两个步骤
./easyrsa build-client-full client1 nopass

Diffie-Hellman

1
./easyrsa gen-dh

TLS认证密钥

1
openvpn --genkey --secret ta.key

整理所有证书到指定文件夹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mkdir /etc/openvpn/keys

cp /etc/openvpn/easy-rsa/ta.key /etc/openvpn/keys/

cp /etc/openvpn/easy-rsa/pki/ca.crt /etc/openvpn/keys

cp /etc/openvpn/easy-rsa/pki/dh.pem /etc/openvpn/keys

cp /etc/openvpn/easy-rsa/pki/issued/server111.crt /etc/openvpn/keys
cp /etc/openvpn/easy-rsa/pki/private/server111.key /etc/openvpn/keys

cp /etc/openvpn/easy-rsa/pki/issued/client1.crt /etc/openvpn/keys
cp /etc/openvpn/easy-rsa/pki/private/client1.key /etc/openvpn/keys

cp /etc/openvpn/easy-rsa/pki/issued/client2.crt /etc/openvpn/keys
cp /etc/openvpn/easy-rsa/pki/private/client2.key /etc/openvpn/keys

c、创建服务端配置文件

1
2
3
4
5
6
7
8
9
# 进入指定文件夹下,解压出server.conf
cd /usr/share/doc/openvpn/examples/sample-config-files
gzip -d /usr/share/doc/openvpn/examples/sample-config-files/server.conf.gz

# 复制server.conf到/etc/openvpn/keys
cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/keys/

# 修改server.conf中的配置,具体如下
# ";"是注释符号,加";"的行不会起作用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
;local a.b.c.d

port 1194

proto tcp
;proto udp

;dev tap
dev tun

;dev-node MyTap

# 如果执行openvpn开启命令时所在的路径就是下列文件的所在路径,只写文件名即可,否则需要写绝对路径
ca ca.crt
cert server111.crt
key server111.key
dh dh.pem

;topology subnet

server 10.8.0.0 255.255.255.0

ifconfig-pool-persist /var/log/openvpn/ipp.txt

;server-bridge 10.8.0.4 255.255.255.0 10.8.0.50 10.8.0.100

;server-bridge

;push "route 192.168.10.0 255.255.255.0"
;push "route 192.168.20.0 255.255.255.0"

;client-config-dir ccd
;route 192.168.40.128 255.255.255.248

;client-config-dir ccd
;route 10.9.0.0 255.255.255.252

;learn-address ./script

;push "redirect-gateway def1 bypass-dhcp"

;push "dhcp-option DNS 208.67.222.222"
;push "dhcp-option DNS 208.67.220.220"

;client-to-client

# 不允许多用户使用同一客户端证书
;duplicate-cn

keepalive 10 120

# 如果执行openvpn开启命令时所在的路径就是ta.key的所在路径,只写文件名即可,否则需要写绝对路径
tls-auth ta.key 0

cipher AES-256-CBC

;compress lz4-v2
;push "compress lz4-v2"

;comp-lzo

;max-clients 100

;user nobody
;group nogroup

persist-key
persist-tun

status /var/log/openvpn/openvpn-status.log

;log /var/log/openvpn/openvpn.log
log-append /var/log/openvpn/openvpn.log

verb 3

;explicit-exit-notify 1

3、PC-vpn客户端配置

a、安装open vpn

1
2
3
4
5
# linux
apt install -y openvpn

# windows
https://openvpn.net/community-downloads/

b、从服务端下载客户端所需证书文件

1
2
3
4
5
6
7
8
# 需要下列文件
ca.crt
ta.key
client1.crt
client1.key

# linux复制到/etc/openvpn/下
# windows复制到\openvpn\config\下

c、创建客户端配置文件

1
2
3
4
5
6
7
# linux中,在/etc/openvpn/下创建client1.ovpn
cd /etc/openvpn/
vim client1.ovpn

# windows中,在\openvpn\config\下创建client1.ovpn

# 配置文件内容如下,根据注释内容按实际情况修改
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
client
dev tun
proto tcp

# 花生壳内网穿透映射配置后提供的公网域名和端口
remote 47xxxx.fun 47557

resolv-retry infinite

nobind
persist-key
persist-tun

# 最好写绝对路径
ca ca.crt
cert client1.crt
key client1.key
tls-auth ta.key 1

key-direction 1

verb 5

4、开启树莓派vpn服务端

1
2
3
4
5
6
# 进入server.conf所在目录下
# 开启服务端
openvpn --config server.conf &

# 打开日志显示,显示“Initialization Sequence Completed”即正常
tail -f /var/log/openvpn/openvpn.log
1
服务端开启后,可查看vpn局域网ip,为10.8.0.1(可在server.conf修改)

5、开启PC vpn客户端

a、Linux系统下开启

1
2
3
# 进入client1.ovpn所在目录下
# 开启客户端
openvpn --config client.ovpn
image-20231117221724520
1
成功开启并连接到服务端后,可查看vpn局域网IP
image-20231117221835264

b、Windows系统下开启

1
2
3
打开openvpn后,在任务栏中找到openvpn图标,右键选择“选项”,打开如下界面,并选择“高级”

在“配置文件”处选择存放客户端相关文件的文件夹路径,点击确定
image-20231117222757811
1
再次双击任务栏中openvpn图标,开始连接服务端,图标中电脑屏幕变绿即连接成功
image-20231117223011065
1
可查看vpn局域网ip

image-20231117223106838

6、vpn虚拟局域网连通性测试

1
2
在PC中ping 10.8.0.1,测试PC与树莓派间的vpn网络是否互通
如果互通,即可使用10.8.0.1这是ip来访问树莓派中应用(SSH、I-CON PLC RTE等)
image-20231121102834931 image-20231121102959380

7、自动化配置

a、树莓派开机自启phddns

1
2
# 设置开机自启,树莓派开机后自动登录phddns客户端,连接花生壳服务器
phddns enable
image-20231121110916163
1
# 可在花生壳管理平台“设备列表”中,查看设备登录情况
image-20231121110802122

b、树莓派开机自动拨号、邮件上报IP、开启VPN服务端

1
2
3
4
# 树莓派开机接入运营商网络后,运营商会为树莓派动态分配IP,导致使用花生壳建立的内网穿透映射失效
# 使用下面的shell脚本和python程序,实现树莓派开机自动拨号上网,并将获取到的IP通过邮件形式自动上报,最后开启VPN服务端
# shell脚本:auto_email_ip.sh
# python程序:email_ip.py
1
2
3
4
5
6
7
#!/bin/bash
export PATH='/home/pi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games:/snap/bin'
# ethx是接入运营商网络使用的网卡
echo root | sudo -s udhcpc -i ethx
while true; do (echo `ip a show ethx |egrep '\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9])\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9])\>' | awk '{print $2}'`)&& break;sleep 1;done;
# python程序路径
python3 /root/code/email_ip/email_ip.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 此程序可以使用一个邮箱账户自己给自己发邮件,也就是说my_sender和my_user使用一个邮箱即可
# coding=utf-8
import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
import os
import time

# RTCQDBHTITKEQAGN

#发送内容t
def mail(t):
ret=True
try:
msg=MIMEText(t,'plain','utf-8')
msg['From']=formataddr(["PI",my_sender]) # 括号里的对应发件人邮箱昵称、发件人邮箱账号
msg['To']=formataddr(["Admin",my_user]) # 括号里的对应收件人邮箱昵称、收件人邮箱账号
msg['Subject']="树莓派IP地址上报" # 邮件的主题,也可以说是标题
server=smtplib.SMTP("smtp.163.com", 25) # 发件人邮箱中的SMTP服务器,端口是25
server.login(my_sender, my_pass) # 括号中对应的是发件人邮箱账号、邮箱密码
server.sendmail(my_sender,[my_user,],msg.as_string()) # 括号中对应的是发件人邮箱账号、收件人邮箱账号、发送邮件
server.quit() # 关闭连接
except Exception: # 如果 try 中的语句没有执行,则会执行下面的 ret=False
ret=False
return ret

cmd='ip a show ethx |egrep \'\\<([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9])\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9])\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9])\\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-9][0-9])\\>\' | awk \'{print $2}\''

t = "empty"
while t == "empty":
with os.popen(cmd,"r") as p:
t = p.read()
if not t:
t = "empty"
time.sleep(5)

# 设置发件人和收件人信息
my_sender='xxx@163.com' # 自己的邮箱账号
my_pass = '' # 发件人邮箱授权码
my_user=my_sender # 自己的邮箱账号

ret=mail(t)

if ret:
print("发送邮件成功")
else:
print("发送邮件失败")
1
2
3
4
# 设置开机自动运行shell脚本
crontab -e

# 在配置文件最后一行添加 @reboot /root/code/email_ip/reportIp.sh
image-20231121112256250
1
2
完成上述配置后,树莓派开机后会自动接入运营商网络,获取到IP后自动发邮件上报,并自动开启vpn服务
用户只需要在花生壳管理平台中修改内网穿透映射配置中的内网IP,然后启动vpn客户端即可