局域网内的主机实现外网访问(IPv6、frp和反向代理)

本文最后更新于:2021年2月23日 凌晨

本文记录如何在树莓派上如何实现反向代理,穿透内网进行远程登录和操作内网主机。本方法也适用于其他 Linux 系统和 mac osx 系统,但目录上有所区别。

一: 必备条件

  1. 相关linux知识、计算机网络知识。
  2. 相关设备(如树莓派、nas、openwrt),支持IPv6的路由器。
  3. frp 需要 云主机或vps
  4. 自己的域名,方便访问。

二: IPv6(主推荐)

需要一个域名和能够支持IPv6的路由器。这种方法的话只能用支持IPv6的设备进行访问内网设备,现在的手机基本上移动数据都支持IPv6,可以用这个方法,但是如果是WiFi的话,需要路由器开启IPv6,否则无法使用。

2.1 通过你的域名提供商获取账号密码

我用的是阿里云域名服务(也可以用免费的域名提供商),阿里云是通过 AccessKey 来控制DDNS服务的,域名请自行购买及配置。

登录阿里云控制台获取AccessKey

注意:提示信息中的云账号AccessKey是您访问阿里云API的密钥,具有该账户完全的权限,请务必妥善保管。请勿通过任何方式(如Github等)将AccessKey公开至外部渠道,以免被恶意利用而造成安全威胁。

2.2 openwrt上设置动态dns(现改为在ikuai上设置动态域名)

  1. 打开openwrt的web端,点击服务 -> 动态DNS -> 输入 openwrt_ipv6 -> 添加
  2. 点击刚刚添加的openwrt_ipv6后面的修改 -> 启用 -> 查询主机名:你所需要解析的子域名 -> ip地址版本:IPv6 -> DDNS服务提供商:选择你的域名提供商 -> 域名:你所需要解析的子域名 -> 用户名:阿里云是AccessKey ID -> 密码:阿里云是AccessKey Secret -> 保存应用。
  3. 如果是用虚拟机安装的openwrt则设置(其他的忽略):高级设置里 -> IP 地址来源 [IPv6]设定为 : 可用的策略。
  4. 点击配置项openwrt_ipv6后面的: 启动
  5. 网络 -> 防火墙 -> 入站、出站、转发:接受 -> 修改 -> 覆盖网络:勾选全部端口 -> 端口触发: 勾选全部端口
  6. 网络 -> 负载均衡 -> 策略 -> 修改-> 备用成员设为 默认(使用主路由器)

登录阿里云的dns解析服务,看看是否解析成功。同时用 你的子域名 使用 ssh登录openwrt 的后台,测试是否生效,不出意外的话,应该成功了。

2.3 利用socat进行端口转发

2.3.1 原理

因为IPv6的网络是直连的,不需要路由端口转发。所以需要用socat来进行IPv6到IPv4的端口转发。

解释下IPV6地址的基础知识,用冒号隔开的一共是8段,每段都有4个字符。前面4段是路由器获取的外面地址。后面4段是路由器分给内部设备的静态地址

例如我的群晖, IPV62409:abcd:ma23:34c1::1ec6/64

写全就是:2409:abcd:ma23:34c1:0:0:0:1ec6

也就是说我的群晖的后4段就是:0:0:0:1ec6

所以,在配置防火墙的时候,该填入:0:0:0:0:0:0:0:1ec6/0:0:0:0:FFFF:FFFF:FFFF:FFFF

上面的意思是,前4段用掩码,后面4段是使用实际的地址。

2.3.2 转发操作

