TLS全流程 + Nginx HTTPS配置实战 + 会话绑定 vs 复制的架构选型

一、HTTPS工作流程:从TLS握手到加密数据传输(含性能关键点)

1. 完整TLS 1.2/1.3握手流程(以Nginx为服务端)

TLS 1.2(传统四次握手,阿里已逐步淘汰)
复制代码
Client                          Server
  |-------- ClientHello -------->|  (支持的Cipher Suites, TLS版本, 随机数C)
  |<------- ServerHello ---------|  (选定Cipher, 随机数S)
  |<------- Certificate --------|  (服务端证书链)
  |<--- ServerKeyExchange? ----|  (ECDHE需此步)
  |<--- ServerHelloDone -------|
  |---- ClientKeyExchange ---->|  (用公钥加密预主密钥 或 ECDHE公钥)
  |---- ChangeCipherSpec ------>|
  |---- Finished -------------->|  (用协商密钥加密校验)
  |<--- ChangeCipherSpec ------|
  |<--- Finished --------------|
  |<====== 加密应用数据 =======>|
TLS 1.3(阿里生产主力,1-RTT甚至0-RTT)
复制代码
Client                          Server
  |---- ClientHello (含密钥共享) -->|
  |<--- ServerHello + Certificate -|  (合并多消息,1-RTT完成)
  |<--- EncryptedExtensions ------|
  |<--- Finished -----------------|
  |---- Finished ---------------->|
  |<====== 加密应用数据 =======>|

优化点

  • 2021年双11:全站切TLS 1.3,首屏加载快200ms;
  • 证书链优化:中间CA证书必须拼接完整,否则iOS客户端握手失败(2019年吃过亏);
  • OCSP Stapling :避免客户端在线验证吊销(ssl_stapling on;),减少100ms延迟。

二、Nginx配置HTTPS:关键文件 + 核心配置项(阿里生产模板)

1. 必需文件

文件类型 说明 规范
证书文件.crt.pem 包含域名证书 + 中间CA证书(顺序:域名证书在上,根CA不用) cat your_domain.crt intermediate.crt > fullchain.crt拼接
私钥文件.key RSA或ECDSA私钥,必须600权限 禁止明文提交Git,用KMS加密托管

2. Nginx HTTPS核心配置(含安全加固)

