A modern, professional WordPress development environment using Docker, Composer, and WPackagist for streamlined plugin and theme management.
- Quick Start
- Common Issues & Troubleshooting
- Features
- Architecture
- Automatic Permission Management
- Plugin & Theme Management
- Development Tools
- Error Filtering & Debug Management
- Must-Use Plugins
- Backup & Restore
- WP-CLI Commands
- Popular Packages
- Environment Variables
- Advanced Troubleshooting
# Clone the repository
git clone https://github.com/vanbess/wp-docker-composer.git
cd wp-docker-composer
# Copy environment file and customize
cp .env.example .env
# Build containers (required for first-time setup)
docker compose build
# Initialize the environment (automatic setup)
./init-wordpress.sh
# Or start manually
docker compose up -d
./composer.sh install
# Access your site
open http://localhost:8111If you see an error like:
OCI runtime exec failed: exec failed: unable to start container process: exec: "/usr/local/bin/fix-permissions.sh": stat /usr/local/bin/fix-permissions.sh: no such file or directory: unknown
Solution:
# Rebuild the WordPress container
docker compose build --no-cache wordpress
# Recreate the container with the new image
docker compose down wordpress
docker compose up -d wordpress
# Test that it's working
./composer.sh installIf plugin/theme removal commands hang at the "Running WP-CLI command with timeout" step:
Solution:
# Force stop any hanging containers
docker compose --profile tools down
# Try the force-remove option instead
./composer.sh plugin force-remove plugin-nameIf you see warnings like:
The repository at "/app" does not have the correct ownership and git refuses to use it:
fatal: detected dubious ownership in repository at '/app'
This is automatically resolved in the latest version. If you still see this warning, ensure your containers are up to date:
Solution:
# Rebuild composer service
docker compose build composer
# Fix file ownership if needed
sudo chown -R $USER:$USER composer.* vendor/If this is your first time running the project or you've pulled recent updates:
Solution:
# Always run this for first-time setup or after pulling updates
docker compose build
# Then proceed with normal startup
docker compose up -d
./composer.sh installIf you can't update plugins/themes through WordPress admin:
# Fix file permissions
./composer.sh fix-permissions
# Permissions are also auto-fixed after Composer operations# Stop containers and remove volumes
docker compose down -v
# Remove vendor directory
rm -rf vendor/
# Rebuild containers from scratch
docker compose build --no-cache
# Start fresh
docker compose up -d
./composer.sh install- π³ Docker-based: Isolated, reproducible development environment
- π¦ Composer Integration: Professional dependency management with WPackagist
- π οΈ Management Script: Easy-to-use CLI for plugin/theme operations
- π§ Auto-Permissions: Automatic file permission fixes for Docker environments
- π Version Control: Pin, upgrade, downgrade plugins and themes with ease
- β‘ Fast Setup: Get running in under 5 minutes with automatic initialization
- π‘οΈ Robust Error Handling: Timeout protection and graceful fallbacks
- π Diagnostics: Built-in health checks and troubleshooting
- π Comprehensive Documentation: Detailed guides and examples
- β Works Out of the Box: No manual permission fixes needed (after initial container build)
- WordPress (6.8 + PHP 8.3 + Apache)
- MariaDB (10.11) - Fast, reliable database
- phpMyAdmin - Database management interface
- Composer - Dependency management
- WP-CLI - WordPress command-line tools
wp-docker-composer/
βββ docker-compose.yml # Docker services configuration
βββ composer.json # Composer dependencies
βββ composer.sh # Management CLI script
βββ init-wordpress.sh # One-command initialization script
βββ .env.example # Environment template
βββ wp_data/ # WordPress installation
βββ db_data/ # Database files
βββ config/ # Configuration files
β βββ php.ini # PHP configuration
β βββ mysql.cnf # MySQL configuration
βββ docs/ # Documentation
βββ scripts/ # Utility scripts
One of the biggest pain points in Docker WordPress setups is file permissions. This environment handles permissions automatically:
- File Ownership: All WordPress files owned by
www-data(the web server user) - Directory Permissions: Set to
755(readable/executable by all, writable by owner) - File Permissions: Set to
644(readable by all, writable by owner) - Uploads Directory: Fully writable for media uploads and plugin files
- wp-config.php: Properly secured but updatable
- Automatically: After every Composer operation (install, require, remove, etc.)
- On Startup: When using
./composer.sh startor./init-wordpress.sh - On Demand: Run
./composer.sh fix-permissionsanytime
# Fix all WordPress file permissions
./composer.sh fix-permissions
# Start containers and auto-fix permissions
./composer.sh start
# Ensure everything is ready (containers + permissions)
./composer.sh ready# Install a plugin from WPackagist
./composer.sh plugin install contact-form-7
./composer.sh plugin install yoast-seo
./composer.sh plugin install akismet
# Or use the full composer require command
./composer.sh require wpackagist-plugin/contact-form-7# Install a theme from WPackagist
./composer.sh theme install twentytwentyfour
./composer.sh theme install astra
# Or use the full composer require command
./composer.sh require wpackagist-theme/twentytwentyfour# Activate a plugin
./composer.sh plugin activate contact-form-7
# Deactivate a plugin
./composer.sh plugin deactivate contact-form-7
# Activate a theme
./composer.sh theme activate twentytwentyfour
# List all plugins
./composer.sh plugin list
# List all themes
./composer.sh theme list# Update all packages
./composer.sh update
# Check for outdated packages
./composer.sh outdated# Safe removal (recommended) - tries to deactivate first, has fallbacks
./composer.sh plugin remove contact-form-7
# Force removal - skips deactivation, removes immediately
./composer.sh plugin force-remove contact-form-7
# Remove a theme
./composer.sh theme remove twentytwentyfour# Run comprehensive diagnostics
./composer.sh doctor
# Check container status, validate composer.json, show installed packages, etc.Note: The safe removal method includes:
- Timeout protection: WP-CLI commands timeout after 10 seconds
- Graceful fallbacks: If deactivation fails, continues with removal
- Manual cleanup: If Composer fails, attempts manual directory removal
- Error handling: Clear feedback on each step
# Check available versions
./composer.sh plugin version wordfence
./composer.sh theme version twentytwentyfour
# Install specific version
./composer.sh plugin install wordfence 7.10.0
./composer.sh theme install twentytwentyfour 1.2.0
# Downgrade to specific version
./composer.sh plugin downgrade wordfence 7.9.0
./composer.sh theme downgrade twentytwentyfour 1.1.0
# Upgrade to latest version
./composer.sh plugin upgrade wordfence
./composer.sh theme upgrade twentytwentyfour
# Check current installed versions
./composer.sh show
# Check for outdated packages
./composer.sh outdated
# Get package information
./composer.sh info wpackagist-plugin/wordfence
# Check why a package is installed
./composer.sh why composer/installers# Search for plugins/themes
./composer.sh plugin search security
./composer.sh theme search blog
# Check plugin/theme status
./composer.sh plugin status wordfence
./composer.sh theme status twentytwentyfour
# Validate composer.json
./composer.sh validate
# Clean and reinstall all dependencies
./composer.sh cleanFor development environments, use the enhanced permission script that provides full read/write access:
# Set development-friendly permissions
./scripts/set-dev-permissions.shFeatures:
- β Full read/write permissions (775/664) for development work
- β Special handling for log files (666) and cache directories (777)
- β Proper ownership (www-data:local-user via group permissions)
- β You can edit, save, and clear debug.log and other files
vs Standard Permissions:
- Standard:
scripts/fix-permissions.sh(production-ready, more restrictive) - Development:
scripts/set-dev-permissions.sh(full access for dev work)
Deploy essential mu-plugins for enhanced debugging and error handling:
# Deploy all mu-plugins to WordPress
./scripts/deploy-mu-plugins.shThis automatically copies and configures:
Create and restore full backups of your WordPress installation, including database, files, and configuration. Perfect for recovering from breaking changes.
# Create a backup (includes database, WordPress files, and configuration)
./scripts/backup.sh create
# List all available backups
./scripts/backup.sh listWhat's Included:
- Database (all tables, triggers, routines)
- WordPress files (wp_data directory)
- Configuration files (.env, composer.json, docker-compose.yml)
- Backup metadata (creation date, git branch/commit, hostname)
# List available backups to find the right one
./scripts/backup.sh list
# Restore from a specific backup
./scripts/backup.sh restore backups/myproject_20241025_120000.tar.gz# Clean up backups older than 30 days (frees disk space)
./scripts/backup.sh cleanup 30
# Clean up backups older than 7 days
./scripts/backup.sh cleanup 7
# Show full help and examples
./scripts/backup.sh helpBest Practices:
- Create backups before making major changes (plugin/theme updates, permissions changes, etc.)
- Run cleanup periodically to manage disk space
- Keep important backups on external storage for safety
- Always verify a restore worked on a test environment first
The repository includes a sophisticated error filtering system to prevent debug log spam while maintaining visibility into real issues.
- π Duplicate Prevention: Same error messages logged only once per 24 hours
- βοΈ Configurable Filtering: Filter notices, warnings, and deprecated messages
- π― Pattern Matching: Blacklist/whitelist specific error patterns
- π§Ή Automatic Cleanup: Removes old cache entries automatically
- π Statistics: View filtering stats via WP-CLI
# Deploy the error filter system
./scripts/deploy-mu-plugins.sh
# Clear debug log to start fresh
echo "" > wp_data/wp-content/debug.log
# Set proper permissions
./scripts/set-dev-permissions.shCustomize filtering behavior in mu-plugins/error-filter-config.php:
# Cache duration (24 hours default)
define('ERROR_FILTER_CACHE_DURATION', 24 * 60 * 60);
# Enable/disable filtering by type
define('ERROR_FILTER_NOTICES', true); # Filter notices
define('ERROR_FILTER_WARNINGS', true); # Filter warnings
define('ERROR_FILTER_DEPRECATED', true); # Filter deprecated
# Custom patterns (regex)
$ERROR_FILTER_BLACKLIST = array(
'/Function _load_textdomain_just_in_time was called.*incorrectly/',
'/Translation loading for the.*domain was triggered too early/',
);# View filter statistics
docker compose exec wordpress wp error-filter-stats
# Check cache status
ls -la wp_data/wp-content/debug-cache.json
# Monitor debug log in real-time
tail -f wp_data/wp-content/debug.log
## π¦ Must-Use Plugins
Must-Use Plugins (mu-plugins) are automatically loaded WordPress plugins that cannot be deactivated through the admin interface. Perfect for essential functionality.
### Available MU-Plugins
| Plugin | Description | Auto-Deploy |
|--------|-------------|-------------|
| **Custom Error Filter** | Prevents debug log spam by filtering duplicate notices/warnings | β
|
| **Error Filter Config** | Configuration file for customizing error filtering behavior | β
|
### Repository Structure
mu-plugins/
βββ custom-error-filter.php # Main error handler
βββ error-filter-config.php # Configuration settings
βββ README.md # Detailed documentation
βββ [your-plugin].php # Add custom mu-plugins here
### Adding Custom MU-Plugins
1. **Add your plugin** to the `mu-plugins/` directory
2. **Deploy to WordPress**: `./scripts/deploy-mu-plugins.sh`
3. **Set permissions**: `./scripts/set-dev-permissions.sh`
4. **Commit to repository** for team sharing
### Key Benefits
- **π Always Active**: Cannot be accidentally deactivated
- **β‘ Early Loading**: Loaded before regular plugins and themes
- **π₯ Team Consistency**: Shared via repository across environments
- **π οΈ Developer Tools**: Perfect for debugging and development utilities
### Usage Examples
```bash
# Deploy all mu-plugins
./scripts/deploy-mu-plugins.sh
# Add custom mu-plugin
cp my-custom-plugin.php mu-plugins/
./scripts/deploy-mu-plugins.sh
# View deployed plugins
ls -la wp_data/wp-content/mu-plugins/
Note: MU-plugins are loaded alphabetically by filename. Prefix with numbers for load order control (e.g., 01-critical.php, 02-utilities.php).
- Custom Error Filter (prevents debug log spam)
- Error Filter Configuration (customizable settings)
## WP-CLI Commands
You can run any WP-CLI command using:
```bash
./composer.sh wp <command>
# Examples:
./composer.sh wp core version
./composer.sh wp user list
./composer.sh wp option get siteurl
./composer.sh wp db check
contact-form-7- Contact formsyoast-seo- SEO optimizationakismet- Anti-spamwordfence- Securityjetpack- All-in-one toolkitelementor- Page builderwoocommerce- E-commerceclassic-editor- Classic WordPress editorduplicate-post- Duplicate posts/pageswp-super-cache- Caching
twentytwentyfour- Latest default themetwentytwentythree- Previous default themeastra- Lightweight themegeneratepress- Fast themeoceanwp- Multi-purpose theme
Edit .env file to customize:
- Database credentials
- WordPress debug settings
- Port numbers
- Admin user details
# WordPress logs
docker compose logs wordpress
# Database logs
docker compose logs db
# All logs
docker compose logs# WordPress container
docker compose exec wordpress bash
# Database container
docker compose exec db bashwp-docker-composer/
βββ docker-compose.yml # Docker services configuration
βββ composer.json # Composer dependencies
βββ composer.sh # Helper script for Composer operations
βββ .env # Environment variables
βββ wp_data/ # WordPress files
βββ db_data/ # Database files
βββ config/ # Configuration files
βββ vendor/ # Composer packages (auto-generated)
Need help? Check the troubleshooting sections above or open an issue on GitHub.