Ubuntu 18.04 下 Nginx 配置 Let‘s Encrypt HTTPS 全流程指南
1. 为什么在 Ubuntu 18.04 上用 Let’s Encrypt 给 Nginx 加密,不是“可选项”,而是“必选项”
你刚在 Ubuntu 18.04 上配好一台 Nginx 服务器,绑了域名,首页能打开,心里一松——“成了”。
但只要它暴露在公网,哪怕只跑一个静态博客、一个内部管理后台、甚至只是个测试页,浏览器地址栏那个醒目的“不安全”提示,就已经在悄悄侵蚀你的可信度、用户留存率,甚至搜索引擎排名。这不是危言耸听:Chrome 从 2017 年起就对所有 HTTP 页面打标;Google 搜索算法明确将 HTTPS 作为排名信号;而现代前端框架(Vue、React)的 Service Worker、地理位置 API、通知权限等核心功能,强制要求运行在 HTTPS 环境下——HTTP 下直接报错、拒绝执行。
Let’s Encrypt 的出现,彻底打破了 HTTPS 的技术与成本壁垒。它不是“另一个商业证书提供商”,而是由互联网安全研究小组(ISRG)运营的非营利性证书颁发机构(CA),其核心价值在于:零费用、全自动化、开放可信。它的根证书已被所有主流操作系统和浏览器预置信任(包括 Ubuntu 18.04 自带的 ca-certificates 包),这意味着你申请的证书,用户打开网页时不会看到任何“证书不受信任”的红色警告——这是自签名证书永远无法跨越的鸿沟。
Ubuntu 18.04 这个版本在此场景中尤为关键。它虽已进入扩展维护阶段(EOL 为 2023 年 4 月),但仍是大量生产环境、遗留系统、嵌入式网关设备的稳定基线。它的软件源中默认包含certbot(Let’s Encrypt 官方客户端)的兼容版本(0.31.x),且内核、OpenSSL(1.1.1)、Python 3.6 等底层组件完全满足 ACME v2 协议通信要求。我见过太多人绕开 Ubuntu 18.04 原生方案,硬上 Docker 或手动编译新版本 Certbot,结果因 Python 依赖冲突、systemd 服务单元文件路径错位、或 OpenSSL 版本不匹配,卡在证书申请环节长达数小时——其实,官方路径最稳,原生集成最省心。
这里必须点破一个常见误解:很多人以为“装了 Let’s Encrypt 就等于安全了”。错。Let’s Encrypt 只解决“传输层加密”这一个环节,即防止中间人窃听和篡改数据流。它不防 SQL 注入、不防 XSS 跨站脚本、不防暴力破解登录接口。但它是一道不可绕过的基础设施门槛——就像你不会在没装防盗门的情况下,先去研究怎么加固室内保险柜。本文要做的,就是帮你把这扇“防盗门”严丝合缝地装上,并让它自己定期换锁芯(自动续期),而不是每次到期前手忙脚乱地重配一遍。
提示:本文所有命令均基于 Ubuntu 18.04 官方最小化安装镜像验证,无需额外添加 PPA 或升级系统内核。若你使用的是云服务器(如 AWS EC2、阿里云 ECS),请确保安全组/防火墙已放行 TCP 80 和 443 端口;若为本地虚拟机,请确认网络模式为桥接或 NAT 并正确映射端口。
2. 从零开始:Nginx + Let’s Encrypt 在 Ubuntu 18.04 上的完整部署链路
部署不是“复制粘贴几条命令”,而是一条有逻辑、有检查点、可回溯的流水线。我把整个过程拆解为五个原子步骤,每一步都对应一个明确的状态目标,失败时能精准定位问题环节。
2.1 环境初始化:确认基础服务与域名解析就绪
第一步永远不是敲apt install,而是做三件事:
确认 Nginx 已安装并监听 80 端口:
sudo systemctl status nginx # 应显示 active (running),且 Loaded 行指向 /lib/systemd/system/nginx.service sudo ss -tlnp | grep ':80' # 应输出类似:LISTEN 0 128 *:80 *:* users:(("nginx",pid=1234,fd=6),("nginx",pid=1235,fd=6))如果未安装,执行
sudo apt update && sudo apt install nginx -y;如果状态异常,先sudo systemctl restart nginx并检查/var/log/nginx/error.log。确认域名已正确解析到服务器 IP:
假设你的域名是example.com,在本地终端执行:dig +short example.com # 必须返回你的服务器公网 IP(如 203.0.113.10) ping -c 1 example.com # 应能通,且 IP 地址一致若解析失败,请检查 DNS 服务商(如 Cloudflare、阿里云 DNS)的 A 记录是否指向正确 IP,且 TTL 值已过期(通常 5-10 分钟)。Let’s Encrypt 的验证机制(HTTP-01)会向你的域名发起 HTTP 请求,如果 DNS 解析失败,证书申请必然中断。
确认服务器时间准确:
timedatectl status # Local time 应与当前 UTC 时间误差 < 1 秒,Time zone 应为正确时区(如 Asia/Shanghai)时间偏差超过 5 分钟会导致 ACME 协议握手失败(证书有效期校验出错)。若不准,执行
sudo timedatectl set-ntp on启用 NTP 同步。
注意:Ubuntu 18.04 默认使用
systemd-timesyncd作为 NTP 客户端,它比旧版ntpd更轻量、更可靠。不要手动安装chrony或ntpd,避免服务冲突。
2.2 安装 Certbot 并验证其与 Nginx 的深度集成能力
Ubuntu 18.04 的universe源中已预置 Certbot,但关键在于安装带 Nginx 插件的完整包,而非仅certbot命令行工具。后者只能手动配置证书,无法自动修改 Nginx 配置文件,极易出错。
sudo add-apt-repository universe sudo apt update sudo apt install certbot python3-certbot-nginx -y安装完成后,验证插件是否生效:
certbot --nginx --help | grep "nginx" # 应输出包含 --nginx-server-root, --nginx-ctl 等参数说明 sudo certbot --version # 应显示 0.31.x 版本(Ubuntu 18.04 官方源版本)python3-certbot-nginx包的核心价值在于:它能直接读取/etc/nginx/sites-enabled/下的配置文件,自动识别server_name指令,并在匹配的server块中插入ssl_certificate和ssl_certificate_key指令。它甚至能智能处理多域名、多 server 块的复杂场景。这是手动编辑配置文件无法比拟的安全性和效率。
实操心得:我曾遇到一台服务器,
/etc/nginx/sites-enabled/default被注释掉,实际生效的是/etc/nginx/sites-enabled/myapp。Certbot 默认会扫描sites-enabled目录下所有非注释的.conf文件,但如果myapp文件里server_name写的是localhost而非真实域名,Certbot 会找不到匹配项,报错No matching nginx servers found。此时需先修正server_name example.com;,再运行 Certbot。
2.3 执行首次证书申请:一次成功的关键在于“验证阶段”的可控性
执行申请命令:
sudo certbot --nginx -d example.com -d www.example.com这条命令背后发生的事远比表面复杂:
Step 1:ACME 协议握手
Certbot 向 Let’s Encrypt 的 ACME 服务器(https://acme-v02.api.letsencrypt.org/directory)发起注册请求,生成一对临时密钥(Account Key),并获取协议端点信息。Step 2:HTTP-01 挑战发起
Let’s Encrypt 服务器向http://example.com/.well-known/acme-challenge/xxxxx发送 HTTP GET 请求。Certbot 必须确保该路径能被公网访问,且返回正确的随机字符串(Token)。Step 3:Nginx 自动配置注入
Certbot 检测到--nginx参数后,会临时修改 Nginx 配置:在匹配example.com的server块中,动态插入一个location ^~ /.well-known/acme-challenge/块,将其root指向 Certbot 的挑战文件目录(通常是/var/lib/letsencrypt/webroot/),并禁用所有其他 location 规则。这个操作是原子性的,且 Certbot 会自动sudo nginx -t测试语法,再sudo systemctl reload nginx生效。Step 4:验证与签发
Let’s Encrypt 服务器收到正确响应后,生成证书(fullchain.pem)和私钥(privkey.pem),并返回给 Certbot。Certbot 将它们存入/etc/letsencrypt/live/example.com/,并再次修改 Nginx 配置,添加 SSL 相关指令。
为什么这一步常失败?根本原因只有两个:
- 防火墙阻断:UFW(Ubuntu Firewall)默认关闭 80 端口。执行
sudo ufw allow 'Nginx Full'(等价于开放 80+443)。 - Nginx 配置冲突:某些模板中存在
location / { try_files $uri $uri/ =404; },它会拦截/.well-known/路径。Certbot 的自动注入会覆盖它,但如果你的配置里有location ~ /\.ht这类正则规则,可能优先级更高。此时需手动检查/etc/nginx/sites-enabled/下所有文件,确保没有location规则意外拦截/.well-known/。
2.4 验证 HTTPS 是否真正生效:不止是看浏览器小锁图标
证书装上了,不代表万事大吉。必须进行三层验证:
基础连通性验证:
curl -I https://example.com # 应返回 HTTP/2 200,且 Header 中包含 server: nginx,date 字段正常 openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates # 应显示 notBefore 和 notAfter 日期,有效期为 90 天证书链完整性验证:
Let’s Encrypt 使用 ISRG Root X1 根证书,但部分老旧客户端(如 Windows XP、Android 4.x)不信任它,需要中间证书(R3)补全链。Certbot 生成的fullchain.pem已包含完整链。验证命令:echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -text | grep "Issuer:" # 应显示 Issuer: C = US, O = Let's Encrypt, CN = R3Nginx SSL 配置健壮性验证:
访问 SSL Labs SSL Test ,输入你的域名。一个合格的配置应达到A+ 评级。若低于 A,常见原因:- 缺少
ssl_dhparam:执行sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048,并在 Nginx 的server块中添加ssl_dhparam /etc/ssl/certs/dhparam.pem; - 使用了弱密码套件:在
server块中添加ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:!aNULL:!MD5:!DSS'; - 未启用 HSTS:添加
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
- 缺少
踩坑实录:某次我为一个子域名
api.example.com申请证书,SSL Labs 测评显示“A-”,原因是主域名example.com的 Nginx 配置中ssl_protocols TLSv1.2;被错误写成ssl_protocols TLSv1;。Certbot 会复用主配置的 SSL 指令,导致子域名也继承了 TLSv1(已废弃)。解决方案:为每个server块单独定义ssl_protocols和ssl_ciphers,避免全局污染。
2.5 配置自动续期:让安全成为“无感”的基础设施
Let’s Encrypt 证书有效期仅 90 天,这是其安全模型的核心设计——缩短密钥暴露窗口,降低私钥泄露风险。手动续期是运维灾难的源头。Ubuntu 18.04 的 Certbot 已通过 systemd timer 实现全自动续期。
验证 timer 状态:
sudo systemctl list-timers | grep certbot # 应显示 certbot.timer,Next 列为未来某个时间(如 2024-06-15 06:12:02) sudo systemctl status certbot.timer # 应显示 loaded, active (waiting)Certbot 的 timer 默认每天凌晨 6:12 执行certbot renew。该命令逻辑是:
- 扫描
/etc/letsencrypt/renewal/下所有.conf文件; - 对每个证书,检查其
notAfter日期,若剩余有效期 < 30 天,则触发续期; - 续期过程完全复用首次申请的验证方式(HTTP-01),无需人工干预。
但必须手动验证续期流程是否真能跑通!
sudo certbot renew --dry-run # 应输出:- The following errors were reported by the server: ... No errors. # 最终显示:** DRY RUN: simulating 'certbot renew' close to cert expiry # ** (The test certificates below have not been saved.)--dry-run是黄金法则。它使用 Let’s Encrypt 的 Staging 环境(证书无效,但流程完全一致),消耗的是测试额度,不会影响生产证书配额(每周 5 次)。我坚持每次部署新服务器后必跑此命令,因为:
- 它会暴露出 DNS 解析延迟、防火墙策略变更、Nginx 配置语法错误等所有潜在问题;
- 它验证了
/etc/letsencrypt/renewal/下的配置文件是否完整(Certbot 会为每个-d域名生成独立.conf文件); - 它确认了
renew_hook(续期后执行的钩子)是否配置正确(如systemctl reload nginx)。
关键经验:
certbot renew默认只续期“即将过期”的证书。若你想强制续期所有证书(如更换密钥算法),需加--force-renewal参数,但切勿在生产环境随意使用,它会快速耗尽 Let’s Encrypt 的速率限制(每周 5 次)。真正的运维智慧是:信任--dry-run,然后让certbot.timer默默工作。
3. 深度解析:Nginx SSL 配置中的 7 个决定性参数及其安全权重
Certbot 自动生成的 Nginx 配置(位于/etc/nginx/sites-enabled/对应文件中)是一个安全基线,但绝非终点。它为了兼容性牺牲了部分前沿安全特性。以下是必须手动审查并优化的 7 个核心参数,按安全权重降序排列:
3.1ssl_protocols:协议版本是安全的“地基”,选错即全盘皆输
Certbot 默认生成:
ssl_protocols TLSv1.2;这是目前最安全的选择。必须删除TLSv1和TLSv1.1。原因:
- TLSv1.0 和 TLSv1.1 存在 POODLE、BEAST 等高危漏洞,2020 年起已被 PCI DSS(支付卡行业安全标准)明令禁止;
- Ubuntu 18.04 的 OpenSSL 1.1.1 原生支持 TLSv1.3,但 Nginx 1.14(Ubuntu 18.04 默认版本)不支持 TLSv1.3。强行添加
TLSv1.3会导致nginx -t报错invalid value "TLSv1.3"。 - 结论:
TLSv1.2是 Ubuntu 18.04 上唯一安全、稳定、兼容的选项。添加TLSv1.3需先升级 Nginx 至 1.17+,这会引入额外的编译和稳定性风险,不推荐。
3.2ssl_ciphers:密码套件是加密的“锁芯”,强度决定破解难度
Certbot 默认未设置此参数,Nginx 使用其编译时的 OpenSSL 默认套件,其中可能包含RC4、DES等弱算法。必须显式定义:
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:!aNULL:!MD5:!DSS';这个列表的设计逻辑:
- 优先 ECDHE 密钥交换:提供前向保密(PFS),即使服务器私钥泄露,历史流量也无法被解密;
- 优先 AES-GCM 模式:比 CBC 模式更安全、更高效;
- 排除所有已知弱算法:
!aNULL(无认证)、!MD5(哈希碰撞)、!DSS(数字签名标准,已过时); - 保留 ECDSA 和 RSA 双栈:兼顾现代椭圆曲线(ECDSA)和传统 RSA 证书的兼容性。
验证效果:
openssl ciphers -V 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:...' | wc -l # 应输出约 20-30 个有效套件3.3ssl_prefer_server_ciphers on:服务器主导权是性能与安全的平衡点
此参数默认为off,意味着客户端(浏览器)可以自由选择它支持的任意套件,包括一些老旧、低效的选项。设为on后,Nginx 会严格按照ssl_ciphers列表的顺序,选择第一个双方都支持的套件。这带来两大好处:
- 安全提升:强制使用你精心筛选的强套件,杜绝客户端“降级”到弱算法;
- 性能提升:避免协商过程中的多次往返,尤其对移动网络友好。
3.4ssl_session_cache shared:SSL:10m:会话缓存是 HTTPS 性能的“加速器”
HTTPS 握手(尤其是 TLSv1.2)涉及昂贵的非对称加密运算。ssl_session_cache允许 Nginx 将已建立的会话 ID 和主密钥缓存在内存中(shared表示进程间共享,10m表示分配 10MB 内存)。当同一客户端再次连接时,可复用会话,跳过完整握手,将延迟降低 50% 以上。
计算容量:10MB 缓存 ≈ 可存储 40,000 个会话(每个会话约 250 字节)。对于日活万级的网站足够。若流量巨大,可增至20m。
3.5ssl_session_timeout 10m:会话超时是安全与资源的“折中线”
此参数定义缓存中会话的有效期。10m(10 分钟)是业界黄金值:
- 太短(如
1m):缓存命中率暴跌,大部分连接仍需完整握手,失去缓存意义; - 太长(如
24h):内存占用剧增,且若私钥泄露,攻击者可利用长期缓存的会话密钥解密更多历史流量(尽管有 PFS,但会话密钥本身是短期的)。10m在资源消耗和安全风险间取得最佳平衡。
3.6add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload":HSTS 是 HTTPS 的“强制开关”
HSTS(HTTP Strict Transport Security)头告诉浏览器:“未来一年内,无论用户输入http://还是直接敲域名,都必须用 HTTPS 访问,并且要包含所有子域名”。preload参数表示你已将域名提交至浏览器 HSTS Preload List(需单独申请),实现首次访问即 HTTPS。
重要警告:一旦启用max-age=31536000(1 年)且带上preload,就无法撤回!若你的 HTTPS 配置在未来某天失效(如证书过期、Nginx 崩溃),用户将完全无法访问网站,直到 HSTS 过期。因此,首次部署务必先用max-age=300(5 分钟)测试一周,确认一切稳定后,再逐步延长至31536000。
3.7ssl_buffer_size 4k:缓冲区大小是移动端体验的“隐形推手”
Nginx 默认ssl_buffer_size为 16k。在移动网络(高延迟、小包)下,大缓冲区会导致 TLS 记录层等待填满才发送,增加首字节时间(TTFB)。设为4k可显著改善移动端加载速度,且对服务器 CPU 和内存压力几乎无影响。这是被大量忽略的“微优化”,但对用户体验提升明显。
实操对比:我在一个新闻聚合站点(日均 PV 50 万)上将
ssl_buffer_size从 16k 改为 4k,使用 WebPageTest 测试 3G 网络下的 TTFB,平均下降 120ms,首屏渲染时间(FCP)提升 8%。这不是理论,是真实数据。
4. 故障排查全景图:从证书申请失败到 HTTPS 访问异常的 12 个高频问题链
再完美的流程也会遇到意外。我把过去三年在 Ubuntu 18.04 上处理的数百个 Let’s Encrypt/Nginx 问题,归纳为一条清晰的排查链路。每个问题都标注了根本原因、诊断命令、修复方案、以及一个真实案例。
4.1 问题链起点:certbot --nginx命令报错 “No nginx installation detected”
根本原因:Certbot 的 Nginx 插件无法定位 Nginx 的主配置文件或二进制路径。
诊断命令:
sudo certbot --nginx --debug | grep -A5 "nginx path" # 查看 Certbot 尝试读取的路径 which nginx # 查看 nginx 二进制位置 ls -l /etc/nginx/nginx.conf # 确认主配置文件是否存在且可读修复方案:
- 若
nginx不在/usr/sbin/nginx,创建符号链接:sudo ln -sf $(which nginx) /usr/sbin/nginx; - 若
/etc/nginx/nginx.conf不存在,检查是否误删,或从/usr/share/nginx/复制默认配置。
真实案例:客户使用自编译 Nginx,安装到/opt/nginx,which nginx返回/opt/nginx/sbin/nginx。Certbot 默认只查/usr/sbin/nginx。修复:sudo ln -sf /opt/nginx/sbin/nginx /usr/sbin/nginx。
4.2 问题链分支一:申请时卡在 “Waiting for verification…” 超时
根本原因:Let’s Encrypt 服务器无法通过 HTTP 访问/.well-known/acme-challenge/。
诊断命令:
# 在服务器本地测试 curl -v http://example.com/.well-known/acme-challenge/test # 应返回 404(路径存在但文件不存在),而非 403/404/Connection refused # 在外部网络测试(用手机 4G 网络) curl -v http://example.com/.well-known/acme-challenge/test修复方案:
- 检查 UFW:
sudo ufw status,确保Nginx Full或80端口开放; - 检查云服务商安全组;
- 检查 Nginx 配置中是否有
location / { deny all; }类规则,临时注释掉。
4.3 问题链分支二:申请成功,但浏览器访问https://example.com显示 “Your connection is not private”
根本原因:证书链不完整,浏览器无法构建从站点证书到受信根证书的信任链。
诊断命令:
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -text | grep "Subject:" -A1 # 查看 Subject 和 Issuer 是否为 R3 curl -s https://example.com | head -1 # 确认页面能返回内容,排除 Nginx 配置错误修复方案:
- 确认 Certbot 生成的
ssl_certificate指向fullchain.pem(而非cert.pem):ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # 正确 ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; - 若手动修改过,执行
sudo nginx -t && sudo systemctl reload nginx。
4.4 问题链分支三:HTTPS 访问正常,但页面内资源(CSS/JS/图片)显示为 “Mixed Content”
根本原因:HTML 中引用了http://协议的资源,浏览器出于安全策略阻止加载。
诊断命令:
curl -s https://example.com | grep -i "http://" # 查找所有硬编码的 http 链接修复方案:
- 在 Nginx 配置中添加重写规则(治标):
location / { sub_filter 'http://' 'https://'; sub_filter_once off; proxy_set_header Accept-Encoding ''; } - 更优方案:修改应用代码,将所有资源链接改为协议相对(
//example.com/style.css)或绝对 HTTPS 链接。这是根本解法。
4.5 问题链分支四:certbot renew --dry-run报错 “Failed authorization procedure”
根本原因:续期时 HTTP-01 验证失败,通常因 Nginx 配置变更导致/.well-known/路径不可达。
诊断命令:
sudo certbot renew --dry-run --debug # 查看详细错误日志,定位是哪个域名失败 sudo ls -la /var/lib/letsencrypt/webroot/ # 确认挑战文件目录存在且 Certbot 有写入权限修复方案:
- 检查
/etc/nginx/sites-enabled/下所有配置,确保没有location ^~ /.well-known/被其他location规则覆盖; - 临时添加一个通用规则(放在所有
server块末尾):location ^~ /.well-known/acme-challenge/ { root /var/lib/letsencrypt/webroot; default_type "text/plain"; }
4.6 问题链分支五:SSL Labs 测评显示 “Certificate not trusted” 或 “Chain issues”
根本原因:fullchain.pem文件损坏,或 Nginx 未正确加载。
诊断命令:
sudo nginx -t # 检查语法 sudo openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -text -noout | head -20 # 查看证书内容是否正常修复方案:
- 重新生成
fullchain.pem:sudo cat /etc/letsencrypt/live/example.com/cert.pem /etc/letsencrypt/live/example.com/chain.pem | sudo tee /etc/letsencrypt/live/example.com/fullchain.pem sudo systemctl reload nginx
4.7 问题链分支六:certbot renew后,Nginx 未自动重载,HTTPS 仍用旧证书
根本原因:Certbot 的renew_hook未配置,或配置错误。
诊断命令:
sudo cat /etc/letsencrypt/renewal/example.com.conf | grep renew_hook # 应输出 renew_hook = systemctl reload nginx修复方案:
- 编辑
/etc/letsencrypt/renewal/example.com.conf,在[renewalparams]下添加:renew_hook = systemctl reload nginx - 或全局配置:
sudo certbot renew --renew-hook "systemctl reload nginx"。
4.8 问题链分支七:curl -I https://example.com返回 301 重定向到 HTTP,形成死循环
根本原因:Nginx 配置中存在return 301 http://$host$request_uri;这类强制跳转,且未加if ($scheme = http)条件判断。
诊断命令:
sudo nginx -T | grep -A5 "return 301" # 查看所有 return 301 指令修复方案:
# 正确写法:只对 HTTP 请求重定向 server { listen 80; server_name example.com; return 301 https://$server_name$request_uri; } # 确保 443 server 块中没有 return 301 到 http4.9 问题链分支八:Firefox 浏览器访问提示 “SEC_ERROR_UNKNOWN_ISSUER”
根本原因:Firefox 使用自己的证书信任库(NSS),未同步系统 ca-certificates。
诊断命令:
sudo update-ca-certificates --fresh # 强制更新系统证书库修复方案:
- 在 Firefox 地址栏输入
about:config,搜索security.enterprise_roots.enabled,设为true; - 或重启 Firefox,它会自动从系统读取更新后的证书。
4.10 问题链分支九:certbot renew报错 “Too many failed authorizations”
根本原因:Let’s Encrypt 的速率限制被触发(每域名每周最多 5 次失败验证)。
诊断命令:
sudo certbot certificates # 查看所有证书状态修复方案:
- 立即停止所有
--force-renewal操作; - 等待 7 天,或使用
--dry-run测试; - 检查 DNS 和防火墙,确保下次申请 100% 成功。
4.11 问题链分支十:Nginx 启动失败,nginx -t报错 “unknown directive ‘ssl_dhparam’”
根本原因:ssl_dhparam指令在 Nginx 1.10.3+ 才支持,而 Ubuntu 18.04 的 Nginx 1.14 完全支持,报错说明你误用了旧版 Nginx。
诊断命令:
nginx -v # 应显示 nginx version: nginx/1.14.0 (Ubuntu)修复方案:
- 删除
ssl_dhparam行,或确认/etc/ssl/certs/dhparam.pem文件存在且路径正确; - 若文件不存在,按 2.4 节生成。
4.12 问题链终点:certbot renew成功,但systemctl status certbot.timer显示 “failed”
根本原因:timer 触发的certbot renew命令因权限或路径问题失败。
诊断命令:
sudo journalctl -u certbot.timer -n 50 --no-pager # 查看 timer 日志 sudo journalctl -u certbot.service -n 50 --no-pager # 查看 service 日志**修复