如何访问家庭局域网中存在只能使用IPv4的设备呢?(比如主路由器下有一个设备(192.168.1.10),该设备不支持IPv6,但现在又希望远程访问其管理页面进行配置)可以通过以下步骤进行操作。

  1. 系统 -> 软件包 -> 可用软件包 -> 过滤器搜索: socatcoreutils-nohup -> 安装
  2. 选择“系统”-“启动项”菜单,切换至“本地启动脚本”选项卡。
  3. 在“exit 0”之前插入如下三条命令,并单击“保存”按钮。
    1. Sleep 120
    2. nohup socat TCP6-LISTEN:8110,reuseaddr,fork TCP4:192.168.1.10:80&
    3. nohup socat UDP6-LISTEN:8110,reuseaddr,fork UDP4:192.168.1.10:80&
  4. nohup的作用是让指令在后台运行,如果不加nohup,则在命令支持后台运行的情况下其会正确执行,如果不支持后台运行,则该命令不会运行。
  5. Sleep 120 指令是防止socat命令运行太早,系统还未启动完成,不具备运行条件。
  6. 重启路由器后即可通过“动态域名:8110”访问IP地址为192.168.1.10的设备。
  7. 如果不想立即重启路由器,可以通过SSH连接路由器,在命令行中输入以下指令完成操作。(该操作成功后,如果路由器重启,设置将不起作用)
    1. socat TCP6-LISTEN:8110,reuseaddr,fork TCP4:192.168.1.10:80&
    2. socat UDP6-LISTEN:8110,reuseaddr,fork UDP4:192.168.1.10:80&

2.4 安全设置

为了安全,需要设置ipv6只能访问指定端口。

2.4.1 更改路由访问端口

(1)更改SSH端口

选择“系统”-“管理权”菜单,切换至“SSH访问”选项卡,在“端口”编辑框中输入自己所需的端口即可。(默认:22)

(2)更改Web端口

  1. 使用SSH工具登录路由器;
  2. 输入“vi /etc/config/uhttpd”命令;
  3. 修改“list listen_http 0.0.0.0:80”和“list listen_http [::]:80”中的80为指定端口号,保存退出;
  4. 打开防火墙相应端口;
  5. 此时通过“动态域名:指定端口”即可访问web管理页面。

未完待续。。。

三: frp的方法(次推荐)

需要一台有公网IP的云主机或者VPS,自己的域名,受限于服务器的带宽。

3.1 云主机上安装一键脚本

直接使用 GitHub 上的一键脚本 MvsCode / frps-onekey

3.1.1 Install(安装)

Aliyun

1
2
3
wget https://code.aliyun.com/MvsCode/frps-onekey/raw/master/install-frps.sh -O ./install-frps.sh
chmod 700 ./install-frps.sh
./install-frps.sh install

Uninstall(卸载)

1
./install-frps.sh uninstall

Update(更新)

1
2
3
./install-frps.sh update
Server management(服务管理器)
Usage: /etc/init.d/frps {start|stop|restart|status|config|version}

3.1.2 配置

执行frps start

2021-2-5运行失败,winscp打开/usr/bin/frps,将里面的$PID全部替换为"$PID",如果运行成功,则无视。

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
# [common] is integral section
[common]
# 默认即可
bind_addr = 0.0.0.0
bind_port = 5443
# frps的默认端口,默认,也可改为你自己的端口
kcp_bind_port = 5443
# frps网页控制端口
dashboard_port = 6443
# 网页端口账号和密码
dashboard_user = 网页端账号
dashboard_pwd = 网页端密码
# 设置http和https的访问端口,PS如被占用改为其他
vhost_http_port = 80
vhost_https_port = 443
# 默认即可
log_file = ./frps.log
# 默认即可
log_level = info
log_max_days = 3
# 认证密匙,改为自己的token
token = 改为自己的token
# 改为你的域名,需要在域名ddns解析里面解析到自己的云主机ip上
# 如果要使用二级域名1)在域名控制台,“主机记录”处填写fr,解析到你的服务器ip;2)“主机记录”处填写*.fr,将记录解析到你的服务器ip。
subdomain_host = fr.域名.com
# 默认即可
#allow_ports = 1-65535
# 默认即可
max_pool_count = 50
# 默认即可
tcp_mux = true

配置完成后,可以通过 http://你的云主机ip:6443http://fr.你的域名:6443/ 访问你的 frps 控制界面。

在云主机上通过如下方式控制 frps

