ลดความยุ่งยากในการใช้คลาวด์ พูดคุยกับเจ้าหน้าที่

Home รัน WordPress ด้วย Docker Compose

รัน WordPress ด้วย Docker Compose

การรัน WordPress ด้วย Docker Compose ช่วยให้ทั้งเว็บไซต์และฐานข้อมูลถูกกำหนดไว้ในไฟล์เดียว ย้ายเครื่อง ทำซ้ำ หรืออัปเดตเวอร์ชันได้ง่าย และไม่ต้องติดตั้ง PHP หรือ MariaDB ลงบนระบบปฏิบัติการโดยตรง เหมาะกับผู้ที่ต้องการแยกเว็บไซต์หลายตัวออกจากกัน หรือทำเครื่องทดสอบที่หน้าตาเหมือนเครื่องจริง

บทความนี้สร้างระบบจาก Image ทางการสองตัว คือ wordpress (Apache + PHP) และ mariadb เก็บข้อมูลใน Named Volume ผูกพอร์ตไว้เฉพาะ localhost แล้วให้ Nginx บนเครื่องทำ Reverse Proxy พร้อม HTTPS ซึ่งเป็นรูปแบบที่ใช้งานจริงได้

สิ่งที่ต้องเตรียม

ขั้นตอนที่ 1: สร้างโฟลเดอร์โปรเจกต์และไฟล์ .env

sudo mkdir -p /opt/wordpress
cd /opt/wordpress

เก็บรหัสผ่านไว้ในไฟล์ .env แยกจากไฟล์ Compose เพื่อไม่ให้หลุดไปกับการแชร์คอนฟิก สร้างรหัสผ่านสุ่มด้วย

openssl rand -base64 24

รันสองครั้งเพื่อได้รหัสผ่านสองชุด แล้วสร้างไฟล์

sudo nano /opt/wordpress/.env
DB_NAME=wordpress
DB_USER=wpuser
DB_PASSWORD=ใส่รหัสผ่านชุดแรก
DB_ROOT_PASSWORD=ใส่รหัสผ่านชุดที่สอง

จำกัดสิทธิ์ให้อ่านได้เฉพาะ root

sudo chmod 600 /opt/wordpress/.env

หมายเหตุ: หลีกเลี่ยงตัวอักษร $ ในรหัสผ่านที่ใส่ใน .env เพราะ Compose จะตีความเป็นตัวแปร ถ้าจำเป็นต้องใช้ ให้เขียนเป็น $

ขั้นตอนที่ 2: เขียนไฟล์ compose.yaml

sudo nano /opt/wordpress/compose.yaml
services:
  db:
    image: mariadb:11.4
    restart: unless-stopped
    environment:
      MARIADB_DATABASE: ${DB_NAME}
      MARIADB_USER: ${DB_USER}
      MARIADB_PASSWORD: ${DB_PASSWORD}
      MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - db_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 10s
      timeout: 5s
      retries: 5

  wordpress:
    image: wordpress:php8.3-apache
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_NAME: ${DB_NAME}
      WORDPRESS_DB_USER: ${DB_USER}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
    volumes:
      - wp_data:/var/www/html
      - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini:ro
    ports:
      - "127.0.0.1:8080:80"

volumes:
  db_data:
  wp_data:

จุดสำคัญของไฟล์นี้

  • ระบุเวอร์ชัน Image (mariadb:11.4 ซึ่งเป็นรุ่น LTS และ wordpress:php8.3-apache) ไม่ใช้ latest เพื่อไม่ให้เวอร์ชันหลักของฐานข้อมูลเปลี่ยนเองตอนดึง Image ใหม่
  • WORDPRESS_DB_HOST: db ใช้ชื่อ Service เป็นชื่อโฮสต์ Compose สร้าง Network ภายในให้ทั้งสอง Service คุยกันได้ โดยไม่ต้องเปิดพอร์ตฐานข้อมูลออกนอกเครื่อง
  • healthcheck ใช้สคริปต์ healthcheck.sh ที่มากับ Image MariaDB ทำให้ WordPress เริ่มหลังฐานข้อมูลพร้อมจริง ลดปัญหา Error ตอนเปิดเครื่องครั้งแรก
  • 127.0.0.1:8080:80 เปิดพอร์ตเฉพาะภายในเครื่อง เพราะพอร์ตที่ Docker เปิดจะข้าม UFW ได้ ถ้าเขียนแค่ 8080:80 คนภายนอกจะเข้าพอร์ต 8080 ได้โดยตรง
  • Named Volume db_data และ wp_data เก็บข้อมูลไว้แม้ลบ Container

