18 April 2016
<p>Guide to automating server deployments with Ansible playbooks, with example files.</p>

Ansible is an essential tool for server deployments, enabling quick repeatable deployments across multiple servers. It is similar to other tools such as:
Once you have installed Ansible, here's a rundown of the key concepts you'll use:
I generally keep my ansible files in a similar structure advocated in the official Best Practices Guidelines, namely:
ansible /
playbooks /
start_servers.yml # Playbook to start servers
group_vars /
production # Group vars for the production environment
staging # Group vars for the staging environment
inventory /
production # List of hosts for production
staging # List of hosts for staging
roles /
webserver / # The webserver role, included in start_servers.yml playbook
defaults /
main.yml # Default vars which may be overridden by group_vars
files /
id_rsa # A static file copied to the server. These are not customized with vars.
meta /
main.yml # List any dependencies for this role
templates /
nginx.conf.j2 # A dynamic file customized with vars for each hosts. Always ends in .j2 extension.
tasks /
main.yml # Main task for this role, which typically includes other subtasks listed here.
01_create_dirs.yml # Subtask to create directories
02_install_nginx.yml # Subtask to install nginx
03_logging.yml # Subtask to configure logging
04_start_services.yml # Subtask to start all services
Here are some simplistic sample files from the tree structure listed previously.
# ansible/playbooks/start_servers.yml
---
- name: MySite | Webserver Playbook
hosts: webservers
sudo: true
roles:
- webserver
- caching # Another role, not shown in this article
- backup # Another role, not shown in this article
# ansible/group_vars/production
---
git:
branch: master
domain: my-site.com
use_pagerduty: True
# ansible/inventory/production
[webservers]
webserver01.mydomain.aws ansible_ssh_host=10.11.12.123
webserver02.mydomain.aws ansible_ssh_host=10.11.12.124
[database]
rds.master.mydomain.aws ansible_ssh_host=10.11.12.125
rds.slave.mydomain.aws ansible_ssh_host=10.11.12.126
# ansible/roles/webserver/defaults/main.yml
---
git:
branch: development # This gets overridden in group_vars
repo: ssh://git@github.com/my-git/my-repo.git
domain: my-site.com
use_pagerduty: False # This gets overridden in group_vars
nginx:
user: myuser
worker_processes: 4
# ansible/roles/webserver/meta/main.yml
---
dependencies:
- { role: logging } # Requires another role, which is not shown in this article
# ansible/roles/webserver/templates/nginx.conf.j2
user {{ nginx.user }};
worker_processes {{ nginx.worker_processes }};
pid /var/run/nginx.pid;
### Rest of nginx config file not shown ... #
# ansible/roles/webserver/tasks/main.yml
---
- name: Clone/pull from github
git: repo={{ git.url }} dest={{ path }} version="{{ git.branch }}" key_file="/home/{{ nginx.user }}/.ssh/id_rsa" accept_hostkey=yes force=yes
sudo_user: "{{ nginx.user }}"
tags:
- update
### Rest of task not shown ... #
With my configuration setup as described previously, I can now deploy a cluster of webservers in seconds by running:
ansible-playbook start_servers.yml -i inventory/production --ask-vault-pass
Note: The --ask-vault-pass option will prompt the user to enter the Ansible Vault password used for any encrypted vars files.
© 2026 Michael Cho