Docker cho WordPress: Từ development đến production không rối

Nếu bạn từng cài WordPress trên server thủ công với LEMP stack, chắc hẳn đã trải qua cảnh sửa nginx.conf rồi quên cấu hình PHP-FPM, hoặc chuyển project sang máy mới và mất cả buổi setup lại môi trường. Docker giải quyết vấn đề này bằng cách đóng gói toàn bộ ứng dụng — WordPress, MySQL, Nginx — vào những container nhẹ, di động, chạy đồng nhất trên mọi môi trường. Bài viết này sẽ hướng dẫn bạn triển khai WordPress với Docker từ zero, không rối, có thể copy-paste và chạy được ngay.

Docker cho WordPress: Từ development đến production không rối

1. Tại sao Docker cho WordPress?

Trước khi đụng tay vào code, hãy hiểu Docker giải quyết vấn đề gì:

Vấn đề truyền thốngCách Docker giải quyếtLợi ích thực tế
“Trên máy tôi chạy được” — môi trường dev khác productionContainer chứa toàn bộ dependencies: PHP version, extensions, Nginx configChạy giống hệt trên laptop, staging server, và production
Cài đặt thủ công tốn thời gian, dễ lỗiMột file docker-compose.yml định nghĩa toàn bộ stackdocker compose up là xong, mất chưa đến 1 phút
Khó quản lý nhiều project với PHP/MySQL version khác nhauMỗi project có container riêng, cô lập hoàn toànProject A dùng PHP 7.4, project B dùng PHP 8.3 — không xung đột
Backup/restore database phức tạpVolume Docker lưu data riêng biệt, dễ backup bằng docker execBackup chỉ là một file SQL, restore chỉ là một lệnh
Scaling khó khănChạy nhiều container WordPress phía sau load balancerHorizontal scaling dễ dàng với Docker Swarm hoặc Kubernetes

2. Kiến trúc stack WordPress + Docker

Chúng ta sẽ xây dựng stack gồm 3 container:

  1. wordpress: Image wordpress:latest — chạy PHP-FPM, chứa mã nguồn WordPress
  2. db: Image mysql:8.0 — database MySQL cho WordPress
  3. nginx: Image nginx:alpine — reverse proxy, xử lý static files, chuyển PHP requests sang WordPress container

Client
Nginx (port 80)
WordPress PHP-FPM (port 9000)
MySQL (port 3306)

3. Cấu trúc thư mục dự án

Tạo thư mục dự án với cấu trúc sau:

wordpress-docker/
|-- -- docker-compose.yml      # Định nghĩa toàn bộ stack
|-- -- nginx/
|      `-- -- default.conf        # Cấu hình Nginx
|-- -- wordpress/              # Mã nguồn WordPress (mount từ container)
`-- -- db_data/                # Data MySQL (Docker volume)

4. File docker-compose.yml — Trái tim của stack

Đây là file quan trọng nhất. Nó định nghĩa 3 services, network chung, và volumes để lưu data:

version: '3.8'

services:
  db:
    image: mysql:8.0
    container_name: wp_db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword123
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpresspass
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - wp_network
    command: --default-authentication-plugin=mysql_native_password

  wordpress:
    image: wordpress:php8.3-fpm
    container_name: wp_app
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpresspass
    volumes:
      - ./wordpress:/var/www/html
    networks:
      - wp_network
    depends_on:
      - db

  nginx:
    image: nginx:alpine
    container_name: wp_nginx
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./wordpress:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    networks:
      - wp_network
    depends_on:
      - wordpress

volumes:
  db_data:

networks:
  wp_network:
    driver: bridge

Giải thích từng phần:

  • restart: unless-stopped — Container tự khởi động lại khi server reboot, trừ khi bạn chủ động stop.
  • volumesdb_data là named volume, Docker quản lý và data tồn tại ngay cả khi xóa container. ./wordpress là bind mount, cho phép bạn chỉnh sửa file từ host.
  • networks — Các container trong cùng network có thể gọi nhau bằng tên service. WordPress kết nối MySQL qua db:3306.
  • depends_on — Đảm bảo MySQL khởi động trước WordPress, tránh lỗi connection refused.

5. Cấu hình Nginx — Xử lý static files và proxy PHP

Tạo file nginx/default.conf:

