先上图,再说具体的内容
一直都在用腾讯云的机器,当时候也有优惠力度比较大活动,就买了一台4核16G内存的云服务器,因为自己做了一些APP啥的,这个配置也能带动需要用的服务,就用了2年左右吧,但是现在快到期了,续费又太贵了,也没有什么类似配置的活动了,直接买同规格的更买不起了,发愁的狠。
后来就想到了家里弄一台本地服务器,正好有个公网IP,于是说干就干,前面的 铭凡X500+5600G迷你主机搭建PVE+爱快+CentOS+网心云 这篇文章就是组的本地服务器的配置,加上网心云的收益正好抵了电费,就很划算。
因为用的东西比较多,此处记录下来方便以后维护使用
准备内容
- 能够装的爱快软路由
- 家庭服务器
- 公网IP服务器(随便一台即可,能装Nginx和PHP就行)
访问逻辑
分为两部分,一部分是内部业务程序主动检测IP进行上报公网IP服务器,另一部分时客户端访问服务器端的逻辑
1. 定时任务
在自己业务程序中增加一个定时任务,然后每隔三秒调用一次爱快的获取拨号IP的接口。
爱快登录后并获取拨号IP的接口请求内容如下
请求地址:http://192.168.123.1/Action/login , 此处的192.168.123.1为爱快的LAN地址,其实就是登录页面地址
http请求内容:
POST /Action/login HTTP/1.1
Host: 192.168.123.1
Content-Type: application/json
Content-Length: 129
{"username":"mrdong916","passwd":"6bbb75c7756b86ec9f69a8fb3ed46110","pass":"c2FsdF8xMURvbmczOTQzOTRA","remember_password":"true"}
passwd的计算逻辑:登录密码MD5后小写
pass的计算逻辑:salt_11+MD5后的密码进行Base64
登录后返回头中会返回一个Cookie,保存此Cookie即可
然后使用Cookie获取PPPOE拨号信息
POST /Action/call HTTP/1.1
Host: 192.168.123.1
Cookie: sess_key=6769ac2fae1be461c19dae8af8f62e36;
Content-Type: application/json
Content-Length: 68
{"func_name":"wan","action":"show","param":{"id":"1","TYPE":"data"}}
获取到的信息如下
{
"Result": 30000,
"ErrMsg": "Success",
"Data": {
"data": [
{
"pppoe_ip_addr": "222.xxx.xxx.125",
"pppoe_netmask": "255.255.255.255",
"pppoe_gateway": "222.xxx.xxx.1",
"pppoe_updatetime": 1695151198,
"pppoe_dns1": "202.xxx.xxx.68",
"pppoe_dns2": "202.xxx.xxx.68",
"pppoe_macremote": "14:23:0a:a5:49:4e",
"dhcp_ip_addr": "",
"dhcp_netmask": "",
"dhcp_gateway": "",
"dhcp_updatetime": 0,
"dhcp_dns1": "",
"dhcp_dns2": "",
"dhcp_lease": 0,
"bandmode": 0,
"internet": 2,
"mac": "",
"speed": 0,
"duplex": 0,
"upload": 0,
"download": 0,
"qos_upload": 512000,
"qos_download": 5120000,
"vendorclass": "",
"clientid": "",
"hostname": "",
"opt_type12": 0,
"opt_type60": 0,
"opt_type61": 0,
"wifi_wisp": 1,
"wifi_bssid": "",
"wifi_ssid": "",
"wifi_psk": "",
"ip_mask": "",
"gateway": "",
"username": "03xxxxxxxx38",
"passwd": "123456",
"timing_rst_switch": 0,
"timing_rst_week": "1234567",
"timing_rst_time": "12:00",
"cycle_rst_time": 0,
"pppoe_service": "",
"pppoe_ac": "",
"mtu": 1480,
"mru": 1480,
"default_route": 1,
"disc_auto_switch": 0,
"link_time": "00:00-23:59",
"check_link_mode": 3,
"check_link_host": "www.baidu.com",
"qos_switch": 1,
"enable_ipv6": 0,
"linkmode": 0,
"policy": 1,
"lte_service": "umts_gprs",
"lte_mode": "auto",
"lte_apn": "3gnet",
"lte_dialnum": "*99#",
"lte_pincode": "",
"lte_antenna_switch": 0,
"pppoe_ass_switch": 1,
"ass_multi_total": 3,
"ass_disc_rst_switch": 1,
"ass_rst_check_week": "1234567",
"ass_rst_check_time": "00:00-23:59",
"ass_rst_check_interval": 10,
"ass_rst_disc_num": 2,
"ass_rst_disc_norestart": 0,
"ass_check_errip_switch": 0,
"ass_check_errip_list": "10,172,192.168",
"dhcp_status": 0,
"pppoe_check_errip_switch": 0,
"pppoe_check_errip_list": "10,172,192.168",
"id": 1,
"modified_time": 1693749748,
"comment": "",
"name": "wan1",
"bandif": "84:47:09:1d:76:c4",
"pppoe_status": 2
}
]
}
}
返回内容中的pppoe_ip_addr
就是拨号的IP,利用定时任务进行对比上次和获取的IP是否一致,如果不一致则请求公网服务器的PHP接口,来重写反向代理配置信息,然后重载配置。
2.PHP接口
先贴一下需要请求的网站的Nginx配置文件
server
{
listen 80;
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen [::]:80;
server_name xxx.xxx.cn;
index index.php index.html index.htm default.php default.htm default.html;
root /www/wwwroot/xxx.xxx.cn;
#SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则
#error_page 404/404.html;
ssl_certificate /www/server/panel/vhost/cert/xxx.xxx.cn/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/xxx.xxx.cn/privkey.pem;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
add_header Strict-Transport-Security "max-age=31536000";
error_page 497 https://$host$request_uri;
#SSL-END
#ERROR-PAGE-START 错误页配置,可以注释、删除或修改
#error_page 404 /404.html;
#error_page 502 /502.html;
#ERROR-PAGE-END
# 最重要的是这行 ↓
include /www/wwwroot/127.0.0.1/ip.conf;
# 最重要的是这行 ↑
#PHP-INFO-START PHP引用配置,可以注释或修改
include enable-php-00.conf;
#PHP-INFO-END
#REWRITE-START URL重写规则引用,修改后将导致面板设置的伪静态规则失效
include /www/server/panel/vhost/rewrite/6api.itooi.cn.conf;
#REWRITE-END
#禁止访问的文件或目录
location ~ ^/(\.user.ini|\.htaccess|\.git|\.env|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
#一键申请SSL证书验证目录相关设置
location ~ \.well-known{
allow all;
}
#禁止在证书验证目录放入敏感文件
if ( $uri ~ "^/\.well-known/.*\.(php|jsp|py|js|css|lua|ts|go|zip|tar\.gz|rar|7z|sql|bak)$" ) {
return 403;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log /dev/null;
access_log /dev/null;
}
location ~ .*\.(js|css)?$
{
expires 12h;
error_log /dev/null;
access_log /dev/null;
}
access_log /www/wwwlogs/xxx.xxx.cn.log;
error_log /www/wwwlogs/xxx.xxx.cn.error.log;
}
上面的配置文件中的这句include /www/wwwroot/127.0.0.1/ip.conf;
非常重要,这句是将PHP接口的网站的ip.conf
文件引入,以便于后面利用PHP进行修改配置文件,文件内容如下
#PROXY-START/
location ^~ /
{
proxy_pass http://222.xxx.xxx.125:xxx;
proxy_set_header Host xxx.xxx.cn;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_http_version 1.1;
# proxy_hide_header Upgrade;
add_header X-Cache $upstream_cache_status;
#Set Nginx Cache
set $static_filepdwGFDzU 0;
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
{
set $static_filepdwGFDzU 1;
expires 1m;
}
if ( $static_filepdwGFDzU = 0 )
{
add_header Cache-Control no-cache;
}
}
#PROXY-END/
ip.conf
配置中的proxy_set_header Host xxx.xxx.cn
和proxy_pass http://222.xxx.xxx.125:xxx;
根据自己的情况进行修改,后续会动态修改proxy_pass参数的对应的IP地址
PHP默认是禁用shell_exec
函数,需要开启该函数,具体的接口文件 nginx.php
如下
<?php
$key = $_GET['key'];
$ip = $_GET['ip'];
header('Content-Type: application/json');
if ($key == 'nginx_reload') {
// 重载nginx 配置
$res = shell_exec("/www/server/nginx/sbin/nginx -s reload");
echo '{"code":200,"msg":"ok"}';
return;
}else if ($key == 'nginx_update') {
// 读取当前目录下的ip.conf
$res = shell_exec("cat ip.conf");
$pattern = '/proxy_pass http:\/\/(.*?):8223;/i';
// 正则匹配需要替换的IP
preg_match($pattern,$res, $matches);
// var_dump($matches);
// 替换IP为新的IP
$res = str_replace('http://'.$matches[1],'http://'.$ip,$res);
// echo $res;
// 将替换过IP的内容覆盖旧的配置文件
file_put_contents("ip.conf",$res);
// 重载nginx 配置
$res2 = shell_exec("/www/server/nginx/sbin/nginx -s reload");
echo '{"code":200,"msg":"ok"}';
return;
}else if ($key == 'nginx_get') {
// 读取当前目录下的ip.conf
$res = shell_exec("cat ip.conf");
$pattern = '/proxy_pass http:\/\/(.*?):8223;/i';
// 正则匹配获取当前的IP
preg_match($pattern,$res, $matches);
echo '{"code":200,"msg":"ok","data":'.json_encode($matches[1]).'}';
return;
}
echo '{"code":403,"msg":"error"}';
?>
在公网服务器上新建一个网站,里面放入nginx.php
,然后通过定时任务的HTTP进行请求来更新和重载nginx
3. 客户端访问
假设我在公网上的域名为api.bzqll.com
,那客户端就去请求api.bzqll.com
,nginx读取对应的反向代理配置,请求反向代理配置文件中的IP,其实就是访问家里动态公网IP,然后到家庭服务器中去,也就实现了不暴露家宽IP还能使用家宽服务器的问题,nginx反向代理是可以抗住超大的访问的,这样也没有内网穿透软件的性能问题。
其他
其实之前是有考虑过跟公网组建一个局域网的,但是嫌弃麻烦还要搭建东西,有可能还会被运营商屏蔽的问题,就放弃了。另外就是也考虑过内网穿透的方案,但是见到网上说有连接数、并发性能以及稳定性的问题,也放弃了。最终还是采用nginx反代的方案,至少不会因为性能和连接,切记家宽端口用数值比较大的端口,还有不要带域名进行访问。
2 条评论
域名做ddns解析,然后域名加端口的形式能行不,避免了修改nginx和重载nginx?也就是最后不要带域名进行访问是为啥?
使用域名DDNS过去是没有问题,但是域名这个会在请求的客户端存在DNS缓存,如果是IP,则是直连,不存在IP问题,还有就是域名解析到家宽IP可能会被运营商逮住私设服务器,而IP大端口通信则稍微好一点