基于 Docker Compose 的 WordPress + 公共 Nginx + HTTPS 自动化部署方案

在实际生产环境中,我们通常不会让每个 WordPress 站点单独暴露 80/443 端口,而是通过一个**统一的反向代理层(公共 Nginx)**来管理:

  • HTTPS 证书
  • 多域名转发
  • 安全控制

本文给出一套完整方案,实现:

✅ WordPress 容器化部署(PHP-FPM)
✅ 公共 Nginx 统一反向代理
✅ Let’s Encrypt 自动申请 + 续期 HTTPS
.env 配置管理
✅ 可扩展多站点


🧱 一、整体架构

浏览器
   ↓
公共 Nginx(80/443 + HTTPS证书)
   ↓
站点 Nginx(容器内部)
   ↓
WordPress PHP-FPM
   ↓
外部 MySQL 数据库

📁 二、目录结构设计

1️⃣ 公共 Nginx 项目

docker-nginx/
├── docker-compose.yaml
├── nginx/
│   ├── conf.d/         # 各站点配置
│   └── certs/          # HTTPS证书
├── www/
│   └── certbot/        # ACME验证目录
└── logs/

2️⃣ WordPress 站点项目

wordpress-site/
├── compose.yaml
├── .env
├── nginx/
│   └── default.conf
└── wp_data/

⚙️ 三、公共 Nginx 配置

docker-compose.yaml

services:
  nginx-proxy:
    image: nginx:alpine
    container_name: common_nginx_proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./nginx/certs:/etc/nginx/certs:ro
      - ./logs:/var/log/nginx
      - ./www/certbot:/var/www/certbot:ro
    networks:
      - common-proxy-net
    restart: unless-stopped

networks:
  common-proxy-net:
    external: true

🌐 四、WordPress 站点部署

1️⃣ .env

DB_HOST=192.168.1.100
DB_PORT=3306
DB_NAME=xxx.com
DB_USER=root
DB_PASSWORD=your_password

DOMAIN=xxx.com
WWW_DOMAIN=xxx.com

2️⃣ compose.yaml

services:
  wordpress:
    image: wordpress:6.8.3-php8.4-fpm
    container_name: wordpress_fpm
    env_file:
      - .env
    environment:
      WORDPRESS_DB_HOST: "${DB_HOST}:${DB_PORT}"
      WORDPRESS_DB_USER: "${DB_USER}"
      WORDPRESS_DB_PASSWORD: "${DB_PASSWORD}"
      WORDPRESS_DB_NAME: "${DB_NAME}"
      WORDPRESS_CONFIG_EXTRA: |
        define('WP_HOME', 'https://${DOMAIN}');
        define('WP_SITEURL', 'https://${DOMAIN}');
        define('FORCE_SSL_ADMIN', true);
        if (strpos($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '', 'https') !== false) {
            $_SERVER['HTTPS'] = 'on';
        }
    volumes:
      - ./wp_data:/var/www/html
    networks:
      - wordpress_net
    restart: unless-stopped

  nginx:
    image: nginx:alpine
    container_name: wordpress_nginx
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
      - ./wp_data:/var/www/html:ro
    networks:
      - wordpress_net
      - common-proxy-net
    restart: unless-stopped

networks:
  wordpress_net:
  common-proxy-net:
    external: true

3️⃣ 站点 Nginx 配置

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

    root /var/www/html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass wordpress_fpm:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

🔐 五、HTTPS 证书申请(Certbot)

脚本:certbot-init.sh

#!/bin/bash

EMAIL="xxx@gmail.com"
DOMAINS=("xxx.com" "www.xxx.com")

BASE_DIR="$(pwd)"
CERT_DIR="$BASE_DIR/nginx/certs"
WEBROOT_DIR="$BASE_DIR/www/certbot"

mkdir -p "$CERT_DIR" "$WEBROOT_DIR"

DOMAIN_ARGS=""
for d in "${DOMAINS[@]}"; do
  DOMAIN_ARGS="$DOMAIN_ARGS -d $d"
done

docker run --rm \
  -v "$CERT_DIR:/etc/letsencrypt" \
  -v "$WEBROOT_DIR:/var/www/certbot" \
  certbot/certbot certonly \
  --webroot -w /var/www/certbot \
  $DOMAIN_ARGS \
  --email "$EMAIL" \
  --agree-tos --no-eff-email

docker exec common_nginx_proxy nginx -s reload

执行位置(重要)

cd /home/xxx/docker-project/docker-nginx
./certbot-init.sh

🔄 六、证书续期

脚本

#!/bin/bash

docker run --rm \
  -v "$(pwd)/nginx/certs:/etc/letsencrypt" \
  -v "$(pwd)/www/certbot:/var/www/certbot" \
  certbot/certbot renew \
  --webroot -w /var/www/certbot

docker exec common_nginx_proxy nginx -s reload

crontab

0 3 * * * cd /home/xxx/docker-project/docker-nginx && ./certbot-renew.sh

🌍 七、公共 Nginx 站点配置

申请证书前(HTTP-only)

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

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

    location / {
        proxy_pass http://wordpress_nginx_tkmiss:80;
    }
}

申请证书后(HTTPS)

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

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

    location / {
        return 301 https://tkmiss.com$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name xxx.com www.xxx.com;

    ssl_certificate /etc/nginx/certs/live/xxx.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/certs/live/xxx.com/privkey.pem;

    location / {
        proxy_pass http://wordpress_nginx_tkmiss:80;
    }
}

⚠️ 八、关键坑点总结

❌ 1. 没证书就启 443

→ nginx 启动失败


❌ 2. 忘记 challenge 目录

→ 续期失败


❌ 3. 关闭 80 端口

→ HTTP-01 验证失败


❌ 4. WordPress 不识别 HTTPS

→ 后台跳 http

✔ 解决:

$_SERVER['HTTPS'] = 'on';

🧠 九、最佳实践总结

项目建议
HTTPS公共 Nginx 统一管理
WordPress使用 php-fpm
配置使用 .env
网络统一 common-proxy-net
证书Certbot + webroot
自动化shell + cron

🚀 十、最终效果

你现在已经具备:

✅ 多站点架构
✅ 自动 HTTPS
✅ 容器隔离
✅ 可扩展能力

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
IrvingLi的头像-TKMiss Notes
评论 抢沙发

请登录后发表评论

    暂无评论内容