In web development, ensuring reliable deployment and management of web applications is crucial. This article provides a detailed guide on using Ansible to set up a Dockerized environment for running a WordPress site, backed by NGINX as a web server and MySQL as the database. By automating this setup, we can enhance security, repeatability, and scalability.
Why Choose Docker, Ansible, NGINX, and MySQL?
-
Docker simplifies deployment by containerizing applications, ensuring that they work uniformly across different environments.
-
Ansible automates software provisioning and configuration management, reducing the potential for human error.
-
NGINX serves as a high-performance web server and reverse proxy, offering better performance and resource utilization than traditional servers.
-
MySQL is a proven and scalable database management system, ideal for managing data-intensive applications like WordPress.
Step 1: Prerequisites
To follow this guide, you’ll need:
-
A Linux system (preferably Ubuntu)
-
Docker and Docker Compose installed
-
Ansible installed on your local machine
Step 2: Prepare the Ansible Playbook
Create a directory for your Ansible playbook and related files:
mkdir wordpress-deploymentcd wordpress-deploymentStep 3: Define the Docker Compose File
Within the wordpress-deployment directory, create a docker-compose.yml file. This file defines the services, networks, and volumes that compose your WordPress environment.
services: db: image: mysql:5.7 volumes: - db_data:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: password123 MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD: wordpress
wordpress: depends_on: - db image: wordpress:latest ports: - "8000:80" restart: always environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD: wordpress volumes: - wordpress_data:/var/www/html
nginx: image: nginx:latest ports: - "80:80" volumes: - ./nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - wordpress
volumes: db_data: wordpress_data:Step 4: NGINX Configuration
Create an NGINX configuration file default.conf in the nginx directory. Configure NGINX to act as a reverse proxy to the WordPress container.
server { listen 80; server_name localhost;
location / { proxy_pass http://wordpress:80; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; }}make sure to change localhost to your domain
Step 5: Ansible Playbook to Deploy Everything
Now, create an Ansible playbook named deploy.yml:
- hosts: all become: true tasks: - name: Ensure Docker is installed apt: name: docker-ce state: latest
- name: Clone project containing Docker Compose file git: repo: 'http://github.com/youraccount/wordpress-docker-compose.git' dest: /home/user/wordpress clone: yes update: yes
- name: Run Docker Compose docker_compose: project_src: /home/user/wordpressWhy This Setup is Secure and Efficient?
-
Isolation: Docker provides an isolated environment for your applications, minimizing conflicts and security risks.
-
Version Control: With Docker and Ansible, specific versions of services can be defined, ensuring consistency across environments.
-
Automation: Ansible automates the entire process, reducing the likelihood of errors and misconfigurations.
-
Scalability: Scaling services is as simple as updating the Docker Compose file and re-running the playbook.
This setup not only ensures a solid deployment strategy for WordPress sites but also simplifies management and scaling, making it an ideal choice for modern web applications.
Related Reading
- Automating Docker via Ansible
- Docker Strategies for Load Balancing and Failover
- Access Docker socket via TCP
- Docker Networking: Connecting to the Host from a Container
- Docker Networking Essential Guide for All Skill Levels
What Actually Breaks This (And How to Fix It)
The playbook above works, until it doesn’t. Here are the landmines you’ll hit on a real deployment, usually at 11 PM before a launch.
The docker_compose Module Is Gone
If you’re on Ansible 6+ with the community.docker collection 3.x, docker_compose no longer exists. It was replaced by community.docker.docker_compose_v2. The old module silently does nothing on newer installs, which is a fantastic way to spend an hour staring at an unchanged server wondering why nothing deployed.
Fix your task:
- name: Run Docker Compose community.docker.docker_compose_v2: project_src: /home/user/wordpress state: presentInstall the collection first if you haven’t:
ansible-galaxy collection install community.dockerMySQL 5.7 Is EOL, Use 8.0
mysql:5.7 hit end-of-life in October 2023. It still pulls and runs, but you’re not getting security patches, and some hosting environments will refuse it outright. Swap it:
image: mysql:8.0One catch: MySQL 8 changed the default authentication plugin. WordPress’s mysqli driver expects mysql_native_password. If you get “Authentication plugin ‘caching_sha2_password’ is not supported”, add this to your db service:
command: --default-authentication-plugin=mysql_native_passwordHardcoded Passwords Will Haunt You
password123 in version-controlled YAML is a support ticket waiting to happen. Use Ansible Vault instead:
# Create an encrypted vars fileansible-vault create group_vars/all/vault.ymlThen reference it in your Compose template:
vault_mysql_root_password: "your-actual-secret"vault_mysql_password: "another-actual-secret"And in your playbook, use {{ vault_mysql_root_password }} instead of the plaintext string. Your future self, the one who accidentally pushes to a public repo, will thank you.
The WordPress Container Starts Before MySQL Is Ready
depends_on only waits for the container to start, not for MySQL to actually accept connections. WordPress will try to connect immediately, fail, and you’ll see a “Error establishing a database connection” page on first load. Restart it and it’s usually fine, but that’s not automation, that’s hoping.
Add a healthcheck to your db service:
healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 10s timeout: 5s retries: 5Then change your WordPress depends_on to:
depends_on: db: condition: service_healthyNow Compose actually waits for MySQL to be ready before WordPress starts trying to connect. It’s a small addition that saves a lot of “is it up yet?” refreshing.