Nginx HTTPS 配置与 SSL 证书管理完整教程

· 阅读约需53分钟

Nginx HTTPS 配置与 SSL 证书管理完整教程

前言:为什么需要 HTTPS

在当今的互联网环境中,HTTPS 已经不再是可选项,而是必需品。无论是个人博客、企业官网还是电商平台,启用 HTTPS 都是保障用户安全和提升网站可信度的基础要求。

HTTPS 的核心价值

  1. 数据加密传输:防止数据在传输过程中被窃听和篡改,保护用户的敏感信息(如密码、支付信息)
  2. 身份验证:确认网站的真实身份,防止钓鱼网站和中间人攻击
  3. 数据完整性:确保数据在传输过程中没有被修改
  4. SEO 优化:Google 等搜索引擎将 HTTPS 作为排名信号,HTTPS 网站在搜索结果中更有优势
  5. 浏览器信任:现代浏览器对 HTTP 网站会标记为”不安全”,影响用户体验和信任度
  6. 功能支持:许多现代 Web 功能(如 Service Worker、HTTP/2、地理位置 API)要求必须使用 HTTPS

HTTP vs HTTPS 对比

特性HTTPHTTPS
端口80443
协议明文传输SSL/TLS 加密
安全性低,易被窃听篡改高,加密传输
证书不需要需要 SSL 证书
速度略快(无加密开销)略慢(加密解密开销)
SEO无优势有排名优势
浏览器标记标记为”不安全”显示锁形图标

HTTPS 与 SSL 证书基础

工作原理

HTTPS 是在 HTTP 基础上加入 SSL/TLS 协议层实现的安全传输协议。其工作流程如下:

  1. 握手阶段:客户端与服务器建立连接,协商加密算法和协议版本
  2. 证书验证:服务器发送 SSL 证书,客户端验证证书的合法性
  3. 密钥交换:双方协商生成会话密钥,用于后续的对称加密
  4. 加密通信:使用会话密钥进行加密数据传输

SSL/TLS 协议版本

  • SSL 3.0:已废弃,存在安全漏洞
  • TLS 1.0:已废弃,不推荐使用
  • TLS 1.1:已废弃,不推荐使用
  • TLS 1.2:目前广泛使用,安全性较好
  • TLS 1.3:最新版本,性能更好,安全性更强(推荐)

证书类型

1. DV(Domain Validation)域名验证证书

  • 验证级别:仅验证域名所有权
  • 颁发速度:几分钟到几小时
  • 价格:免费或低价
  • 适用场景:个人网站、博客、测试环境
  • 浏览器显示:锁形图标

2. OV(Organization Validation)组织验证证书

  • 验证级别:验证域名所有权 + 组织身份
  • 颁发速度:几天到一周
  • 价格:中等
  • 适用场景:企业官网、中小型电商
  • 浏览器显示:锁形图标 + 组织名称

3. EV(Extended Validation)扩展验证证书

  • 验证级别:最严格的身份验证
  • 颁发速度:一周到两周
  • 价格:昂贵
  • 适用场景:大型企业、金融机构、电商平台
  • 浏览器显示:绿色地址栏 + 组织名称(部分浏览器已取消绿色地址栏)

CA(Certificate Authority)证书颁发机构

CA 是受信任的第三方机构,负责颁发和管理 SSL 证书。主要的 CA 包括:

  • Let’s Encrypt:免费、自动化、开放的 CA(推荐)
  • DigiCert:商业 CA,提供各类证书
  • Sectigo(原 Comodo):商业 CA
  • GlobalSign:商业 CA
  • GeoTrust:商业 CA

免费 SSL 证书申请(Let’s Encrypt + Certbot)

Let’s Encrypt 是一个免费、自动化、开放的证书颁发机构,由互联网安全研究小组(ISRG)运营。

1. 环境准备

确保你的服务器满足以下条件:

  • 已安装 Nginx
  • 域名已解析到服务器 IP
  • 服务器可访问外网(80 和 443 端口开放)
  • 拥有 root 权限或 sudo 权限

2. 安装 Certbot

Ubuntu/Debian 系统

# 更新软件包列表
sudo apt update

# 安装 Certbot 和 Nginx 插件
sudo apt install certbot python3-certbot-nginx -y

CentOS/RHEL 系统

# 安装 EPEL 仓库
sudo yum install epel-release -y

# 安装 Certbot 和 Nginx 插件
sudo yum install certbot python3-certbot-nginx -y

Docker 方式(推荐)

# 拉取 Certbot 镜像
docker pull certbot/certbot

# 创建证书存储目录
mkdir -p /etc/letsencrypt

3. 申请证书

方式一:自动配置(推荐)

Certbot 可以自动配置 Nginx,非常方便:

