06-发布版:HTTPS 与 Let’s Encrypt

06-发布版:HTTPS 与 Let’s Encrypt

发布版说明

  • 已对真实域名、公网 IP、具体云厂商指代做脱敏处理。
  • 原始学习笔记未改动,这一版用于公开发布。

专题:HTTPS 与 Let’s Encrypt

这篇专门把前面你已经真实遇到过的 HTTPS 问题讲透。

不是教你背一条 Certbot 命令,而是要真正搞明白:

  1. HTTPS 到底解决什么问题
  2. Let’s Encrypt 到底在验证什么
  3. 为什么明明本机正常,证书还是签不下来
  4. 为什么明明证书已经在机器上了,公网访问还是超时

一、先把 HTTPS 这件事讲人话

用户访问:

http://status.example.com

和访问:

https://status.example.com

区别不是“多了个 s”这么简单。

本质区别有两件事:

1.1 数据被加密了

HTTP 明文传输,链路中间如果有人抓包,理论上能看到内容。

HTTPS 会先建立 TLS 加密通道,再传 HTTP 数据。

所以浏览器、服务器之间传的内容,不再是裸奔。


1.2 浏览器能确认“你连的真是这个域名”

这就涉及证书。

浏览器不是无条件相信服务器的,它需要看:

  • 这个证书是不是可信 CA 签发的
  • 证书里的域名是不是当前访问的域名
  • 证书有没有过期

如果都对,浏览器才会给你安全锁。


二、证书不是“给服务器签”的,是“给域名签”的

这个点特别重要。

比如你申请的是:

status.example.com

那证明的是:

你对这个域名具备控制权

不是证明:

  • 你拥有这台服务器
  • 你会配 Nginx
  • 你的应用没问题

所以证书签发这件事,本质上是:

CA 要确认你真能控制这个域名的访问路径。


三、Let’s Encrypt 的 HTTP-01 挑战到底在干什么

前面你申请证书时,最典型的报错是:

  • CA 去访问 http://status.example.com/.well-known/acme-challenge/...
  • 拿到的不是挑战文件
  • 而是你站点自己的 HTML

这背后其实是 Let’s Encrypt 在做这件事:

3.1 它先给你一个随机 challenge 文件

Certbot 会在你指定的 webroot 里写一个临时文件。

路径通常长这样:

/.well-known/acme-challenge/<token>

3.2 Let’s Encrypt 从公网访问这个 URL

它会主动访问:

http://你的域名/.well-known/acme-challenge/<token>

注意这里是:

HTTP 80 端口

不是先验证 443。

这点很多人一开始容易搞反。


3.3 如果它能拿到正确内容,就认为你控制了这个域名

因为只有真正控制这个域名解析和站点响应的人,才能让这个 URL 返回正确的 challenge 内容。

所以:

HTTP-01 挑战是在验证“域名控制权”,不是在验证 HTTPS 自己是否已经可用。


四、为什么证书签发依赖 80,而不是先依赖 443

这是很多新手最容易绕进去的地方。

直觉上会觉得:

我要申请 HTTPS 证书,那不是应该先验证 443 吗?

其实不是。

原因很简单:

  • 你现在还没有可被浏览器信任的证书
  • 443 这一层还没法先建立可信 HTTPS
  • 所以 CA 必须用一个更基础的方法验证你控制了域名

这个更基础的方法,就是:

先走 HTTP 80 的 challenge。

所以如果 80 不通、或者 challenge 路径被吞了,证书就签不下来。


五、你前面遇到的证书失败,到底失败在哪

当时报错核心是:

Invalid response from http://status.example.com/.well-known/acme-challenge/...

并且返回的是一段 HTML 页面。

这说明不是 DNS 没解析,也不是 Certbot 没写文件,而是:

5.1 CA 已经成功访问到了你的服务器

这点非常关键。

如果它完全访问不到,报错就更偏向:

  • 超时
  • 连接失败
  • 找不到主机

而你这里拿到的是“错误内容”。

说明请求到服务器了,只是被错误处理了。


5.2 挑战路径没有被正确映射到 webroot

最常见原因是:

location / {
    proxy_pass http://127.0.0.1:3001;
}

这种通配规则把 challenge 请求也一起转发走了。

或者你本来做的是静态站点,结果 challenge 请求被默认首页接住了。

于是:

  • Certbot 认为 challenge 文件应该从某个目录直接读出来
  • 但 Nginx 没按这个逻辑处理
  • CA 最终拿到的就不是 token 文件,而是别的页面

这就是你当时失败的根因。


六、正确理解 Nginx 里 challenge 路径的优先级

申请证书时,Nginx 最少要保证一件事:

/.well-known/acme-challenge/ 这条路径能返回 challenge 文件本身

最典型的思路是给它单独留一个 location

location /.well-known/acme-challenge/ {
    root /var/www/certbot;
}

或者你用 webroot 模式时,让它明确指向 Certbot 写文件的目录。

重点不是非得背这个写法,而是理解:

  • challenge 路径必须有独立处理逻辑
  • 不能被笼统的 location / 规则吞掉

这就是证书申请时最容易踩的 Nginx 坑。


七、证书签下来了,为什么公网 HTTPS 还是超时

你前面又碰到了第二个非常典型的坑:

  • 本机 curl --resolve ... 443:127.0.0.1 能通
  • 证书也已经在机器上了
  • nginx 也监听了 443
  • 但公网访问 https://status.example.com 还是超时