server {
    listen 80;
    server_name localhost;
    root /var/www/html;
    index index.php index.html;

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

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

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        expires 6M;
        add_header Cache-Control "public, immutable";
    }

    location ~ /\.ht {
        deny all;
    }
}

Điểm quan trọng:

  • fastcgi_pass wordpress:9000 — Nginx gửi PHP requests đến WordPress container qua port 9000 (PHP-FPM). Docker DNS tự động resolve wordpress thành IP của container.
  • try_files — Hỗ trợ WordPress permalink. Nếu file không tồn tại, chuyển về index.php.
  • expires 6M — Cache static assets 6 tháng, giảm tải server.

6. Khởi động stack — Chạy ngay trong 30 giây

Mở terminal, cd vào thư mục dự án, chạy:

# 1. Tạo thư mục
mkdir -p wordpress-docker/nginx wordpress-docker/wordpress

# 2. Tạo file docker-compose.yml và nginx/default.conf (copy từ trên)

# 3. Khởi động
cd wordpress-docker
docker compose up -d

# 4. Kiểm tra container đang chạy
docker compose ps

# 5. Xem logs nếu cần
docker compose logs -f

Sau khi chạy, truy cập http://localhost và bạn sẽ thấy màn hình cài đặt WordPress. Hoàn tất setup như bình thường.

7. Quản lý WordPress trong Docker — Các lệnh thường dùng

Thao tácLệnh
Xem danh sách containerdocker compose ps
Xem logs real-timedocker compose logs -f
Truy cập shell WordPress containerdocker exec -it wp_app bash
Chạy WP-CLIdocker exec -it wp_app wp --allow-root [command]
Backup databasedocker exec wp_db mysqldump -u wordpress -pwordpresspass wordpress > backup.sql
Restore databasedocker exec -i wp_db mysql -u wordpress -pwordpresspass wordpress < backup.sql
Restart một servicedocker compose restart nginx
Rebuild sau khi sửa configdocker compose up -d --build
Dừng toàn bộ stackdocker compose down
Dừng và xóa cả volume (cẩn thận)docker compose down -v

8. Cài WP-CLI — Quản lý WordPress từ command line

Thay vì vào wp-admin, bạn có thể cài plugin, update core, tạo user bằng WP-CLI:

# Cài WP-CLI vào WordPress container
docker exec -it wp_app bash -c "
curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
mv wp-cli.phar /usr/local/bin/wp
"

# Kiểm tra WP-CLI
docker exec -it wp_app wp --allow-root --info

# Cài plugin
docker exec -it wp_app wp --allow-root plugin install wordpress-seo --activate

# Tạo user admin
docker exec -it wp_app wp --allow-root user create admin [email protected] --role=administrator --user_pass=admin123

# Update WordPress core
docker exec -it wp_app wp --allow-root core update

9. Tối ưu cho production

Development và production khác nhau ở một số điểm quan trọng:

9.1. Sử dụng .env cho secrets

Không hardcode password trong docker-compose.yml. Tạo file .env:

MYSQL_ROOT_PASSWORD=your_secure_root_password
MYSQL_DATABASE=wordpress
MYSQL_USER=wordpress
MYSQL_PASSWORD=your_secure_db_password
WORDPRESS_DB_PASSWORD=your_secure_db_password

Sửa docker-compose.yml:

environment:
  MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
  MYSQL_DATABASE: ${MYSQL_DATABASE}
  MYSQL_USER: ${MYSQL_USER}
  MYSQL_PASSWORD: ${MYSQL_PASSWORD}

Thêm .env vào .gitignore để không push lên Git.

9.2. SSL/TLS với Let’s Encrypt

Thêm container certbot để tự động renew SSL:

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

  nginx:
    # ... existing config
    volumes:
      - ./wordpress:/var/www/html
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./certbot/conf:/etc/letsencrypt
      - ./certbot/www:/var/www/certbot

Sửa nginx/default.conf để redirect HTTP to HTTPS và dùng certificate:

server {
    listen 80;
    server_name yourdomain.com;
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    root /var/www/html;
    index index.php;

    # ... rest of config same as before
}

9.3. PHP OPcache và tuning

Tạo file php.ini custom và mount vào WordPress container:

; php.ini
memory_limit = 256M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300

opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 4000
opcache.revalidate_freq = 2
opcache.fast_shutdown = 1