复制代码
server {
    listen 443 ssl http2;  # 启用HTTP/2(QPS提升30%)
    server_name www.zjx521.com;

    # 证书与密钥
    ssl_certificate /etc/nginx/ssl/fullchain.crt;
    ssl_certificate_key /etc/nginx/ssl/privkey.key;

    # 协议与加密套件(安全红线)
    ssl_protocols TLSv1.2 TLSv1.3;          # 禁用SSLv3/TLS1.0/1.1
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256; # 前向安全
    ssl_prefer_server_ciphers off;          # TLS 1.3必须off

    # 性能优化
    ssl_session_cache shared:SSL:50m;       # 共享内存缓存会话(50MB ≈ 20万会话)
    ssl_session_timeout 10m;                # 会话复用有效期
    ssl_session_tickets on;                 # 启用Session Ticket(TLS 1.3默认)

    # 安全增强
    ssl_stapling on;                        # OCSP Stapling
    ssl_stapling_verify on;
    resolver 100.100.2.136 valid=300s;      # 内网DNS

    # HSTS(防SSL剥离)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    location / {
        proxy_pass http://backend;
    }
}

 server {
  listen 80 default_server;
  server_name www.zjx521.com;
  root /data/server/nginx/web1;
  # return 301 https://$host$request_uri;    # 301重定向
  rewrite ^(.*) https://$server_name$1 permanent; #rewrite 重定向,二选一
默认配置文件里面添加

教训

  • 2018年某业务漏配ssl_session_cache,TLS握手CPU打满,RT飙升3倍;
  • 私钥权限755导致nginx -t报错"unsafe key",大促前夜手忙脚乱。
    自动化建议:用Ansible + Vault管理证书,配合ACME自动续签(阿里内部用自研证书平台,开源可用certbot)。

3.let's encrypt免费证书申请

① 环境准备

复制代码
# CentOS / Rocky / AlmaLinux
sudo yum install -y epel-release
sudo yum install -y certbot

# Ubuntu / Debian
sudo apt update
sudo apt install -y certbot

tee /tmp/ssl.sh <<EOF
# 适用于任何 DNS 服务商(Cloudflare、华为云、Godaddy 等)
DOMAIN="zjx521.com"
sudo certbot certonly \
  --manual \
  --preferred-challenges dns \
  --server https://acme-v02.api.letsencrypt.org/directory \
  --agree-tos --no-eff-email --email admin@$DOMAIN \
  -d "*.$DOMAIN" -d "$DOMAIN"
EOF

② 执行过程

复制代码
chmod +x /tmp/ssl.sh
cd /tmp
./ssl.sh
以下是输出内容 次案例走阿里云dns解析
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for *.zjx521.com and zjx521.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.zjx521.com.

with the following value:

cFl5DxIR9-sH49xHckxJK6XvHIKFOKDXeyzG7BLw8dQ

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

#打开阿里云dns 设置txt  _acme-challenge.zjx521.com.   值:cFl5DxIR9-sH49xHckxJK6XvHIKFOKDXeyzG7BLw8dQ
然后enter

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name:

_acme-challenge.zjx521.com.

with the following value:

3jxOKHAnvNbIACbhObwN4_izeQ-uhBZeo2D8lDn2FrM

(This must be set up in addition to the previous challenges; do not remove,
replace, or undo the previous challenge tasks yet. Note that you might be
asked to create multiple distinct TXT records with the same name. This is
permitted by DNS standards.)

#打开阿里云dns 设置txt  _acme-challenge.zjx521.com.   值:c3jxOKHAnvNbIACbhObwN4_izeQ-uhBZeo2D8lDn2FrM
然后enter
Before continuing, verify the TXT record has been deployed. Depending on the DNS
provider, this may take some time, from a few seconds to multiple minutes. You can
check if it has finished deploying with aid of online tools, such as the Google
Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.zjx521.com.
Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
value(s) you've just added.

#然后 在enter
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/zjx521.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/zjx521.com/privkey.pem
This certificate expires on 2025-12-28.
These files will be updated when the certificate renews.

NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

此刻申请成功:

证书地址和有效时间如上

③ 证书路径

复制代码
tree /etc/letsencrypt/live/zjx521.com/
/etc/letsencrypt/live/zjx521.com/
├── cert.pem -> ../../archive/zjx521.com/cert1.pem # 仅域名证书
├── chain.pem -> ../../archive/zjx521.com/chain1.pem # 仅中间CA
├── fullchain.pem -> ../../archive/zjx521.com/fullchain1.pem # 证书链(Nginx ssl_certificate 用这个)
├── privkey.pem -> ../../archive/zjx521.com/privkey1.pem 私钥(ssl_certificate_key 用这个)
└── README

1 directory, 5 files

权限安全:privkey.pem 默认为 600,属主 root,无需额外处理

④ 提醒续约脚本

复制代码
# 创建提醒脚本
cat > /root/letsencrypt-reminder.sh <<'EOF'
#!/bin/bash
days=$(certbot certificates 2>/dev/null | grep -o 'VALID: [0-9]* days' | grep -o '[0-9]*' | head -1)
if [ -n "$days" ] && [ "$days" -lt 30 ]; then
    echo "⚠️ 证书将在 $days 天后过期!"
fi
echo "命令:sudo certbot certonly --manual --preferred-challenges dns -d '*.zjx521.com' -d 'zjx521.com'"
EOF
chmod +x /root/letsencrypt-reminder.sh

# 加入 crontab,每30天提醒一次
echo "0 9 1 */1 * /root/letsencrypt-reminder.sh | mail -s 'Let\'s Encrypt 证书即将过期' your@email.com" | sudo crontab -

⑤ 续约命令

复制代码
certbot certonly --manual --preferred-challenges dns -d '*.zjx521.com' -d 'zjx521.com'

输入2确定

自动续约版本

核心思路:用 acme.sh 替代 certbot

通用实施步骤(适用于所有环境)

第一步:安装 acme.sh(所有 Linux 通用)

复制代码
# 用普通用户安装(推荐),避免权限问题
curl https://get.acme.sh | sh -s email=your-admin@zjx521.com
source ~/.bashrc

安装后路径:~/.acme.sh/acme.sh

自动创建 cron 任务(每天检查续签)

第二步:根据你的 DNS 服务商,选择验证方式

场景 A:你有 DNS 服务商的 API 权限(推荐!)
环境类型 DNS 服务商 acme.sh 参数 凭据设置方式
阿里云 阿里云 DNS dns_aliyun Ali_Key, Ali_Secret
腾讯云 DnsPod(腾讯云) dns_dp DP_Id, DP_Key
华为云 华为云 DNS dns_huaweicloud HUAWEICLOUD_...
Cloudflare Cloudflare dns_cf CF_TokenCF_Key
AWS Route53 Route53 dns_aws AWS CLI 配置或环境变量
GoDaddy GoDaddy dns_gd GD_Key, GD_Secret
自建 BIND 不支持 API ❌ 不能自动续签 ---

🔗 完整列表:https://github.com/acmesh-official/acme.sh/wiki/dnsapi

操作示例(阿里云)

复制代码
# 设置凭据(只做一次)
export Ali_Key="LTAI5tXXXXXXXXXXXXXX"
export Ali_Secret="XXXXXXXXXXXXXXXXXXXXXXXX"

# 申请泛域名证书(自动续签已内置)
~/.acme.sh/acme.sh --issue --dns dns_aliyun -d zjx521.com -d '*.zjx521.com'

执行后,acme.sh 会自动:

  • 调用阿里云 API 添加 TXT 记录;
  • 等待 DNS 生效;
  • 验证通过后签发证书;
  • 后续自动续签(无需人工干预)

场景 B:你在内网/无 DNS API 权限(如企业自建 DNS)

这是唯一无法全自动的场景,但仍有解!

方案 B1:手动 DNS(半自动,适合低频环境)
复制代码
# 生成 DNS 记录
~/.acme.sh/acme.sh --issue --dns -d zjx521.com -d '*.zjx521.com'

输出:

复制代码
Add the following TXT record:
Domain: _acme-challenge.zjx521.com
Value: abc123...

你手动在 DNS 后台添加后,再执行一次相同命令,它会完成验证。

缺点:无法自动续签 ,每次都要人工操作。

优点:适用于任何 DNS 服务商(包括华为云、自建 BIND 等)。

方案 B2:用一台有公网 DNS API 权限的"跳板机"代申请
  • 在跳板机上用 acme.sh 申请证书;
  • 通过 scp 或内网同步工具(如 rsync)把证书推送到内网服务器;
  • 内网服务使用同步过来的证书。

安全建议:用 --install-cert 指定输出路径,只同步 fullchain.pemprivkey.pem,不暴露凭据。


第三步:安装证书到标准位置(与服务解耦)

复制代码
# 安装到通用目录(acme.sh 会在续签时自动更新这些文件)
~/.acme.sh/acme.sh --install-cert -d zjx521.com \
  --key-file /etc/ssl/private/zjx521.com.key \
  --fullchain-file /etc/ssl/certs/zjx521.com.crt \
  --reloadcmd "systemctl reload nginx"  # 续签后自动 reload 服务

这样 Nginx/Apache 配置只需指向 /etc/ssl/...,无需关心 acme.sh 内部路径。


第四步:验证自动续签(所有环境通用)

复制代码
# 手动触发续签检查(模拟 cron)
~/.acme.sh/acme.sh --cron --home ~/.acme.sh

# 查看 cron 任务(已自动创建)
crontab -l | grep acme.sh
# 输出:0 0 * * * "/home/youruser/.acme.sh"/acme.sh --cron ...

到期前 30 天自动续签,全程无感。


环境适配对照表

环境 是否支持全自动续签 推荐方案
阿里云 ECS dns_aliyun
腾讯云 CVM dns_dp
AWS EC2 dns_aws
Cloudflare 托管 DNS dns_cf
内网服务器(无公网) ✅(需 DNS API) 在内网机器直接跑 acme.sh
企业自建 DNS(无 API) 手动 DNS 或跳板机方案
树莓派 / IoT dns_aliyun(轻量无依赖)

终极建议

  1. 所有新项目强制使用 acme.sh + DNS API ,禁止 certbot --manual

  2. 证书输出路径统一为 /etc/ssl/,避免权限混乱;

  3. 内网环境用跳板机方案,不要为了证书暴露 80 端口;

  4. 监控证书到期 (可选):

    复制代码
    # 在跳板机或内网监控机上跑
    sudo openssl x509 -in /etc/ssl/certs/zjx521.com.crt -noout -enddate

三、会话绑定(Session Sticky) vs 会话复制(Session Replication)

1. 会话绑定(Sticky Session)

  • 原理 :负载均衡器(如Nginx/LVS)将同一用户的所有请求固定转发到同一后端实例

  • Nginx实现

    复制代码
    upstream backend {
        ip_hash;  # 基于客户端IP哈希(简单但不精准)
        # 或用商业版sticky cookie(开源可用nginx-sticky-module)
        sticky cookie srv_id expires=1h domain=.tmall.com path=/;
    }
  • 适用场景

    • 有状态服务:如传统Java Web应用(Tomcat Session未集群);
    • 低频交互:用户操作间隔长,实例故障影响小;
    • 阿里案例:2015年前老版购物车服务(后已改造为无状态)。

致命缺陷 :实例故障时用户会话丢失,"高可用"铁律


2. 会话复制(Session Replication)

  • 原理 :后端实例间实时同步会话数据(如Tomcat Cluster广播)。

  • 典型架构

    复制代码
    Nginx → [App1 ←→ App2 ←→ App3]  # 通过组播/Redis同步Session
  • 适用场景

    • 强一致性要求:如支付确认页,不能丢状态;
    • 小规模集群(≤10节点):广播风暴随节点数平方增长;
    • 教训:2016年大促,Tomcat集群32节点,会话复制网络打满,全站雪崩。

现代解法会话外置(终极方案)

  • 用Redis集中存储Session(spring-session-data-redis);
  • 应用完全无状态,Nginx无需sticky;
  • 实测:10万+实例弹性伸缩,会话零丢失。

四、架构选型决策树

场景 推荐方案 原因
新业务/云原生 会话外置(Redis) 无状态、弹性伸缩、符合云原生
老系统改造中 会话绑定(Sticky) 快速上线,逐步改造
强一致性+小集群 会话复制 仅限遗留系统,不推荐新项目
双11级大促 必须无状态 + 会话外置 铁律:状态即负债

五、现在立刻行动建议

  1. 检查TLS配置

    复制代码
    openssl s_client -connect your_domain:443 -servername your_domain | grep "Cipher is"

    确保是ECDHE开头(前向安全)。

  2. 验证会话方案

    • 如果用ip_hashsticky,马上评估迁移到Redis;
    • redis-cli monitor看Session写入频率,避免大Key。
  3. 开启OCSP Stapling

    复制代码
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8;  # 临时测试用

    能省100ms,用户体验直接提升。

相关推荐
openHiTLS密码开源社区4 小时前
【密码学实战】openHiTLS X509命令行工具: 数字证书生成与转换
https·数字证书·x509·csr·公钥·私钥·自签名
YC运维4 小时前
Nginx核心配置详解:访问控制、用户认证与HTTPS部署
网络·nginx·https
2501_916007475 小时前
前端开发工具都有哪些?常用前端开发工具清单与场景化推荐
android·ios·小程序·https·uni-app·iphone·webview
apple_ttt6 小时前
融合:迈向 “一台计算机” 的终极架构
网络·架构·cxl·数据中心网络
tpoog8 小时前
【C++项目】基于微服务的即使通信系统
微服务·云原生·架构
凤凰战士芭比Q9 小时前
部署Nginx(Kylinv10sp3、Ubuntu2204、Rocky9.3)
linux·运维·nginx
这个人需要休息10 小时前
传统网站架构 和 现代云服务 的区别简要分析
架构
数据智能老司机11 小时前
建构 AI Agent 应用——工具调用
架构·llm·agent
失散1313 小时前
分布式专题——25 深入理解网络通信和TCP、IP协议
java·分布式·网络协议·tcp/ip·架构