Skip to content

树莓派4B自建网页服务器指南(6):树莓派 HTTPS 证书申请 + 公网直连验证

一、引言:为什么要引入 HTTPS 证书?

在互联网上,HTTPS 已成为网站的基本门槛。它不仅能加密数据传输,防止中间人窃听,还能让浏览器显示“安全锁”标识,提升用户信任度。对于个人站点而言,即使只是内网穿透或实验性质,使用受信证书也能避免浏览器反复弹出“不安全”警告,使访问体验更正规、更符合现代 Web 标准。

然而,树莓派(ARM64 架构)在申请证书时面临诸多坑:主流工具 Certbot 依赖 Python 生态,在 ARM64 下编译困难。
acme.sh 作为纯 Shell 脚本方案,成为最佳替代。本文将完整记录证书申请、Nginx 配置、网络瓶颈排查及公网验证的全过程。

本文验证域名统一使用 pi-ddns.jiejinx.cn。

二、证书申请方案选型(踩坑实录)

方案结论原因
Certbot (Let's Encrypt 官方)❌ 树莓派 ARM64 不可用Python 依赖包(acme、cryptography)在 ARM64 下编译失败,snapd 安装也报错,折腾数小时无果
acme.sh✅ 推荐纯 Shell 脚本,无 Python 依赖,ARM64 原生支持,DNS-01 模式可配合阿里云 DNS API 自动签发泛域名证书

三、acme.sh 证书申请(完整流程)

3.1 安装 acme.sh(国内网络适配)

3.1.1 离线安装包下载

由于 官方推荐的 curl https://get.acme.sh | sh 在线安装脚本内部会去 GitHub 拉 master.tar.gz归档,国内网络常卡死,改用离线安装更稳:先用国内代理把 tar.gz 拉到 /tmp,再本地安装。

bash
cd /tmp

wget https://gh.llkk.cc/https://github.com/acmesh-official/acme.sh/archive/master.tar.gz

以上链接中,若代理超时 代理站点可进行替换,通过代理查询站查询可用节点地址替换。
例如: https://gh.llkk.cc/https://github.com/....
替换为: https://777.z321.cc.cd/https://github.com/....

代理查询站:https://github.akams.cn/

3.1.2 本地离线安装:

bash
tar -xzf master.tar.gz
cd acme.sh-master
./acme.sh --install -m standalone

参数说明:
--install:安装到 ~/.acme.sh/,并设置 cron 自动续期
-m standalone:不自动写 ~/.bashrc(Pi OS 默认 bash,装完手动 source ~/.bashrc即可;若你换 zsh/fish 可去掉 -m,让安装脚本自动识别当前 shell 写对应 rc 文件)

可能出现的日志现象(正常现象,无需处理):

#安装末期可能出现类似日志:
Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 28
OK

error code: 28是 libcurl 的 CURLE_OPERATION_TIMEDOUT,来源是 --install末尾顺手执行了一次 acme.sh --upgrade(自检/拉最新版),国内网络出不去 GitHub/Let's Encrypt 导致超时。这不影响安装结果——~/.acme.sh/本体、.bashrc别名、cron 任务均已装好,后面 3.2~3.4 的签发流程不受影响。

安装完刷新环境变量:

bash
source ~/.bashrc

验证安装:

bash
acme.sh --version
# 应输出版本号(如 3.1.0)✅

清理安装残留(可选):

bash
cd /tmp
rm -f master.tar.gz
rm -rf acme.sh-master/

💡 装完顺手清 /tmp残留,SD 卡 IO 和空间都金贵;不 rm 的话 systemd-tmpfiles-clean10 天后也会清,但树莓派上建议主动清。

3.2 配置阿里云 DNS API + 注册邮箱

acme.sh 需要通过阿里云 DNS API 验证域名所有权(DNS-01 模式),同时第一次签发时会向 Let's Encrypt 注册账号,需要一个有效的 contact email。

编辑配置文件:

bash
nano ~/.acme.sh/account.conf

找到这一行:

ACCOUNT_EMAIL='standalone'

改为你的邮箱(例如):

ACCOUNT_EMAIL='your_email@example.com'

然后在文件末尾添加两行(替换成你的真实 AK/SK):

Ali_Key='你的阿里云 AccessKey ID'
Ali_Secret='你的阿里云 AccessKey Secret'

保存退出(Ctrl+O→ Enter→ Ctrl+X)。

💡 为什么不用 export而直接写文件
新版 acme.sh v3 在 --issue内部走注册流程时,export ACCOUNT_EMAIL不一定被注册子进程读到,可能报 invalidContact;且 QQ 数字邮箱(如 123456789@qq.com)偶发被 Let's Encrypt 端点误判为非法格式。直接修改 account.conf是最稳的方式,acme.sh 签发时会自动读取完成注册,无需单独执行注册命令。
文件中原有的 UPGRADE_HASH等字段是 acme.sh 自动生成的,保留不动即可,只改 ACCOUNT_EMAIL并追加 Ali_Key/Ali_Secret是最小改动,不会破坏 acme.sh 的内部状态。
AccessKey 获取方式见第5篇 6.5 节。建议使用 RAM 子账号(仅授予 AliyunDNSFullAccess权限),不要直接使用主账号密钥。

3.3 签发证书(主域名 + 泛域名)

acme.sh --issue --server letsencrypt --dns dns_ali -d jiejinx.cn -d *.jiejinx.cn

💡 为什么显式 --server letsencrypt
acme.sh v3+ 默认 CA 已改为 ZeroSSL,ZeroSSL 需 EAB 凭证,个人树莓派场景用不上。
命令不加 --server新版 acme.sh 会报 No EAB credentials。显式指定最稳,也兼容老版 acme.sh。

这条命令会:

  1. 调用阿里云 DNS API,为 jiejinx.cn和 *.jiejinx.cn添加 TXT 验证记录
  2. 等待 DNS 生效(约 10-60 秒)
  3. 验证通过后,向 Let's Encrypt 申请证书
  4. 签发成功后,自动删除 TXT 记录

💡** 日志中的 error code 说明:** 签发过程中可能出现以下两行错误日志:
Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35 Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 28

error 35​ (CURLE_SSL_CONNECT_ERROR):SSL/TLS 握手失败,通常因网络抖动导致公共 DNS 查询超时
error 28​ (CURLE_OPERATION_TIMEDOUT):连接超时,acme.sh 在通过公共 DNS 检查 TXT 记录是否生效时,因国内网络环境偶发超时

两者均不影响证书签发结果——acme.sh 内置重试机制,上述错误发生后会自动切换到备选检查点,最终 Success即为验证通过。日志末尾的 Your cert is in:和 fullchain.cer出现即代表证书签发成功。

签发成功后,证书文件位于:

~/.acme.sh/jiejinx.cn_ecc/
├── fullchain.cer    # 完整证书链(Nginx 使用)
├── jiejinx.cn.key   # 私钥(Nginx 使用)
├── ca.cer           # CA 中间证书
└── jiejinx.cn.cer   # 域名证书

3.4 验证证书信息

bash
# 查看证书详情
openssl x509 -in ~/.acme.sh/jiejinx.cn_ecc/fullchain.cer -text -noout | grep -E "Subject:|Not Before|Not After|DNS"

# 查看 SAN(Subject Alternative Names),应包含 jiejinx.cn 和 *.jiejinx.cn
openssl x509 -in ~/.acme.sh/jiejinx.cn_ecc/fullchain.cer -text -noout | grep -A1 "Subject Alternative Name"

输出示例:

Subject: CN = jiejinx.cn
Not Before: Apr  1 00:00:00 2026 GMT
Not After: Jun 30 00:00:00 2026 GMT
DNS:jiejinx.cn, DNS:*.jiejinx.cn

3.5 自动续期

acme.sh 安装时已自动添加 cron 任务,无需手动干预。验证 cron 任务是否存在:

crontab -l | grep acme

应输出类似:

56 0 * * * "/home/pi/.acme.sh"/acme.sh --cron --home "/home/pi/.acme.sh" > /dev/null

💡 泛域名证书的优势:*.jiejinx.cn可覆盖所有二级子域名(pi.jiejinx.cn、pi-ddns.jiejinx.cn、pi-cf.jiejinx.cn、www.jiejinx.cn等)。
后续新增子域名时,无需重新申请证书,直接使用现有证书即可。
这是 DNS-01 模式相比 HTTP-01 模式的核心优势——不依赖 80 端口,且支持泛域名。

四、Nginx 配置要点(含完整命令行)

4.1 创建 SSL 证书存放目录

bash
sudo mkdir -p /etc/nginx/ssl/jiejinx.cn

4.2 复制证书文件

bash
sudo cp ~/.acme.sh/jiejinx.cn_ecc/fullchain.cer /etc/nginx/ssl/jiejinx.cn/fullchain.pem
sudo cp ~/.acme.sh/jiejinx.cn_ecc/jiejinx.cn.key /etc/nginx/ssl/jiejinx.cn/privkey.pem
sudo chmod 600 /etc/nginx/ssl/jiejinx.cn/privkey.pem

4.3 编写 Nginx 站点配置

bash
sudo nano /etc/nginx/sites-available/pi

粘贴以下内容:

server {
    listen 9133 ssl;
    listen [::]:9133 ssl;
    http2 on;
    server_name pi-ddns.jiejinx.cn;

    ssl_certificate     /etc/nginx/ssl/jiejinx.cn/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/jiejinx.cn/privkey.pem;

    root /var/www/html;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

💡 server_name包含所有需要 HTTPS 访问的子域名。
泛域名证书 *.jiejinx.cn天然覆盖 pi-ddns、pi-cf等子域,无需为每个子域单独申请证书。

4.4 启用站点并重载 Nginx

bash
# 创建软链接启用站点
sudo ln -s /etc/nginx/sites-available/pi /etc/nginx/sites-enabled/

# 测试配置是否正确
sudo nginx -t

# 重载 Nginx 使配置生效
sudo systemctl reload nginx

4.5 验证监听状态

bash
ss -tlnp | grep 9133

应看到类似输出:

LISTEN 0      511          0.0.0.0:9133      0.0.0.0:*    users:(("nginx",pid=xxx,fd=xx))
LISTEN 0      511             [::]:9133         [::]:*    users:(("nginx",pid=xxx,fd=xx))

[::]:9133表示 Nginx 已在 IPv6 端口上监听 ✅

五、网络与端口问题(宽带限制与光猫防火墙)

5.1 家宽 80/443 端口封锁(现实约束)

三大运营商(电信/联通/移动)家庭宽带线路均封锁 80(HTTP)和 443(HTTPS)入站端口,这是公知事实,非配置错误。

应对策略:

  • 树莓派 Nginx 监听非标高位端口(如 9133)
  • 公网访问时必须显式携带端口号:https://pi-ddns.jiejinx.cn:9133
  • 如需隐藏端口号,需借助反向代理(如阿里云 ECS Nginx 反代)或 Cloudflare Tunnel(备选)

5.2 光猫 IPv6 防火墙防护选项(最大暗坑)

现象:树莓派 IPv6 地址公网可达(ping6 通),Nginx 监听 9133 端口正常,但同地域不同网段的手机/电脑访问 https://[IPv6]:9133始终超时。

根因:光猫(华为、中兴等)默认开启 IPv6 SPI 防火墙 或 IPv6 防护 选项,会拦截所有入站 TCP/UDP 连接(无论端口),仅放行 ICMPv6(ping 通是假象)。

六、防火墙设置(测试用途,附带安全建议)

6.1 关闭光猫与路由器的 IPv6 防火墙(测试用)

6.1.1光猫端

登录光猫管理后台(一般为 192.168.1.1,登陆信息见背面标签),找到 安全防火墙IPv6 SPI 防火墙​ 或 IPv6 防护​ 选项,关闭该选项(部分光猫需在“高级安全”或“攻击防护”子菜单)。保存生效,无需重启光猫。

6.1.2路由器端

光猫防火墙关闭后,若仍无法公网访问,路由器自身的 IPv6 防火墙往往是第二道关卡。家用路由器(华硕、TP-Link、小米、中兴等)默认会拦截所有来自公网的 IPv6 入站连接。

以本文实测的中兴 E2633 为例:

  1. 登录路由器管理后台(一般为 192.168.10.1 登陆信息见路由器背面标签)
  2. 进入 安全 → 防火墙(或 高级安全)
  3. 找到 防火墙级别,将其从“高(推荐)”改为 “低”
  4. 取消勾选 “防攻击保护”(如有)
  5. 点击 提交​ 保存

💡 其他品牌参考位置
华硕:防火墙 → IPv6 防火墙 → 启用 IPv6 防火墙(取消勾选)
TP-Link:安全 → 高级安全 → 忽略来自 WAN 的 Ping(关闭) + 开启 SPI 防火墙(关闭)
小米:常用设置 → 安全中心 → 防火墙 → IPv6 防火墙(关闭)

验证:关闭后,用手机 4G/5G 访问 https://pi-ddns.jiejinx.cn:9133,应能正常显示页面。若仍不通,可能是运营商上行 ACL 拦截,此时纯 IPv6 直连方案已达上限,需进入第7篇 ECS 反代方案。

6.2 ⚠️ 重要免责声明

上述关闭光猫 IPv6 防火墙的操作仅为测试验证链路连通性,不应作为长期安全策略。光猫自带的防火墙虽然简陋,但仍能阻挡一部分扫描攻击。强烈建议生产环境中,在树莓派或路由器上启用专业的防火墙规则(如 iptables 或 ufw),仅放行必要的端口(如 9133),并限制来源 IP 范围。切勿直接关闭防护裸奔,以免设备暴露于公网风险之下。

6.3 推荐的安全加固方案

  • 在树莓派上启用 ufw(见 6.4 节)
  • 或者使用带有防火墙功能的路由器(如 OpenWrt、爱快等),在路由器上控制入站流量
  • 配合 Fail2ban 防止暴力扫描

6.4 树莓派防火墙配置(ufw)

光猫防火墙品牌繁杂、配置各异,但树莓派上的防火墙是统一的。无论光猫侧怎么设,树莓派自身必须做好端口管控。

6.4.1 安装 ufw

bash
sudo apt install ufw -y

6.4.2 设置默认策略

bash
sudo ufw default deny incoming   # 默认阻止所有入站
sudo ufw default allow outgoing  # 允许所有出站

6.4.3 放行必要端口

bash
# SSH(22端口,必须放行否则连不上)
sudo ufw allow 22/tcp comment 'SSH'

# Nginx HTTPS 非标端口(本文用 9133)
sudo ufw allow 9133/tcp comment 'Nginx HTTPS non-standard port'

6.4.4 启用防火墙

bash
sudo ufw enable

启用后查看状态:

bash
sudo ufw status verbose

应输出类似:

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
9133/tcp                   ALLOW       Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
9133/tcp (v6)              ALLOW       Anywhere (v6)

6.4.5 未来新增端口的放行方法

如果需要开放更多端口(例如 frp 的 7000、Docker 的 9443 等),使用相同语法:

bash
sudo ufw allow <端口>/tcp comment '描述'

例如:

bash
sudo ufw allow 8443/tcp comment 'frp dashboard'
sudo ufw allow 9090/tcp comment 'Cockpit'

⚠️ 不要一次性放行过多端口。遵循最小权限原则:只放行业务必需的端口,其余一律拒绝。ufw 的日志位于 /var/log/ufw.log,可用于排查被拦截的连接。

6.4.6 删除误开放的端口

bash
sudo ufw delete allow <端口>/tcp

七、公网访问验证(ddns-go + acme.sh 证书)

前提条件:

  • ✅ ddns-go 已成功将树莓派公网 IPv6 更新到阿里云 DNS AAAA 记录(pi-ddns.jiejinx.cn)

  • ✅ 光猫 IPv6 防火墙已关闭(测试用,见 6.1)

  • ✅ 树莓派 ufw 已放行 9133 端口(见 6.4)

  • ✅ 树莓派 Nginx 监听 9133 ssl,acme.sh 证书 SAN 覆盖 pi-ddns.jiejinx.cn

验证步骤:

bash
# 1. 验证 DNS 解析
nslookup pi-ddns.jiejinx.cn 8.8.8.8
# 应返回公网 IPv6 地址(2409:xxxx)

# 2. 验证 Nginx 响应(本机)
curl -v https://pi-ddns.jiejinx.cn:9133
# 应返回 Nginx 页面,无证书错误

# 3. 外网验证(手机 4G/5G,关闭 WiFi)
# 浏览器访问 https://pi-ddns.jiejinx.cn:9133
# 应显示安全锁(证书受信),页面正常加载

至此,树莓派已实现纯 IPv6 公网直连 HTTPS 访问。

八、本章目标完成清单

项目状态
acme.sh 安装并签发泛域名证书
Nginx 配置 SSL(9133 端口)
树莓派 ufw 防火墙安装与端口放行
光猫 IPv6 防火墙关闭(测试用)
公网 HTTPS 直连验证通过
理解家宽 80/443 端口封锁限制