server-ovh-prod-01-main/docs/wordpress-operations.md

6.8 KiB

WordPress Operations Guide

This document provides WordPress-specific operations, configurations, and troubleshooting for WordPress sites running in Docker behind Traefik on systems-prod-01.

Docker Configuration Best Practices

MariaDB Version Selection

  • Use MariaDB 10.11 for compatibility with existing WordPress databases
  • Avoid MariaDB 10.7 - may cause redo log format errors during restoration
  • MariaDB 10.11 is the recommended LTS version for WordPress

SSL/HTTPS Behind Traefik

  • Real Simple SSL plugin NOT needed when behind Traefik
  • Disable Real Simple SSL to avoid redirect loops
  • Traefik handles all SSL termination automatically
  • Add proxy detection configuration to wp-config.php (see below)

Proxy Detection Configuration

Add this to your wp-config.php before the "That's all, stop editing!" line:

// Proxy SSL detection for Traefik
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
    $_SERVER['HTTPS'] = 'on';
}

Using WP-CLI in Docker

Installing WP-CLI

If WP-CLI is not present in your WordPress container:

docker exec CONTAINER_NAME 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'

Common WP-CLI Commands

List plugins:

docker exec CONTAINER_NAME wp --allow-root plugin list

Deactivate a plugin:

docker exec CONTAINER_NAME wp --allow-root plugin deactivate PLUGIN_NAME

# Example: Disable Real Simple SSL
docker exec CONTAINER_NAME wp --allow-root plugin deactivate really-simple-ssl

Update WordPress core:

docker exec CONTAINER_NAME wp --allow-root core update

Check WordPress version:

docker exec CONTAINER_NAME wp --allow-root core version

Database Operations

Quick WordPress URL Change

When switching between temporary and production domains:

# Generic command (change to production domain)
ssh jared@15.204.247.153 "docker exec CONTAINER_DB mysql -u DB_USER -pDB_PASS -e \"
USE DATABASE_NAME;
UPDATE wp_options SET option_value = 'https://domain.com' WHERE option_name IN ('siteurl', 'home');
\""

# Verify the change
ssh jared@15.204.247.153 "docker exec CONTAINER_DB mysql -u DB_USER -pDB_PASS -e \"
USE DATABASE_NAME;
SELECT option_name, option_value FROM wp_options WHERE option_name IN ('siteurl', 'home');
\""

Real Example - BestSolarTech:

# Change to production domain
ssh jared@15.204.247.153 "docker exec bestsolartech_db mysql -u wordpress -pBST_wp2024_secure -e \"
USE bst_wordpress;
UPDATE wp_vuhx_options SET option_value = 'https://bestsolartech.com' WHERE option_name IN ('siteurl', 'home');
\""

# Verify
ssh jared@15.204.247.153 "docker exec bestsolartech_db mysql -u wordpress -pBST_wp2024_secure -e \"
USE bst_wordpress;
SELECT option_name, option_value FROM wp_vuhx_options WHERE option_name IN ('siteurl', 'home');
\""

Database Access with Skip Grant Tables

If you need to reset database passwords or access without credentials:

# Stop the current database container
docker stop SERVICE_db

# Start temporary database with skip-grant-tables
docker run -d --name temp_db \
  -v ~/services/SERVICE/db_data:/var/lib/mysql \
  mariadb:10.11 --skip-grant-tables

# Access the database (no password needed)
docker exec -it temp_db mysql

# After making changes, stop temp container and restart normal one
docker stop temp_db && docker rm temp_db
docker start SERVICE_db

Database Backup

# Backup WordPress database
docker exec CONTAINER_DB mysqldump -u DB_USER -pDB_PASS DATABASE_NAME > backup.sql

# Example: Backup BestSolarTech
docker exec bestsolartech_db mysqldump -u wordpress -pBST_wp2024_secure bst_wordpress > bestsolartech-backup.sql

Database Restore

# Restore from backup
cat backup.sql | docker exec -i CONTAINER_DB mysql -u DB_USER -pDB_PASS DATABASE_NAME

# Example: Restore BestSolarTech
cat bestsolartech-backup.sql | docker exec -i bestsolartech_db mysql -u wordpress -pBST_wp2024_secure bst_wordpress

Troubleshooting

Redirect Loops

Symptom: Browser shows "too many redirects" error Cause: Real Simple SSL plugin conflicting with Traefik SSL termination Solution: Disable Real Simple SSL plugin using WP-CLI (see above)

Database Connection Errors

Symptom: "Error establishing database connection" Cause: Database container not ready or wrong credentials Solution:

  1. Check database container is running: docker ps | grep db
  2. Check database logs: docker logs CONTAINER_DB
  3. Verify credentials in wp-config.php match docker-compose.yml

Mixed Content Warnings

Symptom: HTTPS page loading HTTP resources Cause: Missing proxy detection in wp-config.php Solution: Add proxy detection code (see above)

Migration Checklist

When migrating a WordPress site to systems-prod-01:

  • Backup WordPress files and database from source
  • Create service directory: ~/services/SITE_NAME
  • Create docker-compose.yml with MariaDB 10.11
  • Add proxy detection code to wp-config.php
  • Deploy containers with temporary domain
  • Test HTTPS on temporary domain
  • Disable Real Simple SSL plugin if present
  • Update site URLs in database for production domain
  • Test all functionality (admin panel, forms, etc.)
  • Update DNS for production cutover
  • Monitor for 24 hours after migration

WordPress-Specific Docker Compose Template

services:
  wordpress:
    image: wordpress:6.7-apache
    restart: unless-stopped
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
    volumes:
      - ./wordpress_data:/var/www/html
    networks:
      - traefik
      - internal
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.SITE.rule=Host(`domain.com`) || Host(`www.domain.com`)"
      - "traefik.http.routers.SITE.entrypoints=websecure"
      - "traefik.http.routers.SITE.tls.certresolver=letsencrypt"

  db:
    image: mariadb:10.11
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - ./db_data:/var/lib/mysql
    networks:
      - internal
    healthcheck:
      test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
      interval: 30s
      timeout: 10s
      retries: 5

networks:
  traefik:
    external: true
  internal:
    external: true

See Also