为什么需要这个方案
树莓派通常部署在家庭局域网内,没有公网 IP,外部无法直接访问。即使通过端口映射暴露服务,HTTP 明文传输也存在安全风险。
理想的方案需要同时解决两个问题:
- 内网穿透——让外部流量能到达树莓派
- HTTPS 加密——保护传输数据,避免中间人攻击
本文使用 frp 解决穿透问题,Caddy 解决 HTTPS 问题,部署在一台阿里云轻量应用服务器上作为中转节点。
架构概览
流量路径:浏览器 → Caddy (HTTPS) → frps (vhost HTTP) → frpc → 树莓派本地服务
环境说明
| 组件 | 环境 |
|---|---|
| 树莓派 | Raspberry Pi 4B, Raspberry Pi OS (Debian 13 Trixie), arm64 |
| 阿里云服务器 | 轻量应用服务器, Ubuntu 24.04 LTS |
| frp | v0.70.0(从 GitHub Releases 下载) |
| Caddy | v2.11.4(通过 apt 安装) |
第一步:部署 frps(阿里云服务器)
下载安装
# 下载 frp v0.70.0
wget https://github.com/fatedier/frp/releases/download/v0.70.0/frp_0.70.0_linux_amd64.tar.gz
tar xzf frp_0.70.0_linux_amd64.tar.gz
sudo cp frp_0.70.0_linux_amd64/frps /usr/local/bin/
编辑配置文件
创建 /etc/frp/frps.toml:
bindPort = 7000
vhostHTTPPort = 8080
transport.tls.force = true
subDomainHost = "example.com" # 替换为你的域名
auth.method = "token"
auth.token = "你的frp认证token" # 建议使用长随机字符串
# Server Dashboard(可选,仅本地访问)
webServer.addr = "127.0.0.1"
webServer.port = 27500
webServer.user = "admin"
webServer.password = "你的dashboard密码"
关键配置说明:
bindPort = 7000:frp 客户端连接端口vhostHTTPPort = 8080:HTTP 子域名路由端口,Caddy 会将匹配子域名的请求转发到这里transport.tls.force = true:强制 TLS 加密 frp 隧道,防止中间人攻击subDomainHost:你的主域名,frpc 配置的子域名会拼接在这个域名下- Dashboard 绑定
127.0.0.1,仅允许本地访问,外部通过 Caddy 反向代理访问
设置 systemd 服务
sudo tee /etc/systemd/system/frps.service << 'EOF'
[Unit]
Description=frp server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now frps
验证服务状态:
sudo systemctl status frps
第二步:部署 frpc(树莓派)
下载安装
# 下载 frp v0.70.0(arm64 版本)
wget https://github.com/fatedier/frp/releases/download/v0.70.0/frp_0.70.0_linux_arm64.tar.gz
tar xzf frp_0.70.0_linux_arm64.tar.gz
sudo cp frp_0.70.0_linux_arm64/frpc /usr/local/bin/
编辑配置文件
创建 ~/.config/frpc.toml(或 /etc/frp/frpc.toml):
serverAddr = "x.x.x.x" # 替换为阿里云服务器公网 IP
serverPort = 7000
auth.method = "token"
auth.token = "你的frp认证token" # 必须与 frps 一致
transport.tls.enable = true
# 客户端 Dashboard(可选,仅本地访问)
webServer.addr = "127.0.0.1"
webServer.port = 27400
webServer.user = "admin"
webServer.password = "你的dashboard密码"
# 代理:SSH 访问
[[proxies]]
name = "raspberrypi-ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 20022
transport.useCompression = true
# 代理:Web 服务(通过子域名访问)
[[proxies]]
name = "raspberrypi-web"
type = "http"
localIP = "127.0.0.1"
localPort = 8080 # 树莓派上实际运行的服务端口
subdomain = "pi" # 访问 pi.example.com 时转发到此服务
transport.useCompression = true
关键配置说明:
transport.tls.enable = true:启用 TLS 加密连接 frps- SSH 代理使用 TCP 类型,映射到服务器的 20022 端口
- Web 服务使用 HTTP 类型 + subdomain,通过子域名访问
transport.useCompression = true:启用压缩,节省带宽
设置 systemd 服务
sudo tee /etc/systemd/system/frpc.service << 'EOF'
[Unit]
Description=frp client
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/frpc -c /home/pi/.config/frpc.toml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now frpc
验证服务状态:
sudo systemctl status frpc
第三步:部署 Caddy(阿里云服务器)
Caddy 的最大优势是自动 HTTPS——它会自动为你的域名申请和续期 Let’s Encrypt 证书,无需手动管理。
安装 Caddy
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
配置 Caddyfile
编辑 /etc/caddy/Caddyfile:
# frp Server Dashboard
pi-admin.example.com {
reverse_proxy 127.0.0.1:27500
}
# 树莓派 Web 服务(通过 frp 子域名代理)
pi.example.com {
reverse_proxy 127.0.0.1:8080 {
header_up Host {host}
}
}
配置说明:
pi-admin.example.com:访问 frps 的 Dashboard 界面pi.example.com:访问树莓派上运行的 Web 服务header_up Host {host}:将原始 Host 头传递给 frps,确保子域名路由正确
验证配置并启动
修改 Caddyfile 后,先验证配置格式是否正确:
# 检查 Caddyfile 语法
sudo caddy validate --config /etc/caddy/Caddyfile
# 格式化 Caddyfile
sudo caddy fmt --overwrite /etc/caddy/Caddyfile
确认无误后启动/重载 Caddy:
# 首次启动
sudo systemctl enable --now caddy
# 后续修改配置后重载(无需重启,零停机)
sudo systemctl reload caddy
# 查看状态
sudo systemctl status caddy
提示:Caddy 支持
reload热重载,修改配置后不需要重启服务,连接不会中断。
Caddy 启动后会自动:
- 检测配置的域名
- 向 Let’s Encrypt 申请证书
- 配置 HTTPS
- 自动续期证书
验证证书是否生效:
curl -I https://pi.example.com
响应头中应包含 server: Caddy 和 strict-transport-security 等 HTTPS 相关头。
第四步:验证完整链路
测试 HTTPS 访问
在浏览器中访问:
https://pi.example.com→ 树莓派 Web 服务https://pi-admin.example.com→ frps Dashboard
两个地址都应显示有效的 HTTPS 证书(Let’s Encrypt)。
测试 SSH 访问
ssh -p 20022 user@你的阿里云服务器IP
安全建议
- frp token:使用
openssl rand -hex 32生成高强度 token,不要使用弱密码 - Dashboard 访问:frps 和 frpc 的 Dashboard 都绑定
127.0.0.1,仅通过 Caddy 反向代理对外暴露,建议为 Dashboard 添加认证 - TLS 强制加密:frps 配置
transport.tls.force = true,frpc 配置transport.tls.enable = true,确保隧道全程加密 - 端口最小化:仅暴露必要的服务端口,SSH 可限制来源 IP
- 定期更新:保持 frp、Caddy 和系统处于最新版本
常见问题
Caddy 证书申请失败
确保域名的 DNS A 记录已正确指向阿里云服务器的公网 IP,且 80 端口未被其他服务占用(Caddy 需要 80 端口进行 HTTP-01 验证)。
子域名访问 404
检查 frpc 的 subdomain 配置是否与 Caddy 的域名匹配。frps 会将 pi.example.com 的请求路由到 frpc 注册的 pi 子域名代理。
frp 连接断开
检查 frpc 和 frps 的 token 是否一致,TLS 配置是否匹配。查看日志排查:
# frps 日志
sudo journalctl -u frps -f
# frpc 日志(如果使用 systemd)
journalctl -u frpc -f
总结
这套方案的几个实在好处:
- 证书不用管:Caddy 自动搞定 Let’s Encrypt 证书的申请和续期,到期自动续,不用操心
- 全程加密:frp 走 TLS 隧道,外面再套一层 Caddy HTTPS,双重保险
- 成本低:就一台阿里云轻量应用服务器,树莓派那边连公网 IP 都不需要
- 省心:三个服务都走 systemd,崩了自动拉起来,开机自启
树莓派上跑的博客、HomeAssistant、文件服务之类的,都可以用这套方式安全地暴露到外网。
环境版本参考:frp v0.70.0, Caddy v2.11.4, Raspberry Pi OS (Debian 13 Trixie), Ubuntu 24.04 LTS