SiamCafe.net Blog
Technology

WordPress Headless Production Setup Guide

wordpress headless production setup guide
WordPress Headless Production Setup Guide | SiamCafe Blog
2025-07-27· อ. บอม — SiamCafe.net· 11,494 คำ

เตรียมความพร้อมสำหรับ Production

การนำ WordPress Headless ขึ้น Production ต้องเตรียมหลายด้าน ได้แก่ Server Configuration ที่เหมาะสม, Security Hardening ป้องกันการโจมตี, Performance Optimization ให้ API ตอบสนองเร็ว, Backup Strategy ป้องกันข้อมูลสูญหาย และ Monitoring ติดตามปัญหา

WordPress Headless ใช้เป็น API Server อย่างเดียว ไม่ต้อง Render Frontend ทำให้ Optimize ได้ง่ายกว่า WordPress ปกติ แต่ต้องให้ความสำคัญกับ API Performance และ Security เป็นพิเศษ

Nginx Configuration สำหรับ WordPress Headless

# === Nginx Configuration สำหรับ WordPress Headless ===
# /etc/nginx/sites-available/wp-headless.conf

# Rate Limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

# Upstream PHP-FPM
upstream php-fpm {
    server unix:/run/php/php8.3-fpm.sock;
    keepalive 16;
}

# Redirect HTTP to HTTPS
server {
    listen 80;
    server_name api.example.com;
    return 301 https://$host$request_uri;
}

