0

Docker LNMP SSL证书配置:Let's Encrypt免费HTTPS从申请到自动续期完整实战

2026.05.23 | youres | 14次围观

为什么Docker LNMP必须配置SSL证书

现在网站不上HTTPS基本等于裸奔——浏览器会标记"不安全",搜索引擎排名也会受影响。对于Docker LNMP环境来说,配置SSL证书有两个核心优势:数据传输加密保护用户隐私,HTTPS是Google等搜索引擎的排名加分项。

Let's Encrypt提供免费SSL证书,配合Docker容器化的Certbot工具,整个申请和续期过程都能自动化完成,不需要花钱买证书,也不需要手动续期。

整体方案架构

Docker LNMP配置SSL的核心思路:Nginx容器负责HTTPS服务 + Certbot容器负责证书申请与续期,两者通过共享卷交换证书文件。

  • Nginx容器:监听80端口处理HTTP请求和ACME验证,监听443端口提供HTTPS服务
  • Certbot容器:通过webroot方式验证域名所有权,证书文件写入共享卷
  • 共享卷:Nginx读取Certbot生成的证书,实现无缝配合

一、项目目录结构准备

先搭建好Docker LNMP的目录结构,重点增加certbot相关的挂载目录:

docker-lnmp/
├── docker-compose.yml
├── nginx/
│   ├── conf.d/
│   │   └── default.conf
│   └── nginx.conf
├── php/
│   └── Dockerfile
├── mysql/
│   └── data/
├── www/
│   └── html/          # 网站根目录
├── certbot/
│   ├── conf/          # 证书文件存放
│   └── www/           # ACME验证目录
└── scripts/
    └── renew-cert.sh  # 续期脚本

二、docker-compose.yml配置

在原有LNMP基础上,增加Certbot服务,并添加证书共享卷:

version: '3.8'

services:
  nginx:
    image: nginx:1.24-alpine
    container_name: lnmp-nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./www/html:/usr/share/nginx/html
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    depends_on:
      - php
    restart: unless-stopped

  php:
    build: ./php
    container_name: lnmp-php
    volumes:
      - ./www/html:/usr/share/nginx/html
    restart: unless-stopped

  mysql:
    image: mysql:8.0
    container_name: lnmp-mysql
    environment:
      MYSQL_ROOT_PASSWORD: your_root_password
    volumes:
      - ./mysql/data:/var/lib/mysql
    restart: unless-stopped

  certbot:
    image: certbot/certbot
    container_name: lnmp-certbot
    volumes:
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot
    entrypoint: "/bin/sh -c 'trap exit TERM; while :; do sleep 6h & wait $${!}; certbot renew; done;'"
    restart: unless-stopped

关键点说明:

  • Nginx和Certbot共享/etc/letsencrypt/var/www/certbot两个卷
  • Certbot容器内置自动续期循环,每6小时检查一次证书是否需要更新
  • 先只启动Nginx申请证书,证书到手后再开启HTTPS配置

三、Nginx配置(申请证书阶段)

申请证书前,Nginx需要先配置HTTP服务,让Certbot能通过webroot方式验证域名:

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

    # Certbot ACME验证路径
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    # 其他请求重定向到HTTPS(证书申请成功后再开启)
    location / {
        root /usr/share/nginx/html;
        index index.php index.html;
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
        include fastcgi_params;
    }
}

注意:/.well-known/acme-challenge/这个location是Let's Encrypt验证域名所有权的核心,必须指向Certbot的验证目录。

四、申请SSL证书

先启动Nginx服务,再运行Certbot申请证书:

# 启动Nginx
docker-compose up -d nginx

# 申请证书(首次申请)
docker-compose run --rm certbot certonly \
  --webroot \
  --webroot-path=/var/www/certbot \
  --email your-email@example.com \
  --agree-tos \
  --no-eff-email \
  -d yourdomain.com \
  -d www.yourdomain.com

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

  • fullchain.pem — 完整证书链
  • privkey.pem — 私钥文件

五、Nginx配置(HTTPS阶段)

证书到手后,修改Nginx配置开启HTTPS,并配置安全参数:

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

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

    # HTTP强制跳转HTTPS
    location / {
        return 301 https://$host$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;

    # 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;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # HSTS(可选,建议开启)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    root /usr/share/nginx/html;
    index index.php index.html;

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
        include fastcgi_params;
    }
}

六、自动续期配置

Let's Encrypt证书有效期90天,必须定期续期。Docker环境下有两种自动续期方案:

方案1:Certbot容器内置续期

上面的docker-compose.yml中,Certbot容器的entrypoint已经配置了每6小时自动检查续期的循环。Nginx需要配合重载配置:

# 在Nginx容器中添加续期后重载的定时任务
docker-compose exec nginx sh -c "echo '0 0 * * * nginx -s reload' >> /etc/crontabs/root"

方案2:宿主机cron续期脚本(推荐)

更可控的方式是在宿主机设置cron任务:

#!/bin/bash
# renew-cert.sh
cd /path/to/docker-lnmp
docker-compose run --rm certbot renew
docker-compose exec nginx nginx -s reload

添加cron定时任务:

# 每天凌晨2点检查续期
0 2 * * * /path/to/docker-lnmp/scripts/renew-cert.sh >> /var/log/certbot-renew.log 2>&1

七、常见问题排查

1. 证书申请失败:Connection refused

检查80端口是否对外开放,域名DNS是否正确解析到服务器IP。Let's Encrypt需要通过HTTP访问你的服务器完成验证。

2. 证书申请失败:Forbidden

检查Nginx配置中/.well-known/acme-challenge/的root路径是否指向/var/www/certbot,以及该目录是否有读取权限。

3. HTTPS访问提示证书无效

确认Nginx配置中ssl_certificatessl_certificate_key路径正确,使用docker-compose exec nginx nginx -t测试配置是否正常。

4. 续期失败

手动执行docker-compose run --rm certbot renew --dry-run测试续期流程,查看具体错误信息。

八、SSL安全评分优化

配置完成后,建议到SSL Labs测试你的SSL配置评分。几个提升评分的关键点:

  • 禁用TLSv1.0和TLSv1.1,只保留TLSv1.2和TLSv1.3
  • 使用ECDHE密钥交换算法实现前向保密
  • 开启OCSP Stapling减少证书验证延迟
  • 配置HSTS告诉浏览器始终使用HTTPS

总结

Docker LNMP配置SSL证书并不复杂,核心就是Nginx和Certbot通过共享卷协作:Nginx提供验证路径和HTTPS服务,Certbot负责证书申请和续期。整个流程可以总结为三步:先配HTTP跑通验证 → 申请证书 → 再配HTTPS并设置自动续期。一次配置,长期自动运行,告别手动续证书的烦恼。

相关文章

版权声明

本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论