无公网IPv4条件下使用Lucky和stun-plex实现Plex外网访问

最近部署了公网IPv6的外网访问,但是Plex的客户端有的时候无法获取到IPv6地址,在中国移动大内网之下又没有公网IPv4,考虑使用Lucky的stun协议来获取公网IPv4地址。但是stun协议获取的IPv4地址的端口号是随机的,一段时间之后无法继续使用。一般情况下我们的解决方案是

  • 使用Lucky的stun协议获取IPv4地址,然后使用Nginx反向代理到Plex的端口。
  • 使用Cloudflare的重定向功能,将公网IPv4地址重定向到Plex的端口。

但是问题来了,当我买了一个域名并将Nameserver挂到cf之后,发现很多地区把cf墙了。这个方案行不通。

看到这篇文章,他是用plexapi将Lucky获取到的stunIPv4公网端口并通过api实时修改plex中「设置-远程访问-手动修改端口」的设置:

但是这样也会存在问题:
当Plex走梯子时,Plex的公网IPv4地址会发生变化,在Plex的设置中修改端口虽然正确,但是Plex获取到的公网IP是梯子IP,无法访问。

因此我们使用Plex的「设置-网络-自定义服务器访问URL」,即custom URL的功能,将Lucky获取到的stunIPv4公网端口实时修改至Plex,通过custom URL访问或Plex自带的官方客户端远程访问。

使用要求

STUN 技术允许 NAT1 用户获取公网端口,通过路由端口转发或者 LUCKY 内置转发,将内网服务端口暴露到外网,从而实现内网穿透的目的。

关于是否仅仅只有NAT1类型路由器可以实现不是很确定,很多NAT2和NAT3类型的路由器都可以实现使用STUN打洞。根据这个测试,我自己的网络条件是NAT3类型,仍旧可以实现使用STUN打洞。

NAT有四个类型:

  • NAT1: Full Cone NAT
  • NAT2: Address-Restricted Cone NAT
  • NAT3: Port-Restricted Cone NAT
  • NAT4: Symmetric NAT

按我的理解所谓「公网IP」和「NAT1」类型的网络是不太一样的。公网IP是指在路由器WAN口获取到全球可以路由到的一个IP地址;而NAT1类型的网络的概念强调内部地址与外部地址的映射。Full Core NAT也就是NAT1是内部地址和外部地址都可以自由映射。可以直接通过路由器转发来将内网服务映射到公网IP上,但是运营商如果在路由器外还有一层内网,那么我们路由器上获取到的IP并不是可以全球路由的地址,而是运营商内网IP。

简单来说,访问这里可以看到一个IP地址,把它与路由器WAN接口获取到的IP进行比较,如果不一致则说明运营商分配给我们的是运营商的内网。我们的路由器无法获取公网IP。今天我们讲的是无IPv4公网的条件下用STUN协议打洞,将内网服务映射到公网IP的随机端口上。

要求我们使用NAT1类型的路由器,路由器或光猫可以设置端口转发。

下面是实现步骤:

配置Lucky的stun

Lucky的项目地址:

https://lucky666.cn/

https://github.com/gdy666/lucky

当我们docker部署完Lucky之后,进入左侧「STUN内网穿透」,点击新建穿透规则:

image

  • 穿透类型:选择IPv4-TCP
  • 穿透通道本地端口:选择空闲没有被占用的端口一个
  • 目标地址和目标端口选择Plex内网地址和端口

穿透通道本地端口:此端口用于Lucky的stun协议维持连接使用。如果是光猫拨号,需要设置DMZ主机指向Nas服务器的IP地址;如果是路由器桥接光猫,需要设置端口转发。

下面我们设置端口转发:

image

我是路由器桥接光猫,因此在OpenWrt-防火墙内将18644端口转发至Nas所在的Lucky的stun穿透通道本地端口。

image

此时点击保存,使用手机流量通过下面外网ip+端口访问Plex成功,则Lucky的stun穿透配置成功。

配置plex-stun

这时候就要用到我写的plex-stun工具了:

https://github.com/PrentissLiu/plex-stun

此代码从上述论坛的代码改动而来,可以部署为docker容器。

写完代码打包镜像,docker push到docker hub,可费了老大劲啊。下面我们开始部署:

使用Docker Compose部署:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
version: '3'
services:
plex-stun:
build: .
container_name: plex-stun
ports:
- "4201:4201"
volumes:
- ./token:/app/token
environment:
- PLEX_USERNAME=your_username
- PLEX_PASSWORD=your_password
- PLEX_URL=http://your_plex_server:32400
restart: unless-stopped

或者使用Docker命令:

1
2
3
4
5
6
7
8
9
docker run -d \
--name plex-stun \
-p 4201:4201 \
-v ./token:/app/token \
-e PLEX_USERNAME=your_username \
-e PLEX_PASSWORD=your_password \
-e PLEX_URL=http://your_plex_server:32400 \
--restart unless-stopped \
plex-stun:latest

其中PLEX_USERNAME是Plex的用户名;PLEX_PASSWORD是Plex的密码;PLEX_URL是Plex的地址。程序通过登陆Plex来刷新Plex的token,保存到./token/plex_token.json文件中。若token过期,则会自动刷新token。

部署完成之后我们打开http://your_host:4201, 看到以下界面则表示部署成功:

image

我们将其中的自定义URL端口

1
http://192.168.2.165:4201/change-custom-url/#{ipAddr}

复制到之前我们创建的Lucky的stun的Webhook中,并填写号接口调用成功包含的字符串等,点击保存。此时Plex的custom URL就配置成功了。

image

此时我们打开手机流量,发现可以正常外网访问Plex,而且Plex的custom URL端口会自动更新为Lucky的stun穿透通道本地端口。完结撒花!🎉