1 环境
在家里电脑部署了一个 nextcloud 服务,想实现在公网访问,可以利用 frp 实现内网穿透,用 IP 端口来访问。但是暴露一个端口不是很优雅,网上林林总总的有一些教程是通过二级域名 + 端口或三级域名的方式实现的,实践起来存在诸多问题。本文介绍一种较为全面教程,使用 Nginx 加 frp 的方式,实现三级域名访问到 nextcloud 的服务。
一台公网云服务器 A, 举例,ip 地址:101.12.12.12。
家里的内网机器 B,部署 nextcloud 服务,ip 地址:192.168.14.64, 部署的端口 443
一个顶级域名abc.com,域名做 A 记录,nextcloud.abc.com 指向公网云服务机器 ip 101.12.12.12
软件 frp,Frp 是一款开源的反向代理工具,能够帮助我们反向代理出在内网的服务,下载地址,frp 下载地址
目标:实现通过
https://nextcloud.abc.com访问部署在家里的 nextcloud 服务。
2 frp部署
frp 分为服务端和客户端两部分,公网云服务器上安装服务端,家里内网服务器上安装客户端。
2.1 frp服务端
首先在云服务器 A 上部署 frps 服务端,这里的版本是frp_0.38.0_linux_amd64.tar.gz
切换到/root下
cd /root
frp_0.38.0_linux_amd64.tar.gz放于/root下,解压
tar -zxf frp_0.38.0_linux_amd64.tar.gz
建立软连接
ln -s /root/frp_0.38.0_linux_amd64 /root/frp
编辑配置frps.ini,修改如下
[common]
bind_addr = 0.0.0.0
#默认为7000端口,需要在公网云服务器的安全组中打开。
bind_port = 7000
#内网穿透http协议的统一访问端口,http配置vhost_http_port,https配置vhost_https_port,
#所有的frp客户端http都是由vhost_http_port代理,所有的https都是由vhost_https_port代理。
vhost_http_port = 28800
vhost_https_port = 28443
#frpc客户端连接Frps服务端时的token[可选,为了增强安全,建议设置]
privilege_token = xxxxxxx
#web端管理控制面板相关配置[可选],37500也是需要在公网云服务器的安全组打开,如果不用再次进行关闭
dashboard_port = 37500
dashboard_user = admin
dashboard_pwd = xxxxxxx如果需要启动,直接使用/root/frp/frps -c /root/frp/frps.ini 命令启动即可。
可选使用 systemd 控制 frps 服务端的启动,停止,后台运行和开机自启动。
创建 /root/frps.service 文件,添加如下配置
[Unit]
# 服务名称,可自定义
Description=Frp Server Service
After=network.target
[Service]
Type=simple
User=root
Restart=on-failure
RestartSec=5s
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart=/root/frp/frps -c /root/frp/frps.ini
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target将该文件移动到/etc/systemd/system,
mv /root/frps.service /etc/systemd/system
使用 systemd 管理 frps 服务
#启动frps服务
systemctl start frps
#关闭frps服务
systemctl stop frps
#重启frps服务
systemctl restart frps
#查看frps状态
systemctl status frps
#开启自启动frps
systemctl enable frps2.2 frp客户端
登录到家里的部署 nextcloud 内网服务器上,将frp_0.38.0_linux_amd64.tar.gz上传到 /root 下
切换到/root下
cd /root
frp_0.38.0_linux_amd64.tar.gz放于/root下,解压
tar -zxf frp_0.38.0_linux_amd64.tar.gz
建立软连接
ln -s /root/frp_0.38.0_linux_amd64 /root/frp
编辑 frpc.ini 文件,修改如下:
[common]
#公网云服务器的ip地址
server_addr = 101.12.12.12
#在frps.ini中配置的端口
server_port = 7000
#在frps.ini中配置的token
privilege_token = xxxxx
# 启用admin端口,提供API服务,用于客户端配置文件热加载[可选]
admin_addr = 127.0.0.1
admin_port = 7400
admin_user = admin
admin_pwd = xxxxx
#nextcloud的web配置方式
[nextcloud]
#这里采用https方式
type = https
#本机的内网ip地址
local_ip = 192.168.14.64
#nextcloud的服务端口
local_port = 443
#配置在frps.ini中配置的vhost_https_port
remote_port = 28443
#这里是解析到公网101.12.12.12的域名
custom_domains = nextcloud.abc.com
#启用加密[可选]
use_encryption = true
#启用压缩[可选]
use_compression = true如果需要启动,直接使用/root/frp/frpc -c /root/frp/frpc.ini 命令启动即可。
可选使用 systemd 控制 frps 服务端的启动,停止,后台运行和开机自启动。
创建 /root/frpc.service 文件,添加如下配置
[Unit]
# 服务名称,可自定义
Description=Frp client Service
After=network.target
[Service]
Type=simple
User=root
Restart=on-failure
RestartSec=5s
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart=/root/frp/frpc -c /root/frp/frpc.ini
# reload配置文件
ExecReload=/root/frp/frpc reload -c /root/frp/frpc.ini
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target将该文件移动到/etc/systemd/system,
mv /root/frpc.service /etc/systemd/system
使用 systemd 管理 frpc 服务
#启动frpc服务
systemctl start frpc
#关闭frpc服务
systemctl stop frpc
#重启frpc服务
systemctl restart frpc
#查看frpc状态
systemctl status frpc
#开启自启动frpc
systemctl enable frpc3 宝塔添加nginx代理
在公网云服务器上,使用宝塔安装 nginx, 版本是 nginx 1.22.1,添加反向代理。如下图所示:




