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

228 lines
6.8 KiB
Markdown

# 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:
```php
// 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:
```bash
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:**
```bash
docker exec CONTAINER_NAME wp --allow-root plugin list
```
**Deactivate a plugin:**
```bash
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:**
```bash
docker exec CONTAINER_NAME wp --allow-root core update
```
**Check WordPress version:**
```bash
docker exec CONTAINER_NAME wp --allow-root core version
```
## Database Operations
### Quick WordPress URL Change
When switching between temporary and production domains:
```bash
# 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:**
```bash
# 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:
```bash
# 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
```bash
# 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
```bash
# 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
```yaml
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
- [Configuration Reference](./configuration-reference.md) - Docker Compose templates
- [Services Inventory](./services-inventory.md) - Current WordPress sites
- [CLAUDE.md](../CLAUDE.md) - General server operations