20251222 frp与nginx实现多端口多域名访问外网
20251222 frp与nginx实现多端口多域名访问外网
要实现群晖通过 frp 结合 Nginx 实现多端口 / 多域名对外访问,核心思路是:
- 服务器端(公网)部署
frps接收转发流量,并用Nginx做域名反向代理(把域名映射到 frps 转发的端口); - 群晖端(内网)部署
frpc,配置多个端口转发规则,将群晖内不同应用的端口映射到 frps 服务器; - 配合域名解析(A 记录指向 frps 服务器 IP),最终实现「域名→Nginx→frps→frpc→群晖应用」的流量链路。
1227最终实现配置
群晖系统设置
客户端 frpc.toml
/usr/local/frp/frpc.toml
serverAddr = "47.113.x.x"
serverPort = 7000
auth.method = "token"
auth.token = "***"
[[proxies]]
name = "dsm"
type = "http"
localIp = "127.0.0.1"
localPort = 5000
customDomains = ["nas.liufeisheng.cn"]
[[proxies]]
name = "test"
type = "http"
localIp = "127.0.0.1"
localPort = 5050
customDomains = ["test.liufeisheng.cn"]
[[proxies]]
name = "jxcg"
type = "http"
localIp = "127.0.0.1"
localPort = 8080
customDomains = ["jxcg.liufeisheng.cn"]
[[proxies]]
name = "dh"
type = "http"
localIp = "127.0.0.1"
localPort = 81
customDomains = ["dh.liufeisheng.cn"]
[[proxies]]
name = "blog"
type = "http"
localIp = "127.0.0.1"
localPort = 8081
customDomains = ["blog.liufeisheng.cn"]
[[proxies]]
name = "crm"
type = "http"
localIp = "127.0.0.1"
localPort = 8082
customDomains = ["crm.liufeisheng.cn"]
群晖中nginx配置
/etc/nginx/sites-enable/nas1.conf
- 注意群晖有自带的nginx软件,它的设置中默认加载/etc/nginx/sites-enable目录下的配置文件,所以新建配置文件得放在该目录下,放到/etc/nginx/conf.d/并不能生效
server {
listen 0.0.0.0:5050;
server_name test.liufeisheng.cn;
root /var/services/homes/fei/www/test;
index index.html index.htm;
access_log /var/services/homes/fei/www/nginx_logs/localhost_access.log;
error_log /var/services/homes/fei/www/nginx_logs/localhost_error.log;
location / {
try_files $uri $uri/ =404;
allow all;
autoindex off;
default_type text/html;
}
}
server {
listen 0.0.0.0:81;
server_name dh.liufeisheng.cn;
root /var/services/homes/fei/www/digitalhum;
index index.html index.htm;
access_log /var/services/homes/fei/www/nginx_logs/dh_access.log;
error_log /var/services/homes/fei/www/nginx_logs/dh_error.log;
location / {
try_files $uri $uri/ =404;
allow all;
autoindex off;
default_type text/html;
proxy_redirect ~*:5001(.*) /$1;
}
}
server {
listen 0.0.0.0:8080;
server_name jxcg.liufeisheng.cn;
root /var/services/homes/fei/www/jxcg;
index index.html index.htm;
access_log /var/services/homes/fei/www/nginx_logs/jxcg_access.log;
error_log /var/services/homes/fei/www/nginx_logs/jxcg_error.log;
location / {
try_files $uri $uri/ =404;
allow all;
autoindex off;
default_type text/html;
proxy_redirect ~*:5001(.*) /$1;
}
}
云服务器配置
云服务器的frps.toml配置
/usr/local/frp/frps.toml
bindAddr = "0.0.0.0"
bindPort = 7000
#kcpBindPort = 7000
quicBindPort = 7000
vhostHTTPPort = 8080
vhostHTTPSPort = 8443
transport.maxPoolCount = 2000
transport.tcpMux = true
transport.tcpMuxKeepaliveInterval = 60
transport.tcpKeepalive = 7200
transport.tls.force = flase
transport.tls.certFile = "/etc/letsencrypt/live/liufeisheng.cn/fullchain.pem"
transport.tls.keyFile = "/etc/letsencrypt/live/liufeisheng.cn/privkey.pem"
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "***"
webServer.pprofEnable = false
log.to = "./frps.log"
log.level = "info"
log.maxDays = 3
log.disablePrintColor = false
auth.method = "token"
auth.token = "***"
allowPorts = [
{ start = 1000, end = 50000 }
]
- transport.tls.force = flase ,注意这一条,原先是true。强制 frps 只接受 TLS 加密的传输连接,包括用户流量部分)
这意味着 frps 期望用户访问 HTTP 子域名的流量必须是 HTTPS(TLS 加密后)的请求到达 vhostHTTPPort,但实际上 Nginx 已经解密了 TLS,并发送 明文 HTTP 请求到 127.0.0.1:8080。
frps 检测到是非 TLS 流量,直接拒绝或无法正确处理,导致这些 HTTP proxy(test、dh、jxcg 等)失败,返回错误(如 502、连接拒绝或空白页)。
云服务器的nginx配置
/etc/nginx/conf.d/nas.conf
# 80 端口统一跳转 HTTPS
server {
listen 80;
server_name *.liufeisheng.cn liufeisheng.cn;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name *.liufeisheng.cn;
ssl_certificate /etc/letsencrypt/live/liufeisheng.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/liufeisheng.cn/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
具体实现过程
一、整体架构梳理
用户访问 → 域名(如 nas-app1.com)→ DNS解析 → 公网服务器IP
↓
公网服务器 Nginx → 根据域名反向代理到 frps 监听的端口
↓
公网服务器 frps → 转发流量到内网群晖的 frpc
↓
内网群晖 frpc → 转发到群晖内对应应用的端口(如8080/5000等)
- 服务端:
- Nginx:负责处理
liufeisheng.cn及其子域名的 HTTP 和 HTTPS 请求。80 端口请求重定向到 443 端口,443 端口请求代理到本地 8080 端口。 - frps:运行在服务器上,监听 7000 端口(TCP 和 QUIC 协议)与 frpc 客户端通信。设置了虚拟主机 HTTP 端口为 8080,HTTPS 端口为 8443。
- 客户端:
- frpc:通过配置文件
frpc.toml连接到服务端的 frps,将本地不同端口的服务通过 frps 映射到特定的子域名。 - Nginx:在客户端监听不同端口,为不同子域名提供服务,处理静态文件等请求。
二、前置准备
- 公网服务器:有公网 IP,安装
frps+Nginx; - 群晖:安装
frpc(群晖可通过 Docker、手动安装二进制包实现); - 域名:提前将多个域名(如
nas-app1.com、nas-file.com)解析到公网服务器的 IP; - 端口放行:公网服务器需放行
frps端口(如 7000)、Nginx 的 80/443 端口;群晖所在内网无需放行端口(frp 是主动连接)。
三、分步配置
第一步:公网服务器配置 frps
frps 负责接收 frpc 的连接,并转发 Nginx 过来的流量。
1. 安装 frps(以 Linux 为例)
2. 配置 frps.toml(核心:监听端口 + 授权)
- /usr/local/frp/frps.toml
bindAddr = "0.0.0.0"
bindPort = 7000
#kcpBindPort = 7000
quicBindPort = 7000
vhostHTTPPort = 8080
vhostHTTPSPort = 8443
transport.maxPoolCount = 2000
transport.tcpMux = true
transport.tcpMuxKeepaliveInterval = 60
transport.tcpKeepalive = 7200
transport.tls.force = true
transport.tls.certFile = "/etc/letsencrypt/live/liufeisheng.cn/fullchain.pem"
transport.tls.keyFile = "/etc/letsencrypt/live/liufeisheng.cn/privkey.pem"
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "***"
webServer.pprofEnable = false
log.to = "./frps.log"
log.level = "info"
log.maxDays = 3
log.disablePrintColor = false
auth.method = "token"
auth.token = "***"
allowPorts = [
{ start = 1000, end = 50000 }
]
maxPortsPerClient = 8
udpPacketSize = 1500
natholeAnalysisDataReserveHours = 168
3. 启动 frps(后台运行)
# 直接启动(测试)
nohup frps -c /usr/local/bin/frps.ini > /var/log/frps.log 2>&1 &
# 推荐:配置systemd服务(开机自启)
cat > /etc/systemd/system/frps.service << EOF
[Unit]
Description=frps service
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /usr/local/bin/frps.ini
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
# 启动并设置开机自启
systemctl daemon-reload
systemctl start frps
systemctl enable frps
第二步:群晖配置 frpc(多端口转发)
群晖需配置 frpc,将内部不同应用的端口映射到 frps 服务器的不同端口(或用自定义域名)。
1. 安装 frpc(群晖两种方式)
-
方式 1:Docker 安装(推荐)群晖 Docker 搜索
frpc,选择snowdreamtech/frpc镜像,启动时挂载配置文件。 -
方式 2:手动安装下载 frp 的 arm/amd64 版本(对应群晖 CPU),上传到
/volume2/@appstore/frpc/目录,赋予执行权限:
bash
chmod +x /volume1/@appstore/frpc/frpc
2. 配置 frpc.toml(核心:多应用端口映射)
- /usr/local/frp/frpc.toml
1 serverAddr = "47.113.x.x"
2 serverPort = 7000
3
4 auth.method = "token"
5 auth.token = "***"
6
7 [[proxies]]
8 name = "dsm"
9 type = "http"
10 localIp = "127.0.0.1"
11 localPort = 5000
12 customDomains = ["nas.liufeisheng.cn"]
13
14 [[proxies]]
15 name = "dsm_https"
16 type = "https"
17 localIp = "127.0.0.1"
18 localPort = 5001
19 customDomains = ["nas.liufeisheng.cn"]
20
21 [[proxies]]
22 name = "test"
23 type = "https"
24 localIp = "127.0.0.1"
25 localPort = 5050
26 customDomains = ["test.liufeisheng.cn"]
27
28 [[proxies]]
29 name = "blog"
30 type = "http"
31 localIp = "127.0.0.1"
32 localPort = 8081
33 customDomains = ["blog.liufeisheng.cn"]
3. 启动 frpc(群晖开机自启)
systemctl start frpc
systemctl status frpc
systemctl enable frpc
第三步:公网服务器配置 Nginx(域名反向代理)
Nginx 的作用是:将「域名」映射到 frps 暴露的端口,实现域名访问(而非端口),同时可配置 HTTPS。
1. 安装 Nginx(公网服务器)
# CentOS
yum install nginx -y
# Ubuntu/Debian
apt install nginx -y
2. 配置 Nginx 虚拟主机(多域名映射)
修改配置文件 /etc/nginx/conf.d/nas.conf,内容如下(每个域名对应一个 server 块,代理到 frps 的对应端口):
server {
listen 80;
server_name www.liufeisheng.cn;
location / {
proxy_pass http://127.0.0.1:82;
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;
}
location /crm {
proxy_pass http://127.0.0.1:83;
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;
}
location /messages {
proxy_pass http://127.0.0.1:8082;
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;
}
}
server {
listen 80;
server_name blog.liufeisheng.cn;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
server {
listen 80;
server_name crm.liufeisheng.cn;
location / {
proxy_pass http://127.0.0.1:83;
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;
}
}
server {
listen 84;
server_name dh.liufeisheng.cn;
root /usr/local/digitalhum;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name jp.liufeisheng.cn;
location / {
proxy_pass http://127.0.0.1:8888;
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;
}
}
server {
listen 80;
server_name nas.liufeisheng.cn;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
server{
listen 80;
server_name jxcg.liufeisheng.cn;
root /usr/local/www/jxcg;
index index.html;
location / {
try_files $uri $uri/ = 404;
}
}
server {
listen 80;
server_name test.liufeisheng.cn;
location / {
proxy_pass http://127.0.0.1:8080;
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;
}
}
3. 配置 HTTPS(可选,推荐)
用 Let’s Encrypt 免费证书,自动配置 HTTPS:
# 安装certbot
apt install certbot python3-certbot-nginx -y # Ubuntu
# 自动申请证书并配置Nginx
certbot --nginx -d nas-admin.com -d nas-photo.com -d nas-download.com
4. 重启 Nginx
nginx -t # 测试配置是否正确
systemctl restart nginx
申请泛域证书
不能通过https协议访问的原因
Nginx 仅配置了 80 端口(HTTP)的反向代理,完全缺失 443 端口(HTTPS)的配置;同时 frps 的 HTTPS 转发链路(vhostHTTPSPort=8443)未被 Nginx 代理,导致 HTTPS 请求无匹配的服务器配置,直接被 Nginx 拒绝 / 返回默认页。
以下是问题拆解和完整的 HTTPS 配置解决方案:
一、核心问题拆解
1. Nginx 无 443 端口配置(最关键)
你的 Nginx 配置中所有 server 块仅监听 80 端口(HTTP),没有任何 listen 443 ssl; 的配置。当浏览器用 HTTPS 访问 test.liufeisheng.cn/blog.liufeisheng.cn 时:
- 请求会发送到服务器 443 端口,但 Nginx 未监听该端口(或监听了但无匹配的
server块); - 最终返回「无法访问」「证书错误」或 Nginx 默认的 443 端口响应(若未配置则直接拒绝)。
2. frps 的 HTTPS 转发链路未被 Nginx 代理
frps 配置了 vhostHTTPSPort = 8443(HTTPS 类型 frp 代理的端口),但你的 Nginx 没有将 443 端口的请求代理到 frps 的 8443 端口,导致 HTTPS 流量无法进入 frp 转发链路。
3. 证书缺失
HTTPS 访问需要域名对应的 SSL 证书,你虽为 nas.liufeisheng.cn 配置了证书,但 test/blog 域名未配置证书,即使监听 443 端口也会报证书错误。
二、完整解决方案(配置 Nginx HTTPS + 对接 frps 8443 端口)
第一步:申请泛域名证书(推荐,覆盖所有子域名)
为避免每个域名单独申请证书,建议申请 *.liufeisheng.cn 泛域名证书(Let's Encrypt 免费),一次性覆盖 test/blog/nas 等所有子域名:
# 安装 certbot
apt install certbot python3-certbot-nginx -y # Ubuntu/Debian
# yum install certbot python3-certbot-nginx -y # CentOS
# 申请泛域名证书(需手动验证 DNS,按提示添加 TXT 记录)
certbot certonly --manual --preferred-challenges dns -d *.liufeisheng.cn -d liufeisheng.cn
证书生成后,路径通常为:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/liufeisheng.cn/fullchain.pem
Key is saved at: /etc/letsencrypt/live/liufeisheng.cn/privkey.pem
This certificate expires on 2026-03-22.
These files will be updated when the certificate renews.
- 证书:
/etc/letsencrypt/live/liufeisheng.cn/fullchain.pem - 私钥:
/etc/letsencrypt/live/liufeisheng.cn/privkey.pem
第二步:修改 Nginx 配置(添加 443 端口 HTTPS 代理)
在现有 Nginx 配置中,为 test.liufeisheng.cn、blog.liufeisheng.cn、nas.liufeisheng.cn 添加 443 端口的 HTTPS 配置,代理到 frps 的 vhostHTTPSPort=8443(HTTPS 转发)或 vhostHTTPPort=8080(HTTP 转发,通过 Nginx 加密为 HTTPS)。
完整的 Nginx 配置
# ========== 预定义映射表(新增子域名仅需加一行) ==========
# 注意:静态文件域名单独标记,不写在这个映射表中
map $host $proxy_target {
test.liufeisheng.cn http://127.0.0.1:8080;
nas.liufeisheng.cn http://127.0.0.1:8080;
blog.liufeisheng.cn http://127.0.0.1:8080;
crm.liufeisheng.cn http://127.0.0.1:83;
default http://127.0.0.1:8080; # 默认代理地址
}
# ========== 80 端口:强制跳转 HTTPS ==========
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name test.liufeisheng.cn blog.liufeisheng.cn nas.liufeisheng.cn crm.liufeisheng.cn jxcg.liufeisheng.cn;
return 301 https://$host$request_uri;
}
# 保留非跳转的 80 端口配置
server {
listen 80;
server_name www.liufeisheng.cn;
location / {
proxy_pass http://127.0.0.1:82;
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;
}
location /crm {
proxy_pass http://127.0.0.1:83;
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;
}
location /messages {
proxy_pass http://127.0.0.1:8082;
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;
}
}
server {
listen 84;
server_name dh.liufeisheng.cn;
root /usr/local/digitalhum;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name jxcg.liufeisheng.cn;
root /usr/local/www/jxcg;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 80;
server_name jp.liufeisheng.cn;
location / {
proxy_pass http://127.0.0.1:8888;
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;
}
}
# ========== 443 端口:单个 server 块覆盖所有子域名(修复核心) ==========
server {
listen 443 ssl;
# 通配符匹配所有子域名 + 显式列出静态文件域名
server_name *.liufeisheng.cn jxcg.liufeisheng.cn;
# 通用 SSL 配置
ssl_certificate /etc/letsencrypt/live/liufeisheng.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/liufeisheng.cn/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
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;
proxy_ssl_verify off;
location / {
proxy_pass $proxy_target;
}
}
第三步:关键配置说明(避免踩坑)
- proxy_pass 端口选择:
test.liufeisheng.cn是https类型 frp 代理 → 代理到 frps 的8443端口;blog.liufeisheng.cn是http类型 frp 代理 → 代理到 frps 的8080端口;- Nginx 会自动将 HTTP 请求加密为 HTTPS(对外暴露 443 端口)。
-
proxy_ssl_verify off:frps 的 TLS 证书是
nas.liufeisheng.cn的,当 Nginx 代理到https://127.0.0.1:8443时,会校验证书域名是否匹配,添加该配置可跳过校验(仅内网转发,安全可控)。 -
泛域名证书:若不想申请泛域名证书,可单独为
test/blog域名申请证书:
bash
certbot certonly --nginx -d test.liufeisheng.cn -d blog.liufeisheng.cn
第四步:重启服务并验证
- 测试 Nginx 配置语法:
bash
nginx -t
- 重启 Nginx:
bash
systemctl restart nginx
- 验证 HTTPS 访问:
- 访问
https://test.liufeisheng.cn→ 应正常跳转群晖 5050 端口; - 访问
https://blog.liufeisheng.cn→ 应正常跳转群晖 8081 端口; - 若仍无法访问,检查服务器 443 端口是否放行(防火墙 / 安全组)。
三、额外优化(可选)
- frps 证书优化:若想让 frps 使用泛域名证书,修改
frps.toml的 TLS 证书路径为泛域名证书:liufei
toml
transport.tls.certFile = "/etc/letsencrypt/live/liufeisheng.cn/fullchain.pem"
transport.tls.keyFile = "/etc/letsencrypt/live/liufeisheng.cn/privkey.pem"
重启 frps:systemctl restart frps。
- 关闭不必要的 HTTP 访问:按配置中的
301 跳转,将所有 80 端口的请求强制跳转到 HTTPS,提升安全性。
1227 实现主域名访问各服务
将大部分服务从子域名改为路径方式(如 https://www.liufeisheng.cn/blog、https://www.liufeisheng.cn/dh 等)是更常见的做法,这样只需维护一个主域名和一个 SSL 证书,访问也更统一。
下面给你一个完整、可直接操作的改造方案。
1. 云服务器 Nginx 配置修改
替换或修改 /etc/nginx/conf.d/nas.conf,内容如下:
nginx
# 1. HTTP 全站跳转 HTTPS
server {
listen 80;
server_name liufeisheng.cn www.liufeisheng.cn *.liufeisheng.cn;
return 301 https://$host$request_uri; # 保持原子域名跳转到对应 HTTPS
}
# 2. 处理所有子域名(包括 nas.liufeisheng.cn, blog.liufeisheng.cn 等)
# 这就是你原来的配置,几乎不动
server {
listen 443 ssl;
server_name *.liufeisheng.cn;
ssl_certificate /etc/letsencrypt/live/liufeisheng.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/liufeisheng.cn/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host; # 关键:传递原始子域名给 frps
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;
}
}
# 3. 新增:专门处理 www.liufeisheng.cn 和 liufeisheng.cn(路径访问)
server {
listen 443 ssl;
server_name www.liufeisheng.cn liufeisheng.cn;
ssl_certificate /etc/letsencrypt/live/liufeisheng.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/liufeisheng.cn/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
# 根路径访问时可重定向到 nas 或留空
location = / {
# 可选:访问 www 主页时跳转到 nas 管理界面
return 301 https://nas.liufeisheng.cn/;
# 或者 return 301 /blog/; 跳转到博客
}
# 路径代理(配合 frpc 中的 subdomain 使用)
location /blog/ {
proxy_pass http://127.0.0.1:8080/;
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;
}
location /test/ {
proxy_pass http://127.0.0.1:8080/;
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;
}
location /dh/ {
proxy_pass http://127.0.0.1:8080/;
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;
}
location /jxcg/ {
proxy_pass http://127.0.0.1:8080/;
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;
}
location /crm/ {
proxy_pass http://127.0.0.1:8080/;
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;
}
}
- 保留子域名的同时,所有 服务还都能走路径
2. frpc.toml 修改(群晖端)
- 为什么 subdomain = "blog" 能实现路径访问(如 /blog)
-
你在 frps.toml 中添加了: subDomainHost = "www.liufeisheng.cn"
-
当外部请求
https://www.liufeisheng.cn/blog/
到达云服务器 Nginx 时:
- Nginx 把 Host 头保持为 www.liufeisheng.cn,然后代理到 frps 的 8080 端口
- frps 收到 Host 是 www.liufeisheng.cn,但路径是 /blog/
- frps 检测到路径以某个 subdomain 开头(如 /blog),就会自动改写 Host 头为 blog.www.liufeisheng.cn,然后根据这个新 Host 路由到对应的 proxy
- 所以:路径 /blog/ → 内部虚拟子域名 blog.www.liufeisheng.cn → 匹配到 subdomain = "blog" 的代理
这完全是 FRP 官方支持的机制(称为 “subdomain-based routing with subDomainHost”),不是 hack,因此没有问题。
- 要同时支持两种访问方式,frpc.toml 最佳配置方式
每个需要同时支持子域名和路径访问的服务(如 blog、test、dh、jxcg、crm),同时写 customDomains 和 subdomain 即可,FRP 完全支持两者并存。
修改 /usr/local/frp/frpc.toml:
toml
serverAddr = "47.113.x.x"
serverPort = 7000
auth.method = "token"
auth.token = "***"
# 1. DSM 管理界面,只保留子域名访问(路径访问通常不适合 DSM)
[[proxies]]
name = "dsm"
type = "http"
localIp = "127.0.0.1"
localPort = 5000
customDomains = ["nas.liufeisheng.cn"]
# 2. 以下服务同时支持 子域名 和 路径 两种访问
[[proxies]]
name = "blog"
type = "http"
localIp = "127.0.0.1"
localPort = 8081
customDomains = ["blog.liufeisheng.cn"] # 支持 https://blog.liufeisheng.cn
subdomain = "blog" # 支持 https://www.liufeisheng.cn/blog
[[proxies]]
name = "test"
type = "http"
localIp = "127.0.0.1"
localPort = 5050
customDomains = ["test.liufeisheng.cn"]
subdomain = "test"
[[proxies]]
name = "dh"
type = "http"
localIp = "127.0.0.1"
localPort = 81
customDomains = ["dh.liufeisheng.cn"]
subdomain = "dh"
[[proxies]]
name = "jxcg"
type = "http"
localIp = "127.0.0.1"
localPort = 8080
customDomains = ["jxcg.liufeisheng.cn"]
subdomain = "jxcg"
[[proxies]]
name = "crm"
type = "http"
localIp = "127.0.0.1"
localPort = 8082
customDomains = ["crm.liufeisheng.cn"]
subdomain = "crm"
3. 云服务器 frps.toml 小调整(可选)
确保支持 subdomain:
toml
vhostHTTPPort = 8080
subDomainHost = "www.liufeisheng.cn" # 关键!新增这一行
加了这行后,FRP 会把 blog.www.liufeisheng.cn 这样的虚拟主机名路由到 subdomain = "blog" 的代理。
最终访问效果(全部正常)
| 访问方式 | 对应服务 | 是否可用 |
|---|---|---|
| https://nas.liufeisheng.cn | DSM | 是 |
| https://blog.liufeisheng.cn | 博客 | 是(customDomains) |
| https://www.liufeisheng.cn/blog | 博客 | 是(subdomain) |
| https://test.liufeisheng.cn | test | 是 |
| https://www.liufeisheng.cn/test | test | 是 |
| 同理 dh、jxcg、crm | 全部支持两种方式 |
为什么是修改云服务器端的nginx设置,而不是群晖客户端的nginx
详细解释为什么在“把子域名改为路径访问”(如 www.liufeisheng.cn/blog)这个需求下,主要修改的是云服务器端的 Nginx,而几乎不动群晖端的 Nginx。
整体流量走向回顾
外部用户 → HTTPS(443) → 云服务器 Nginx → HTTP(8080) → frps → frp 隧道 → frpc → 群晖本地服务(5000/5050/8080/8081 等)
关键点在于:
- 外部用户访问的 URL 是 https://www.liufeisheng.cn/blog(主域名 + 路径)
- 到达云服务器时,**Host 头是 www.liufeisheng.cn**,路径是/blog
- 云服务器的 Nginx 是第一个收到完整 HTTPS 请求的地方,它负责决定这个请求该往哪里转。
为什么必须改云服务器 Nginx
要实现路径区分(如 /blog、/test、/dh),就必须有人根据路径(path)来决定把请求转发给哪个后端服务。
在这个架构里:
- 只有云服务器的 Nginx 看到了真实的路径 /blog。
- 当请求到达 frps 的 8080 端口时,FRP 的 HTTP 虚拟主机功能是只看 Host 头来区分不同代理的(或者 subdomain 生成的虚拟 Host),它不会根据路径来路由到不同的 proxy(除非你用更复杂的高版本 location 配置,但普通版 FRP 不支持路径级路由)。
换句话说:
- 如果不改云服务器 Nginx,所有路径(如 /blog、/test、/crm)都会被统一代理到 http://127.0.0.1:8080/。
- frps 收到后,看到 Host 都是 www.liufeisheng.cn,它只能把请求发给同一个 frpc proxy(除非你用 subdomain 方式生成不同 Host)。
- 结果就是所有路径都跑到同一个服务去了,无法区分。
因此,必须在云服务器 Nginx 里用 location /blog/ { ... } 这样的规则,先把不同路径“分流”,但实际上我们这里的分流是假的——所有路径还是代理到同一个 8080 端口,只是靠后面的 subdomain 机制来真正区分。
为什么配合修改的是 frpc,而不是群晖 Nginx
我们用的是 FRP 的 subdomain 功能 来实现真正区分:
- 云服务器 Nginx 把所有路径的请求都发到 frps 的 8080 端口(Host 头保持 www.liufeisheng.cn)。
- frps 收到后,根据配置的 subDomainHost = "www.liufeisheng.cn",会把 Host 改写成 blog.www.liufeisheng.cn、test.www.liufeisheng.cn 等(根据 frpc 里声明的 subdomain)。
- frps 再根据这个新的虚拟 Host 把请求路由到对应的 frpc proxy(blog → 8081,test → 5050 等)。
这个过程完全由 FRP 自己完成,不需要路径参与,所以群晖端的 Nginx 仍然像以前一样:
- 监听本地端口(如 5050、81、8080)
- 根据 server_name test.liufeisheng.cn 或其他来处理请求(但现在 Host 变成了 test.www.liufeisheng.cn,一般也能匹配,或者你干脆把 server_name 改成更宽松的)
群晖 Nginx 的作用只是提供本地服务,它不需要知道外部是用路径还是子域名访问的,只要能响应本地请求即可。
总结对比
| 操作 | 修改位置 | 原因 |
|---|---|---|
| 路径分流(location /blog/ 等) | 云服务器 Nginx | 它是唯一能看到真实路径的地方,必须在这里“伪分流” |
| 真正服务区分(blog → 8081,test → 5050) | frpc 的 subdomain + frps 的 subDomainHost | FRP 用虚拟子域名(Host 头)来路由,不依赖路径 |
| 服务本身配置 | 群晖 Nginx | 只需要保持本地能访问,不需要改动路径逻辑 |
简单说:云服务器 Nginx 负责“接入口”和路径伪装,FRP 负责真正的服务路由,群晖 Nginx 只负责本地服务。
这样设计的好处是:
- 外部统一用一个域名、一个证书
- 不需要给每个服务都配子域名和 DNS 记录
- 群晖端配置最少,几乎不用动