实战记录:我是如何用Nginx + frp,把家里NAS的Web服务套上自签名HTTPS并安全穿透出去的
家庭实验室实战:用Nginx与frp构建安全HTTPS内网穿透方案
去年冬天,我在书房里搭建了一套家庭NAS系统,初衷只是为了备份孩子的成长照片和视频。但随着智能家居设备增多,我逐渐意识到需要一种安全的方式远程访问这些服务——从私人云盘到智能家居控制面板。市面上现成的解决方案要么太贵,要么隐私存疑。经过反复尝试,最终选择了Nginx+frp+自签名证书的方案,不仅成本为零,还能完全掌控数据流向。本文将分享这套方案从搭建到优化的完整过程,特别是如何让全家人的手机、平板、电脑都"信任"你的自签名证书,告别烦人的安全警告。
1. 为什么选择frp与自签名HTTPS组合?
市面上内网穿透工具五花八门,ngrok、ZeroTier、Tailscale各有拥趸。但经过实测对比,frp在家庭场景下展现出独特优势:
性能对比表:
| 工具 | 协议支持 | 配置复杂度 | 带宽限制 | 证书管理 |
|---|---|---|---|---|
| frp | TCP/HTTP/HTTPS | 中等 | 无 | 完全自主 |
| ngrok | HTTP/HTTPS | 简单 | 免费版有限 | 依赖第三方 |
| ZeroTier | 虚拟局域网 | 简单 | 无 | 自动管理 |
| Tailscale | WireGuard | 极简 | 无 | 自动管理 |
选择frp的核心原因有三:
- 协议自由度:支持原始TCP流量转发,不像ngrok强制HTTP包装
- 零成本控制:无需依赖第三方服务商,避免突然的服务变更或收费
- 证书自主权:配合自签名证书可实现端到端加密,连证书颁发机构都无法窥探你的流量
自签名证书虽然会被浏览器"嫌弃",但在家庭内部网络环境中,只要正确部署到设备信任链,反而比Let's Encrypt等公共证书更安全——毕竟私钥完全由你掌控,没有中间人风险。
2. 环境准备与基础服务搭建
2.1 硬件选择与网络规划
我的实验环境基于一台树莓派4B(4GB内存)和Synology DS218j NAS。关键是要确保:
- 内网服务设备(树莓派/NAS)有固定内网IP(通过路由器DHCP静态分配)
- 云服务器(frps端)有公网IP和域名(我用的是腾讯云轻量服务器,年费约¥120)
网络拓扑示例:
[家庭路由器] │ ├─ [树莓派] (192.168.1.100) ← 运行frpc和Nginx ├─ [NAS] (192.168.1.101) ← 提供SMB/web服务 └─ 其他智能家居设备 [云服务器] (公网IP 1.2.3.4) └─ frps服务监听7000/443端口2.2 证书生成的最佳实践
原始文章用的openssl命令虽然能用,但缺乏现代SSL证书应有的扩展属性。改进后的命令如下:
openssl req -x509 -nodes -days 3650 -newkey rsa:4096 \ -keyout /etc/nginx/ssl/home-lab.key \ -out /etc/nginx/ssl/home-lab.crt \ -subj "/CN=home.example.com" \ -addext "subjectAltName = DNS:home.example.com, DNS:*.home.example.com" \ -addext "extendedKeyUsage = serverAuth" \ -addext "keyUsage = digitalSignature, keyEncipherment"关键改进点:
- 添加了
subjectAltName支持通配符子域名 - 明确证书用途为服务器认证(
serverAuth) - 通过
-subj参数避免交互式输入(适合自动化脚本)
生成后建议追加创建合并文件:
cat /etc/nginx/ssl/home-lab.{key,crt} > /etc/nginx/ssl/home-lab.pem3. 穿透配置的进阶技巧
3.1 frpc.ini的优化配置
原始配置直接暴露了33443端口,存在被扫描风险。我的安全增强方案:
[common] server_addr = frps.example.com server_port = 7000 tls_enable = true # 加密控制通道 login_fail_exit = false # 网络波动时自动重连 [secure-web] type = https local_ip = 127.0.0.1 local_port = 33443 remote_port = 4443 # 非标准HTTPS端口 custom_domains = home.example.com # 心跳检测配置 health_check_type = http health_check_url = /health health_check_interval_s = 30 health_check_timeout_s = 10 health_check_max_failed = 3关键安全措施:
- 使用非标准端口(4443)减少自动化攻击
- 启用TLS加密frp控制通道
- 增加健康检查自动恢复故障
- 通过iptables限制33443端口只接受本地访问:
iptables -A INPUT -p tcp --dport 33443 ! -s 127.0.0.1 -j DROP
3.2 Nginx的多服务代理
通过一个frp通道代理多个家庭服务:
# /etc/nginx/conf.d/home-services.conf server { listen 33443 ssl; server_name home.example.com; ssl_certificate /etc/nginx/ssl/home-lab.pem; ssl_certificate_key /etc/nginx/ssl/home-lab.key; location /cloud { proxy_pass http://192.168.1.101:5000; # NAS的Web界面 proxy_set_header Host $host; } location /hass { proxy_pass http://192.168.1.100:8123; # Home Assistant proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } location /health { return 200 'OK'; add_header Content-Type text/plain; } }4. 全设备证书信任方案
自签名证书最大的痛点在于各设备的信任管理。经过反复测试,各平台最佳实践如下:
4.1 Windows系统
- 导出证书为DER格式:
openssl x509 -in home-lab.crt -outform DER -out home-lab.der - 通过组策略批量部署:
- 运行
gpedit.msc - 导航到:计算机配置 → 策略 → Windows设置 → 安全设置 → 公钥策略 → 受信任的根证书颁发机构
- 右键导入
home-lab.der
- 运行
4.2 macOS/iOS设备
创建移动配置文件(.mobileconfig)自动安装:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadContent</key> <array> <dict> <key>PayloadCertificateFileName</key> <string>home-lab.crt</string> <key>PayloadContent</key> <data>$(cat home-lab.crt | base64)</data> <key>PayloadDescription</key> <string>添加家庭实验室根证书</string> <key>PayloadDisplayName</key> <string>Home Lab CA</string> <key>PayloadIdentifier</key> <string>com.homelab.certificate</string> <key>PayloadType</key> <string>com.apple.security.root</string> <key>PayloadUUID</key> <string>$(uuidgen)</string> <key>PayloadVersion</key> <integer>1</integer> </dict> </array> <key>PayloadDescription</key> <string>家庭设备证书配置</string> <key>PayloadDisplayName</key> <string>家庭实验室安全配置</string> <key>PayloadIdentifier</key> <string>com.homelab.profile</string> <key>PayloadOrganization</key> <string>家庭实验室</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadUUID</key> <string>$(uuidgen)</string> <key>PayloadVersion</key> <integer>1</integer> </dict> </plist>通过家庭群组iMessage发送此文件,点击即可安装。
4.3 Android设备
使用adb命令批量安装:
adb root adb push home-lab.crt /system/etc/security/cacerts/ adb shell chmod 644 /system/etc/security/cacerts/$(openssl x509 -noout -hash -in home-lab.crt).05. 安全加固与监控
5.1 网络层防护
在云服务器端配置防火墙规则:
# 只允许特定IP访问管理端口 iptables -A INPUT -p tcp --dport 7000 -s 办公室IP -j ACCEPT iptables -A INPUT -p tcp --dport 7000 -j DROP # 限制HTTPS端口访问频率 iptables -A INPUT -p tcp --dport 443 -m connlimit --connlimit-above 20 -j DROP iptables -A INPUT -p tcp --dport 443 -m recent --name HTTPS --set iptables -A INPUT -p tcp --dport 443 -m recent --name HTTPS --update --seconds 60 --hitcount 30 -j DROP5.2 应用层防护
Nginx配置增加安全头:
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'";5.3 自动化监控
使用Prometheus+Alertmanager监控方案:
# frp监控配置 - job_name: 'frp' static_configs: - targets: ['192.168.1.100:7400'] # frpc metrics端口 metrics_path: '/metrics' # 告警规则示例 groups: - name: frp-alerts rules: - alert: FrpConnectionDown expr: up{job="frp"} == 0 for: 5m labels: severity: critical annotations: summary: "frp客户端连接中断 (instance {{ $labels.instance }})" description: "frp到{{ $labels.instance }}的连接已断开超过5分钟"这套系统运行半年来,经历了家庭宽带IP变更、设备增减、证书更新等各种情况,最长的连续稳定运行时间达到117天。期间唯一的中断是因为路由器固件升级,通过配置DDNS备用方案解决了这个问题。现在全家人都能安全地在外访问家庭服务,孩子的照片备份再也没出过问题。
