Compose 实战:WordPress + MySQL 一键建站

理论讲得差不多了,来个真家伙。小够带你用 Docker Compose 把 WordPress + MySQL 跑起来:从选镜像版本、写 compose 文件、.env 分离密码,到完成安装、配 Nginx 反代、定时备份,全流程一次走通。

我是小够,只推够用的 VPS。

今天来个完整实战:用 Compose 把 WordPress 跑起来——一个 Web 应用 + 一个数据库,正好演示多容器配合。跟着一步一步做,半小时能跑起来。

准备工作

一台装好 Docker 和 compose 插件的 VPS。1 核 2G 比较舒服,1 核 1G 也能跑但后台慢。

建个项目目录:

mkdir -p ~/apps/wordpress && cd ~/apps/wordpress

小够的习惯:一个应用一个目录。这个目录以后就是你的"网站总部",compose 文件、.env、备份脚本全放这。

选镜像:tag 别乱用

docker pull wordpress:6-php8.2-apache

tag 里 6 是 WordPress 大版本,php8.2 是 PHP 版本,apache 是 Web 服务器。写全:升级/回滚有据可查,不会被 latest 吓到。

MySQL 用 mysql:8.0,和 WordPress 6 是官方测试组合,别混搭 5.7(认证插件不一样)。

写 compose 文件

services:
  db:
    image: mysql:8.0
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: 这里换成你自己的强密码
      MYSQL_ROOT_PASSWORD: 这里换另一个强密码
    volumes:
      - db-data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  wordpress:
    image: wordpress:6-php8.2-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: 这里换成和上面一样的强密码
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - wp-data:/var/www/html
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

volumes:
  db-data:
  wp-data:

逐段解释:

  • WORDPRESS_DB_HOST: db——用服务名当数据库地址,Compose 自动做内部 DNS 解析,不用记 IP。
  • depends_on + condition: service_healthy:等到 MySQL 就绪才启动,第一次部署基本不会遇到"数据库连不上"。
  • start_period 是初始化宽限期,1 核小机器第一次启动慢,设 60s 更稳。
  • 两个 volumes 都是具名数据卷,数据库和网站文件都持久化,容器删了重建数据还在。
  • logging 限制日志大小,长期跑的服务一定要配。

密码别硬编码:用 .env

上面的密码直接写在文件里,能用但不好——一不小心传到 GitHub 就公开了。建个 .env(和 compose 文件同目录):

MYSQL_ROOT_PASSWORD=强密码1
MYSQL_PASSWORD=强密码2

compose 文件改成引用变量:

    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}

Compose 自动读取同目录 .env。.env 进 .gitignore,密码单独保管。强密码 16 位以上,大小写+数字+符号,密码管理器生成,别自己编 wordpress123。.env 文件权限设成 600:

chmod 600 .env

启动并完成安装

docker compose up -d
docker compose logs -f db   # 看一眼 MySQL 初始化日志,确认没报错

两个容器 Up 且 db 是 healthy 后,打开 http://服务器IP:8080,按向导完成安装。

如果打开是数据库连接错误:先看 docker compose logs db 找报错。常见原因就三个:密码含 $、# 这类特殊字符没加单引号、healthcheck 还没通过(等一分钟)、端口被占了(8080 换个别的)。

配域名和 HTTPS

8080 端口裸奔只是临时状态,正式用要配域名。两种路线:

路线一:Cloudflare 免费版(推荐新手)。 域名 DNS 接入 Cloudflare,开 CDN 代理,SSL 选 Flexible。VPS 上继续跑 8080,Cloudflare 负责 HTTPS 和加速。

路线二:自己配 Nginx 反代 + Let’s Encrypt。 在 VPS 上再起一个 Nginx 容器:

services:
  proxy:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certs:/etc/nginx/certs:ro

nginx.conf 里按域名转发到 wordpress:80,证书用 acme.sh 申请+定时续期。控制力最强,但要多花半小时。

不管哪条路线,WordPress 后台的"站点地址"记得改成域名,不然图片链接全是 IP,换域名就乱。

备份:网站的命根子

数据都在 db-data 和 wp-data 两个卷里,备份脚本放项目目录:

#!/bin/bash
cd ~/apps/wordpress
BACKUP_DIR=~/backup/wordpress
mkdir -p $BACKUP_DIR
DATE=$(date +%F)
docker compose down
docker run --rm -v wordpress_db-data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/db-$DATE.tar.gz -C /data .
docker run --rm -v wordpress_wp-data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/wp-$DATE.tar.gz -C /data .
docker compose up -d