ssl 域名申请完毕后,使用 https://nextcloud.abc.com 访问报 502 网关异常。这是由于使用 nginx 反代 https 的引发的。接下来详细阐述该问题的解决思路。
3.1 nginx反代https 502异常
查询了相关资料发现很少。如果没有必须使用 Nginx 的需求,可以直接使用 frp 绑定 80 和 443 端口即可。 如果必须使用 Nginx 作为前端(比如反向代理服务器上还有其他网站),这时你会发现常规 https 访问就会直接返回 502 了。
如下 nginx 的一份样例配置:
server {
listen 80;
listen 443 ssl http2 ;
listen [::]:80;
listen [::]:443 ssl http2 ;
server_name nextcloud.abc.com;
ssl_certificate /www/server/panel/vhost/cert/nextcloud.abc.com/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/nextcloud.abc.com/privkey.pem;
location ^~ / {
proxy_pass https://127.0.0.1:28443;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_ssl_server_name on;
proxy_connect_timeout 60s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
}看上去还是很合理的,但是访问就会出现 502,在客户端和 nginx 日志中也没找到有用的信息。
在frp 671 issue找到了解决思路。
个人推测:frp 在反向代理 https 的时候,因为 Nginx 已经处理过了 https 的握手信息。所以, Frp 无法获取到 SNI 信息,导致发送请求的时候就是不完整的 https 请求。如果改成 http 或者 tcp 反向代理都能成功,个人认为是 Frp 的问题,访问的域名变成 127.0.0.1,没有 SNI 信息。因此,在上面那份配置的情况下,可以通过域名 + 端口号成功访问。
解决方案:
在反向代理前使用动态域名解析。具体如下:
由于在公网云服务器使用的 ubuntu 系统,ubuntu 默认使用了 systemd-resolved 的 DNS 服务,因此在公网云服务器的 /etc/hosts 中加入127.0.0.1 nextcloud.abc.com映射,systemd-resolved 默认会读取 /etc/hosts 文件,完成域名的解析服务。
使用 resolvectl query 命令检测解析是否生效
resolvectl query nextcloud.abc.com
若显示 nextcloud.abc.com: 127.0.0.1表示配置成功。
如果没有成功,可以强制刷新生效,需要重启 systemd-resolved 服务。
systemctl restart systemd-resolved
改造后的 nginx 配置文件如下:
server {
listen 80;
listen 443 ssl http2 ;
listen [::]:80;
listen [::]:443 ssl http2 ;
server_name nextcloud.abc.com;
ssl_certificate /www/server/panel/vhost/cert/nextcloud.abc.com/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/nextcloud.abc.com/privkey.pem;
location ^~ / {
resolver 127.0.0.53;#使用systemd-resolved动态域名解析
proxy_pass https://$host:28443; #改造为https://$host:28443
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-Port $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_ssl_server_name on;
proxy_connect_timeout 60s;
proxy_send_timeout 600s;
proxy_read_timeout 600s;
}
}在宝塔中具体修改如下:


记得重新加载 nginx 配置。
再次访问 https://nextcloud.abc.com, 就正常了。
4 总结
虽然整体上配置和实践的过程踩了很多坑,但是,通过不断查阅资料,完善资料,提升了自身的能力。上述过程可以扩展很多的网站。同时,也为了想把 web 服务部署在家里的小伙伴们提供了一种思路和方案,控制了成本。希望可以帮助到各位,如果疑问,欢迎来信。
评论区