How to deploy WordPress with Docker on Linux

How to Deploy WordPress with Docker on Linux Docker has revolutionized the way we deploy and manage applications, and WordPress is no exception. This comprehensive guide will walk you through the entire process of deploying WordPress using Docker on Linux systems, from basic setup to advanced configuration and troubleshooting. Table of Contents 1. [Introduction](#introduction) 2. [Prerequisites](#prerequisites) 3. [Understanding Docker and WordPress](#understanding-docker-and-wordpress) 4. [Installing Docker on Linux](#installing-docker-on-linux) 5. [Setting Up WordPress with Docker Compose](#setting-up-wordpress-with-docker-compose) 6. [Advanced Configuration](#advanced-configuration) 7. [Security Best Practices](#security-best-practices) 8. [Performance Optimization](#performance-optimization) 9. [Backup and Maintenance](#backup-and-maintenance) 10. [Troubleshooting Common Issues](#troubleshooting-common-issues) 11. [Best Practices and Tips](#best-practices-and-tips) 12. [Conclusion](#conclusion) Introduction Deploying WordPress with Docker on Linux offers numerous advantages including consistency across environments, easy scalability, simplified dependency management, and enhanced security through containerization. Whether you're a developer looking to streamline your workflow or a system administrator managing multiple WordPress installations, this guide provides everything you need to successfully deploy and maintain WordPress using Docker containers. By the end of this tutorial, you'll have a fully functional WordPress installation running in Docker containers, complete with a MySQL database, proper networking, and security configurations. You'll also understand how to customize, scale, and troubleshoot your deployment effectively. Prerequisites Before beginning this tutorial, ensure you have the following: System Requirements - A Linux server or desktop (Ubuntu 18.04+, CentOS 7+, Debian 9+, or similar) - Minimum 2GB RAM (4GB recommended for production) - At least 10GB free disk space - Root or sudo access to the system - Stable internet connection for downloading Docker images Technical Knowledge - Basic understanding of Linux command line - Familiarity with text editors (nano, vim, or similar) - Basic networking concepts - Understanding of web servers and databases (helpful but not required) Software Prerequisites - Updated Linux system with package manager access - SSH access (if working on a remote server) - Domain name or IP address for external access (optional) Understanding Docker and WordPress What is Docker? Docker is a containerization platform that packages applications and their dependencies into lightweight, portable containers. These containers can run consistently across different environments, making deployment and scaling much simpler. Benefits of Using Docker for WordPress 1. Isolation: Each component runs in its own container 2. Consistency: Same environment across development, testing, and production 3. Scalability: Easy to scale individual components 4. Version Control: Easy rollbacks and updates 5. Resource Efficiency: Containers share the host OS kernel 6. Security: Enhanced isolation between applications Docker Components for WordPress A typical WordPress Docker deployment includes: - WordPress Container: Runs the WordPress application - MySQL/MariaDB Container: Handles database operations - Nginx/Apache Container: Web server (optional, as WordPress container includes Apache) - Volume Storage: Persistent data storage - Network: Container communication Installing Docker on Linux Installing Docker on Ubuntu/Debian First, update your package index and install required packages: ```bash sudo apt update sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release ``` Add Docker's official GPG key: ```bash curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg ``` Add the Docker repository: ```bash echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null ``` Install Docker Engine: ```bash sudo apt update sudo apt install docker-ce docker-ce-cli containerd.io ``` Installing Docker on CentOS/RHEL Install required packages: ```bash sudo yum install -y yum-utils sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo ``` Install Docker: ```bash sudo yum install docker-ce docker-ce-cli containerd.io ``` Post-Installation Steps Start and enable Docker service: ```bash sudo systemctl start docker sudo systemctl enable docker ``` Add your user to the docker group (optional, for running Docker without sudo): ```bash sudo usermod -aG docker $USER ``` Note: Log out and back in for group changes to take effect. Verify Docker installation: ```bash docker --version docker run hello-world ``` Installing Docker Compose Docker Compose simplifies multi-container deployments. Install it using: ```bash sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose ``` Verify installation: ```bash docker-compose --version ``` Setting Up WordPress with Docker Compose Creating the Project Directory Create a dedicated directory for your WordPress project: ```bash mkdir ~/wordpress-docker cd ~/wordpress-docker ``` Basic Docker Compose Configuration Create a `docker-compose.yml` file: ```yaml version: '3.8' services: wordpress: image: wordpress:latest container_name: wordpress_app restart: unless-stopped ports: - "80:80" - "443:443" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: secure_password_here WORDPRESS_DB_NAME: wordpress volumes: - wordpress_data:/var/www/html depends_on: - db networks: - wordpress_network db: image: mysql:8.0 container_name: wordpress_db restart: unless-stopped environment: MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: secure_password_here MYSQL_ROOT_PASSWORD: root_password_here volumes: - db_data:/var/lib/mysql networks: - wordpress_network volumes: wordpress_data: db_data: networks: wordpress_network: driver: bridge ``` Environment Variables Security For better security, create a `.env` file to store sensitive information: ```bash .env file MYSQL_ROOT_PASSWORD=your_strong_root_password MYSQL_DATABASE=wordpress MYSQL_USER=wordpress MYSQL_PASSWORD=your_strong_wordpress_password WORDPRESS_DB_HOST=db:3306 ``` Update your `docker-compose.yml` to use environment variables: ```yaml version: '3.8' services: wordpress: image: wordpress:latest container_name: wordpress_app restart: unless-stopped ports: - "80:80" - "443:443" environment: WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST} WORDPRESS_DB_USER: ${MYSQL_USER} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} WORDPRESS_DB_NAME: ${MYSQL_DATABASE} volumes: - wordpress_data:/var/www/html depends_on: - db networks: - wordpress_network db: image: mysql:8.0 container_name: wordpress_db restart: unless-stopped environment: MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} volumes: - db_data:/var/lib/mysql networks: - wordpress_network volumes: wordpress_data: db_data: networks: wordpress_network: driver: bridge ``` Launching Your WordPress Site Deploy the containers: ```bash docker-compose up -d ``` Check container status: ```bash docker-compose ps ``` View logs if needed: ```bash docker-compose logs wordpress docker-compose logs db ``` Accessing WordPress Open your web browser and navigate to: - `http://localhost` (if running locally) - `http://your-server-ip` (if running on a remote server) Complete the WordPress installation wizard by providing: - Site title - Admin username and password - Admin email address Advanced Configuration Adding SSL/TLS with Let's Encrypt Create an enhanced setup with Nginx reverse proxy and SSL: ```yaml version: '3.8' services: nginx: image: nginx:alpine container_name: wordpress_nginx restart: unless-stopped ports: - "80:80" - "443:443" volumes: - ./nginx/conf.d:/etc/nginx/conf.d - ./nginx/ssl:/etc/nginx/ssl - wordpress_data:/var/www/html depends_on: - wordpress networks: - wordpress_network wordpress: image: wordpress:latest container_name: wordpress_app restart: unless-stopped expose: - "80" environment: WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST} WORDPRESS_DB_USER: ${MYSQL_USER} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} WORDPRESS_DB_NAME: ${MYSQL_DATABASE} volumes: - wordpress_data:/var/www/html depends_on: - db networks: - wordpress_network db: image: mysql:8.0 container_name: wordpress_db restart: unless-stopped environment: MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} volumes: - db_data:/var/lib/mysql networks: - wordpress_network certbot: image: certbot/certbot container_name: wordpress_certbot volumes: - ./nginx/ssl:/etc/letsencrypt - wordpress_data:/var/www/html command: certonly --webroot --webroot-path=/var/www/html --email your-email@domain.com --agree-tos --no-eff-email -d your-domain.com volumes: wordpress_data: db_data: networks: wordpress_network: driver: bridge ``` Custom PHP Configuration Create a custom PHP configuration file: ```bash mkdir -p ./php/conf.d ``` Create `./php/conf.d/custom.ini`: ```ini file_uploads = On memory_limit = 256M upload_max_filesize = 64M post_max_size = 64M max_execution_time = 600 ``` Update your WordPress service in `docker-compose.yml`: ```yaml wordpress: image: wordpress:latest container_name: wordpress_app restart: unless-stopped ports: - "80:80" environment: WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST} WORDPRESS_DB_USER: ${MYSQL_USER} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} WORDPRESS_DB_NAME: ${MYSQL_DATABASE} volumes: - wordpress_data:/var/www/html - ./php/conf.d/custom.ini:/usr/local/etc/php/conf.d/custom.ini depends_on: - db networks: - wordpress_network ``` Database Optimization Optimize MySQL for WordPress by creating `./mysql/conf.d/mysql.cnf`: ```ini [mysqld] innodb_buffer_pool_size = 256M innodb_log_file_size = 64M innodb_file_per_table = 1 innodb_flush_method = O_DIRECT key_buffer_size = 32M max_allowed_packet = 64M table_open_cache = 256 sort_buffer_size = 1M net_buffer_length = 32K read_buffer_size = 256K read_rnd_buffer_size = 512K myisam_sort_buffer_size = 8M ``` Update the database service: ```yaml db: image: mysql:8.0 container_name: wordpress_db restart: unless-stopped environment: MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} volumes: - db_data:/var/lib/mysql - ./mysql/conf.d:/etc/mysql/conf.d networks: - wordpress_network ``` Security Best Practices Container Security 1. Use specific image tags instead of `latest`: ```yaml services: wordpress: image: wordpress:6.3-apache db: image: mysql:8.0.34 ``` 2. Run containers as non-root users when possible: ```yaml wordpress: image: wordpress:6.3-apache user: "1000:1000" ``` 3. Limit container resources: ```yaml wordpress: image: wordpress:6.3-apache deploy: resources: limits: cpus: '0.5' memory: 512M reservations: cpus: '0.25' memory: 256M ``` Network Security Create isolated networks and restrict external access: ```yaml networks: wordpress_network: driver: bridge internal: false db_network: driver: bridge internal: true ``` File Permissions Set proper file permissions for WordPress: ```bash After containers are running docker exec wordpress_app chown -R www-data:www-data /var/www/html docker exec wordpress_app find /var/www/html -type d -exec chmod 755 {} \; docker exec wordpress_app find /var/www/html -type f -exec chmod 644 {} \; ``` WordPress Security Headers Add security headers via Nginx configuration: ```nginx nginx/conf.d/default.conf server { listen 80; server_name your-domain.com; # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "no-referrer-when-downgrade" always; add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; location / { proxy_pass http://wordpress:80; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` Performance Optimization Caching with Redis Add Redis caching to your setup: ```yaml redis: image: redis:7-alpine container_name: wordpress_redis restart: unless-stopped volumes: - redis_data:/data networks: - wordpress_network volumes: wordpress_data: db_data: redis_data: ``` Content Delivery Network (CDN) Configure WordPress to use a CDN by adding environment variables: ```yaml wordpress: environment: WORDPRESS_DB_HOST: ${WORDPRESS_DB_HOST} WORDPRESS_DB_USER: ${MYSQL_USER} WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD} WORDPRESS_DB_NAME: ${MYSQL_DATABASE} WORDPRESS_CONFIG_EXTRA: | define('WP_CACHE', true); define('CDN_URL', 'https://your-cdn-domain.com'); ``` Database Connection Pooling For high-traffic sites, consider using ProxySQL for connection pooling: ```yaml proxysql: image: proxysql/proxysql:latest container_name: wordpress_proxysql restart: unless-stopped volumes: - ./proxysql/proxysql.cnf:/etc/proxysql.cnf ports: - "6032:6032" - "6033:6033" networks: - wordpress_network ``` Backup and Maintenance Automated Database Backups Create a backup script `backup.sh`: ```bash #!/bin/bash Configuration BACKUP_DIR="/backups" DATE=$(date +%Y%m%d_%H%M%S) CONTAINER_NAME="wordpress_db" DB_NAME="wordpress" DB_USER="wordpress" DB_PASSWORD="your_password" Create backup directory mkdir -p $BACKUP_DIR Create database backup docker exec $CONTAINER_NAME mysqldump -u $DB_USER -p$DB_PASSWORD $DB_NAME > $BACKUP_DIR/wordpress_db_$DATE.sql Create WordPress files backup docker run --rm -v wordpress_data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/wordpress_files_$DATE.tar.gz -C /data . Remove backups older than 7 days find $BACKUP_DIR -name "*.sql" -mtime +7 -delete find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete echo "Backup completed: $DATE" ``` Make it executable and add to crontab: ```bash chmod +x backup.sh crontab -e Add this line for daily backups at 2 AM 0 2 * /path/to/backup.sh ``` Container Health Checks Add health checks to your services: ```yaml wordpress: image: wordpress:latest healthcheck: test: ["CMD", "curl", "-f", "http://localhost"] interval: 30s timeout: 10s retries: 3 start_period: 40s db: image: mysql:8.0 healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 30s timeout: 10s retries: 3 start_period: 40s ``` Log Management Configure log rotation and management: ```yaml wordpress: image: wordpress:latest logging: driver: "json-file" options: max-size: "10m" max-file: "3" ``` Troubleshooting Common Issues Container Startup Issues Problem: Containers fail to start Solutions: 1. Check Docker service status: ```bash sudo systemctl status docker ``` 2. Verify Docker Compose file syntax: ```bash docker-compose config ``` 3. Check available disk space: ```bash df -h ``` 4. Review container logs: ```bash docker-compose logs [service_name] ``` Database Connection Problems Problem: WordPress cannot connect to database Solutions: 1. Verify database container is running: ```bash docker-compose ps db ``` 2. Check database logs: ```bash docker-compose logs db ``` 3. Test database connectivity: ```bash docker exec wordpress_app ping db ``` 4. Verify environment variables: ```bash docker exec wordpress_app env | grep WORDPRESS_DB ``` Permission Issues Problem: File upload or plugin installation failures Solutions: 1. Fix WordPress file permissions: ```bash docker exec wordpress_app chown -R www-data:www-data /var/www/html ``` 2. Check volume mounts: ```bash docker inspect wordpress_app | grep -A 10 "Mounts" ``` Memory and Performance Issues Problem: Slow performance or out-of-memory errors Solutions: 1. Monitor resource usage: ```bash docker stats ``` 2. Increase PHP memory limit: ```ini In custom.ini memory_limit = 512M ``` 3. Optimize database queries: ```bash docker exec wordpress_db mysql -u root -p -e "SHOW PROCESSLIST;" ``` SSL Certificate Issues Problem: SSL certificate problems with Let's Encrypt Solutions: 1. Check certificate status: ```bash docker exec wordpress_certbot certbot certificates ``` 2. Renew certificates: ```bash docker exec wordpress_certbot certbot renew ``` 3. Verify domain DNS settings: ```bash nslookup your-domain.com ``` Port Conflicts Problem: Port already in use errors Solutions: 1. Check what's using the port: ```bash sudo netstat -tulpn | grep :80 ``` 2. Stop conflicting services: ```bash sudo systemctl stop apache2 # or nginx ``` 3. Use different ports in docker-compose.yml: ```yaml ports: - "8080:80" ``` Best Practices and Tips Development vs Production Development Environment: - Use `latest` tags for easy updates - Enable debug mode - Mount source code as volumes for live editing - Use simpler networking Production Environment: - Use specific version tags - Implement proper logging and monitoring - Use secrets management - Enable SSL/TLS - Implement backup strategies - Use resource limits Resource Management 1. Set appropriate resource limits: ```yaml deploy: resources: limits: cpus: '1.0' memory: 1G reservations: cpus: '0.5' memory: 512M ``` 2. Monitor resource usage regularly: ```bash docker stats --no-stream ``` 3. Clean up unused resources: ```bash docker system prune -a docker volume prune ``` Version Control 1. Track your Docker configuration: ```bash git init echo ".env" >> .gitignore git add docker-compose.yml git commit -m "Initial WordPress Docker setup" ``` 2. Use tagged releases: ```yaml services: wordpress: image: wordpress:6.3.1-apache ``` Monitoring and Logging 1. Implement centralized logging: ```yaml logging: driver: syslog options: syslog-address: "tcp://your-log-server:514" ``` 2. Set up monitoring with Prometheus: ```yaml prometheus: image: prom/prometheus ports: - "9090:9090" volumes: - ./prometheus:/etc/prometheus ``` Scaling Considerations 1. Horizontal scaling with load balancer: ```yaml wordpress1: image: wordpress:latest # configuration wordpress2: image: wordpress:latest # configuration loadbalancer: image: nginx:alpine # load balancer configuration ``` 2. Database clustering for high availability: ```yaml db-master: image: mysql:8.0 # master configuration db-slave: image: mysql:8.0 # slave configuration ``` Security Hardening 1. Regular security updates: ```bash Update base images regularly docker-compose pull docker-compose up -d ``` 2. Scan for vulnerabilities: ```bash docker scan wordpress:latest ``` 3. Use Docker secrets for sensitive data: ```yaml secrets: db_password: file: ./secrets/db_password.txt services: wordpress: secrets: - db_password ``` Conclusion Deploying WordPress with Docker on Linux provides a robust, scalable, and maintainable solution for hosting WordPress sites. This comprehensive guide has covered everything from basic setup to advanced configuration, security hardening, and troubleshooting. Key Takeaways 1. Docker simplifies WordPress deployment by providing consistent environments and easy dependency management 2. Docker Compose orchestrates multi-container applications effectively, making complex setups manageable 3. Security should be implemented at multiple layers, including container security, network isolation, and application-level protections 4. Regular maintenance and monitoring are essential for production deployments 5. Backup strategies should be implemented from day one to prevent data loss Next Steps After successfully deploying WordPress with Docker, consider these advanced topics: 1. Implement CI/CD pipelines for automated deployments 2. Set up monitoring and alerting with tools like Prometheus and Grafana 3. Explore container orchestration with Kubernetes for large-scale deployments 4. Implement advanced caching strategies with Redis and CDN integration 5. Set up development workflows with Docker for your team Additional Resources - [Official WordPress Docker Documentation](https://hub.docker.com/_/wordpress) - [Docker Compose Documentation](https://docs.docker.com/compose/) - [WordPress Security Best Practices](https://wordpress.org/support/article/hardening-wordpress/) - [MySQL Docker Documentation](https://hub.docker.com/_/mysql) Remember to keep your Docker images, WordPress installation, and plugins updated regularly to maintain security and performance. With proper setup and maintenance, your Dockerized WordPress deployment will provide reliable service while remaining easy to manage and scale. This guide provides a solid foundation for WordPress deployment with Docker, but remember that each use case may require specific customizations. Always test configurations in a development environment before applying them to production systems.