Linux 网站运维实战:HTTP 全链路 + 数字签名 CA + 分层排错(SCDN 项目篇 Day17)
文章目录
- Linux 网站运维实战:HTTP 全链路 + 数字签名 CA + 分层排错(SCDN 项目篇 Day17)
- 零、环境准备
- 一、URL 与 URI:先分清这俩
- 二、HTTP 请求与响应:一次访问的内部
-
- 2.1 请求报文:请求行 + 请求头 + 请求体
- 2.2 响应报文:状态行 + 响应头 + 响应体
- 2.3 用 curl 看真实报文(最实用的排错起点)
- 三、响应状态码全解释
- 四、数字签名与 CA:HTTPS 为什么可信
-
- 4.1 非对称加密:公钥和私钥
- 4.2 数字签名:证明“是我发的、没被改”
- 4.3 CA 给服务器签发证书:解决“你怎么证明你是你”
- 4.4 看看证书里到底有啥
- 4.5 申请一张正式证书的流程(以 Let's Encrypt 为例)
- 五、网站排错实战:分层定位(全篇重点)
- 六、总结
前言:SCDN 项目上线后,最常接到的报警就是“网站打不开”。 但“打不开”三个字背后,可能是 DNS 没解析、端口没监听、nginx 配错、文件丢了、证书过期……十几处都可能。 这一篇把 URL/URI 概念 → HTTP 请求响应 → 数字签名与 CA 证书 → 分层排错 一次讲透,让你下次看报错不再抓瞎。
零、环境准备
| Web 服务器 | srv01 | 192.168.10.11 | Ubuntu 22.04,跑 Nginx,域名 www.example.com |
| 客户端 | 你手边任意机 | — | 用 dig/curl/nc 测试 |
| 账号 | storeadm | 有 sudo 权限 | 全篇用它操作 |
下面所有命令均以 Ubuntu(apt 系) 为准,你替换成自己的域名和 IP 即可。
一、URL 与 URI:先分清这俩
很多人混用,其实不一样:
URI = Uniform Resource Identifier 统一资源标识符(告诉“是什么”,身份)
URL = Uniform Resource Locator 统一资源定位符(告诉“在哪”,位置)
URN = Uniform Resource Name 统一资源名称(按名字定位,少用)
关系一句话:URL 是 URI 的一种——能定位的标识符。
URI(大圈)
├── URL:https://www.example.com:443/path?name=1 ← 既标识又定位 ✅
└── URN:urn:isbn:9787111111111 ← 只标识(ISBN 号)
拆开一个 URL 看每一段:
https://www.example.com:443/book/list?page=2#top
| https | 协议 (scheme) | 用啥方式访问;https = http + TLS 加密 |
| www.example.com | 主机名 (host) | 给 DNS 去查 IP 的 |
| 443 | 端口 (port) | 默认 80(http)/443(https),写了就覆盖默认 |
| /book/list | 路径 (path) | 服务器上对应哪个资源 |
| ?page=2 | 查询 (query) | 给资源传参数 |
| #top | 片段 (fragment) | 浏览器本地定位锚点,不会传到服务器 |
二、HTTP 请求与响应:一次访问的内部
你在浏览器敲下回车,背后是一次 请求 (Request) 和一次 响应 (Response),都是纯文本报文。
① 浏览器 ──请求报文(请求行 + 请求头 + 请求体)──► 服务器(Nginx)
② 浏览器 ◄──响应报文(状态行 + 响应头 + 响应体)── 服务器(Nginx)
2.1 请求报文:请求行 + 请求头 + 请求体
POST /login HTTP/1.1 ← 请求行:方法 路径 协议版本
Host: www.example.com ← 请求头:告诉服务器“我是访问哪个域名来的”
User-Agent: Mozilla/5.0 …
Accept: text/html
Content-Type: application/json ← 告诉服务器:我传的数据是 JSON
Content-Length: 36
Cookie: session=abc123
{"user":"alice","pwd":"******"} ← 请求体(body):真正提交的数据
常用请求头逐个解释:
| Host | 必须有,HTTP/1.1 靠它区分一台服务器上多个域名 |
| User-Agent | 客户端身份(浏览器/爬虫/脚本);服务端可据此返回不同内容 |
| Accept | 客户端能接受的数据类型(html/json…) |
| Content-Type | 请求体是什么格式:application/json、x-www-form-urlencoded、multipart/form-data(上传) |
| Content-Length | 请求体字节数;少了/错了,服务端读不全 |
| Cookie | 把上次服务端给的凭证带回去(维持登录态) |
| Authorization | 鉴权头:Bearer <token> 或 Basic 账号密码 |
| Referer | 从哪个页面跳过来的(防盗链常用) |
| Connection | keep-alive 复用连接,省握手开销 |
请求体 (body): 只在 POST/PUT 等有数据的请求里出现,放提交的内容——表单字段、JSON、上传的文件字节流。GET 请求一般没有 body(参数都放在 URL 的 query 里)。
2.2 响应报文:状态行 + 响应头 + 响应体
HTTP/1.1 200 OK ← 状态行:协议 状态码 原因短语
Server: nginx/1.24.0
Content-Type: text/html; charset=utf-8 ← 响应体是什么类型
Content-Length: 1024
Set-Cookie: session=xyz; Path=/ ← 让浏览器种 cookie
Cache-Control: max-age=3600
<!DOCTYPE html>… ← 响应体:浏览器真正渲染的 HTML
常用响应头:
| Content-Type | 响应体类型;写错浏览器会乱码或不执行 |
| Content-Length | 响应体大小;和实际不符会截断 |
| Server | 服务器软件及版本(安全起见常被隐藏) |
| Set-Cookie | 下发 cookie,建立会话 |
| Location | 重定向目标;配合 3xx 状态码使用 |
| Cache-Control | 缓存策略(多久过期) |
| Strict-Transport-Security | 强制 https(HSTS) |
2.3 用 curl 看真实报文(最实用的排错起点)
curl -v https://www.example.com/ # -v 把请求头、响应头全部打印出来
-v 输出里:
- > 开头的是你发出去的请求(请求行 + 请求头)
- < 开头的是服务器回来的响应(状态行 + 响应头)
- 最后才是响应体
# 只看响应头(不要 body),排查状态码/证书最快
curl -I https://www.example.com/
# 顺便看握手详情(证书、TLS 版本)
curl -Iv https://www.example.com/
三、响应状态码全解释
状态码是服务器给你的“诊断字”,看到它基本就知道往哪查。
1xx 信息:请求已收,继续
2xx 成功
3xx 重定向:要去别的地方拿
4xx 客户端错:你(请求)有问题
5xx 服务端错:服务器自己挂了/后端挂了
| 200 OK | 成功 | 正常,无需处理 |
| 201 Created | 资源已创建 | POST 成功建了数据 |
| 204 No Content | 成功但无返回体 | 删除/更新成功常见 |
| 301 Moved | 永久重定向 | 域名迁移;看 Location |
| 302 Found | 临时重定向 | 登录跳转常见 |
| 304 Not Modified | 缓存命中 | 资源没变,用本地缓存,正常 |
| 400 Bad Request | 请求畸形 | 参数/格式错误 |
| 401 Unauthorized | 未认证 | 没登录/没带 token |
| 403 Forbidden | 服务器拒绝(权限) | 文件权限、SELinux、nginx 的 deny、索引目录被关 |
| 404 Not Found | 找不到资源 | 文件路径/root 配错、URL 拼错 |
| 405 Method | 方法不被允许 | GET 接口用了 POST |
| 429 Too Many | 限流 | 请求太频繁,被防刷 |
| 500 | 服务器内部错 | 后端代码崩;查 error.log |
| 502 Bad Gateway | 网关错 | nginx 连不上后端(后端挂/端口错) |
| 503 | 服务不可用 | 过载/维护/限流 |
| 504 Gateway Timeout | 网关超时 | 后端响应太慢,超时;查后端+proxy_timeout |
排错口诀:4xx 看请求(URL/权限/参数),5xx 看后端(error.log + 后端进程),3xx 看 Location。
四、数字签名与 CA:HTTPS 为什么可信
HTTP 是明文,HTTPS = HTTP + TLS。TLS 靠非对称加密 + 数字签名 + CA 三件套保证“加密 + 防冒充”。
4.1 非对称加密:公钥和私钥
公钥:公开,谁都能拿,专门“上锁/验签”
私钥:自己藏好,专门“解锁/签名”
→ 公钥加密的内容,只有私钥能解;私钥签名的内容,公钥能验
4.2 数字签名:证明“是我发的、没被改”
发送方:对内容算一个哈希值 → 用自己的私钥加密这个哈希 → 这就是“数字签名”
接收方:用发送方公钥解密签名 → 得到哈希A;自己再算内容哈希B
A == B → 内容没被篡改,且确实来自持有私钥的那一方
4.3 CA 给服务器签发证书:解决“你怎么证明你是你”
光有公私钥还不够——攻击者也能生成一套公私钥冒充你(中间人)。需要一个大家都信的第三方来背书,这就是 CA(证书颁发机构)。
CA 做的事(签发证书):
① 服务器生成自己的公钥,连同域名等信息,生成 CSR 发给 CA
② CA 核实域名确实归你,用自己的【私钥】对“服务器公钥+域名+有效期”签名
③ 产出一张【服务器证书】交给你部署到 Nginx
浏览器验证(信任链):
① 浏览器内置各大 CA 的【公钥】
② 拿到服务器证书,用对应 CA 公钥验证那枚签名
③ 签名通过 → 确认证书里的服务器公钥可信、且域名匹配 → 用它加密通信
信任链(层层向上):
你的服务器证书 ← 被【中间 CA】签名
中间 CA 证书 ← 被【根 CA】签名(根 CA 自签名,内置在系统/浏览器)
根 CA ← 信任锚(出厂就信它)
为什么浏览器警告“自签名证书”? 自签名 = 你自己当 CA 给自己签名。可你的公钥没被任何浏览器内置的 CA 认可,浏览器无从验证,只能一律当成不可信。自签名只适合内网测试,公网必须上正规 CA(或 Let’s Encrypt 免费证书)。
4.4 看看证书里到底有啥
# ① 先把服务器的证书抓下来存成文件(Ubuntu 自带 openssl,无需安装)
echo | openssl s_client -connect www.example.com:443 2>/dev/null \\
| openssl x509 > /tmp/cert.pem
# ② 看证书全部内容(颁发者、域名、有效期、公钥都在里面)
openssl x509 -in /tmp/cert.pem -noout -text
# ③ 只看关键几项(命令短,不易抄错)
openssl x509 -in /tmp/cert.pem -noout -dates -subject -issuer
# notBefore / notAfter → 有效期(过期浏览器就报 ERR_CERT_DATE_INVALID)
# Subject → 证书绑定的域名
# Issuer → 谁签的(Let's Encrypt / DigiCert…)
注意是 s_client(s = ssl),别写成 x_client——没有这个子命令。
4.5 申请一张正式证书的流程(以 Let’s Encrypt 为例)
# 用 certbot 一键申请 + 自动续期(80 端口需可用,用于域名所有权验证)
sudo apt update
sudo apt install -y certbot python3-certbot-nginx
sudo certbot –nginx -d www.example.com
# 成功后证书在 /etc/letsencrypt/live/www.example.com/
# nginx 自动改好 ssl_certificate / ssl_certificate_key
# 续期:sudo certbot renew(Ubuntu 装完自带 systemd timer,会自动跑;手动测一次:sudo certbot renew –dry-run)
五、网站排错实战:分层定位(全篇重点)
把用户给你的排错链,落成一张可照着点的“作战图”。从外到内一层层查,不要瞎试。
第0层 域名解析对不对 ── 访问前先确认“地址没指错”
dig www.example.com +short # 返回 IP 是不是 srv01 的 192.168.10.11
dig www.example.com +trace # 看解析链,确认不是缓存/解析错
→ 解析到别人 IP / 空 → DNS 记录没配或没生效,先修域名
第1层 端口通不通 ── 确认“门开着”
客户端:nc -zv 192.168.10.11 443 # 能连上 → 端口在监听
服务端:sudo ss -tnlp | grep :443 # 看哪个进程在监听(nginx? 监听 0.0.0.0 还是 127.0.0.1?)
→ 不通/没监听 → nginx 没起,或只监听了 localhost(外网当然连不上)
第2层 服务能不能响应 ── 确认“能对话”
curl -I https://www.example.com/ # 看返回的状态码和响应头
→ curl: (7) Failed → 第1层没过;返回 000 → TLS/连接层挂了
第3层 nginx 配置与文件路径 ── 确认“资源找得到”
sudo nginx -t # 先查配置语法有没有错
grep -R "server_name\\|root\\|location" /etc/nginx/ # 域名/根目录/路由是否匹配
ls -l /var/www/html/index.html # 文件是不是真在那个 root 下
→ 404:路径/root 错;403:文件权限 or 目录没 index 且 autoindex off
第4层 状态码对症下药(见第三节表)
4xx → 看请求(URL/权限/参数);5xx → 看后端进程 + error.log
第5层 看请求头/body 与日志 ── 确认“到底发生了什么”
构造请求:curl -H "X-Test:1" -d '{"a":1}' https://… # 带自定义头和数据
sudo tail -f /var/log/nginx/access.log # 每条请求:IP 时间 状态码 字节 UA
sudo tail -f /var/log/nginx/error.log # 具体报错:权限拒绝/502 upstream/文件找不到
一张表对照“症状→去哪层→查啥”:
| 浏览器“找不到服务器 / DNS 错” | 第0层 | dig 解析结果 |
| 连接超时 / 拒绝 | 第1层 | ss -tnlp、防火墙、nginx 是否起 |
| 证书红斜杠 | 第1/4层 | openssl 看有效期/域名匹配 |
| 404 | 第3层 | nginx root/location、文件是否存在 |
| 403 | 第3层 | 文件权限、SELinux、autoindex |
| 502 / 504 | 第4/5层 | 后端进程、error.log 的 upstream 报错、proxy_timeout |
| 偶尔慢/丢请求 | 第5层 | access.log 状态码分布、后端负载 |
六、总结
本篇一条主线:从 URL 到响应,从明文到可信,从报错到定位。
概念层:URI 包含 URL;一次访问 = 请求(行+头+体)→响应(状态码+头+体)
信任层:非对称加密 → 数字签名(验身+验完整) → CA 签发证书(信任链背书)
排错层:解析→端口→响应→配置/路径→状态码→日志,由外到内逐层剥
口诀:
URL 先分 URI,请求响应看报文; 签名验身 CA 背书,HTTPS 才可信; 排错由外往里剥:解析→端口→响应→日志。
如果这篇帮到了你,点个赞 + 收藏再走~ 线上排错遇到拿不准的现象,评论区贴 curl -v 和 error.log 关键行,我看到都会回。 我是 秋@枫,每天一个 Linux 实战知识点,我们下篇见。