# Main Server Block
server {
    listen 443 ssl http2;
    server_name api.example.com;
    root /var/www/wordpress;
    index index.php;

    # SSL
    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # Security Headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Strict-Transport-Security "max-age=63072000" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # CORS สำหรับ Headless Frontend
    set $cors_origin "";
    if ($http_origin ~* "^https://(www\.)?example\.com$") {
        set $cors_origin $http_origin;
    }
    add_header Access-Control-Allow-Origin $cors_origin always;
    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS" always;
    add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
    add_header Access-Control-Max-Age 86400 always;

    if ($request_method = OPTIONS) {
        return 204;
    }

    # FastCGI Cache สำหรับ API
    fastcgi_cache_path /tmp/nginx-cache levels=1:2
        keys_zone=wpcache:100m max_size=1g inactive=60m;
    fastcgi_cache_key "$scheme$request_method$host$request_uri";

    # REST API — Cache 60 วินาที
    location /wp-json/ {
        limit_req zone=api burst=50 nodelay;

        fastcgi_cache wpcache;
        fastcgi_cache_valid 200 60s;
        fastcgi_cache_bypass $http_authorization;
        add_header X-Cache-Status $upstream_cache_status;

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

    # GraphQL — Cache 60 วินาที (GET only)
    location /graphql {
        limit_req zone=api burst=50 nodelay;

        fastcgi_cache wpcache;
        fastcgi_cache_valid 200 60s;
        fastcgi_cache_methods GET;
        fastcgi_cache_bypass $http_authorization;

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

    # wp-admin — จำกัด IP
    location /wp-admin {
        allow 10.0.0.0/8;
        allow 192.168.1.0/24;
        # allow YOUR_OFFICE_IP;
        deny all;
        try_files $uri $uri/ /index.php?$args;
    }

    # wp-login — Rate Limit
    location = /wp-login.php {
        limit_req zone=login burst=3 nodelay;
        allow 10.0.0.0/8;
        deny all;
        include fastcgi_params;
        fastcgi_pass php-fpm;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # Block XML-RPC
    location = /xmlrpc.php {
        deny all;
        return 403;
    }

    # Block wp-cron (use system cron instead)
    location = /wp-cron.php {
        deny all;
    }

    # PHP Processing
    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php-fpm;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_read_timeout 300;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
    }

    # Static Files — Cache ยาว
    location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff2|woff|ttf)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

    # Block sensitive files
    location ~ /\.(ht|git|env) {
        deny all;
    }
    location ~ /wp-config\.php {
        deny all;
    }
}

wp-config.php สำหรับ Production

# === wp-config.php — Production Settings ===
# เพิ่มหลัง DB Settings ใน wp-config.php

# --- Performance ---
# Redis Object Cache
define('WP_REDIS_HOST', '127.0.0.1');
define('WP_REDIS_PORT', 6379);
define('WP_REDIS_DATABASE', 0);
define('WP_REDIS_PREFIX', 'wp_');

# Disable File Editing
define('DISALLOW_FILE_EDIT', true);
define('DISALLOW_FILE_MODS', true);

# Limit Revisions
define('WP_POST_REVISIONS', 5);
define('AUTOSAVE_INTERVAL', 300);

# Memory
define('WP_MEMORY_LIMIT', '256M');
define('WP_MAX_MEMORY_LIMIT', '512M');

# Cron — ใช้ System Cron แทน
define('DISABLE_WP_CRON', true);
# เพิ่มใน crontab: */5 * * * * curl -s https://api.example.com/wp-cron.php > /dev/null

# --- Headless Mode ---
define('WP_HOME', 'https://api.example.com');
define('WP_SITEURL', 'https://api.example.com');
define('HEADLESS_MODE_CLIENT_URL', 'https://www.example.com');

# Disable Frontend Theme Rendering
# ใช้ Plugin "Headless Mode" หรือเพิ่มใน functions.php:
# add_action('template_redirect', function() {
#   if (!is_admin() && !wp_doing_ajax() &&
#       !defined('REST_REQUEST') && !defined('GRAPHQL_REQUEST')) {
#     wp_redirect('https://www.example.com');
#     exit;
#   }
# });

# --- Security ---
define('FORCE_SSL_ADMIN', true);
define('WP_DEBUG', false);
define('WP_DEBUG_LOG', false);
define('WP_DEBUG_DISPLAY', false);

# Security Keys (generate from https://api.wordpress.org/secret-key/1.1/salt/)
# define('AUTH_KEY', '...');
# define('SECURE_AUTH_KEY', '...');
# define('LOGGED_IN_KEY', '...');
# define('NONCE_KEY', '...');

# === PHP-FPM Configuration ===
# /etc/php/8.3/fpm/pool.d/wordpress.conf
# [wordpress]
# user = www-data
# group = www-data
# listen = /run/php/php8.3-fpm.sock
# pm = dynamic
# pm.max_children = 50
# pm.start_servers = 10
# pm.min_spare_servers = 5
# pm.max_spare_servers = 20
# pm.max_requests = 500
# php_admin_value[memory_limit] = 256M
# php_admin_value[upload_max_filesize] = 64M
# php_admin_value[post_max_size] = 64M
# php_admin_value[max_execution_time] = 300
# php_admin_value[opcache.enable] = 1
# php_admin_value[opcache.memory_consumption] = 256
# php_admin_value[opcache.max_accelerated_files] = 20000

Backup และ Monitoring Scripts

#!/bin/bash
# wp-backup.sh — Automated Backup Script สำหรับ WordPress
# เพิ่มใน crontab: 0 2 * * * /opt/scripts/wp-backup.sh

set -e

# Configuration
WP_DIR="/var/www/wordpress"
DB_NAME="wordpress"
DB_USER="wp_user"
DB_PASS="secure_password"
BACKUP_DIR="/backups/wordpress"
S3_BUCKET="s3://my-backups/wordpress"
RETENTION_DAYS=30
DATE=$(date +%Y%m%d_%H%M%S)

echo "[$(date)] Starting WordPress backup..."

# สร้าง Backup Directory
mkdir -p "$BACKUP_DIR"

# 1. Database Backup
echo "  Backing up database..."
mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" \
  --single-transaction --quick --lock-tables=false \
  | gzip > "$BACKUP_DIR/db_.sql.gz"

# 2. Files Backup (wp-content only — ไม่ต้อง Backup Core)
echo "  Backing up wp-content..."
tar czf "$BACKUP_DIR/files_.tar.gz" \
  -C "$WP_DIR" wp-content/ \
  --exclude="wp-content/cache" \
  --exclude="wp-content/upgrade"

# 3. Upload to S3 (ถ้ามี AWS CLI)
if command -v aws &> /dev/null; then
    echo "  Uploading to S3..."
    aws s3 cp "$BACKUP_DIR/db_.sql.gz" "$S3_BUCKET/"
    aws s3 cp "$BACKUP_DIR/files_.tar.gz" "$S3_BUCKET/"
fi

# 4. ลบ Backup เก่า
echo "  Cleaning old backups..."
find "$BACKUP_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete

# 5. ตรวจสอบ Backup Size
DB_SIZE=$(du -h "$BACKUP_DIR/db_.sql.gz" | cut -f1)
FILES_SIZE=$(du -h "$BACKUP_DIR/files_.tar.gz" | cut -f1)

echo "[$(date)] Backup complete!"
echo "  Database: $DB_SIZE"
echo "  Files: $FILES_SIZE"

# === Monitoring Script ===
# wp-monitor.sh — ตรวจสอบสถานะ WordPress

# #!/bin/bash
# # ตรวจสอบ WordPress API
# API_URL="https://api.example.com"
# ALERT_EMAIL="admin@example.com"
#
# # Check REST API
# HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \
#   "$API_URL/wp-json/wp/v2/posts?per_page=1")
#
# if [ "$HTTP_CODE" != "200" ]; then
#   echo "WordPress API DOWN! HTTP $HTTP_CODE" | \
#     mail -s "ALERT: WordPress API Down" "$ALERT_EMAIL"
# fi
#
# # Check Response Time
# RESPONSE_TIME=$(curl -s -o /dev/null -w "%{time_total}" \
#   "$API_URL/wp-json/wp/v2/posts?per_page=1")
#
# # Alert if response > 2 seconds
# if (( $(echo "$RESPONSE_TIME > 2.0" | bc -l) )); then
#   echo "WordPress API SLOW! s" | \
#     mail -s "ALERT: WordPress API Slow" "$ALERT_EMAIL"
# fi
#
# # Check Disk Usage
# DISK_USAGE=$(df -h /var/www/wordpress | tail -1 | awk '{print $5}' | tr -d '%')
# if [ "$DISK_USAGE" -gt 80 ]; then
#   echo "Disk usage: %" | \
#     mail -s "ALERT: Disk Usage High" "$ALERT_EMAIL"
# fi
#
# echo "[$(date)] Health: HTTP=$HTTP_CODE Time=s Disk=%"

Production Checklist

WordPress Headless Production ต้องเตรียมอะไรบ้าง

Web Server (Nginx), PHP 8.x, MySQL/MariaDB, Redis Object Cache, SSL Certificate, CDN, Backup System, Monitoring ติดตั้ง WPGraphQL, ACF, Yoast SEO และ Security Plugins

วิธี Secure WordPress Headless ทำอย่างไร

ปิด XML-RPC จำกัด wp-admin เฉพาะ IP ที่อนุญาต ใช้ Application Passwords ตั้ง CORS Headers ติดตั้ง Wordfence ปิด File Editor ใช้ HTTPS เท่านั้น Update สม่ำเสมอ

วิธี Optimize Performance ทำอย่างไร

Redis Object Cache ลด DB Queries, CDN สำหรับ Media, OPcache สำหรับ PHP, Nginx FastCGI Cache สำหรับ API, Optimize Database ลบ Revisions, ใช้ WebP สำหรับรูปภาพ

Backup Strategy สำหรับ WordPress ควรทำอย่างไร

Backup Database และ Files ทุกวัน Automated Script หรือ Plugin เก็บ Local + Cloud (S3) ทดสอบ Restore เดือนละครั้ง เก็บ Backup อย่างน้อย 30 วัน

สรุป

WordPress Headless สำหรับ Production ต้องให้ความสำคัญกับ Security (ปิด XML-RPC, จำกัด wp-admin, CORS), Performance (Redis Cache, Nginx FastCGI Cache, CDN), Backup (ทุกวัน Local + Cloud) และ Monitoring (API Response Time, Disk Usage) ใช้ Nginx Configuration ที่เหมาะสม wp-config.php ที่ Hardened และ Automated Scripts สำหรับ Backup และ Health Check

📖 บทความที่เกี่ยวข้อง

CDK Construct Production Setup Guideอ่านบทความ → WordPress Headless SSL TLS Certificateอ่านบทความ → Terraform Module Production Setup Guideอ่านบทความ → WordPress Headless Security Hardening ป้องกันแฮกอ่านบทความ → WordPress Headless Post-mortem Analysisอ่านบทความ →

📚 ดูบทความทั้งหมด →