# 自动申请并配置 Nginx
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

方式二:手动申请

如果你想手动配置 Nginx:

# 仅申请证书,不自动配置
sudo certbot certonly --nginx -d yourdomain.com -d www.yourdomain.com

方式三:Webroot 方式

如果 Nginx 已经在运行,可以使用 webroot 方式:

# 创建 webroot 目录
sudo mkdir -p /var/www/letsencrypt

# 申请证书
sudo certbot certonly --webroot -w /var/www/letsencrypt -d yourdomain.com

方式四:DNS 验证(适合泛域名证书)

# 使用 DNS 验证方式申请泛域名证书
sudo certbot certonly --manual --preferred-challenges dns -d "*.yourdomain.com" -d yourdomain.com

执行后会提示你在 DNS 中添加 TXT 记录,完成验证后即可获得证书。

4. 证书文件说明

申请成功后,证书文件会保存在 /etc/letsencrypt/live/yourdomain.com/ 目录下:

文件说明
cert.pem服务器证书
chain.pem证书链(中间证书)
fullchain.pem完整证书链(cert.pem + chain.pem)Nginx 配置使用这个
privkey.pem私钥文件

5. 自动续期

Let’s Encrypt 证书有效期为 90 天,需要定期续期。

测试续期

# 测试续期是否正常工作
sudo certbot renew --dry-run

手动续期

# 手动续期所有即将过期的证书
sudo certbot renew

自动续期(Cron 定时任务)

# 编辑 crontab
sudo crontab -e

# 添加以下内容(每天凌晨 2 点检查续期)
0 2 * * * /usr/bin/certbot renew --quiet --renew-hook "systemctl reload nginx"

Systemd Timer 方式(推荐)

大多数系统已经自动配置了 systemd timer:

# 查看 timer 状态
sudo systemctl list-timers | grep certbot

# 如果没有,手动启用
sudo systemctl enable --now certbot.timer

Nginx HTTPS 配置

1. 基础配置

创建或编辑 Nginx 配置文件:

sudo nano /etc/nginx/sites-available/yourdomain.com

基础 HTTPS 配置:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    # 将 HTTP 重定向到 HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    # SSL 证书配置
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # 网站根目录
    root /var/www/yourdomain.com;
    index index.html index.htm;

    # 日志配置
    access_log /var/log/nginx/yourdomain.com.access.log;
    error_log /var/log/nginx/yourdomain.com.error.log;
}

启用配置并重启 Nginx:

# 启用站点
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/

# 测试配置
sudo nginx -t

# 重启 Nginx
sudo systemctl restart nginx

2. 强加密套件配置

为了获得最佳安全性,建议使用强加密配置:

server {
    listen 443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

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

    # SSL 协议版本(禁用旧版本)
    ssl_protocols TLSv1.2 TLSv1.3;

    # 加密套件(优先使用前向保密)
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;

    # 优先使用服务器端加密套件
    ssl_prefer_server_ciphers off;

    # 会话缓存(提升性能)
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # 会话票据(提升性能)
    ssl_session_tickets off;

    # OCSP Stapling(提升握手速度)
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;
}

3. HTTP/2 配置

HTTP/2 可以显著提升网站性能,Nginx 1.9.5+ 支持 HTTP/2。

server {
    # 在 listen 指令中添加 http2
    listen 443 ssl http2;
    server_name yourdomain.com;

    # 其他 SSL 配置...
}

4. HSTS 配置

HSTS(HTTP Strict Transport Security)强制浏览器使用 HTTPS 访问:

server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    # SSL 配置...

    # HSTS 配置(1 年有效期,包含子域名,允许预加载)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # 其他安全头
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Referrer-Policy "strict-origin-when-cross-origin";
}

注意:HSTS 的 preload 指令会将你的域名提交到浏览器的 HSTS 预加载列表,一旦启用很难撤销,请谨慎使用。

5. 完整的推荐配置

以下是一个完整的、安全的 Nginx HTTPS 配置模板:

# HTTP 重定向到 HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name yourdomain.com www.yourdomain.com;

    # ACME 挑战验证(用于 Certbot 续期)
    location ~ /.well-known/acme-challenge {
        allow all;
        root /var/www/letsencrypt;
    }

    location / {
        return 301 https://$server_name$request_uri;
    }
}

# HTTPS 主配置
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name yourdomain.com www.yourdomain.com;

    # SSL 证书
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    # SSL 协议和加密套件
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # 会话配置
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 1.1.1.1 valid=300s;
    resolver_timeout 5s;

    # 安全头
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Frame-Options SAMEORIGIN;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Referrer-Policy "strict-origin-when-cross-origin";

    # 网站根目录
    root /var/www/yourdomain.com;
    index index.html index.htm index.php;

    # 日志
    access_log /var/log/nginx/yourdomain.com.access.log;
    error_log /var/log/nginx/yourdomain.com.error.log;

    # PHP 配置(如果需要)
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
    }

    # 静态资源缓存
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
}