注意卷名的前缀是项目目录名(wordpress_db-data),docker volume ls 可以确认。每周日凌晨 3 点跑:

crontab -e
0 3 * * 0 bash ~/apps/wordpress/backup.sh >> ~/backup/wordpress/backup.log 2>&1

备份文件一定要拷到别处——放同一台机器上不叫备份,至少每周拷一份到本地电脑或对象存储。小够见过太多"备份了但和机器一起没了"的悲剧。

每季度做一次恢复演练:按迁移那节的流程恢复一遍,确认网站能打开。没演练过的备份,等于没备份。

升级 WordPress

docker compose pull wordpress
docker compose up -d

拉新镜像重建容器,数据卷不动,原地升级。先备份,大版本升级看官方说明,别无脑升。

性能优化

1 核 2G 的机器,MySQL 8.0 默认配置就能跑个人博客,访问量不大不用调优。按优先级来:

第一,装页面缓存插件。 WP Super Cache 这类,动态变静态,效果比调 MySQL 明显,还零风险。

第二,开 PHP OPcache。 官方镜像默认没开,在 compose 里加环境变量就行:

environment:
  PHP_OPCACHE_ENABLE: 1
  PHP_OPCACHE_MEMORY_CONSUMPTION: 128

OPcache 把 PHP 编译结果缓存住,效果立竿见影,零风险。

第三,Redis 对象缓存。 compose 里加个 redis 服务,WordPress 装 Redis Object Cache 插件:

services:
  cache:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis-data:/data
    deploy:
      resources:
        limits:
          memory: 256M

volumes:
  redis-data:

查询缓存到 Redis,后台操作快很多。访问量不大时 OPcache + 页面缓存就够了。

第四,图片压缩。 博客慢一半原因是原图直传,压一下再传,WebP 更好。先 docker stats 看内存,别上来就折腾 MySQL 参数。

优化按顺序来:页面缓存 > OPcache > Redis > 调 MySQL 参数,别反着折腾。

迁移到新机器

换 VPS 是迟早的事,Compose 让迁移很简单:

  1. 老机器跑一遍备份脚本,打出两个 tar 包。
  2. 新机器装 Docker,把 docker-compose.yml 和 .env 拷过去,up -d 跑起来(空数据)。
  3. 停容器,把 tar 包解到对应数据卷,再 up -d。
docker compose down
docker run --rm -v wordpress_db-data:/data -v ~/backup:/backup alpine tar xzf /backup/db-2025-07-05.tar.gz -C /data
docker run --rm -v wordpress_wp-data:/data -v ~/backup:/backup alpine tar xzf /backup/wp-2025-07-05.tar.gz -C /data
docker compose up -d

域名 DNS 切过去,完事。迁移后记得检查:网站能打开、后台能登录、图片显示正常。

已经在虚拟主机/宝塔上有站的:老站用 UpdraftPlus 打完整备份,新站后台导入恢复,DNS 切过去观察几天再停老站。插件导入比手动拷数据卷省心,备份插件别卸,留着当定期备份。

顺带一提:WordPress 有 Multisite 模式,一个后台管多个域名(wp-config.php 加 define('WP_ALLOW_MULTISITE', true);)。插件兼容性差,数据量大建议分开——一个数据库出问题全挂。

常见问题

Q:depends_on 加了 condition,为什么第一次还是慢? A:MySQL 首次初始化就要几十秒,加上检查间隔,第一次 up 等 1-2 分钟正常。start_period 设大点。

Q:我想用域名访问,不想记端口号,怎么办? A:再起一个 Nginx 容器做反代,把 80/443 按域名转发到 wordpress:80,上面"配域名"那节有两种路线。

Q:数据卷到底存在主机的哪里? A:一般在 /var/lib/docker/volumes/ 下,用 docker volume inspect wordpress_db-data 看具体路径。别直接改,走备份/恢复流程。

Q:MySQL 密码忘了怎么办? A:密码在 .env 文件里写着。所以这文件别乱传,丢了等于把数据库钥匙送人。

Q:1 核 1G 的机器能跑吗? A:能跑,但体验一般:MySQL 8.0 在 1G 上吃力,后台会卡。个人博客建议 2G 起步,1G 机器更适合 Halo、Typecho 这类轻量应用。

Q:WordPress 容器和数据库放一台机器,安全吗? A:没问题。compose 默认网络下数据库端口没映射到主机,外面连不进来,只有 wordpress 容器能访问。