ขั้นตอนที่ 3: ปรับขนาดไฟล์อัปโหลด

ค่าเริ่มต้นของ PHP ใน Image จำกัดขนาดไฟล์อัปโหลดไว้ต่ำ สร้างไฟล์ที่ Mount ไว้ในขั้นตอนก่อน

sudo nano /opt/wordpress/uploads.ini
upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M
max_execution_time = 120

ต้องสร้างไฟล์นี้ก่อนสั่ง up ถ้าไม่มีไฟล์ Docker จะสร้างเป็นโฟลเดอร์ชื่อ uploads.ini แทนและ PHP จะไม่อ่านค่า

ขั้นตอนที่ 4: เริ่มระบบ

cd /opt/wordpress
sudo docker compose up -d

ครั้งแรกจะดาวน์โหลด Image ใช้เวลาสักครู่ จากนั้นตรวจสถานะ

sudo docker compose ps

ควรเห็น Service db มีสถานะ Up ... (healthy) และ wordpress เป็น Up ถ้าต้องการดูรายละเอียด ใช้ sudo docker compose logs -f

ทดสอบจากตัวเครื่อง

curl -I http://127.0.0.1:8080

ผลที่ถูกต้องคือ HTTP/1.1 302 Found พร้อม Location: .../wp-admin/install.php แปลว่า WordPress ต่อฐานข้อมูลได้และรอติดตั้ง

ขั้นตอนที่ 5: ตั้ง Nginx เป็น Reverse Proxy

