Deploying a WordPress Website with Ansible
Level 1 – Single VM with Caddy Reverse Proxy
In this article, we will deploy a simple and automated WordPress infrastructure using Ansible. The goal is to demonstrate how to deploy a website in a reproducible way, similar to how a DevOps engineer would manage infrastructure in production. For this Level 1 architecture, we intentionally keep things simple:
Everything is fully deployed using Ansible automation. This approach allows you to:
Each directory has a specific responsibility within the automation workflow.
Understanding this structure is the first step to learning how to organize real-world Ansible projects.
Project Architecture
The project is organized as an infrastructure repository.
devops-wp-caddy/
│
├── ansible/
│ ├── inventory/
│ │ └── production.ini
│ │
│ ├── playbooks/
│ │ └── site.yml
│ │
│ ├── roles/
│ │ ├── common/
│ │ ├── docker/
│ │ ├── wordpress_backend/
│ │ └── caddy_proxy/
│ │
│ └── group_vars/
│ └── all.yml
│
├── deploy/
│ ├── compose.yml
│ └── Caddyfile
│
└── README.md
The inventory Directory
ansible/inventory/
└── production.ini
The inventory defines the machines that Ansible will manage.
Example:
[web] vm-prod ansible_host=10.0.0.10 ansible_user=devops
This means:
-
vm-prod is a server managed by Ansible
-
its IP address is 10.0.0.10
-
the SSH user is devops
When running a playbook, Ansible will:
-
connect via SSH
-
execute the defined tasks on the target host
The group_vars Directory
ansible/group_vars/
└── all.yml
This directory contains global variables used across the roles.
Example:
domain: lavallee.tech
wordpress_port: 8080
db_name: wordpress
db_user: wpuser
db_password: securepassword
Using variables allows you to:
-
centralize configuration
-
avoid modifying role code directly
-
easily adapt infrastructure settings
In more advanced setups, sensitive values like passwords are stored using Ansible Vault.
The playbooks Directory
ansible/playbooks/
└── site.yml
The playbook is the main entry point of the automation.
Example:
– hosts: web
become: trueroles:
– common
– docker
– wordpress_backend
– caddy_proxy
This file tells Ansible:
-
which hosts to target
-
which roles to execute
-
in which order they should run
To deploy the infrastructure, run:
ansible-playbook -i inventory/production.ini playbooks/site.yml
Ansible will execute each role sequentially.
The roles Directory
Roles are the core building blocks of an Ansible project.
They allow infrastructure to be modular and reusable.
Each role represents a specific responsibility:
roles/
├── common
├── docker
├── wordpress_backend
└── caddy_proxy
The common Role
This role prepares the system.
Typical tasks include:
-
updating the system
-
installing base packages
-
preparing the environment
Structure:
roles/common/
├── tasks/
│ └── main.yml
Example task:
– name: Install base packages
apt:
name:
– curl
– git
– vim
state: present
The docker Role
This role installs and configures Docker on the VM.
Structure:
roles/docker/
├── tasks/
│ └── main.yml
Typical tasks:
-
add Docker repository
-
install Docker engine
-
enable and start the Docker service
Example:
– name: Install docker
apt:
name: docker.io
state: present
The wordpress_backend Role
This role deploys the WordPress application using Docker.
Structure:
roles/wordpress_backend/
├── tasks/
│ └── main.yml
├── templates/
│ └── compose.yml.j2
Templates use Jinja2, allowing configuration files to be generated dynamically.
For example, a docker-compose.yml file.
Example:
services:
db:
image: mariadb
environment:
MYSQL_DATABASE:
MYSQL_USER:
MYSQL_PASSWORD:wordpress:
image: wordpress
ports:
– ":80"
The variables are injected from group_vars.
The caddy_proxy Role
Caddy is a modern reverse proxy that automatically manages HTTPS certificates.
Structure:
roles/caddy_proxy/
├── tasks/
│ └── main.yml
└── templates/
└── Caddyfile.j2
Example Caddy configuration:
Caddy automatically:
-
obtains Let's Encrypt certificates
-
handles HTTPS configuration
-
forwards requests to the WordPress container
The deploy Directory
deploy/
├── compose.yml
└── Caddyfile
This directory contains the configuration files used by Docker and the reverse proxy.
In some projects, these files are:
-
generated dynamically via Ansible templates
-
copied to the target server during deployment
Typical files include:
-
docker-compose.yml -
Caddyfile
Full Deployment
Once everything is configured, the entire infrastructure can be deployed with a single command:
ansible-playbook -i ansible/inventory/production.ini ansible/playbooks/site.yml
Ansible will:
-
connect to the VM
-
install Docker
-
deploy WordPress containers
-
configure Caddy
-
enable HTTPS automatically