EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
WordPress Deployment Pattern - "Egg" Architecture

Overview

Following the Pterodactyl "egg" pattern, WordPress sites are deployed with:

  1. Fresh WordPress core downloaded on each deployment
  2. Configuration generated from environment variables
  3. Content (wp-content) stored on DigitalOcean Spaces CDN
  4. Minimal GitHub repo containing only deployment scripts

Repository Structure

wordpress-{sitename}/
├── .docker/
│ ├── init.sh # Container initialization script
│ ├── create-wp-config-from-env.php # wp-config generator
│ └── Dockerfile # Container definition (App Platform)
├── .do/
│ └── app.yaml # DigitalOcean App Platform spec
├── .gitignore # Exclude WordPress core files
├── README.md # Site documentation
└── sync-content-to-bucket.sh # Upload wp-content to DO Spaces

What's NOT in the Repo

  • ❌ WordPress core files (wp-admin, wp-includes, etc.)
  • ❌ wp-config.php (generated from env vars)
  • ❌ wp-content/* (stored on DO Spaces bucket)
  • ❌ Plugins, themes, uploads (on CDN)

Deployment Flow

1. Container Starts

App Platform deploys → Docker container initializes

2. Initialization Script Runs

.docker/init.sh executes:
1. Download latest WordPress core (if not present)
2. Generate wp-config.php from env vars (DB credentials)
3. Sync wp-content from DO Spaces bucket
4. Detect table prefix from database
5. Set permissions
6. Start web server

3. WordPress Serves Requests

WordPress core (fresh) → wp-config (env-generated) → wp-content (CDN-synced)

Benefits

Security

  • ✅ Fresh WordPress core on every deploy (auto security updates)
  • ✅ No credentials in GitHub repo
  • ✅ Content CDN-backed (fast, distributed)

Efficiency

  • ✅ Tiny Git repos (~100KB instead of 1GB)
  • ✅ Fast deployments (no large file transfers)
  • ✅ Shared WordPress core across deploys

Maintenance

  • ✅ Update WordPress by redeploying (pulls latest)
  • ✅ Content updates independent of code deploys
  • ✅ Easy rollback (redeploy previous commit)

Content Management

Initial Setup: Upload wp-content to Bucket

# From existing WordPress installation
./sync-content-to-bucket.sh upload
# This uploads:
# - wp-content/themes/
# - wp-content/plugins/
# - wp-content/uploads/
# To: s3://wordpress-{sitename}-content/wp-content/

Update Content (Add plugins, themes, media)

# Option 1: Upload directly to bucket
rclone copy /local/wp-content/plugins/new-plugin \
do-spaces:wordpress-sitename-content/wp-content/plugins/new-plugin
# Option 2: Update via WordPress admin, then sync
# After making changes in WordPress admin:
./sync-content-to-bucket.sh sync

Restore Content from Bucket

# Pull latest content
./sync-content-to-bucket.sh download

Environment Variables

Each App Platform app requires:

Database

  • DB_HOST - MySQL cluster hostname
  • DB_PORT - MySQL port (25060)
  • DB_NAME - Database name (e.g., performwritecom_wp)
  • DB_USER - Isolated database user
  • DB_PASSWORD - User password

DO Spaces (Content CDN)

  • BUCKET_NAME - Bucket name (e.g., wordpress-performwritecom-content)
  • BUCKET_ENDPOINT - DO Spaces endpoint (e.g., nyc3.digitaloceanspaces.com)
  • BUCKET_ACCESS_KEY - Spaces access key
  • BUCKET_SECRET_KEY - Spaces secret key

Site Configuration

Migration from Current Setup

For each WordPress site:

1. Upload wp-content to Bucket

# Create bucket
doctl spaces create wordpress-{sitename}-content --region nyc3
# Upload content from Lightsail/existing server
rclone sync /opt/bitnami/wordpress/wp-content/ \
do-spaces:wordpress-{sitename}-content/wp-content/ \
--exclude 'cache/**' \
--exclude 'upgrade/**'

2. Clean GitHub Repo

cd /tmp/wordpress-repos/wordpress-{sitename}
# Remove all WordPress core files
find . -mindepth 1 -maxdepth 1 ! -name '.git' ! -name '.docker' ! -name '.do' ! -name 'README.md' -exec rm -rf {} +
# Copy deployment templates
cp -r ~/Documents/IBG_HUB/rmm-psa-devops/wordpress-templates/.docker .
cp -r ~/Documents/IBG_HUB/rmm-psa-devops/wordpress-templates/.do .
cp ~/Documents/IBG_HUB/rmm-psa-devops/wordpress-templates/.gitignore .
cp ~/Documents/IBG_HUB/rmm-psa-devops/wordpress-templates/sync-content-to-bucket.sh .
# Commit
git add .
git commit -m "Migrate to egg architecture - minimal deployment files only"
git push origin main

3. Update App Platform Spec

# Add bucket env vars to app
doctl apps update {app-id} --spec .do/app.yaml

4. Redeploy

# App Platform detects change and redeploys
# init.sh downloads fresh WordPress, syncs content from bucket

Example: performwritecom

Before (Current)

wordpress-performwritecom/ (1.2 GB)
├── wp-admin/ (19 MB)
├── wp-includes/ (45 MB)
├── wp-content/ (1.1 GB)
├── wp-config.php
└── ... (hundreds of core files)

After (Egg Architecture)

wordpress-performwritecom/ (150 KB)
├── .docker/
│ ├── init.sh
│ ├── create-wp-config-from-env.php
│ └── Dockerfile
├── .do/
│ └── app.yaml
├── README.md
├── .gitignore
└── sync-content-to-bucket.sh

wp-content/s3://wordpress-performwritecom-content/wp-content/ (1.1 GB on CDN)

Updating WordPress

Core Updates

# Automatic: Just redeploy the app
# init.sh will download latest WordPress core
doctl apps create-deployment {app-id}

Plugin/Theme Updates

# Option 1: Via WordPress admin UI (changes saved to bucket)
# Option 2: Update locally and sync to bucket
rclone sync /local/wp-content/plugins/ \
do-spaces:wordpress-{sitename}-content/wp-content/plugins/

Database Schema Updates

WordPress handles automatically on first load after core update.

Rollback Strategy

Rollback Deployment

# Redeploy previous Git commit
git revert HEAD
git push origin main
# App Platform auto-deploys previous version

Rollback Content

# DO Spaces supports versioning
# Enable versioning on buckets:
doctl spaces create wordpress-{sitename}-content --region nyc3 --versioning enabled
# Restore previous version of object
aws s3api list-object-versions --bucket wordpress-{sitename}-content
aws s3api restore-object --bucket ... --key ... --version-id ...

Cost Comparison

Current Approach (Full WordPress in Git)

  • GitHub storage: ~1.5 GB × 16 sites = 24 GB
  • Deployment time: ~5-10 minutes (large transfers)
  • Bandwidth: High (download entire site on each deploy)

Egg Architecture

  • GitHub storage: ~150 KB × 16 sites = 2.4 MB (1000× reduction)
  • Deployment time: ~1-2 minutes (small scripts)
  • Bandwidth: Minimal (WordPress downloads once, content cached on CDN)
  • DO Spaces: ~$5/month for 250 GB + transfer (shared across all sites)

Security Considerations

Bucket Access

  • Create separate access keys per site
  • Use read-only keys for production deployments
  • Restrict bucket policies to specific IPs/services

Content Validation

  • Scan uploads for malware before syncing to bucket
  • Use WordPress security plugins (Wordfence, Sucuri)
  • Monitor bucket for unauthorized changes

Credentials

  • Never commit credentials to Git
  • Use App Platform environment variables
  • Rotate keys regularly

Monitoring

Deployment Health

# Check if WordPress core downloaded successfully
doctl apps logs {app-id} | grep "WordPress core downloaded"
# Verify wp-content sync
doctl apps logs {app-id} | grep "wp-content synced"
# Test site
curl -I https://wordpress-{sitename}-{hash}.ondigitalocean.app

Bucket Usage

# Check bucket size
doctl spaces list-objects wordpress-{sitename}-content --recursive | wc -l
# Monitor bandwidth
doctl monitoring metrics bandwidth --resource-type spaces_bucket --resource-id wordpress-{sitename}-content

Troubleshooting

"WordPress core files not found"

  • Check init.sh ran successfully: doctl apps logs {app-id} | grep init.sh
  • Verify wget worked: Container needs internet access
  • Manual fix: SSH into container and run wget https://wordpress.org/latest.tar.gz

"wp-content not syncing from bucket"

  • Verify bucket exists: doctl spaces list
  • Check credentials: BUCKET_ACCESS_KEY, BUCKET_SECRET_KEY in env vars
  • Test rclone manually: rclone ls do-spaces:wordpress-{sitename}-content

"Database table prefix mismatch"

  • init.sh auto-detects prefix from {prefix}_options table
  • If detection fails, set manually: TABLE_PREFIX env var
  • Check logs: doctl apps logs {app-id} | grep "Table prefix"

Related Documentation


Quick Start: Convert Existing Site

# 1. Upload wp-content to bucket
doctl spaces create wordpress-mysite-content --region nyc3
rclone sync /path/to/wordpress/wp-content/ do-spaces:wordpress-mysite-content/wp-content/
# 2. Clean Git repo
cd wordpress-mysite
find . -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} +
cp -r ../wordpress-templates/{.docker,.do,.gitignore,sync-content-to-bucket.sh} .
# 3. Commit and push
git add .
git commit -m "Migrate to egg architecture"
git push origin main
# 4. Add bucket env vars to App Platform
# (Use DigitalOcean console or doctl)
# 5. Redeploy
doctl apps create-deployment {app-id}
# Done! Fresh WordPress with content from CDN