1
2
3
4
5
frps status manage : frps {start|stop|restart|status|config|version}
Example:
start: frps start
stop: frps stop
restart: frps restart

3.2 本地客户端操作

3.2.1 通用方法

可以下载 fatedier/frp,使用里面的frpc; 或者 使用 windows的便携脚本,配置文件参考→官方文档

配置FrpsPro文件夹里面的frpc.ini,配置如下:

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
# 绑定你的 frps 服务器:
# 1.服务器IP地址或域名 2.密钥 3.端口
# 如网络卡慢,可删除最后一行注释标签“#”开启kcp传输

[common]
server_addr = XXX.XXX.XXX.XXX
token = 你的token
server_port = 5443
# protocol = kcp


# http 端口转发设置
# custom_domains 可以是域名或者服务器 IP
# 如需开启密码访问,删除最后两行注释标签“#”即可

[http_001]
type = http
local_port = http访问端口,需要开启
custom_domains = 你的域名
# http_user = admin
# http_pwd = admin


# https 端口转发,需要使用时删除掉每行注释标签“#”即可

# [https_001]
# type = https
# local_port = 443
# custom_domains = super-brain.ml

# 开启本机文件共享

[share_file]
type = tcp
remote_port = 8080
plugin = static_file
# 要对外暴露的文件目录
plugin_local_path = D:\
plugin_strip_prefix = static
plugin_http_user = 账号
plugin_http_passwd = 密码
# 修改链接内为自己的服务器IP,通过浏览器访问 http://170.130.142.170:8080/static/
# 来查看位于 C:\ 目录下的文件,会要求输入已设置好的用户名和密码(如不需要可以注释掉)
# 提示:此功能可以用于搭建静态博客

# 远程桌面,无需修改。如不需要此项可在每行前加“#”号注释掉
# 默认远程桌面连接端口为:9090

[remote_desktop]
type = tcp
# windows的默认远程桌面端口为3389,可修改
local_port = 3389
# 默认域名:9090访问frpc,可设置
remote_port = 9090

windows的便携脚本

3.2.2 openwrt 上插件

因为我使用的 openwrt 路由器固件自带 frp 内网穿透 插件,直接在上面设置即可,openwrt上参考配置如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
基本设置  启用
服务器 你的域名或云主机ip
端口 上面的bind_port端口,默认5443
令牌 上面的token
HTTP服务端口 默认80,跟上面一致
HTTPS服务端口 默认443,跟上面一致

服务列表 添加
开启状态 启用
Frp 协议类型 HTTP或TCP,网页访问就是http,远程ssh连接就是TCP
HTTP:
域名类型 子域名
子域名 如nas,pi,openwrt
TCP:
远程主机端口 随意,需要在云主机安全组开放此端口
内网主机地址 你内网提供服务的内网ip
内网主机端口 如网页服务一般是80,nas是5000,ssh连接的一般是22
数据加密 开启
使用压缩 开启
服务备注名 唯一即可

【示例】 远程控制win 10主机(需要打开win 10的远程控制,还要先使用网络唤醒,然后才能远程控制)

服务备注名 Frp协议类型 域名/子域名 远程主机端口 内网主机地址 内网主机端口
my_pc tcp 域名 9090 windows主机内网ip地址 3389

四: 反向代理

4.1 准备工作(局域网主机上操作)

  1. 局域网主机生成密匙(如果已经生成,请跳过)
    打开终端,输入。
    ssh-keygen # 然后连续按三次Enter
  2. 输入如下命令:
    ssh-copy-id -i ~/.ssh/id_rsa.pub 中文改为你的云主机用户名@中文改为你的云主机外网IP
  3. 使pi默认可以root登录
    sudo passwd root # 修改pi的root密码
    sudo nano /etc/ssh/sshd_config
    找到PermitRootLogin这一行,将前面的‘#’去掉,这一行改为PermitRootLogin yes

4.2 反向代理的操作

原理图:

编号 IP 用户名 说明
A 192.168.1.A U_a 目标 计算机,(即树莓派),在局域网中,可以访问 A
B B.B.B.B U_b 代理服务器(我们的 vps 或云主机),在外网中,无法访问 A
C - U_c 外部的计算机,比如公司的电脑,可以访问B,无法直接访问 A

4.2.1 设计方案

在 A 机器上做到 B 机器的反向代理;在 B 机器上做正向代理本地端口转发

4.2.2环境需求

  • 每台机器上都需要 SSH 客户端
  • A、B 两台机器上需要 SSH 服务器端。通常是 openssh-server。

ubuntu和debian上安装ssh代码如下:
sudo apt install openssl-server

4.2.3 SSH 参数解释

1
2
3
4
5
6
7
-f 后台运行
-C 允许压缩数据
-N 不执行任何命令
-R 将端口绑定到远程服务器,反向代理
-L 将端口绑定到本地客户端,正向代理

*******************区分大小写啊各位亲******************

4.3 具体步骤

4.3.1 登录云主机上开启自动端口转发【云主机上操作】

sudo vi /etc/ssh/sshd_config

找到GatewayPorts把前面的#去掉,后面改成yes,开启自动端口转发

4.3.2 为 B 机器上端口,用来与 A 机器上的22端口绑定 【云主机上操作】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

`ssh -fCNL '*:<port_b2>:localhost:<port_b1>' localhost`
# 其中<port_b1>跟上面的端口相同
# <port_b2>改为和<port_b1>不同的大于1000端口号,如12345
# 代码示例:
ssh -fCNL '*:12345:localhost:7280' localhost


# 查看ssh进程
ps aux | grep ssh


# 将云主机设为开机就正向代理
which rc.local
# cd进入上面的路径,我这边的路径是/etc/
sudo vi /etc/rc.local

#按i编辑,最后一行添加如下代码,:qw保存退出
sshpass -p '云主机密码' ssh -fCNL '*:12345:localhost:7280' localhost

4.4 autossh 反向代理

4.4.1 局域网主机(树莓派)开启autossh反向代理

在上文中,我们已经能够在C 计算机通过 B 计算机访问 A 计算机,但这个代理是暂时的,会出现代理随时断开或者下次重启树莓派又要重新开启,步骤麻烦。因此,我们把方案优化,升级 ssh 的代理工具,使用 autossh 这个工具。

我们先要安装 autossh,在局域网主机(树莓派)上。
sudo apt install autossh -y
sudo apt install sshpass -y

然后输入命令绑定
autossh -M 5678 -NR <port_b1>:localhost:22 云主机用户名@云主机外网IP
代码示例:
sudo sshpass -p '云主机密码' autossh -M 5678 -CNR 7280:localhost:22 root@123.123.123.123

1
2
3
#ssh密码登录
sudo nano /etc/rc.local
sudo sshpass -p '云主机密码' autossh -M 5678 -CNR 7280:localhost:22 root@123.123.123.123

就这样开启了反向代理,作用跟前面的一致。但,这里当代理连接断开后,会自动重连,不需要担心,突然连不上自己的 树莓派 了。

但我们的 pi 重启后,也是要输入上述 autossh 的命令,为了更加自动化,把autossh 加入开机启动里(需要ssh免密码登录)

1
2
3
4
5
# ssh免密码登录
sudo nano /etc/rc.local

# 光标移动到exit 0 的上一行,输入命令。比如花生壳是用phddns.start启动,再这里加入后花生壳就会自动启动了。
/bin/su -c /usr/bin/autossh -M 5678 -CNR 7280:localhost:22 root@123.123.123.123

-M 5678参数,负责通过5678端口监视连接状态,连接有问题时就会自动重连.

4.4.2 通过其他电脑手机访问局域网主机(树莓派)

ssh -p <port_b2> 你的云主机用户名@你的云主机外网IP
<port_b2>改成上面的端口号,如1234

代码示例:
ssh -p12345 root@123.123.123.123

五: 参考文档

参考文档

参考文档2

参考文档3

参考文档4


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!