使用Nginx前置代理与FRP实现安全内网穿透

一、方案概述
本方案通过Nginx统一管理HTTPS证书和域名路由,FRP仅处理TCP层流量穿透,实现:
- 多子域名共享443端口
- 证书集中管理
- 避免FRP重复处理HTTPS
- 生产级安全加固
二、服务端部署(FRP + Nginx)
1. FRP服务端配置(Docker版)
frps.toml
核心配置
bash
bindAddr = "0.0.0.0"
bindPort = 7000 # FRP控制通道端口
transport.tls.force = true # 强制TLS加密
auth.method = "token"
auth.token = "your_secure_token"
# 开放Nginx转发用的TCP端口范围
allowPorts = [{ start = 10080, end = 10100 }]
# 管理面板(可选)
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin@Secure123"
Docker启动命令
bash
docker run -d --name frps \
-p 7000:7000 \
-p 7500:7500 \
-p 10080-10100:10080-10100 \ # 映射开放Nginx转发用的TCP端口范围
--network host \ # 推荐host模式避免端口映射嵌套
-v /data/frp/frps.toml:/etc/frp/frps.toml \
-v /data/frp/logs:/var/log/frp \
snowdreamtech/frps:latest
端口映射说明:
7000
:FRP客户端连接端口10080-10100
:Nginx反向代理转发端口7500
:管理面板端口
2. Nginx服务端配置
证书准备
bash
mkdir -p /etc/nginx/ssl/
# 将证书放入以下路径(需包含完整链)
/etc/nginx/ssl/www.loveddz.com.crt
/etc/nginx/ssl/www.loveddz.com.key
Nginx虚拟主机配置
bash
# /etc/nginx/conf.d/frp_proxy.conf
# 主域名代理
server {
listen 443 ssl;
server_name www.loveddz.com;
ssl_certificate /etc/nginx/ssl/www.loveddz.com.crt;
ssl_certificate_key /etc/nginx/ssl/www.loveddz.com.key;
location / {
proxy_pass http://127.0.0.1:10080; # 转发到FRP监听的端口
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# 子域名代理示例
server {
listen 443 ssl;
server_name api.loveddz.com;
ssl_certificate /etc/nginx/ssl/api.loveddz.com.crt;
ssl_certificate_key /etc/nginx/ssl/api.loveddz.com.key;
location / {
proxy_pass http://127.0.0.1:10081;
proxy_set_header Host $host;
}
}
Docker启动Nginx
bash
docker run -d --name nginx \
--network host \ # 与frps共享网络命名空间
-v /etc/nginx/conf.d:/etc/nginx/conf.d \
-v /etc/nginx/ssl:/etc/nginx/ssl \
nginx:latest
三、客户端配置(FRP TCP模式)
frpc.toml
示例
bash
# ========================
# 全局配置
# ========================
serverAddr = "114.113.112.111" # FRP服务器IP
serverPort = 7000 # 与服务端bindPort一致
auth.method = "token"
auth.token = "your_secure_token" # 与服务端auth.token一致
transport.tls.enable = true # 启用TLS加密传输(必须与服务端一致)
# ========================
# 代理配置(TCP模式)
# ========================
# 代理1:主域名 www.loveddz.com→ 本地8088
[[proxies]]
name = "web_tcp"
type = "tcp" # 必须为tcp模式(由Nginx处理HTTPS)
localIP = "127.0.0.1"
localPort = 8088 # 本地服务端口
remotePort = 10080 # 对应Nginx的proxy_pass端口
# 代理2:子域名 api.loveddz.com→ 本地8089
[[proxies]]
name = "api_tcp"
type = "tcp"
localPort = 8089
remotePort = 10081 # Nginx中配置的另一个proxy_pass端口
四、安全加固建议
-
防火墙规则
bash# 仅开放必要端口 ufw allow 443,7000,7500,10080:10081/tcp
-
Nginx安全头
bashadd_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header Content-Security-Policy "default-src 'self'";
-
FRP日志监控
bash# 实时监控异常连接 tail -f /data/frp/logs/frps.log | grep -E 'failed|error'
五、验证与调试
-
检查服务连通性
bashcurl -vk https://www.loveddz.com curl -vk https://api.loveddz.com
-
端口占用检查
bashss -tulnp | grep -E '7000|7500|10080'
-
Nginx日志分析
bashdocker logs -f nginx | grep "10080"
六、常见问题解决
问题现象 | 解决方案 |
---|---|
Nginx报502 Bad Gateway | 检查FRP客户端是否运行,且localPort 与本地服务一致 |
HTTPS证书错误 | 确保证书包含完整链,且域名与server_name 完全匹配 |
FRP连接超时 | 检查服务端防火墙/安全组是否放行7000 端口 |
七、方案优势
- 证书集中管理:无需在FRP中配置证书
- 性能优化:Nginx处理HTTPS卸载,降低FRP负担
- 扩展性强:新增子域名只需修改Nginx配置,无需重启FRP
部署效果 :
通过 https://www.loveddz.com
访问本地8088端口服务,https://api.loveddz.com
访问8089端口服务,所有HTTPS加密由Nginx统一处理。