Thêm vào docker-compose.yml:

  wordpress:
    # ...
    volumes:
      - ./wordpress:/var/www/html
      - ./php.ini:/usr/local/etc/php/conf.d/custom.ini

9.4. Backup tự động với cron

Tạo script backup hàng ngày:

#!/bin/bash
# backup.sh
DATE=$(date +%Y%m%d_%H%M%S)
docker exec wp_db mysqldump -u wordpress -pwordpresspass wordpress | gzip > ./backups/wordpress_$DATE.sql.gz
find ./backups -name "*.sql.gz" -mtime +7 -delete

Thêm vào crontab:

0 2 * * * /path/to/wordpress-docker/backup.sh

10. So sánh: Docker vs LEMP truyền thống

Tiêu chíLEMP thủ côngDocker
Thời gian setup30-60 phút (cài từng thành phần, config từng file)1-2 phút (docker compose up -d)
Tính tái lặpThấp — mỗi server có thể khác nhau do cấu hình tayCao — cùng một docker-compose.yml chạy giống hệt mọi nơi
Quản lý versionKhó — downgrade PHP/MySQL phức tạpDễ — đổi tag image, restart container
Multi-projectKhó — xung đột port, PHP versionDễ — mỗi project một stack container riêng
Resource usageThấp hơn (chạy trực tiếp trên host)Cao hơn một chút (overhead container ~1-5%)
Learning curveThấp — chỉ cần biết Linux + Nginx + MySQLTrung bình — cần hiểu container, volume, network
Production-readyCần nhiều công sức tối ưu thủ côngDễ scale, dễ backup, dễ CI/CD

11. Troubleshooting — Các lỗi thường gặp

LỗiNguyên nhânCách fix
Error establishing database connectionWordPress chưa kết nối được MySQLĐợi thêm vài giây cho MySQL khởi động xong, hoặc chạy docker compose restart wordpress
502 Bad GatewayNginx không kết nối được PHP-FPMKiểm tra fastcgi_pass wordpress:9000 trong nginx config. Đảm bảo WordPress container đang chạy.
Port 80 đã được sử dụngApache/Nginx khác đang chạy trên hostDừng service đang chiếm port: sudo systemctl stop nginx hoặc đổi port mapping thành 8080:80
Permission denied khi sửa file WordPressFile trong container thuộc về user www-dataChạy sudo chown -R $USER:$USER ./wordpress trên host
Database bị mất sau khi docker compose downDùng -v flag hoặc không dùng named volumeĐảm bảo dùng named volume db_data, không chạy down -v trừ khi thực sự muốn xóa data

12. Từ Docker đến Kubernetes — Bước tiếp theo

Khi site lớn lên, bạn có thể cần:

  • Docker Swarm — orchestration đơn giản, tích hợp sẵn trong Docker. Phù hợp cho 1-3 server.
  • Kubernetes — orchestration mạnh mẽ, auto-scaling, self-healing. Phù hợp cho hệ thống lớn, multi-cloud.
  • Docker + Cloud — AWS ECS, Google Cloud Run, Azure Container Instances đều hỗ trợ chạy container WordPress mà không cần quản lý server.

Nhưng đừng vội. Với hầu hết các WordPress site, một server đơn với Docker Compose đã quá đủ. Chỉ nghĩ đến Kubernetes khi bạn có thực sự cần scale ngang (horizontal scaling) hoặc chạy trên nhiều availability zone.

13. Kết luận

Docker không phải công nghệ “thần thánh” — nó chỉ là công cụ. Nhưng với WordPress, Docker giải quyết đúng những vấn đề đau đầu nhất: môi trường không đồng nhất, setup lặp đi lặp lại, backup/restore phức tạp.

Với chỉ 2 file — docker-compose.ymlnginx/default.conf — bạn đã có một stack WordPress production-ready, có thể chạy trên bất kỳ máy nào có Docker, từ laptop cá nhân đến cloud VPS.

Hãy thử copy config ở trên, chạy docker compose up -d, và trải nghiệm cảm giác “mọi thứ chỉ hoạt động” — đó chính là lý do Docker đã trở thành tiêu chuẩn công nghiệp cho việc triển khai ứng dụng.

Bình luận


  • Không có bình luận.

Công cụ trực tuyến

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...