《Lucky反向代理教程》
说明:本篇文章并非纯粹的Lucky教程,而是作为《Movie-Pilot部署与微信推送教程》的补充。Lucky本身有非常多的功能,只是使用了其中一些功能来保障VPS的安全,具体的Lucky教程还请各位同学去Lucky官网查看详细说明。
非常开心之前的文章能够获得各位的喜欢!有很多同学根据教程搭建好了自己的微信推送服务。但是之前的教程有一些不完美,就是我们把太多的端口暴露在了公网,尽管在教程的开头就说明了强密码的重要性,但还是有很多同学低估了网络的风险,让一些别有用心的人拿到了cookie (在目前NexusPHP架构下,cookie就等同于账号本身)
本文不仅会教各位同学如何隐藏VPS上的端口/服务,同时也会补充说明《Movie-Pilot部署与微信推送教程》中的“可公用”到底怎么样分享给其他小伙伴。
一、安装Lucky
“可公用”说明:Lucky可以管理多个域名与多个证书,可以做到A同学的域名代理A同学的服务,B同学的域名代理B同学的服务。也可以多个人使用同一域名,但请一定要与信任的同学共用,防止坏人作祟。
补充:frps可同时连接多个frpc的接入,只要与同伴沟通好remote_port范围,即可多人使用。
在上一篇《Movie-Pilot部署与微信推送教程》中的第一节中已经教过各位同学如何安装docker服务了,所以默认已经安装好了docker。本教程假定VPS的IP为:203.51.76.218,假定域名:abc.xyz,注意这是一个随便写的IP和随便写的域名,后续内容中需要替换为自己的VPS地址。
# root 身份
ssh root@203.51.76.218
# 在不支持 root 身份的VPS上
ssh 用户名@203.51.76.218
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
之后输入密码即可。进入后为root则跳过此步骤,若不是则执行。
sudo -i
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
在VPS上拉取Lucky镜像
docker pull gdy666/lucky:latest
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
创建Lucky容器 (第5行请按需修改)
docker run -itd \
--name="lucky" \
--restart=always \
--network=host \
-v /etc/container/lucky:/goodluck \
gdy666/lucky:latest
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
等待Lucky创建完成后,放行Lucky的web服务端口16601
ufw allow 16601
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
火速访问Lucky的后台 http://203.51.76.218:16601 默认账号:666,默认密码:666
输入密码后我们进入了主页
点击左边设置,进入设置页,并按照顺序确认或修改需要确认/修改的选项,设置中的一些其他选项,各位同学也可按照自身需求修改。一定要使用非admin / root等账号!一定要使用强密码!
最后点击保存
恭喜各位同学成功安装Lucky!
二、确认防火墙
查看防火墙当前状态
ufw status
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
根据《Movie-Pilot部署与微信推送教程》中所讲,VPS的docker中我们已经创建了wxchat、cookiecloud、frps容器,理论上已经放行端口如下
Status: active
To Action From
-- ------ ----
22 ALLOW Anywhere
5001 ALLOW Anywhere
9000 ALLOW Anywhere
9001 ALLOW Anywhere
9080 ALLOW Anywhere
9088 ALLOW Anywhere
16601 ALLOW Anywhere
22 (v6) ALLOW Anywhere (v6)
5001 (v6) ALLOW Anywhere (v6)
9000 (v6) ALLOW Anywhere (v6)
9001 (v6) ALLOW Anywhere (v6)
9080 (v6) ALLOW Anywhere (v6)
9088 (v6) ALLOW Anywhere (v6)
16601 (v6) ALLOW Anywhere (v6)
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
其中22是SSH端口,5001是(๐•ᴗ•๐)映射端口,9000与9001(frps的web端口)是frps使用端口,9080是cookie-cloud使用端口,9088是wxchat微信代理使用端口,16601是Lucky端口。如果还放行了其他端口,这里也会有显示。本文会跳过SSH端口防护,还请各位同学自行Google查阅。但请一定要记住,在做任何更改之前,请先放行对应端口!
删除 除SSH、frp、Lucky的其他端口
ufw delete allow 5001
ufw delete allow 9001
ufw delete allow 9080
ufw delete allow 9088
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
开放http与https的80和443端口给Lucky监听
ufw allow 80
ufw allow 443
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
此时再执行
ufw status
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
出现如下信息
Status: active
To Action From
-- ------ ----
22 ALLOW Anywhere
80 ALLOW Anywhere
443 ALLOW Anywhere
9000 ALLOW Anywhere
16601 ALLOW Anywhere
22 (v6) ALLOW Anywhere (v6)
80 (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
9000 (v6) ALLOW Anywhere (v6)
16601 (v6) ALLOW Anywhere (v6)
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
其中的16601端口在做完反向代理后也会被删除,仅剩下22、80、443、9000(frp连接端口),就相对比较安全了。
三、SSL证书申请
“可公用”说明:并不是不同域名使用同一证书,而是说Lucky可以为多个域名申请证书,且自动延长证书时间。
请注意!本节默认各位同学已经拥有了自己的域名!由于域名申请的过程比较冗长,而且还存在实名或非实名的选择,所以仅给出官方文档,请各位没有域名的同学按照各官方文档的操作指南/流程自行注册。
阿里云-域名文档-新手指引
腾讯云-域名注册-新手指引
百度云-域名服务-快速入门-域名注册
接下来我们申请SSL证书,用于https协议的加密,当然也可以用http协议裸奔。用http的话浏览器前面会出现不安全标识(难看☹️),具体https与http的区别还请各位同学自行查询 (补充阅读:HTTP 和 HTTPS 协议详解)
请按照1~11的顺序完成步骤
备注请填写后不要修改,如果修改还需要重新向服务器申请证书。添加方式选ACME,证书颁发机构选择Let's Encrypt,验证方式选择自己域名的注册商。步骤7会因为步骤6的选择而改变,此处展示腾讯云的密钥创建。
点击创建后会显示SecretID与SecretKey,请记录下来,我自己就有一个专门的txt用于记录各种指令和相关密钥等。
假设注册的域名为:abc.xyz,请实际操作时更改为自己的域名! 那么在步骤10的地方要填写两行:abc.xyz与*.abc.xyz,即域名与泛域名。
都填写完成后点击最后的添加。添加完成后在更新时间/状态中会显示:证书申请中。如果幸运的话过一会儿就会申请成功,点击日志,如下图所示。
不幸的话还请多试几次......完成后如下图所示
四、动态域名
“可公用”说明:可同时为多个域名更新地址
其实我们使用的VPS是固定的IPv4与IPv6,无需做动态域名更新。但有些同学家中是动态公网,想在自己NAS上部署Lucky并通过域名访问家中设备,那么就需要做DDNS将变化后的IP同步到域名记录里。
如下图所示步骤填写即可 (DNSpod是腾讯云推出的域名解析服务,购买的域名在 腾讯云-控制台-我的域名 和 DNSpod-账号中心-我的域名 当中都能看到,所以选DNSpod和腾讯云都可以)
添加成功后再同样添加一个IPv6的任务,完成后如下图所示
点击任务日志,应该显示如下信息
2024/04/13 13:56:39 开始执行DDNS定时任务
2024/04/13 13:56:40 DDNS定时任务执行结束
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
并且登入DNSpod的控制台-我的域名-解析,应该看到如下信息
此时我们在终端ping自己的域名,应该就会返回VPS的IP地址了
ping abc.xyz
PING abc.xyz (203.51.76.218): 56 data bytes
64 bytes from 203.51.76.218: icmp_seq=0 t(๐•ᴗ•๐)=49 time=82.848 ms
64 bytes from 203.51.76.218: icmp_seq=1 t(๐•ᴗ•๐)=49 time=135.221 ms
64 bytes from 203.51.76.218: icmp_seq=2 t(๐•ᴗ•๐)=49 time=173.783 ms
64 bytes from 203.51.76.218: icmp_seq=3 t(๐•ᴗ•๐)=49 time=139.915 ms
64 bytes from 203.51.76.218: icmp_seq=4 t(๐•ᴗ•๐)=49 time=182.650 ms
64 bytes from 203.51.76.218: icmp_seq=5 t(๐•ᴗ•๐)=49 time=107.924 ms
--- abc.xyz ping statistics ---
6 packets transmitted, 6 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 82.848/137.057/182.650/34.704 ms
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
五、反向代理
“可公用”说明:在连接多个frpc时,将各位的端口做区间处理,例如:11000~11999,12000~12999等,再将各自的域名绑定上各自的服务。
本节我们将正式教各位同学如何使用域名直接访问自己的服务。在上篇教程完成后,各位同学访问远端服务的方式应该都是:http://203.51.76.218:5001 来打开(๐•ᴗ•๐),完成本节后可直接访问:https://mp.abc.xyz 来打开(๐•ᴗ•๐),相比原先暴露端口,显然域名更加安全。
这里留个坑,就是反向代理确实隐藏了端口,将所有web服务都统一于80和443端口,但其实通过ping域名,很轻松的就知道了我们VPS的真实地址,尽管别人无法访问我们的服务了,但依然有可能通过域名知道VPS的真实地址,进而对我们的VPS造成破坏。
那么如何使用CloudFlare来隐藏我们VPS的真实地址,以及解决家庭动态公网IP因运营商屏蔽80和443端口在使用域名时必须加端口号的问题,还请各位同学期待后续文章来教你如何使用CloudFlare。
这里我们先讲一下数据通(๐•ᴗ•๐),即为什么端口都被关闭了,却还能访问相关服务。(仅我个人理解,如有错误还请指正,虚心学习)
左侧为外部访问VPS里的端口,未被放行的端口会被防火墙阻挡,被放行的端口(消息)会进入系统,其中80和443在被Lucky监听,那么该消息会进入Lucky进行处理,Lucky在解析访问head之后,会将消息转发给对应的端口,而那些端口正被frps监听,于是通过frp链(๐•ᴗ•๐)连接到了NAS。
也就是说系统中的5001端口在系统内部是可以被访问的,但无法被系统外部的IP访问。这里其实可以安装一个docker版的Firefox,访问 127.0.0.1:5001,发现是可以正常使用的,但在家里电脑上访问 203.51.76.218:5001 则无法访问。
创建反向代理服务。点击左侧web服务,然后按照1~8步骤操作,监听端口需改为https默认端口443。
点击添加子规则,然后按照1~6的步骤填写/检查
我们稍微来讲解一下这些选项
前端域名/地址:你要访问这个服务的子域名
后端地址:该服务在本机上的真实地址(主要是端口号,具体写127.0.0.1或localhost均可)
万事大吉:帮我们添加了一些常用的反向代理head
自定义配置:一般情况下这里不需要配置,但(๐•ᴗ•๐)文档中要求在进行反向代理时要添加以下内容,否则可能会导致部分功能无法访问。(我自己在未添加时会出现登入页一直转圈的问题,添加后暂时没有出现)
location / {
proxy_pass http://ip:port;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
实际上Lucky并不支持设置proxy_pass,而且Lucky要求每条配置为一行,所以具体天下如下
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
BasicAuth认证:这是给没有登入页的服务加密码用的
比如我的Transmission是没有密码可以直接访问的,用了这个功能后打开网址 https://tr.abc.xyz 会有这么一个认证
相当于给无密码的页面添加了一个保护,非常不错!
到这里其实我们就已经完成了反向代理的步骤,你可以通过修改frpc.ini将自己的服务都映射到VPS上,然后通过添加子规则的方法,实现对应的反向代理。比如我自己就将 威联通管理页、(๐•ᴗ•๐)、qBittorrent、Transmission、Jellyfin、Portainer等服务做了反向代理,在外面直接访问 https://qb.abc.xyz,https://tr.abc.xyz,https://mp.abc.xyz 就可以访问对应服务,非常方便!
但有时这么直接输入网址的时候,浏览器会先访问80端口即http服务(即网址为:http://qb.abc.xyz),会没有回应,因为我们部署的是https服务(即网址为 https://qb.abc.xyz),为了让访问80端口时能正确跳转至443端口,即http重定向至https,我们还需要多加一步。
如上图所示,按照1~11步骤填写/检查,最后点击添加Web服务规则即可。
都完成后,理论上如图所示
可以做个小测试,在浏览器中输入 http://mp.abc.xyz 即指定http访问,你会发现他自动跳转到了 https://mp.abc.xyz
然后我们再给本机上的其他服务添加反向代理
六、后续
从防火墙规则中删去Lucky的端口
ufw delete allow 16601
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
此时执行
ufw status
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
出现如下
Status: active
To Action From
-- ------ ----
22 ALLOW Anywhere
80 ALLOW Anywhere
443 ALLOW Anywhere
9000 ALLOW Anywhere
22 (v6) ALLOW Anywhere (v6)
80 (v6) ALLOW Anywhere (v6)
443 (v6) ALLOW Anywhere (v6)
9000 (v6) ALLOW Anywhere (v6)
if(window.hljsLoader && !document.currentScr(๐•ᴗ•๐).parentNode.hasAttribute('data-s9e-livepreview-onupdate')) {
window.hljsLoader.highlightBlocks(document.currentScr(๐•ᴗ•๐).parentNode);
}
基本上做到尽可能少的开端口了,22是SSH端口(有很多改SSH端口的教程,无论怎么操作,切记先放行端口,再操作),80和443是http(s)端口,9000是与frpc绑定端口。
做完反向代理后,之前填写过{IP}:{Port}的地方都要修改
以前填微信代理地址的地方现在要填写 https://wxchat.abc.xyz
以前填cookiecloud地址的地方现在要填写 https://cookie.abc.xyz
七、补充
搞这么一圈有什么用呢?和原先直接使用{IP}:{Port}有区别吗?
当然是有的!最主要的就是别人没有办法通过扫IP+猜端口号的方式来访问你的服务了。我们的服务都隐藏于反向代理之下,更安全了。
那么我们的VPS更安全了吗?
VPS本身并没有很安全,因为无论是ping域名还是扫IP,都会知道你VPS的实际地址,如果VPS的账户密码不强,还是会被爆破SSH(但这一点貌似没有什么好的方法,不过国内云服务器可以通过安全组来开关SSH端口)。如果别人直接访问VPS的IP:80会直接返回404,因为请求head没有携带相关信息,会被Lucky阻挡,算是安全了一些吧。
做这些主要还是为了后续上CloudFlare,让别人ping域名ping不出我们VPS的真实地址(也让更多的人可以使用相关服务),就算是真的攻击也会被CloudFlare吸收😎
作者: @Caffe ,协助: @woshitao ,转载请标明出处,谢谢!