WordPress作为全球使用最广泛的内容管理系统,占据了超过40%的网站市场份额。然而传统的WordPress部署方式——手动安装PHP、MySQL、Nginx/Apache——不仅步骤繁琐,而且环境隔离性差、迁移困难、版本升级容易踩坑。Docker Compose的出现彻底改变了这一局面:通过一个
1 | docker-compose.yml |
文件,我们可以定义完整的WordPress运行环境,包括数据库、Web服务器、SSL证书自动续期,实现一键部署、秒级重建和无缝迁移。
本文将手把手教你用Docker Compose在VPS上部署一个生产级WordPress站点,涵盖MariaDB数据库配置、Nginx反向代理、Let’s Encrypt自动SSL证书、数据持久化与备份恢复等完整流程。无论你是第一次建站的新手,还是希望从传统部署迁移到容器化的老站长,都能从中获得可直接复用的配置和实战经验。

一、为什么用Docker Compose部署WordPress:容器化建站的核心优势
传统WordPress部署最大的痛点在于环境依赖管理。PHP版本、MySQL配置、Nginx规则、SSL证书——这些组件之间相互依赖,一旦某个环节出问题,排查成本极高。Docker Compose通过容器化技术将每个组件封装在独立容器中,各自拥有隔离的文件系统和网络,从根本上解决了”在我的机器上能跑”的问题。
容器化部署WordPress的具体优势包括:
| 对比维度 | 传统部署(宝塔/LNMP) | Docker Compose部署 |
|---|---|---|
| 环境一致性 | 依赖手动配置,易出现环境差异 | 镜像固化环境,开发生产完全一致 |
| 部署速度 | 30分钟-2小时(含排错) | 5分钟(拉取镜像即就绪) |
| 迁移成本 | 需重新配置全部环境 | 复制compose文件+数据卷即可 |
| 版本升级 | 手动编译,风险高 | 修改镜像tag,一键回滚 |
| 资源隔离 | 共享系统环境,互相干扰 | 容器隔离,CPU/内存可限制 |
| SSL证书 | 手动配置certbot或面板 | 自动化容器,零干预续期 |
对于VPS建站场景,Docker Compose还有一个常被忽视的优势:数据卷持久化。所有WordPress文件、数据库数据、上传的图片都挂载在宿主机目录中,即使容器被删除重建,数据也完整保留。这意味着你可以随时升级WordPress版本、切换PHP版本、甚至更换VPS,而不会丢失任何站点数据。
如果你想了解Docker Compose更基础的知识,可以参考我们之前写的Docker + Docker Compose实战指南,本文将在此基础上聚焦WordPress专用配置。
二、项目结构与核心配置文件
一个生产级的Docker Compose WordPress部署项目结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 wordpress-docker/
├── docker-compose.yml # 核心编排文件
├── .env # 环境变量(密码等敏感信息)
├── nginx/
│ ├── nginx.conf # Nginx主配置
│ └── conf.d/
│ └── wordpress.conf # WordPress站点配置
├── mysql/
│ └── init/
│ └── init.sql # 数据库初始化脚本(可选)
├── wordpress/
│ └── wp-content/ # WordPress内容目录(持久化挂载)
└── certbot/
├── conf/ # SSL证书存储
└── www/ # 证书验证目录
首先创建项目目录和
1 | .env |
文件。将敏感信息(数据库密码等)放在
1 | .env |
中是Docker Compose的最佳实践,避免在
1 | docker-compose.yml |
中硬编码密码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 mkdir -p wordpress-docker/{nginx/conf.d,mysql/init,wordpress/wp-content,certbot/conf,certbot/www}
cd wordpress-docker
# 创建环境变量文件
cat > .env << 'EOF'
# 数据库配置
MYSQL_ROOT_PASSWORD=YourStrongRootPass123!
MYSQL_DATABASE=wordpress
MYSQL_USER=wp_user
MYSQL_PASSWORD=YourStrongWpPass456!
# WordPress配置
WORDPRESS_DB_HOST=db:3306
WORDPRESS_DB_NAME=wordpress
WORDPRESS_DB_USER=wp_user
WORDPRESS_DB_PASSWORD=YourStrongWpPass456
# 域名
DOMAIN=example.com
EMAIL=admin@example.com
EOF
安全提示:务必使用强密码(至少16位,包含大小写字母、数字和特殊字符),切勿使用示例中的默认密码。
1 | .env |
文件应加入
1 | .gitignore |
,不要提交到版本库。
三、Docker Compose编排文件详解:WordPress + MariaDB + Nginx + Certbot
核心的
1 | docker-compose.yml |
文件定义了四个服务:Nginx(反向代理)、WordPress(PHP-FPM)、MariaDB(数据库)、Certbot(SSL证书自动化)。下面逐段解析每个服务的配置要点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 version: '3.8'
services:
db:
image: mariadb:10.11
container_name: wp_db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- db_data:/var/lib/mysql
- ./mysql/init:/docker-entrypoint-initdb.d
networks:
- wp_internal
healthcheck:
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
interval: 10s
timeout: 5s
retries: 5
wordpress:
image: wordpress:6.4-php8.2-fpm
container_name: wp_app
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST}
WORDPRESS_DB_NAME: ${WORDPRESS_DB_NAME}
WORDPRESS_DB_USER: ${WORDPRESS_DB_USER}
WORDPRESS_DB_PASSWORD: ${WORDPRESS_DB_PASSWORD}
volumes:
- wp_data:/var/www/html
- ./wordpress/wp-content:/var/www/html/wp-content
networks:
- wp_internal
nginx:
image: nginx:1.25-alpine
container_name: wp_nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
- wp_data:/var/www/html:ro
- certbot_conf:/etc/letsencrypt:ro
- certbot_www:/var/www/certbot:ro
depends_on:
- wordpress
networks:
- wp_internal
certbot:
image: certbot/certbot:latest
container_name: wp_certbot
restart: unless-stopped
volumes:
- certbot_conf:/etc/letsencrypt
- certbot_www:/var/www/certbot
entrypoint: >
sh -c "trap exit TERM;
while :; do
certbot renew --webroot -w /var/www/certbot --quiet
sleep 12h
done"
networks:
- wp_internal
volumes:
db_data:
wp_data:
certbot_conf:
certbot_www:
networks:
wp_internal:
driver: bridge
上述配置中有几个关键设计决策值得展开说明:
1. 使用MariaDB而非MySQL。MariaDB 10.11是当前长期支持版本,对WordPress兼容性极佳,且在容器环境中内存占用比MySQL低15%-20%。对于1核512M的小型VPS,MariaDB的优势尤为明显。
2. PHP-FPM而非Apache镜像。选择
1 | wordpress:6.4-php8.2-fpm |
而非默认的Apache镜像,是因为Nginx + PHP-FPM的组合在高并发下性能显著优于Apache mod_php。PHP 8.2相比7.4在WordPress场景下性能提升约30%。
3. 健康检查机制。MariaDB服务配置了
1 | healthcheck |
,WordPress的
1 | depends_on |
使用
1 | condition: service_healthy |
。这确保WordPress容器在数据库完全就绪后才启动,避免首次启动时连接数据库失败的竞态条件。
4. Certbot自动续期。证书有效期90天,续期容器每12小时检查一次(Let’s Encrypt建议每12小时检查,实际续期只在到期前30天才会执行)。这种设计无需在宿主机配置cron任务。
四、Nginx反向代理配置:性能优化与安全加固
Nginx配置是整个部署中技术含量最高的部分。我们需要处理HTTP到HTTPS的跳转、Let’s Encrypt验证、WordPress的伪静态规则、以及各种安全头和性能优化。
首先是Nginx主配置文件
1 | nginx/nginx.conf |
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 user nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
# 基础性能优化
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
keepalive_requests 1000;
types_hash_max_size 2048;
server_tokens off;
# Gzip压缩
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 256;
gzip_types
text/plain text/css text/xml text/javascript
application/json application/javascript application/xml
application/rss+xml application/atom+xml image/svg+xml;
# 上游PHP-FPM
upstream php-fpm {
server wordpress:9000;
keepalive 32;
}
# 限制请求体大小(WordPress上传文件)
client_max_body_size 64m;
client_body_timeout 60s;
include /etc/nginx/conf.d/*.conf;
}
接下来是WordPress站点配置
1 | nginx/conf.d/wordpress.conf |
,包含SSL配置和WordPress伪静态规则:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 # HTTP -> HTTPS 重定向 + Let's Encrypt验证
server {
listen 80;
server_name example.com www.example.com;
# Let's Encrypt证书验证
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
# 其余请求重定向到HTTPS
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS 主站点
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# SSL证书路径
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.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 1d;
ssl_session_tickets off;
# HSTS安全头
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
# WordPress根目录
root /var/www/html;
index index.php index.html;
# WordPress伪静态规则
location / {
try_files $uri $uri/ /index.php?$args;
}
# PHP文件处理
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass php-fpm;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
# FastCGI性能优化
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_read_timeout 120s;
fastcgi_send_timeout 120s;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 365d;
add_header Cache-Control "public, immutable";
access_log off;
}
# 禁止访问敏感文件
location ~ /\.(ht|git|env) {
deny all;
}
location ~ /(wp-config\.php|xmlrpc\.php|readme\.html|license\.txt) {
deny all;
}
}
关于Nginx配置的更多性能调优技巧,如worker进程数调优、连接数优化等,可以参考我们的Nginx性能调优与安全加固指南。
五、首次部署:SSL证书初始化与一键启动
由于首次获取SSL证书需要Nginx先在80端口运行以响应Let’s Encrypt的验证请求,我们需要分两步部署:先以HTTP模式启动Nginx获取证书,再切换到完整HTTPS配置。
步骤1:创建临时HTTP配置获取证书
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 # 临时HTTP配置(仅用于首次获取证书)
cat > nginx/conf.d/wordpress.conf << 'EOF'
server {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
}
EOF
# 启动Nginx和Certbot容器
docker compose up -d nginx
# 获取SSL证书
docker compose run --rm certbot certonly --webroot -w /var/www/certbot --email admin@example.com --agree-tos --no-eff-email -d example.com -d www.example.com
# 证书获取成功后,替换为完整配置(上面的HTTPS版本)
# 重新加载Nginx
docker compose restart nginx
步骤2:一键启动全部服务
1
2
3
4
5
6
7
8 # 启动所有服务
docker compose up -d
# 查看运行状态
docker compose ps
# 查看日志
docker compose logs -f --tail=50
启动成功后,浏览器访问
1 | https://example.com |
即可看到WordPress安装向导。完成安装后,建议立即在WordPress后台进行以下安全配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 # 在wp-config.php中添加安全配置(通过容器执行)
docker compose exec wordpress sh -c '
cat >> /var/www/html/wp-config.php << "WPCONF"
// 禁用文件编辑
define("DISALLOW_FILE_EDIT", true);
// 自动更新核心
define("WP_AUTO_UPDATE_CORE", true);
// 限制修订版本数量
define("WP_POST_REVISIONS", 5);
// 自动清空回收站(天数)
define("EMPTY_TRASH_DAYS", 7);
WPCONF
'

六、数据备份与迁移:让站点永不丢失
容器化部署最大的误区是认为”容器就是数据”。事实上,容器本身是无状态的,真正的数据存储在 volumes 中。一个完整的备份方案需要同时备份数据库和WordPress文件。
以下是一个生产可用的自动备份脚本,支持数据库导出和文件打包:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #!/bin/bash
# wordpress-backup.sh — WordPress Docker站点自动备份
set -euo pipefail
BACKUP_DIR="/root/backups/wordpress"
RETAIN_DAYS=30
PROJECT_DIR="/root/wordpress-docker"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/wp_backup_${DATE}.tar.gz"
mkdir -p "$BACKUP_DIR"
cd "$PROJECT_DIR"
# 1. 导出数据库
echo "[$(date)] 开始导出数据库..."
docker compose exec -T db mysqldump -u root -p"${MYSQL_ROOT_PASSWORD}" --single-transaction --routines --triggers "${MYSQL_DATABASE}" > "${BACKUP_DIR}/db_${DATE}.sql"
# 2. 打包WordPress文件和数据库导出
echo "[$(date)] 打包备份文件..."
tar czf "$BACKUP_FILE" "${BACKUP_DIR}/db_${DATE}.sql" docker-compose.yml .env nginx/ wordpress/wp-content/
# 3. 清理临时文件
rm -f "${BACKUP_DIR}/db_${DATE}.sql"
# 4. 清理过期备份
find "$BACKUP_DIR" -name "wp_backup_*.tar.gz" -mtime +${RETAIN_DAYS} -delete
# 5. 显示备份结果
SIZE=$(du -sh "$BACKUP_FILE" | cut -f1)
echo "[$(date)] 备份完成: $BACKUP_FILE ($SIZE)"
echo "[$(date)] 当前备份总数: $(ls -1 ${BACKUP_DIR}/wp_backup_*.tar.gz | wc -l)"
将此脚本加入crontab即可实现自动备份:
1
2 # 每天凌晨3点自动备份
0 3 * * * /bin/bash /root/wordpress-docker/wordpress-backup.sh >> /var/log/wp-backup.log 2>&1
迁移到新VPS只需三步:复制
1 | docker-compose.yml |
和
1 | .env |
文件、传输备份的
1 | wp-content |
目录、导入数据库SQL文件。这比传统部署的迁移效率提升了10倍以上。如果你需要将备份自动同步到对象存储,可以参考我们的Nginx反向代理与Let’s Encrypt自动SSL配置指南中关于多站点管理的方案。
七、常见问题排查与性能调优
在实际运行中,你可能会遇到以下常见问题。这里给出排查思路和解决方案:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 502 Bad Gateway | PHP-FPM未启动或超时 | 检查docker compose logs wordpress,增加fastcgi_read_timeout |
| 数据库连接失败 | MariaDB未就绪 | 检查healthcheck状态,确认depends_on条件 |
| SSL证书获取失败 | 域名DNS未解析到VPS | 用dig example.com确认解析,等待DNS传播 |
| 上传文件403/413 | 请求体超过Nginx限制 | 调整client_max_body_size为64m或更大 |
| 页面加载慢 | PHP-FPM进程数不足 | 配置PHP_FPM_PM_MAX_CHILDREN参数 |
| 内存溢出(OOM) | 容器内存限制过低 | 在compose中添加mem_limit,或升级VPS |
对于1核512M的低配VPS,建议做以下优化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 # 针对低配VPS的资源限制
services:
db:
deploy:
resources:
limits:
memory: 256M
command: >
--innodb-buffer-pool-size=128M
--innodb-log-file-size=32M
--max-connections=50
--key-buffer-size=16M
--table-open-cache=200
wordpress:
deploy:
resources:
limits:
memory: 128M
environment:
PHP_FPM_PM: dynamic
PHP_FPM_PM_MAX_CHILDREN: 8
PHP_FPM_PM_START_SERVERS: 2
PHP_FPM_PM_MIN_SPARE_SERVERS: 1
PHP_FPM_PM_MAX_SPARE_SERVERS: 3
对于高配VPS(2核2G以上),可以启用FastCGI缓存进一步提升性能:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 # 在nginx.conf的http块中添加
fastcgi_cache_path /var/cache/nginx levels=1:2
keys_zone=wordpress:100m inactive=60m
max_size=1g use_temp_path=off;
# 在wordpress.conf的server块中添加
set $skip_cache 0;
# 登录用户和POST请求不缓存
if ($http_cookie ~* "wordpress_logged_in") { set $skip_cache 1; }
if ($request_method = POST) { set $skip_cache 1; }
if ($query_string != "") { set $skip_cache 1; }
location ~ \.php$ {
fastcgi_pass php-fpm;
fastcgi_cache wordpress;
fastcgi_cache_valid 200 301 302 10m;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache_use_stale error timeout invalid_header;
add_header X-Cache-Status $upstream_cache_status;
}
启用FastCGI缓存后,匿名访客的页面加载速度通常可以提升3-5倍,因为PHP-FPM只在缓存未命中时才被调用。
总结
用Docker Compose部署WordPress是一次性投入、长期受益的选择。本文覆盖了从项目结构设计、核心配置文件编写、Nginx反向代理与SSL自动化、首次部署流程、数据备份到性能调优的完整链路。核心要点总结如下:
- 环境隔离:MariaDB、WordPress、Nginx各自运行在独立容器中,互不干扰,迁移时只需复制配置和数据卷
- SSL自动化:Certbot容器每12小时检查证书状态,到期前30天自动续期,完全零维护
- 数据持久化:通过Named Volumes和bind mounts确保数据安全,容器重建不影响站点数据
- 性能可调:从512M低配VPS到4核8G高配服务器,通过调整PHP-FPM进程数和FastCGI缓存即可适配
- 备份可复用:一套备份脚本覆盖数据库和文件,迁移到新VPS只需三步操作
相比传统的宝塔面板或手动LNMP部署,Docker Compose方案在环境一致性、部署速度、迁移便利性和升级安全性上都有质的飞跃。如果你正在规划一个新WordPress站点或考虑从传统部署迁移,这套方案是当前最成熟的容器化建站实践之一。
汤不热吧