证书管理

1. 查看证书信息

查看证书有效期

# 查看证书详细信息
sudo openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -text -noout

# 仅查看有效期
sudo openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -dates -noout

# 查看证书剩余天数
sudo openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -checkend 864000 -noout

在线查看证书信息

# 查看远程服务器证书
echo | openssl s_client -servername yourdomain.com -connect yourdomain.com:443 2>/dev/null | openssl x509 -text -noout

2. 证书续期管理

查看证书状态

# 查看所有证书状态
sudo certbot certificates

手动续期

# 续期所有即将过期的证书
sudo certbot renew

# 强制续期特定证书
sudo certbot renew --cert-name yourdomain.com --force-renewal

续期钩子

可以在续期后执行特定操作:

# 续期后重新加载 Nginx
sudo certbot renew --renew-hook "systemctl reload nginx"

# 续期后发送邮件通知
sudo certbot renew --renew-hook "echo 'Certificate renewed' | mail -s 'SSL Certificate Renewal' admin@yourdomain.com"

3. 证书备份与迁移

备份证书

# 备份整个 letsencrypt 目录
sudo tar -czf letsencrypt-backup-$(date +%Y%m%d).tar.gz /etc/letsencrypt

# 仅备份特定域名的证书
sudo tar -czf yourdomain.com-certs-$(date +%Y%m%d).tar.gz /etc/letsencrypt/live/yourdomain.com /etc/letsencrypt/archive/yourdomain.com /etc/letsencrypt/renewal/yourdomain.com.conf

迁移证书到新服务器

  1. 在新服务器上安装 Certbot
  2. 复制备份文件到新服务器
  3. 恢复证书:
# 解压备份
sudo tar -xzf letsencrypt-backup-20240101.tar.gz -C /

# 重新安装证书
sudo certbot install --nginx --cert-name yourdomain.com

# 测试续期
sudo certbot renew --dry-run

4. 证书删除

# 删除特定证书
sudo certbot delete --cert-name yourdomain.com

# 交互式删除
sudo certbot delete

常见问题与排错

1. 证书不被信任

症状:浏览器显示”您的连接不是私密连接”或证书无效。

可能原因和解决方案

  • 证书链不完整:确保使用 fullchain.pem 而不是 cert.pem

    # 错误
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/cert.pem;
    
    # 正确
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
  • 证书过期:检查证书有效期并续期

    sudo certbot renew
  • 域名不匹配:证书中的域名与实际访问的域名不一致

    # 查看证书中的域名
    sudo openssl x509 -in /etc/letsencrypt/live/yourdomain.com/cert.pem -text -noout | grep DNS
  • 系统时间不正确:服务器时间错误导致证书验证失败

    # 同步时间
    sudo timedatectl set-ntp true

2. 混合内容警告

症状:浏览器地址栏的锁形图标上有感叹号。

原因:HTTPS 页面中加载了 HTTP 资源(图片、CSS、JS 等)。

解决方案

  1. 使用相对协议:将 http:// 改为 //

    <!-- 错误 -->
    <script src="http://example.com/script.js"></script>
    
    <!-- 正确 -->
    <script src="//example.com/script.js"></script>
  2. Nginx 自动修复:添加 CSP 头自动升级请求

    add_header Content-Security-Policy "upgrade-insecure-requests";
  3. 301 重定向:确保所有资源都通过 HTTPS 访问

3. 性能问题

症状:HTTPS 网站比 HTTP 慢很多。

优化方案

  1. 启用会话缓存

    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
  2. 启用 OCSP Stapling

    ssl_stapling on;
    ssl_stapling_verify on;
  3. 启用 HTTP/2

    listen 443 ssl http2;
  4. 使用 TLS 1.3:TLS 1.3 握手更快

    ssl_protocols TLSv1.2 TLSv1.3;

4. Certbot 申请失败

常见错误和解决方案

  • 端口 80 被占用:确保 80 端口可访问,防火墙开放

    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
  • DNS 解析问题:确认域名已正确解析到服务器 IP

    dig yourdomain.com
  • 验证失败:检查 .well-known 目录权限

    sudo mkdir -p /var/www/letsencrypt/.well-known/acme-challenge
    sudo chown -R www-data:www-data /var/www/letsencrypt

5. SSL Labs 评分优化

使用 SSL Labs Server Test 测试你的服务器配置,目标是 A+ 评分。

优化要点

  • 禁用弱加密算法
  • 启用前向保密(PFS)
  • 配置 HSTS
  • 启用 OCSP Stapling
  • 使用强私钥(至少 2048 位 RSA 或 256 位 ECDSA)