最后发现不是 Nginx 本身,而是:

云厂商安全组没放行 443

这件事非常值钱,因为它直接把“本机配置”和“公网链路”分开了。


八、你那次问题,按层拆开到底是什么样

那次其实可以拆成 4 层:

8.1 域名层

dig +short "status.example.com" 能返回:

203.0.113.10

说明域名已经指向服务器。


8.2 应用/Nginx 本机层

你测过:

curl -vkI --resolve "status.example.com:443:127.0.0.1" "https://status.example.com"

它能正常建立 TLS,并返回 302 /dashboard

这说明:

  • Nginx 的 443 站点存在
  • 证书加载成功
  • 本机 HTTPS 链路没问题

8.3 Linux 防火墙层

你当时 ufw status 已经显示:

  • 80 已放行
  • 443 已放行

说明 Ubuntu 本机防火墙并没有拦住它。


8.4 云安全组层

外网还是超时,最后问题落在云厂商安全组。

这一步一旦没放行,外面的流量根本到不了你这台机器。

所以才会出现这种看起来很拧巴的现象:

  • 本机一切正常
  • 公网就是不通

不是系统玄学,就是外层网络策略拦住了。


九、所以 HTTPS 问题以后该怎么排

以后你碰到 HTTPS 不通,不要一上来就反复删证书重签,先按层查。

第 1 步:查域名解析

dig +short "status.example.com"

先确认域名确实指向你的服务器公网 IP。


第 2 步:查 80 端口的 HTTP 站点是否可达

curl -I "http://status.example.com"

如果连 HTTP 都完全不通,先别谈证书。

因为 HTTP-01 挑战本来就依赖 80。


第 3 步:查 challenge 路径是否真的能拿到文件

证书申请时最重要的是这一层。

如果 challenge 请求拿到的是:

  • 默认页
  • 应用首页
  • 302 跳转
  • 404

那都说明 challenge 路径没被正确接住。


第 4 步:查 Nginx 配置语法和监听

sudo nginx -t
sudo ss -lntp | grep -E ':80|:443'

看:

  • 配置有没有语法错误
  • 80/443 有没有真的被 Nginx 监听

第 5 步:查本机 HTTPS 是否正常

curl -vkI --resolve "status.example.com:443:127.0.0.1" "https://status.example.com"

这个命令非常硬核,价值很高。

它验证的是:

  • 域名证书是否装进了 Nginx
  • 本机 443 站点本身是否可用

如果这一步通,说明 Nginx 和证书八成没问题。


第 6 步:查防火墙和云安全组

如果本机 443 正常,但公网访问超时,就去查:

  • ufw
  • 云厂商安全组

这一步你已经亲手踩过一次了,以后就不会忘。


十、证书文件装上去以后,Nginx 在干什么

HTTPS 站点大概会变成这样:

server {
    listen 443 ssl http2;
    server_name status.example.com;

    ssl_certificate /etc/letsencrypt/live/status.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/status.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3001;
    }
}

这几行的意思其实很朴素:

  • listen 443 ssl:这个站点走 HTTPS
  • ssl_certificate:浏览器握手时发给对方的证书链
  • ssl_certificate_key:和证书配套的私钥
  • proxy_pass:TLS 解开以后,再把 HTTP 请求转给后端应用

所以 HTTPS 往往是:

浏览器
  -> HTTPS 到 Nginx
  -> Nginx 解密
  -> HTTP 到本机后端

很多应用本身并不需要自己处理证书,这正是反代架构的好处。


十一、你现在应该彻底建立的几个判断

11.1 证书申请阶段,重点是 80 和 challenge 路径

不是先盯着 443。


11.2 本机证书正常,不代表公网一定通

因为公网还受:

  • 本机防火墙
  • 云安全组

影响。


11.3 challenge 失败,不一定是 Certbot 命令错了

很多时候是:

  • Nginx 路由规则不对
  • challenge 文件目录不对
  • 80 端口没通

11.4 浏览器报 HTTPS 问题,不一定是应用有问题

先分清:

  1. 是证书签发失败
  2. 还是证书装载失败
  3. 还是 443 外网不通
  4. 还是应用反代后端挂了

这四个不是一回事。


十二、把你这几次实战串成一句完整的话

现在你前面做过的那几次部署,已经能用一句非常完整的话描述:

先让域名解析到服务器,再让 Nginx 在 80 口正确接住域名请求,给 challenge 路径留出能被 CA 访问到的静态文件入口,签发 Let’s Encrypt 证书后,再在 443 口加载证书并把 HTTPS 请求反代到本机后端应用;如果本机正常但公网超时,还要继续检查 Linux 防火墙和云安全组。

你能说出这句话,说明 HTTPS 这套逻辑已经不是“会用命令”,而是真懂了。


十三、下一步最适合继续学什么

下一课建议接:

06-专题:云服务器网络分层排障

或者更直接一点叫:

07-专题:云厂商安全组、UFW、端口监听与公网访问

因为你现在最值钱的经验,已经不只是“应用怎么部署”,而是开始真正进入:

  • 请求到底卡在哪一层
  • 为什么本机通但公网不通
  • 怎么快速定位是 DNS、Nginx、应用、Linux 防火墙,还是云安全组

这块一旦吃透,以后排障效率会直接翻倍。

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容