前言:为什么你需要 Docker Compose?
如果你曾经在 VPS 上手动装过 LNMP/LEMP 环境,你一定记得那种痛——Nginx、MySQL、PHP 一个一个装,配置文件改来改去,apt 源版本不对、依赖冲突、端口被占、跑起来了又不知道哪里挂掉。换个服务器?重来一遍。升级系统?心惊胆战。
Docker Compose 就是解决这个问题的。 它让你把一整个应用栈(Nginx + MySQL + PHP/WordPress)写进一个 YAML 文件,一条命令全部启动,删掉也是一条命令全部清理干净。环境隔离、版本锁定、迁移丝滑——这就是容器编排的力量。
这篇文章我在 Ubuntu 24.04 上实操了一遍,从零开始用 Docker Compose 部署一个完整的 Nginx + MySQL + WordPress 栈。我会把每一步的命令和输出都贴出来,让你可以跟着敲。
前置条件
- 一台 Ubuntu 24.04 服务器(我用的是阿里云 2C4G,系统刚装好的)
- 有 sudo 权限的用户
- 域名指向服务器 IP(我用
demo.devlearn.club做演示) - SSH 能连上就行,不需要装任何东西
第一步:安装 Docker 和 Docker Compose
Ubuntu 24.04 的官方源里 Docker 版本偏旧,我习惯用 Docker 官方源安装。一条龙脚本拿走:
$ sudo apt update && sudo apt install -y ca-certificates curl
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update
$ sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
验证安装:
$ docker --version
Docker version 28.0.4, build b8034c0
$ docker compose version
Docker Compose version v2.36.0
注意:Ubuntu 24.04 用的是新版的 docker compose(中间空格,不是 docker-compose 带连字符)。新版是 Docker CLI 的插件,不用单独装 docker-compose 了。如果你在网上看到旧教程用连字符版本,直接替换成空格版本就行。
把当前用户加到 docker 组,免得每次都要 sudo:
$ sudo usermod -aG docker $USER
$ newgrp docker
第二步:创建项目目录结构
$ mkdir -p ~/wordpress-docker/{nginx,wordpress,mysql-data}
$ cd ~/wordpress-docker
目录说明:
nginx/— 放 Nginx 配置文件wordpress/— WordPress 文件挂载目录mysql-data/— MySQL 数据持久化目录
第三步:编写 docker-compose.yml
这是整个项目的核心。三个服务:Nginx 做反向代理、MySQL 做数据库、WordPress 跑 PHP。用自定义网络把它们连在一起:
$ cat > docker-compose.yml << 'EOF'
services:
db:
image: mysql:8.0
container_name: wp_mysql
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: MyStr0ng!Pass2024
MYSQL_DATABASE: wordpress
MYSQL_USER: wpuser
MYSQL_PASSWORD: WpP@ssw0rd2024
volumes:
- ./mysql-data:/var/lib/mysql
networks:
- wp_net
wordpress:
image: wordpress:php8.3-fpm-alpine
container_name: wp_app
restart: unless-stopped
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wpuser
WORDPRESS_DB_PASSWORD: WpP@ssw0rd2024
WORDPRESS_DB_NAME: wordpress
volumes:
- ./wordpress:/var/www/html
depends_on:
- db
networks:
- wp_net
nginx:
image: nginx:alpine
container_name: wp_nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx:/etc/nginx/conf.d
- ./wordpress:/var/www/html
depends_on:
- wordpress
networks:
- wp_net
networks:
wp_net:
driver: bridge
EOF
几个关键点:
- WordPress 镜像选了
php8.3-fpm-alpine,因为 Nginx 需要 PHP-FPM 来处理 PHP 请求,Apache 版 WordPress 自带 web server 反而用不上。alpine 镜像体积小(不到 100MB),启动快。 depends_on不等于等待就绪。 它只保证启动顺序,不保证 MySQL 已经准备好接受连接。实际生产环境建议加 healthcheck,我后面会提。- 数据持久化靠 volumes。 不用 volumes 的话,容器删了数据就没了。mysql-data 和 wordpress 目录都映射到宿主机,随便折腾容器,数据不丢。
- 密码别用我这份, 改一个强密码。
第四步:配置 Nginx
创建 Nginx 的 server block 配置,让它把请求转发给 PHP-FPM(WordPress 容器):
$ cat > nginx/wordpress.conf << 'EOF'
server {
listen 80;
server_name demo.devlearn.club;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass wordpress:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
location ~ /\.ht {
deny all;
}
}
EOF
fastcgi_pass wordpress:9000; 这行的 wordpress 是 docker-compose.yml 里定义的服务名,Docker 的内部 DNS 会自动解析成容器 IP。这就是 Compose 网络的好处——不用记 IP,直接用服务名互相访问。
第五步:启动整个栈
$ docker compose up -d
[+] Running 4/4
✔ Network wordpress-docker_wp_net Created 0.0s
✔ Container wp_mysql Started 0.5s
✔ Container wp_app Started 1.2s
✔ Container wp_nginx Started 1.8s
检查容器状态:
$ docker compose ps
NAME IMAGE STATUS PORTS
wp_mysql mysql:8.0 Up 2 minutes 3306/tcp
wp_app wordpress:php8.3-fpm-alpine Up 2 minutes 9000/tcp
wp_nginx nginx:alpine Up 2 minutes 0.0.0.0:80->80/tcp
三个容器全部 Up,端口映射正常。这时候打开浏览器访问你的域名,应该看到 WordPress 安装界面了。
第六步:完成 WordPress 安装
浏览器打开 http://你的域名,看到 WordPress 经典的五分钟安装界面。选语言、填站点信息、设置管理员账户,一路下一步就完了。
安装完成后你应该能在后台愉快地写文章了。等等——你现在还没有 HTTPS?没错,目前只配了 80 端口。生产环境必须上 SSL,但 HTTPS 配置我专门写过一篇 Let’s Encrypt SSL 证书自动续期教程,配合 Certbot + Nginx 一条龙搞定,这里不展开了。
日常管理命令速查
# 查看日志
$ docker compose logs -f nginx
# 重启某个服务
$ docker compose restart wordpress
# 停止所有服务
$ docker compose down
# 停止并删除数据卷(危险!)
$ docker compose down -v
# 重新构建并启动
$ docker compose up -d --build
# 进入容器内 shell
$ docker compose exec wordpress sh
踩坑记录
我在实际部署时踩了几个坑,记录一下省得你重复掉:
坑一:MySQL 8.0 认证方式变更。 WordPress 默认用 mysql_native_password 连接,但 MySQL 8.0 默认用 caching_sha2_password。不过官方的 WordPress 镜像已经处理好了这个问题,如果用第三方的 WordPress 镜像或者自己 build,可能需要手动加 --default-authentication-plugin=mysql_native_password 参数。
坑二:Nginx 502 Bad Gateway。 访问站点看到 502,99% 是 fastcgi_pass 写错了。检查 nginx 配置里 fastcgi_pass 后面的服务名是不是 docker-compose.yml 里的 service name,端口是不是 9000。
坑三:文件权限。 WordPress 容器内部以 www-data 用户运行,如果你在宿主机上编辑 wordpress/ 目录下的文件,可能会遇到权限问题。解决方法:
$ sudo chown -R 33:33 wordpress/ # 33 是容器内 www-data 的 UID
进阶:加健康检查
前面提过 depends_on 不保证服务就绪。如果你遇到 WordPress 容器启动时 MySQL 还没准备好(概率不高但确实存在),可以在 docker-compose.yml 里给 db 服务加 healthcheck:
db:
image: mysql:8.0
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
然后在 wordpress 服务里把 depends_on 改成条件依赖:
depends_on:
db:
condition: service_healthy
常见问题 FAQ
Q: 我在国内 VPS 上拉 Docker 镜像特别慢怎么办?
配置国内镜像加速器。编辑 /etc/docker/daemon.json:
{"registry-mirrors": ["https://mirror.ccs.tencentyun.com"]}
然后 sudo systemctl restart docker。截至 2026 年,国内可用的加速器推荐 腾讯云、阿里云(需注册获取专属地址)和 DaoCloud。Docker Hub 官方镜像在中国大陆已不可用。
Q: 我要给 WordPress 升级或装插件,容器重启后会丢失吗?
不会。因为 ./wordpress:/var/www/html 这个 volume 映射把 WordPress 文件持久化到了宿主机。你通过后台安装的插件、主题、上传的媒体文件都存在宿主机磁盘上,容器删了重建也不丢。同理,MySQL 数据在 ./mysql-data 目录下。
Q: 怎么给这个 WordPress 加上 HTTPS / SSL 证书?
推荐用 Certbot + Let’s Encrypt 免费证书。具体步骤我在另一篇文章里写过——Let’s Encrypt SSL 证书自动续期配置教程。简单说就是在宿主机上安装 Certbot,生成证书后挂在 Nginx 容器里,然后修改 nginx/wordpress.conf 加上 443 端口的 server block。配合 cron 定时任务自动续期,一劳永逸。
总结
用 Docker Compose 部署 WordPress 比传统方式有几个明显优势:
- 一条命令起 —
docker compose up -d,不用一个一个装软件 - 环境隔离 — PHP、MySQL、Nginx 各跑各的容器,版本互不干扰
- 迁移简单 — 把整个项目目录打包拷到另一台服务器,
docker compose up -d就能跑 - 清理干净 —
docker compose down -v删得干干净净,不留垃圾
如果你之前一直用宝塔面板或者手动编译安装,强烈建议试试 Docker Compose。搭过一次你就回不去了。这玩意儿和 VPS 安全加固 配合起来,一台干净的 Ubuntu VPS 配上 Docker Compose,就是你的最佳生产环境底座。
下一篇我计划写 systemctl 服务管理完全指南,把 systemd 的原理、常用命令、定时器替代 crontab 都讲透。感兴趣的话留意更新。
🔗 相关阅读:MySQL慢查询优化实战:一条SQL从8秒干到0.03秒的全过程复盘 — 搭好MySQL只是第一步,性能优化才是重头戏。