共计 9020 个字符,预计需要花费 23 分钟才能阅读完成。
更新记录
2023-10-26
由于租用到了国内的 300Mbps 大带宽vps,所以现在基本全面转向使用 frp 方式进行内网穿透。
ddns + 端口映射只作为备用的入口,不打算在上面运行任何大流量 web 服务器,避免运营商的审查。
2023-08-26
本文章的评论数量是压测导致,目的是为了测试腾讯云cdn的限流和限QPS功能。压测结果符合预期。到达预定的量级时可以触发设定好的规则。
需要注意的是腾讯云的统计会有 5~10 分钟的延时,所以尽量限制下上传速率,否则也可能会被刷爆流量。
背景
很早我就购置了一台 itx 服务器放在家里,尽管机箱不大,但是配置已经足够满足我的使用。
我会将很多服务运行在这台服务器上,同时绝大部分服务都可以提供公网访问,例如笔记、云盘、个人博客、密码管理工具、自建GPT聊天机器人、给媳妇用的流媒体plex等等。
我已经习惯将我的一切服务放在云上,享受无论身处何地随时可用的快乐。
配置如下:
- 主板:MS-Terminator B660M
- CPU:Intel i5 12400
- 内存:酷兽 32GB * 2
- 电源:益衡 7025B 250W
需求慢慢的越来越多,对网络的质量要求和安全要求也越来越高。网络性能一般可以通过四个指标来观测:丢包
、延时
、抖动
、速率
。
一些静态的资源对网络质量要求并不高,但是流媒体软件不一样。同时,之前的服务大多是提供给自己用,均做了加密鉴权,不太担心被攻击。现在这个博客上线后,是会公开在互联网上,对安全和防攻击的要求也提上了日程。
经过一段时间的梳理和实践,现在新的网络方案已经上线。
我将家宽暴露在互联网上,我使用了以下几种方式:
- 租用 vps 部署
frp
进行内网穿透。 - 向运营商索要公网IP,通过
ddns
+端口映射
方式将直接暴露在互联网上。- 运营商封禁了
80
、8080
、443
等web端口,使用非标web端口,会增大用户的使用成本,域名+端口的形式不美观且难以记忆。对于一些个人用的服务其实影响并不大,但是对于需要提供在公网的服务,例如本博客站点,是绝对不适合的。 - 将家宽服务作为源站,使用cdn作为网关回源家宽服务。利用cdn提供的
80
和443
端口对公网提供服务。
- 运营商封禁了
网络链路存在木桶效应,最差的端点会直接限制网络性能的上限。上述方案并不冲突,可以根据不同的场景组合起来使用,消去单一架构带来的短板。
我现在的家宽网络:30Mbps上行,1000Mbps下行。对外服务使用到的是上行。
即无论我在其它侧如何优化,30Mbps上行带宽是我能提供的最大能力,对我目前而言已经足够使用。
下文会具体介绍三种网络方案,可以组合使用,以平衡成本和网络性能。
vps 部署 frp 进行内网穿透
适用场景
结论放前面
此方式适用:
- 预算不够,且对网络带宽要求不高的服务,以静态资源居多
-
对网络稳定性要求不高的服务
通过此方式穿透到家里服务的有:
- 思源笔记
- 虚拟化平台 web管理界面
- 堡垒机
- 路由器 web 管理界面
- 迅雷 docker 版
- grafana 监控面板
- 密码管理工具
- GPT web端机器人
我租用过的 vps 和独立服务器有很多台,它们分布在 各家大大小小的云厂,全球各个区域,从1core & 0.5GB RAM 到80 core & 512G RAM。
计算和存储不在本文展开讨论,根据网络的不同我认为可以分为两大类:
- 大陆
- 优点:延时低,丢包率低,抖动小
- 缺点:带宽或流量的成本极其高昂;提供 web 服务 域名需要备案
- 非大陆,港澳台 + 国外
- 优点:带宽或流量成本低;无需备案
- 缺点:延时高,丢包率高,抖动大,80 443端口容易被阻断。同时晚高峰期质量极其差劲,即使部分云提供的 vps 网络链路是经过优化的,例如
cn2
、9929
。但是对比国内的依然很差劲。
最开始为了大带宽,我使用的是非大陆的 vps。
最开始 vps 位于香港,线路为 cn2。延时很漂亮,延时最低只有45ms左右。但是丢包率太高,日均大约有10%,导致我的服务网络稳定性很差,时通时不通。成本约为150/年。
后来用的是美国 vps ,线路为 9929。延时比较高,但是丢包率对比香港低太多了,日均1%左右。成本约为200元/年。
在写本文之前,我的所有的服务都依赖于此 vps 提供的公网网络。而现在,我使用的是国内的阿里云广州折扣服务器,线路为三线BGP。成本为45元/年。
美国vps配置如下:
- 硬件
- 核心数:1 core
- 内存:1GB
- 硬盘:10G
- 网络
- 带宽:1000 Mbps
- 线路:9929
阿里云广州配置如下:
- 硬件
- 核心数:2 core
- 内存:2GB
- 硬盘:40G
- 网络
- 带宽:4 Mbps
- 线路:三网BGP
硬件配置已经完全足够,因为我并不依赖云上VPS提供的计算和存储,仅利用它的公网网络。
美国 vps 的网络纸面带宽很漂亮,其实并没有什么用,从国内连接是跑不满的。同时我家宽带上行是 30Mbps,按上文说的木桶效应,用美国 vps 穿透到家里的服务器,能提供的理论最大带宽也只会有 30Mbps。
现在之所以换成 广州的 4Mbps 服务器,是因为我可以通过 ddns + 端口映射
方式来实现大带宽场景。一些简单的网站,4Mbps 已经足够使用,例如笔记、密码管理、GPT机器人。
更新:已购入国内 300Mbps VPS,基本所有场景都可以覆盖和满足。
但是传言在高并发(QPS > 1000)时,frp 会有性能问题,我的服务暂时没有这么高的量级,遇到了再解决吧。
frp部署方式
下载时选择对应CPU架构的版本。
服务端 frps 部署
服务端部署在能够提供公网能力的vps上,请注意安全组和防火墙不要拦截 frp 服务端口,以便在家里部署的 frpc 可以主动访问 vps 上部署的 frps。
# 下载frp二进制包
wget https://github.com/fatedier/frp/releases/download/v0.51.3/frp_0.51.3_linux_amd64.tar.gz
# 解压缩
tar xf frp_0.51.3_linux_amd64.tar.gz
# 复制二进制到环境变量目录
cd frp_0.51.3_linux_amd64/
cp frps /usr/local/bin/
# 创建配置文件目录
mkdir /etc/frp
# 编辑配置文件
# vim /etc/frp/frps.ini
[common]
bind_addr = 0.0.0.0
bind_port = 7300
token = 178a634a52a077394fd2b53
tls_enable = true
log_file = /var/log/frps.log
log_level = info
log_max_days = 365
# 使用 systemd 管理frps,编辑配置文件
# vim /etc/systemd/system/frps.service
[Unit]
Description=Frp Server Service
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.ini
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
# 启动frps
systemctl start frps.service
# 配置开机自启
systemctl status frps.service
# 检查服务状态
# systemctl status frps.service
● frps.service - Frp Server Service
Loaded: loaded (/etc/systemd/system/frps.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2022-12-08 17:44:20 CST; 8 months 13 days ago
Main PID: 66650 (frps)
Tasks: 6 (limit: 2194)
Memory: 42.3M
CGroup: /system.slice/frps.service
└─66650 /usr/local/bin/frps -c /etc/frp/frps.ini
# netstate -anltup|grep 7300
tcp6 0 0 :::7300 :::* LISTEN 66650/frps
可以看到,frps 的配置项很简单
- bind_port = 7300 :监听7300作为服务端口
- token = 178a634a52a077394fd2b53:配置密钥,下文中 frpc 也配置成一样的
- tls_enable = true:开启tls混淆
客户端 frpc 部署
frpc 部署在家里虚拟机上。它会主动请求 frps。
下文以最简单的方式,将家里一台内网虚拟机的22端口穿透到公网。
# 下载frp二进制包
wget https://github.com/fatedier/frp/releases/download/v0.51.3/frp_0.51.3_linux_amd64.tar.gz
# 解压缩
tar xf frp_0.51.3_linux_amd64.tar.gz
# 复制二进制到环境变量目录
cd frp_0.51.3_linux_amd64/
cp frpc /usr/local/bin/
# 创建配置文件目录
mkdir /etc/frp
# 编辑配置文件
# vim /etc/frp/frpc.ini
[common]
server_addr = 8.134.***.***
server_port = 7300
token = 178a634a52a077394fd2b53
tls_enable = true
[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 20222
# 使用 systemd 管理frpc,编辑配置文件
# vim /etc/systemd/system/frpc.service
[Unit]
Description=Frp Client Service
After=network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.ini
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
# 启动frps
systemctl start frpc.service
# 配置开机自启
systemctl status frpc.service
# 检查服务状态
# systemctl status frps.service
● frpc.service - Frp Client Service
Loaded: loaded (/etc/systemd/system/frpc.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2023-08-17 09:33:50 CST; 5 days ago
Process: 31962 ExecReload=/usr/bin/frpc reload -c /etc/frp/frpc.ini (code=exited, status=0/SUCCESS)
Main PID: 18753 (frpc)
Tasks: 5
Memory: 8.7M
CGroup: /system.slice/frpc.service
└─18753 /usr/local/bin/frpc -c /etc/frp/frpc.ini
可以看到,frpc 的配置文件相比 frps 复杂一些
- [common] :此块用于定义公共配置,
- server_addr = 8.134.. :部署 frps 的 vps 公网IP
- server_port = 7300:frps 的端口
- token = 178a634a52a077394fd2b53:密钥,和 frps 配置保持一致
- tls_enable = true:开启tls混淆
- [ssh]:此块用于定义不同的映射规则,可以有多个,名字不冲突即可
- type = tcp:映射到公网的服务,在本地端口的类型
- local_ip = 127.0.0.1:映射到公网的服务,在本地的IP
- local_port = 22:映射到公网的服务,在本地的端口
- remote_port = 20222:映射到公网的服务,在公网服务器创建的端口
验证
首先我们在公网 vps 查看,由 frpc 向 frps 申请的端口是否已经成功监听
# netstat -anltup|grep 20222
tcp6 0 0 :::20222 :::* LISTEN 66650/frps
成功后,我们随便找台机器进行测试 ssh访问
# ssh root@8.134.180.141 -p 20222
root@8.134.180.141's password:
输入密码后,可以发现我们可以使用 公网 vps 的 IP 和 端口,ssh连接到家里的虚拟机。
部署 nginx 作为网关
实际使用中,我非常不建议把家里服务的端口直接穿透暴露在公网上。主要是因为安全问题,22 和 3389 这种远程控制端口暴露在公网极其不安全。同样的,其他服务端口也有一样的问题。
我在家里部署了 nginx 作为网关,统一控制家里所有服务的流量。nginx可以加密鉴权,也可以精细控制流量如何路由分发。
nginx如何部署与使用,部分步骤可以参考站内文章:使用 nginx 代理 tcp 端口,使用 acme 获取免费 https 证书
这里不再展开说明nginx配置,根据你的服务进行个性化定义。
ddns + 端口映射
适用场景
结论放前面
此方式适用:
- 对网络传输速率要求较高的服务。
- 对端口要求不敏感的服务。家庭宽带不能使用 80 443 等常见的web端口。
我通过此方式穿透到家里服务的有:
- plex流媒体服务,用来给媳妇在外面看家里下载好的影视剧
- nextcloud私人网盘,用来在外传输文件
如果你有足够的预算,其实可以不需要使用此方式。
- 云厂 vps 绑定按流量计费的公网IP,费用大约为 0.8 元/GB
- 云厂 vps 绑定按带宽计费的公网IP,费用大约为 20元/Mbps
家庭带宽,其实运营商本质上不希望你暴露在公网提供服务。原因很简单。家宽其实是国家补贴的,国家是高价出售商业带宽来补贴家用带宽。
流媒体服务也好,网盘服务也好,对传输速率的要求很高。最少云上的 4Mbps带宽是完全不能承载我的使用。让我在云上花几百元每月的价格购买和家宽同样能力的 30Mbps IP,我是万万舍不得的😂。
本方案的原理:
- 先从运营商处申请独立的公网IP,如果不申请,你和你的小区其他宽带用户其实是公用一个IP出口,光猫分配到的IP只是一个内网IP,是不能提供对外服务的。
- 申请到的公网IP是动态IP,每次重新拨号(路由器重启)等,IP 会发生改变。利用 ddns 方式,当IP发生变化时,可以将域名动态的解析到每次变更后的新IP上。
- 有了公网IP后,可以在路由器上配置端口映射,将
公网ip:port
映射到家里的内网ip:port
上。即实现服务对外提供访问。
公网IP获取
我的家宽使用的是电信,直接拨打电信人工客服 10000 号,说明自己需要公网IP即可。大约两小时左右后重启光猫,就可以获取到动态公网 IP 了。
每次重新拨号,公网 IP 地址都会发生改变。
请提前从运营商处获取到宽带的 账号
和 密码
。下文会使用到。
路由转桥接配置
默认光猫使用的是路由模式,路由模式下,拨号是由光猫完成的。以及下文所说的端口映射也需要配置在光猫上,因为是光猫拨号获取到的公网IP。
而桥接模式下,光猫仅用于做光电信号转换,拨号和端口映射都可以在路由器上实现。
根据光猫的 cidr 配置和型号,访问路由转桥接的后台页面地址也不一样。
我家光猫的IP是 192.168.1.1
,即访问 `http://192.168.1.1:8080/bridge_route.gch`就可以进行路由转桥接配置:
在转换为桥接模式后,此时光猫已经不承载拨号功能。并且家庭网络也会彻底断开。
需要在路由器上配置PPPoE
拨号上网。我使用的路由器是华硕 AC5300
。
WAN 联机类型:PPPoE
填入账号密码进行拨号。
配置界面:
ddns
ddns 的原理其实很简单。每次家里的公网 IP 变化后,有很多种方式可以获取到。当发生变化时,调用 dns 域名托管商的接口,更新你的域名解析。
我从 github 上找了一个:github.com/jeessy2/ddns-…
配置
# 下载二进制包
wget https://github.com/jeessy2/ddns-go/releases/download/v5.6.1/ddns-go_5.6.1_linux_x86_64.tar.gz
# 解压缩
tar xf ddns-go_5.6.1_linux_x86_64.tar.gz
# 启动服务,-f 参数 指定探测周期,单位为秒
./ddns-go -s install -f 60
# 检查服务状态
# systemctl status ddns-go.service
● ddns-go.service - 简单好用的DDNS。自动更新域名解析到公网IP(支持阿里云、腾讯云dnspod、Cloudflare、Callback、华为云、百度云、Porkbun、GoDaddy、Google Domain)
Loaded: loaded (/etc/systemd/system/ddns-go.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2023-08-20 20:28:53 CST; 2 days ago
Main PID: 14109 (ddns-go)
Tasks: 8
Memory: 6.3M
CGroup: /system.slice/ddns-go.service
└─14109 /data/scripts/ddns-go -l :9876 -f 60 -cacheTimes 5 -c /root/.ddns_go_config.yaml
Aug 22 23:56:42 centos-ops ddns-go[14109]: 2023/08/22 23:56:42 IPv4未改变,将等待 2 次后与DNS服务商进行比对
Aug 22 23:57:42 centos-ops ddns-go[14109]: 2023/08/22 23:57:42 IPv4未改变,将等待 1 次后与DNS服务商进行比对
Aug 22 23:58:44 centos-ops ddns-go[14109]: 2023/08/22 23:58:44 你的IP 27.16.212.229 没有变化, 域名 cdnsrc.bwbit.com
这个服务在执行 install 后,会做几件主要的事情:
- 使用 systemd 管理服务
- 生成配置文件,路径
/root/.ddns_go_config.yaml
- 提供 web端服务用于可视化编辑配置,端口为 9876
- 定时检查IP变化,将 IP 更新到配置文件指定的 dns 托管商和需要更新的域名
从浏览器使用 ip:port
访问服务,例如 192.168.2.10:9876
配置项目很简单:
- 选择 dns 托管商
- 填入访问密钥,cloudflare 上为 Token,阿里云是 ak sk
- 填入需要更新的域名
关于 cloudflare 和 阿里云如何分配访问密钥,可以参考站内文章:使用 acme 获取免费 https 证书
验证
在路由器上执行重新拨号,或者直接重启路由器。等待5~10分钟后,观察服务日志即可
systemctl status ddns-go.service
端口映射配置
各家路由器基本都可以实现端口映射,将 公网ip:port
映射到家里的 内网ip:port
上。即实现服务对外提供访问。
我以我家的 华硕 ac5300
示例:
补充配置 nginx 301跳转
端口映射的时候,外部端口是不能使用 80 443 等web端口的。而使用 65432 这种非标端口很难记忆。
我们可以在公网 vps 的 nginx 上配置 301 跳转,例如我想以 plex.com 对外提供服务,可以在nginx上配置如下规则,跳转到 media.plex.com 的 65432上去。
记忆 plex.com
比 media.plex.com:65432
,要简单的多,降低了记忆 url 的心智成本。
# vim test.conf
server {
listen 80;
server_name plex.com ;
satisfy any;
return 301 https://media.plex.com:65432$request_uri;
}
server {
listen 443 ssl http2;
server_name plex.com;
satisfy any;
return 301 https://media.plex.com:65432$request_uri;
}
CDN
frp 和 ddns 方式,各有长短。上文已经讨论了它们的使用场景。
那么如何综合它们的优点呢,例如我即希望能够使用家宽的 30Mbps上行,又希望以 80 443 端口提供公开的 web 服务。
使用 cdn 方式可以解决。
我们还是需要用到 ddns + 端口映射
,将服务暴露在公网出来。然后使用cdn,配置暴露出来的 域名:端口
作为源站,让 cdn 进行回源。
cdn 本身是可以提供 80 和 443 端口的,并且可以隐藏你的后端,除了 cdn 厂商,没人会知道你的源站是什么,提供了很好的保护能力。
这依赖于 cdn 在配置源站时,可以自定义端口,并不是每家cdn厂商都可以做到,经过我实际验证较为知名的cdn厂商发现:
可以自定义源站端口的厂商有:
- 腾讯云
- 阿里云
不支持自定义源站端口的厂商有
- 华为云
- 七牛云
- 火山引擎
而目前我使用的是腾讯云,因为它对比阿里云的优点有:可以实现 QPS限流,带宽阈值限制,总流量限制。这样可以很大避免被攻击产生高额费用。
并且腾讯云提供了半年免费的100GB流量包,已经足够本站使用了。
这里不详述如何进行 cdn 配置,各家 cdn 厂商都会有详细的文档和专业的客服,贴几张图参考下即可:
结论
不同的网络方案没有高低之别,我详细说明了每种方案的优缺点和适用场景。针对不同的需求选择合适的方式即可。