sudo nano /etc/nginx/sites-available/example.com
server {
    listen 80;
    server_name example.com www.example.com;

    client_max_body_size 64M;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

client_max_body_size ต้องตรงหรือมากกว่าค่าใน uploads.ini ไม่เช่นนั้นอัปโหลดไฟล์ใหญ่จะได้ 413 จาก Nginx ก่อนถึง PHP จากนั้นขอ SSL ตาม ติดตั้ง SSL ฟรีจาก Let's Encrypt ด้วย Certbot บน Nginx Certbot จะแก้ไฟล์นี้ให้ฟัง 443 เอง

Image wordpress อ่าน Header X-Forwarded-Proto อยู่แล้ว (มีโค้ดตรวจสอบนี้ในไฟล์ wp-config.php ที่ Image สร้างให้) เมื่อ Nginx ส่งค่า https มา WordPress จะรู้ว่าผู้ใช้เข้าผ่าน HTTPS และไม่เกิดการ Redirect วนซ้ำ

หมายเหตุ: เปิดพอร์ต 80 และ 443 ใน Firewall ของเครื่อง หากเซิร์ฟเวอร์มี Security Group หรือ Firewall ภายนอกจากฝั่งผู้ให้บริการ ให้เปิดพอร์ตนั้นเพิ่มด้วย

ขั้นตอนที่ 6: ติดตั้ง WordPress ผ่านเบราว์เซอร์

  1. เปิด https://example.com จะพบหน้าเลือกภาษา
  2. กรอกชื่อเว็บไซต์ ชื่อผู้ใช้ผู้ดูแล (อย่าใช้ admin) รหัสผ่าน และอีเมล
  3. กด Install WordPress แล้วเข้าสู่ระบบ
  4. ไปที่ Settings > General ตรวจว่า WordPress Address และ Site Address ขึ้นต้นด้วย https://

ไม่ต้องกรอกข้อมูลฐานข้อมูล เพราะ Image สร้าง wp-config.php จากตัวแปรใน Compose ให้แล้ว

ตรวจสอบผลลัพธ์

  • sudo docker compose ps แสดงทั้งสอง Service ทำงาน
  • curl -I https://example.com ได้ 200 และไม่มี Redirect วน
  • อัปโหลดไฟล์ขนาดประมาณ 20 MB ใน Media Library ได้สำเร็จ
  • sudo docker volume ls แสดง wordpress_db_data และ wordpress_wp_data (Compose เติมชื่อโฟลเดอร์โปรเจกต์ไว้ข้างหน้า)
  • รีบูตเครื่องแล้วเว็บกลับมาเองเพราะตั้ง restart: unless-stopped

การอัปเดตและดูแลต่อ

ตัว WordPress Core และปลั๊กอินอัปเดตจากหน้า Dashboard ได้ตามปกติ เพราะไฟล์อยู่ใน Volume wp_data ส่วนการอัปเดต PHP หรือ MariaDB ให้ดึง Image ใหม่

cd /opt/wordpress
sudo docker compose pull
sudo docker compose up -d

สำรองข้อมูลก่อนเปลี่ยนเวอร์ชันหลักของ MariaDB ทุกครั้ง ดู สำรองและกู้คืนข้อมูล Docker Volume สำหรับงานจัดการ WordPress ผ่าน Command Line ใช้ sudo docker compose run --rm กับ Image wordpress:cli หรือดูแนวทางที่ จัดการ WordPress ด้วย WP-CLI

ปัญหาที่พบบ่อย

Error establishing a database connection

มักเกิดจากเปลี่ยนรหัสผ่านใน .env หลังจากรันไปแล้ว ตัวแปร MARIADB_* ใช้เฉพาะตอนสร้างฐานข้อมูลครั้งแรกเท่านั้น เมื่อ Volume มีข้อมูลแล้ว การแก้ .env จะไม่เปลี่ยนรหัสผ่านในฐานข้อมูล ให้เปลี่ยนกลับเป็นค่าเดิม หรือเปลี่ยนรหัสผ่านใน MariaDB ด้วยคำสั่ง SQL ให้ตรงกัน ดูแนวทางตรวจสอบเพิ่มเติมที่ แก้ปัญหา Error Establishing a Database Connection ใน WordPress

เว็บ Redirect วนไม่จบ (ERR_TOO_MANY_REDIRECTS)

Nginx ไม่ได้ส่ง X-Forwarded-Proto หรือใช้ Cloudflare ในโหมด Flexible ตรวจบล็อก location ตามขั้นตอนที่ 5 และโหมด SSL ตาม เลือก SSL/TLS Mode บน Cloudflare ให้ถูกต้อง

502 Bad Gateway

Container wordpress ไม่ได้ทำงานหรือยังเริ่มไม่เสร็จ ตรวจด้วย sudo docker compose ps และ sudo docker compose logs wordpress

อัปโหลดไฟล์ใหญ่ไม่ได้

ตรวจว่า uploads.ini เป็นไฟล์จริง (ไม่ใช่โฟลเดอร์) และค่าเข้าไปแล้วด้วย sudo docker compose exec wordpress php -i | grep upload_max_filesize แก้ไฟล์แล้วต้องสั่ง sudo docker compose restart wordpress

หากต้องการคำแนะนำเรื่องการวางระบบ WordPress บน Docker ติดต่อทีมงาน THAI DATA CLOUD ได้ที่ https://thaidata.cloud/contact/

ผู้ให้บริการคลาวด์ไทย
เพื่อธุรกิจของคนไทย

"มุ่งมั่น" และ "มั่นคง"
พร้อมรับมือทุกการเติบโต
Trust Cloud
คลาว์ที่ปลอดภัย
คือรากฐานที่มั่นคง
cloud security