Ansible playbooks for automated database backup, synchronization, and management across Trellis environments.
- Overview
- Prerequisites
- Installation
- Usage
- Configuration
- File Naming Convention
- Compression Methods
- URL Search and Replace
- Security Considerations
- Error Handling
- Automation
- Integration with CI/CD
- Troubleshooting
- Best Practices
- Support
This directory contains Ansible playbooks that integrate with your existing Trellis setup to provide automated database and files operations:
- database-backup.yml - Create database backups from any environment
- database-pull.yml - Pull database from remote environment to development
- database-push.yml - Push database from development to remote environment
- files-backup.yml - Create WordPress uploads backups from any environment
- files-pull.yml - Pull WordPress uploads from remote environment to development
- files-push.yml - Push WordPress uploads from development to remote environment
- Working Trellis installation with configured environments
- Ansible installed and configured
- SSH access to all target environments
- WP-CLI available on all servers (included with Trellis)
-
Copy the playbook files to your Trellis directory:
# From your trellis-tools directory cp -r backup/trellis/* /path/to/your/trellis/
-
Or reference them directly from this repository:
# Run from your Trellis directory ansible-playbook /path/to/trellis-tools/backup/trellis/database-backup.yml -e site=example.com -e env=production
All playbooks require two variables:
site- The site name as defined in your Trellis configurationenv- The environment (development, staging, production)
Creates a compressed database backup and stores it in the database_backup directory.
# Backup production database
ansible-playbook database-backup.yml -e site=example.com -e env=production
# Backup staging database
ansible-playbook database-backup.yml -e site=example.com -e env=staging
# Backup development database
ansible-playbook database-backup.yml -e site=example.com -e env=developmentWhat it does:
- Creates timestamped compressed SQL backup
- For remote environments: downloads backup to development server
- Stores backup in
web/app/database_backup/directory - Automatically cleans up temporary files
Pulls database from a remote environment to development with automatic URL replacement.
# Pull production database to development
ansible-playbook database-pull.yml -e site=example.com -e env=production
# Pull staging database to development
ansible-playbook database-pull.yml -e site=example.com -e env=stagingWhat it does:
- Creates backup of current development database
- Exports database from remote environment
- Downloads and imports to development
- Performs URL search-replace for local development URLs
- Cleans up temporary files
Note: Cannot pull from development to development (will abort with error).
For interactive development work, you can use a direct shell script approach that runs inside the Trellis VM. This method is simpler and faster than the Ansible playbook, using SSH pipes to stream the database directly without intermediate files.
Standard site example:
cd /path/to/trellis && trellis vm shell --workdir /srv/www/example.com/current -- bash -c "
echo '=== Backing up current development database ==='
wp db export /tmp/dev_backup_\$(date +%Y%m%d_%H%M%S).sql.gz --path=web/wp
echo ''
echo '=== Pulling production database dump ==='
ssh -o StrictHostKeyChecking=no web@example.com 'cd /srv/www/example.com/current && wp db export - --path=web/wp' | gzip > /tmp/prod_import.sql.gz
echo ''
echo '=== Importing production database to development ==='
gunzip < /tmp/prod_import.sql.gz | wp db import - --path=web/wp
echo ''
echo '=== Running search-replace for URLs ==='
wp search-replace 'https://example.com' 'https://example.test' --all-tables --precise --path=web/wp
echo ''
echo '=== Flushing cache ==='
wp cache flush --path=web/wp
echo ''
echo '=== Database pull complete! ==='
"Multisite example:
cd /path/to/trellis && trellis vm shell --workdir /srv/www/example.com/current -- bash -c "
echo '=== Backing up current development database ==='
wp db export /tmp/dev_backup_\$(date +%Y%m%d_%H%M%S).sql.gz --path=web/wp
echo ''
echo '=== Pulling production database dump ==='
ssh -o StrictHostKeyChecking=no web@example.com 'cd /srv/www/example.com/current && wp db export - --path=web/wp' | gzip > /tmp/prod_import.sql.gz
echo ''
echo '=== Importing production database to development ==='
gunzip < /tmp/prod_import.sql.gz | wp db import - --path=web/wp
echo ''
echo '=== Running search-replace for URLs (multisite) ==='
wp search-replace 'https://example.com' 'http://example.test' --all-tables --precise --path=web/wp --url=https://example.com
echo ''
echo '=== Fixing multisite blog domains ==='
wp db query \"UPDATE wp_blogs SET domain = REPLACE(domain, 'example.com', 'example.test');\" --path=web/wp
echo ''
echo '=== Flushing cache ==='
wp cache flush --path=web/wp
echo ''
echo '=== Database pull complete! ==='
"Advantages of this approach:
- Single command execution with full visibility
- Streams database via SSH pipe (no intermediate transfer files)
- Includes cache flushing step
- Progress messages show exactly what's happening
- Faster than Ansible playbook for quick manual operations
When to use:
- Manual, interactive development work
- Quick database syncs during active development
- When you want full visibility into each step
- Testing or troubleshooting database operations
When to use Ansible playbooks instead:
- Automated/scheduled operations
- CI/CD pipelines
- When you need consistent, repeatable automation
- Managing multiple sites or environments
Multisite notes:
- Include
--url=https://example.comparameter inwp search-replace - This ensures WordPress knows which site context to use for the search-replace operation
- Critical: Must update
wp_blogstable domains separately with direct SQL query - The
wp_blogstable stores the domain for each site in the network - Use
wp db query "UPDATE wp_blogs SET domain = REPLACE(domain, 'production.com', 'local.test');"to update all blog domains - Both
wp search-replace(for content/options) andwp_blogsupdate (for network domains) are required for proper multisite operation
Pushes database from development to a remote environment with URL replacement.
# Push development database to staging
ansible-playbook database-push.yml -e site=example.com -e env=staging
# Push development database to production (use with caution!)
ansible-playbook database-push.yml -e site=example.com -e env=productionWhat it does:
- Creates backup of target environment database
- Exports development database
- Uploads and imports to target environment
- Performs URL search-replace for target environment URLs
- Cleans up temporary files
Note: Cannot push from development to development (will abort with error).
Creates a compressed backup of WordPress uploads directory and stores it in the files_backup directory.
# Backup production uploads
ansible-playbook files-backup.yml -e site=example.com -e env=production
# Backup staging uploads
ansible-playbook files-backup.yml -e site=example.com -e env=staging
# Backup development uploads
ansible-playbook files-backup.yml -e site=example.com -e env=developmentWhat it does:
- Creates timestamped compressed uploads backup
- For remote environments: downloads backup to development server
- Stores backup in
web/app/files_backup/directory - Automatically cleans up temporary files
Pulls WordPress uploads from a remote environment to development.
# Pull production uploads to development
ansible-playbook files-pull.yml -e site=example.com -e env=production
# Pull staging uploads to development
ansible-playbook files-pull.yml -e site=example.com -e env=stagingWhat it does:
- Creates backup of current development uploads
- Creates archive of uploads from remote environment
- Downloads and extracts to development
- Cleans up temporary files
Note: Cannot pull from development to development (will abort with error).
Pushes WordPress uploads from development to a remote environment.
# Push development uploads to staging
ansible-playbook files-push.yml -e site=example.com -e env=staging
# Push development uploads to production (use with caution!)
ansible-playbook files-push.yml -e site=example.com -e env=productionWhat it does:
- Creates backup of target environment uploads
- Creates archive of development uploads
- Uploads and extracts to target environment
- Cleans up temporary files
Note: Cannot push from development to development (will abort with error).
Ensure your site is properly configured in your Trellis group_vars files:
# group_vars/development/wordpress_sites.yml
wordpress_sites:
example.com:
site_hosts:
- canonical: example.test
local_path: ../site # Path to your Bedrock installation
# ... other configuration# group_vars/production/wordpress_sites.yml
wordpress_sites:
example.com:
site_hosts:
- canonical: example.com
# ... other configurationBackups are stored in the following structure:
site/current/web/app/
├── database_backup/
│ ├── example_com_production_2023_12_01_14_30_45.sql.gz
│ ├── example_com_staging_2023_12_01_15_15_22.sql.gz
│ └── example_com_development_2023_12_01_16_45_33.sql.gz
└── files_backup/
├── example_com_production_uploads_2023_12_01_14_30_45.tar.gz
├── example_com_staging_uploads_2023_12_01_15_15_22.tar.gz
└── example_com_development_uploads_2023_12_01_16_45_33.tar.gz
Backup files use the following naming patterns:
{site_name}_{environment}_{date}_{time}.sql.gz
{site_name}_{environment}_uploads_{date}_{time}.tar.gz
Where:
site_name- Site name with dots replaced by underscoresenvironment- development, staging, or productiondate- YYYY_MM_DD formattime- HH_MM_SS format
Examples:
example_com_production_2023_12_01_14_30_45.sql.gzexample_com_production_uploads_2023_12_01_14_30_45.tar.gzmysite_co_uk_staging_2023_12_01_15_15_22.sql.gzmysite_co_uk_staging_uploads_2023_12_01_15_15_22.tar.gz
Different compression methods are used based on backup type for optimal performance:
- Database backups:
.sql.gz- Usesgzipcompression for single SQL files. Faster with direct piping (wp db export - | gzip) without temporary files. - Files backups:
.tar.gz- Usestar+gzipfor directory archives. Required for preserving directory structure and handling multiple files efficiently.
The playbooks automatically handle URL replacement when moving databases between environments:
- From Production:
https://example.com→http://example.test - From Staging:
https://staging.example.com→http://example.test
- To Production:
http://example.test→https://example.com - To Staging:
http://example.test→https://staging.example.com
URLs are determined from your Trellis site configuration using the canonical hostname.
-
Backup Storage: Backups contain sensitive data. Ensure proper file permissions on backup directories.
-
Production Pushes: Be extremely cautious when pushing to production. Always test on staging first.
-
Database Credentials: All database operations use WP-CLI, which reads credentials from WordPress configuration.
-
SSH Access: Ensure SSH keys are properly configured for all target environments.
"Site folder doesn't exist"
- Verify the site name matches your Trellis configuration
- Check that the site has been deployed to the target environment
"Cannot pull/push from development to development"
- These operations are blocked by design
- Use
database-backup.ymlfor development backups
"WP-CLI command failed"
- Verify WordPress is properly installed
- Check database connectivity
- Ensure WP-CLI is available on the server
Permission denied errors
- Verify SSH access to target servers
- Check file permissions in WordPress directories
Add to your server's crontab for automated backups:
# Daily production backup at 2 AM
0 2 * * * cd /path/to/trellis && ansible-playbook database-backup.yml -e site=example.com -e env=production
# Weekly staging backup on Sundays at 3 AM
0 3 * * 0 cd /path/to/trellis && ansible-playbook database-backup.yml -e site=example.com -e env=stagingCreate a cleanup script to manage old backups:
#!/bin/bash
# cleanup-backups.sh
SITE_PATH="/srv/www/example.com/current/web/app"
RETENTION_DAYS=30
# Clean up old database backups
find "$SITE_PATH/database_backup" -name "*.sql.gz" -mtime +$RETENTION_DAYS -delete
# Clean up old files backups
find "$SITE_PATH/files_backup" -name "*.tar.gz" -mtime +$RETENTION_DAYS -deletename: Database Sync
on:
workflow_dispatch:
inputs:
environment:
description: 'Source environment'
required: true
default: 'production'
type: choice
options:
- production
- staging
jobs:
sync-database:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup SSH
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Pull database
run: |
cd trellis
ansible-playbook database-pull.yml -e site=example.com -e env=${{ github.event.inputs.environment }}Run playbooks with verbose output for debugging:
ansible-playbook database-backup.yml -e site=example.com -e env=production -vvvVerify backup integrity:
# Test database backup file
gunzip -t /path/to/backup.sql.gz
# Check database backup contents
gunzip -c /path/to/backup.sql.gz | head -20
# Test files backup file
tar -tzf /path/to/uploads.tar.gz
# Check files backup contents
tar -xzOf /path/to/uploads.tar.gz | head -20Monitor backup operations:
# Check Ansible logs
tail -f /var/log/ansible.log
# Check WordPress logs
tail -f /srv/www/example.com/shared/logs/error.log- Test First: Always test pull/push operations on staging before production
- Backup Before Push: The playbooks automatically create backups, but verify they complete successfully
- Monitor Disk Space: Regular backups can consume significant disk space
- Document Procedures: Keep a record of when and why database operations are performed
- Verify URLs: Check that URL replacements work correctly after pull/push operations
- Regular Cleanup: Implement automated cleanup of old backup files
For issues specific to these playbooks:
- Check the Ansible output for specific error messages
- Verify your Trellis configuration is correct
- Test SSH connectivity to target servers
- Ensure WP-CLI is working on all environments
For general Trellis support, refer to the official Trellis documentation.