进阶配置

1. 多域名/泛域名证书

申请多域名证书

# 申请包含多个域名的证书
sudo certbot --nginx -d domain1.com -d www.domain1.com -d domain2.com -d www.domain2.com

申请泛域名证书

# 申请泛域名证书(需要 DNS 验证)
sudo certbot certonly --manual --preferred-challenges dns -d "*.yourdomain.com" -d yourdomain.com

Nginx 多域名配置

# 域名 1
server {
    listen 443 ssl http2;
    server_name domain1.com www.domain1.com;

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

    root /var/www/domain1.com;
    # 其他配置...
}

# 域名 2
server {
    listen 443 ssl http2;
    server_name domain2.com www.domain2.com;

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

    root /var/www/domain2.com;
    # 其他配置...
}

2. 反向代理配置

基础反向代理

server {
    listen 443 ssl http2;
    server_name app.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/app.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

WebSocket 反向代理

server {
    listen 443 ssl http2;
    server_name ws.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/ws.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ws.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }
}

3. SSL 性能优化

使用 ECDSA 证书

ECDSA 证书比 RSA 证书更小、更快:

# 申请 ECDSA 证书
sudo certbot --nginx --key-type ecdsa --elliptic-curve secp384r1 -d yourdomain.com

启用 Brotli 压缩

# 需要先安装 ngx_brotli 模块
brotli on;
brotli_comp_level 6;
brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

TCP 优化

# 在 http 块中配置
http {
    # TCP 优化
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;

    # 其他配置...
}

4. 自动证书管理脚本

创建一个自动化管理脚本:

#!/bin/bash
# /usr/local/bin/ssl-manager.sh

DOMAINS=("domain1.com" "domain2.com" "domain3.com")
EMAIL="admin@yourdomain.com"
WEBROOT="/var/www/letsencrypt"

# 检查并续期证书
for domain in "${DOMAINS[@]}"; do
    echo "Checking certificate for $domain..."

    # 检查证书是否在 30 天内过期
    if ! openssl x509 -checkend 2592000 -noout -in /etc/letsencrypt/live/$domain/cert.pem 2>/dev/null; then
        echo "Renewing certificate for $domain..."
        certbot renew --cert-name $domain --quiet
    else
        echo "Certificate for $domain is valid."
    fi
done

# 重新加载 Nginx
systemctl reload nginx

echo "SSL certificate check completed at $(date)"

设置定时执行:

# 添加执行权限
chmod +x /usr/local/bin/ssl-manager.sh

# 添加到 crontab(每周一凌晨 3 点执行)
echo "0 3 * * 1 /usr/local/bin/ssl-manager.sh >> /var/log/ssl-manager.log 2>&1" | sudo tee -a /etc/crontab

总结与最佳实践

核心要点回顾

  1. HTTPS 是必需品:所有网站都应该启用 HTTPS,不再有例外
  2. Let’s Encrypt 是首选:免费、自动化、足够安全
  3. 安全配置很重要:使用强加密、禁用旧协议、配置安全头
  4. 自动化管理:设置自动续期,避免证书过期
  5. 性能优化:HTTP/2、会话缓存、OCSP Stapling 等可以显著提升性能

最佳实践清单

✅ 必须做的

  • 为所有域名启用 HTTPS
  • 将 HTTP 重定向到 HTTPS
  • 使用 Let’s Encrypt 等可信 CA 的证书
  • 配置自动续期
  • 使用 TLS 1.2 和 TLS 1.3
  • 启用 HSTS
  • 配置强加密套件
  • 启用 OCSP Stapling
  • 定期检查 SSL Labs 评分

⚠️ 谨慎做的

  • 启用 HSTS preload(难以撤销)
  • 使用 EV 证书(性价比不高)
  • 禁用 TLS 1.2(可能影响旧设备)

❌ 不要做的

  • 使用自签名证书(生产环境)
  • 使用 SSL 3.0、TLS 1.0、TLS 1.1
  • 使用弱加密算法(如 RC4、MD5)
  • 手动管理证书续期
  • 混合 HTTP 和 HTTPS 内容

推荐工具

  1. 证书申请与管理:Certbot、acme.sh
  2. SSL 测试:SSL Labs Server Test、testssl.sh
  3. 性能测试:WebPageTest、GTmetrix
  4. 安全扫描:Qualys SSL Labs、Mozilla Observatory
  5. 监控告警:UptimeRobot、证书过期监控

学习资源


结语:HTTPS 配置看似复杂,但只要按照规范一步步操作,其实并不难。关键是理解原理、使用正确的工具、建立自动化的管理流程。希望这篇教程能帮助你顺利为网站启用 HTTPS,为用户提供更安全的访问体验。