From dd2362d0994a797d091203984ac65de5f5ac5f92 Mon Sep 17 00:00:00 2001 From: "ekko.bao" Date: Sun, 7 Jul 2024 16:56:15 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BC=96=E5=86=99=E6=9C=AC=E5=9C=B0web?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=86=85=E7=BD=91=E7=A9=BF=E9=80=8F=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E6=96=B9=E6=A1=88=E7=9A=84md=EF=BC=8C=E5=89=A9?= =?UTF-8?q?=E4=BD=99=E5=9B=BE=E7=89=87=E6=B2=A1=E8=A1=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _posts/本地web服务内网穿透解决方案.md | 297 +++++++++++++++++++++++++- 1 file changed, 296 insertions(+), 1 deletion(-) diff --git a/_posts/本地web服务内网穿透解决方案.md b/_posts/本地web服务内网穿透解决方案.md index e8fa933..3a5809d 100644 --- a/_posts/本地web服务内网穿透解决方案.md +++ b/_posts/本地web服务内网穿透解决方案.md @@ -2,6 +2,301 @@ title: 本地web服务内网穿透解决方案 date: 2024-07-06 11:05:30 tags: + - frp + - nginx + - 内网穿透 + - ssl +categories: + - 网络 +index_img: http://cdn.7niu.begild.com/%E7%94%B5%E8%84%91%E8%BF%81%E7%A7%BB%E5%90%8E%E5%BC%80%E6%9C%BA%E6%97%A0%E6%98%BE%E7%A4%BA%E8%BE%93%E5%87%BA/%E6%90%AC%E5%AE%B6%E5%B7%A5%E4%BD%9C%E4%BD%8D%E7%BD%AE%E5%9B%BE.jpg --- -![本地web服务内网穿透解决方案-arch](http://cdn.7niu.begild.top/%E6%9C%AC%E5%9C%B0web%E6%9C%8D%E5%8A%A1%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-arch.svg) +## 前言 +前段时间搭了一个NAS: +| 部件 | 渠道 | 参数 | 价格 | +| --------- | ---- | -------------------------------------- | ---- | +| 主板+机箱 | 淘宝 | 蜗牛星际的4盘位,J1900 8G内存,16G固态 | 385 | +| 硬盘 | 京东 | 两个4T西部数据红盘组一个RAID1阵列 | 1200 | + +装了一个黑群晖7.X,基本的网盘功能已经组建好了,和手机电脑之间互通也没啥问题,其他的基本也就没有继续捣鼓,诸如什么影音之类的,因为搬家投影仪卖了,也没那么多时间去看。 + +但是话又说回来了,不搞这些搞了其他的,哎嘿。我搭了一个代码版本管理的server。用的是[gitea](https://about.gitea.com/)。本来之前自己写的一些自有的code(不涉及公司的代码,公司的代码都是内网的),都是传到coding上的,但是这玩意现在越来越恶心了,并且公司也直接ban掉了访问的权限,导致说给我的一些code的同步带来了阻碍。所以既然公的不行那就来私的,在NAS上搭建了一个gitea server,这样我就可以自由的进行异地的开发和同步了。 +众所周知: +1. NAS是在自己家内网的。而运营商是ban掉了你的公网IP的,宽带的出口仅仅是在运行商大的内网里面,还是不通公网的,所以百度查到的公网IP也并不是你独有的。 +2. 写code的环境是在另外的一个内网,比如公司的内网,酒店的内网等等。 +二者都没法直接联系到对方,所以就请出了我们的工具:内网穿透了。这也是本片所说的重点,但是并不是讲内网穿透的原理,仅仅是记录一下由于这个跨两个内网访问web服务带来的问题以及我的处理过程。 + +--- + +## 内网穿透方案 +### 虚拟局域网 +在搭建NAS的时候就已经使用了[ZeroTier](https://www.zerotier.com +)来组建了一个虚拟局域网,也就是我说的手机,PC,笔记本等之间的访问。利用这个其实已经能够解决大部分的场景,但是他必须依赖于每个设备都需要装一个zerotier客户端,这就直接导致公司的电脑没有办法完成,因为职员的账户是没有软件安装的权限的。只能走普通的web访问的路线。 + +### FRP +在看了一些资料后,我选择了[FRP](https://gofrp.org/zh-cn/)作为本次的主角,其使用是非常简单的, 随便搜一下教程即可。 +这里主要是要有一台云服务器。因为之前博客备案而当时腾讯云搞活动所以直接99一年的服务器买了。有现成的服务器就好办了。 + +--- +## 实施 + +### FRP +frp的配置网络都有教程。不过注意的是有很多教程比较老,还停留ini的配置。新版的已经是toml了,所以语法上稍有不同。我是参考的这个-> [Linux搭建frp服务](https://blog.csdn.net/u013250861/article/details/130750631) +核心就是: +1. 在服务端(云服务器)配置一个通信端口以监听来自客户端访问。 + ```bash + $ cat frps.toml + bindPort = 22700 #服务端监听的端口 + ``` +2. 在客户端(NAS)配置 + 1. 要访问的服务器端口 + 2. 要反向代理的本地服务的端口,像gitea默认的端口是8418,所以直接填写8418即可 + ```bash + $ cat frpc.toml + serverAddr = "xxxx.com" #需要自行添加域名解析 + serverPort = 22700 #服务端端口 + + [[proxies]] + name = "gitea-proxy" + type = "tcp" + localIP = "127.0.0.1" + localPort = 8418 #代理本地的8418端口 + remotePort = 44556 #服务器端使用44556端口对外提供服务 + ``` + 这里的 serverAddr 可以是域名也可以是云服务器IP,因为不知道那天哪里有更便宜的服务器,我就会迁过去,所以我是填的域名,这样我迁移服务器修改一下dns即可。 + 下面的 proxies 是个表数组,可以定义多个代理,copy改一改代理的内容即可。 + +配置完毕后,启动两边的程序,看到打印连接正常即可通过,服务器IP加端口访问服务了。 +记得把服务器的防火墙的 44556、22700 端口访问打开。 +比如 http://43.56.67.12:44556。即可看到gitea主页面了。登录后即可看到自己的仓库等等。 + +为了方便持续运行,异常恢复,搭建一个system service来管理也是极好的,所以 +客户端的service 配置: +```bash +$ cat /etc/systemd/system/frpc.service +[Unit] +Description=frpc +After=network.target +Wants=network.target + +[Service] +Restart=on-failure +RestartSec=5 +ExecStart=/var/services/homes/work/run/frp/frpc -c /var/services/homes/work/run/frp/frpc.toml + +[Install] +WantedBy=multi-user.target +``` +服务端的service 配置: +```bash +$ cat /etc/systemd/system/frps.service +[Unit] +Description=frps +After=network.target +Wants=network.target + +[Service] +Restart=on-failure +RestartSec=5 +ExecStart=/home/ubuntu/frp/frp_0.58.1_linux_amd64/frps -c /home/ubuntu/frp/frp_0.58.1_linux_amd64/frps.toml + +[Install] +WantedBy=multi-user.target +``` + +服务相关命令,服务端的改成frps.service即可 +```bash +systemctl daemon-reload #刷新服务 +systemctl enable frpc.service # 开机自启 +systemctl start frpc.service #启动 +systemctl restart frpc.service #重启 +systemctl status frpc.service #服务状态 +systemctl is-enabled frpc.service #检查是否处于开机自启 +``` +http://43.56.67.12:44556。 这样你以为就结束了?,no no no。这样之后呢,实际下来会有这么几个问题。 +1. 访问的IP和端口不好记,IP可以通过域名解析来解决,但是端口不行,时间长容易忘。 +2. 非web端口(80/433)基本被公司防火墙干掉了,所以在公司电脑上还是无法访问,等于白搞! + +所以还得继续搏斗 + +### NGINX +为什么浏览器可以访问其他的网页但是这个网页就不行呢,明明我备案的博客网页也是在这个服务器上的,在公司电脑也是能访问的,所以防火墙肯定不是防IP也不是HTTP协议,那大概率就是端口了! +使用wireshark,过滤下访问服务器IP的流量看下,我发现了一个问题,请求时建立TCP连接的握手,在本机发送的SYN信号后,正确发给了服务器的44556端口,但是一直没有回应,后面都是重试的错误,所以应该就是端口被防火墙挡道了。 +无所谓,Nginx会出手,通过Nginx对80端口的流量分流,根据访问的域名分流到不通的后端,来代理不同的业务服务。 +因为备案的原因,80端口必须要给到备案网页的web服务,所以这里的域名就分流如下。 +| 域名 | 服务 | 实际端口 | +| ----------------- | ----------- | -------- | +| xxx.com | 备案网页 | 80 | +| gitserver.xxx.com | gitea的网页 | 44556 | + +当然这里的gitserver这个二级域名也需要域名解析是到服务器的IP。 + +```bash +$ sudo vim /etc/nginx/sites-available/gitea +server { + listen 80; + server_name gitserver.xxx.com; # 将此替换为你希望用来访问Gitea的域名或IP + + location / { + proxy_pass http://localhost:44556; + proxy_set_header Host $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; + } +} +``` +生效配置 +```bash +$ sudo ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/ +$ sudo nginx -t +nginx: the configuration file /etc/nginx/nginx.conf syntax is ok +nginx: configuration file /etc/nginx/nginx.conf test is successful +$ sudo systemctl reload nginx +``` + +这样你就可以直接通过 http://gitserver.xxx.com 来访问到gitea server了。相比较通过 http://43.56.67.12:44556 是不是已经非常现代了! +并且在公司电脑的浏览器一样可以浏览仓库和代码,因为防火墙只能看到的是Nginx对外提供的80端口在和他通信,完全绕过了防火墙的限制! + +桥豆麻袋,桥豆麻袋,还没结束,正当我兴冲冲的打开终端, git pull 拉code的时候, WTF,还是不行! + +### TLS终止代理 +难道是git另外起了其他的端口去访问吗,不应该啊,我在家也试过可以的,不需要额外的代理端口啊,老方法,wireshark上马,筛选和服务器的流量看下,发起git pull的时候会显示一个GIT协议的请求,然后后面就不行了,大意了原来是防火墙直接拦截掉了GIT的请求了,难道就要这样结束了吗? 不不不,我还有一计!祭出我的屠龙宝刀:流量加密!。既然你识别GIT协议,那我就加密整个TCP流量,你怎么识别? + +先看下gitea是否支持HTTPS,是支持的,不过貌似没有必要这么彻底,我只要公司电脑到服务器是加密的即可,后续无所谓。所以为了减少改动范围,使用了Nginx来一手TLS终止代理即可。 + +随便用openssl生成了nginx可用的证书和公钥,配置一下即可。 +这里另外配置了重定向,让http访问也重新向到https +```bash +$ sudo vim /etc/nginx/sites-available/gitea +server { + listen 80; + server_name gitserver.xxx.com; + return 301 https://$server_name$request_uri; +} + +server { + listen 443 ssl; + server_name gitserver.xxx.com; + + ssl_certificate /home/ubuntu/ssl/nginx/xxx.pem + ssl_certificate_key /home/ubuntu/ssl/nginx/xxx.key; + + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + location / { + proxy_pass http://localhost:44556; + proxy_set_header Host $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; + } +} +``` +然后再次使用git pull code, git push code。 OJBK,**完全没有问题**! + +到此已经完全无障碍的使用NAS上搭建的gitea服务了! + +不过,是的还有一点小瑕疵,那就是证书并不是CA颁发的,无论是git 还是web都会报警告证书不受信,很烦!!。虽然可以工作但是警告真的很烦,所以工作还未结束! + +## 免费CA ssl证书 + +我的域名是在阿里买的,他会给免费的证书的,不过只有90天并且我实测下来下来的貌似也不受到认可,不知道是不是我操作有问题,但是即使他有用,90天我就的换一下岂不是麻烦死了,除非可以自动更新。哎,还真有,果然像我一样懒得还是很多的,一开始我想是不是写一个脚本去自动获取,但是已经有人做了这样得工具可以自动获取自动更新!完美,兄弟!。 + +[Certbot](https://certbot.eff.org/),一个免费的证书管理工具。他颁发的证书来自 [Let's Encrypt](https://letsencrypt.org/zh-cn/getting-started/) 。具体的工作原理可以看他们的文档,这里主要是域名的所有权要保证是你的,所以这里需要他支持查询的DNS服务上才能用。 +参考官网进行了安装,我一开始在文档里并没有找到阿里还以为不支持,想着不应该啊阿里还是用户蛮多的,死马当活马医,试试看真有! +```bash +sudo snap install --classic certbot +sudo ln -s /snap/bin/certbot /usr/bin/certbot +sudo snap set certbot trust-plugin-with-root=ok +sudo snap install certbot-dns-aliyun #我的域名dns提供商是阿里云的,这里可以把aliyun删掉然后用table键看下都支持哪些dns提供商 +``` +它非常方便,自动检测nginx的配置,并且生成和替换,完全不用额外的命令。过程贴这里了 +``` bash +$ sudo certbot --nginx +Saving debug log to /var/log/letsencrypt/letsencrypt.log +Enter email address (used for urgent renewal and security notices) + (Enter 'c' to cancel): xxxx@126.com + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Please read the Terms of Service at +https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in +order to register with the ACME server. Do you agree? +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +(Y)es/(N)o: Y + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Would you be willing, once your first certificate is successfully issued, to +share your email address with the Electronic Frontier Foundation, a founding +partner of the Let's Encrypt project and the non-profit organization that +develops Certbot? We'd like to send you email about our work encrypting the web, +EFF news, campaigns, and ways to support digital freedom. +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +(Y)es/(N)o: y +Account registered. + +Which names would you like to activate HTTPS for? +We recommend selecting either all domains, or all domains in a VirtualHost/server block. +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +1: gitserver.xxx.com # 我这里这里检测到两个域名。需要颁发给哪一个 +2: yyy.xxx.com +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Select the appropriate numbers separated by commas and/or spaces, or leave input +blank to select all options shown (Enter 'c' to cancel): 1 #我选择1 +Requesting a certificate for gitserver.xxx.com + +Successfully received certificate. +Certificate is saved at: /etc/letsencrypt/live/xxx.begild.com/fullchain.pem +Key is saved at: /etc/letsencrypt/live/xxx.begild.com/privkey.pem +This certificate expires on 2024-10-03. +These files will be updated when the certificate renews. +Certbot has set up a scheduled task to automatically renew this certificate in the background. + +Deploying certificate +Successfully deployed certificate for gitserver.xxx.com to /etc/nginx/sites-enabled/gitea +Congratulations! You have successfully enabled HTTPS on https://xxxx.begild.com + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +If you like Certbot, please consider supporting our work by: + * Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate + * Donating to EFF: https://eff.org/donate-le +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +``` +这样浏览器就不会弹证书警告了,默认证书就是90天有效期,这个工具可以自动续期,所以相当于就是无限期,只要你确保域名在你手里。 + +测试续期是否能够成功 + +```bash +$ sudo certbot renew --dry-run +Saving debug log to /var/log/letsencrypt/letsencrypt.log + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Processing /etc/letsencrypt/renewal/gitserver.xxx.com.conf +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Account registered. +Simulating renewal of an existing certificate for gitserver.xxx.com + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Congratulations, all simulated renewals succeeded: + /etc/letsencrypt/live/gitserver.xxx.com/fullchain.pem (success) +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +``` + +当我配置完上面这一切之后,不知不觉,已经迭代了很多个版本呢。每个版本解决一个问题,再上一个问题解决前我也不知道后面的问题,就这样不断升级打怪,我可能本身已经不仅仅是为了访问gitea的服务了,转而变成了:你不让我这样,我就要试试,看看我能不能成? + +希望我能一直保持有这种对于问题和未知源源不绝的兴趣! + +## FRP 的优化 +这是一个彩蛋,上面说的gitea暴露给公网访问是通过frp,frp本身的流量其实并不是加密的,一不做二不休,做都做了,来都来了,阅读了frp相关的文档对其进行了一些优化修改: +1. FRP的双向加密,这样端到端之间都是加密的。 +2. TCP改为QUIC,提升速度。TCP的拥塞控制并不是很优秀。 +这些都是小小菜就不展开说的,都是参考文档简单配置一下即可。 + +## 最后 +最后贴一下整体的架构是这个样子: +![本地web服务内网穿透解决方案-arch](https://cdn.7niu.begild.com/%E6%9C%AC%E5%9C%B0web%E6%9C%8D%E5%8A%A1%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88-arch.svg)