nginx HTTPS 学习笔记

环境:WSL 2 Debian + nginx 1.26.3 · 自签名证书(本机学习用)
日期:2026-10-08
前置:静态托管 + 负载均衡已掌握


一、HTTPS 是什么(HTTP vs HTTPS)

HTTP  = 明文传输(明信片):路上任何人都能看见内容
HTTPS = 加密传输(保险箱):数据加密后再上路,只有收件人有钥匙
HTTP HTTPS
传输内容 明文 加密
浏览器标记 "不安全" 锁图标
适用 纯浏览场景 一切有敏感数据的场景

二、为什么必须 HTTPS(生产铁律)

风险 后果
明文传输 密码、个人信息可被抓包直接看到
中间人篡改 数据可被改(网页被注入广告/恶意代码)
浏览器不信任 访问 HTTP 网站被标记"不安全"

铁律:只要有登录、支付、个人信息的网站,必须 HTTPS。

三、证书机制(锁和钥匙)

HTTPS 依赖一对"锁和钥匙":

东西 学名 作用
锁(公开) 证书 certificate 发给浏览器,用它加密
钥匙(保密) 私钥 private key 服务器自己留,用它解密

握手过程(一句话版):

① 浏览器:我要访问
② nginx:这是我的证书(锁),给你
③ 浏览器:验证锁真伪 → 用锁加密一个"会话密码"发过去
④ nginx:用钥匙解开 → 双方用密码加密通信 ✅

四、自签名证书 vs 受信任证书

自签名 受信任(CA 签发)
谁签名 自己给自己签 权威机构(如 Let's Encrypt)
类比 自制身份证自己盖章 公安局办的身份证
浏览器 ❌ 警告"不可信" ✅ 自动信任
用途 本机学习、内网测试 生产网站

浏览器警告不是网站坏了——是浏览器看到"自制身份证",出于安全拒绝自动信任。点"高级→继续"是手动放行。

五、配置(Where & How)

文件位置

/etc/nginx/sites-available/mysite
(Windows 记事本:\\wsl$\Debian\etc\nginx\sites-available\mysite)

加在哪:server 块内、listen 8080; 正下方

加之前:

server {
    listen 8080;
    server_name localhost;

加之后(新增 4 行):

server {
    listen 8080;
    listen 8443 ssl;                          # 新增 HTTPS 入口(8443,避开 443)
    ssl_certificate     /etc/nginx/ssl/mysite.crt;   # 锁的地址
    ssl_certificate_key /etc/nginx/ssl/mysite.key;   # 钥匙的地址
    server_name localhost;

为什么加在这:HTTPS 入口 = 一个监听端口,所以加在监听区(listen 旁边);证书地址是配套,惯例紧跟。

部署四步口诀(不变)

改:加 4 行 → 测:nginx -t → 载:service nginx reload → 验:curl

验证

curl -sk https://localhost:8443/     # -k = 忽略证书验证(自签名)
# 不带 -k 会报证书错误 —— 和浏览器警告同理

六、HTTP→HTTPS 自动跳转(301,生产标配)

什么是 301

301 = 永久重定向:地址永久搬家,浏览器自动跳到新地址。

用户访问 http://localhost:8080/mynote.html
        ↓ nginx 返回 301 + Location
浏览器自动跳到 https://localhost:8443/mynote.html(路径原样保留)

为什么 80 端口必须跳 443

  • 用户输网址很少主动打 https://,浏览器默认走 HTTP
  • 不跳转 = 留了个"裸奔通道",HTTPS 白装
  • SEO:http 和 https 是两个站,301 把权重合并

配置:拆成两个 server(各管各的)

# ===== server 1:HTTP 入口,一律踢到 HTTPS =====
server {
    listen 8080;
    server_name localhost;
    return 301 https://$host:8443$request_uri;
    # $host = 用户访问的域名,$request_uri = 请求的路径
}

# ===== server 2:HTTPS,真正站点 =====
server {
    listen 8443 ssl;
    ssl_certificate     /etc/nginx/ssl/mysite.crt;
    ssl_certificate_key /etc/nginx/ssl/mysite.key;
    server_name localhost;
    root /var/www/mysite;
    ... # 其余 location 规则不变
}

验证

curl -I http://localhost:8080/          # 301 + Location: https://localhost:8443/
curl -I http://localhost:8080/mynote.html   # 跳转后路径还在

301 vs 302(重要区别)

301 永久 302 临时
含义 地址永久搬家 暂时换地方
浏览器 记住新地址 每次重新问
SEO 权重合并 不合并
用途 HTTP→HTTPS 维护页等临时场景

七、生产方案:Let's Encrypt(免费受信任证书)

apt install certbot python3-certbot-nginx
certbot --nginx -d example.com    # 自动申请证书 + 配置 + 跳转
自签名(学习) Let's Encrypt(生产)
信任 浏览器警告 自动信任
获取 openssl 一条命令 certbot 一条命令
有效期 自定 90 天(自动续期)

八、三个概念的澄清(协议 / 端口 / 路径)

协议 = 加不加密(http:// 明文 / https:// 加密)
端口 = 找谁(哪个服务在听)
路径 = 要什么(哪个资源/文件)

http://localhost:8080/mynote.html
│     │        │       └ 路径:要 mynote.html
│     │        └ 端口:8080(nginx 在听)
│     └ 主机
└ 协议:HTTP(明文)

一个端口可挂无数资源:/(首页)、/mynote.html(文件)、/api/(转发后端)……路径决定 nginx 送你去哪。

九、入口收敛(安全架构核心)

❌ 生产禁止:用户 → 9000 后端(绕过 nginx = 绕过 HTTPS/限流/防护/日志)
✅ 正确:用户 → 8080/8443(nginx 唯一入口)→ 9000/9001/9002(用户摸不到)

端口不是网站专属——任何程序都能监听(python 后端也听 9000)。生产里后端只监听内网/被防火墙挡死,用户物理上够不着后端,只能从 nginx 这个口进。

十、本实验命令速查

# 生成自签名证书(有效期 1 年)
mkdir -p /etc/nginx/ssl
cd /etc/nginx/ssl
openssl req -x509 -newkey rsa:2048 -keyout mysite.key -out mysite.crt -days 365 -nodes -subj "/CN=localhost"

# 验证
curl -sk https://localhost:8443/         # 页面内容
curl -skI https://localhost:8443/        # 响应头
# 浏览器体验:访问 https://localhost:8443/ → 看警告 → 高级→继续

十一、常见坑

坑 现象 解决
自签名证书警告 浏览器"不是私密连接" 正常!学习环境手动放行;生产用 certbot
/etc/nginx/ssl 不存在 生成证书找不到目录 先 mkdir -p /etc/nginx/ssl
证书生成在别处 nginx 找不到证书 证书/私钥要放在配置指定的路径
443 端口冲突 默认站点占着 443 学习环境用 8443 避开

十二、一句话总结

HTTPS = 证书(锁)+ 私钥(钥匙)加密通信。
配置只需 3 行:listen 8443 ssl + 证书路径两行。
HTTP 入口用 return 301 全部踢到 HTTPS(生产标配)。
学习用自签名(浏览器警告正常),生产用 certbot 申请受信任证书。
后端永远不能直接暴露给用户 —— 入口只留 nginx。

🔗 相关笔记