← Back to all cheatsheets
DevOps
Ansible Cheat Sheet
Basic Syntax
ansible [pattern] -m [module] -a "[module options]"
ansible-playbook [options] playbook.yml
Ad-Hoc Commands
Basic Command Structure
# Ping all hosts
ansible all -m ping
# Ping specific host group
ansible webservers -m ping
# Run command on all hosts
ansible all -a "uptime"
# Run command as sudo
ansible all -a "apt update" --become
# Run command as specific user
ansible all -a "whoami" --become --become-user=www-data
Common Modules in Ad-Hoc
# Shell commands
ansible all -m shell -a "df -h"
# Copy files
ansible all -m copy -a "src=/local/file dest=/remote/file"
# Install package
ansible all -m apt -a "name=nginx state=present" --become
# Restart service
ansible all -m service -a "name=nginx state=restarted" --become
# Create user
ansible all -m user -a "name=deploy state=present" --become
# Gather facts
ansible all -m setup
ansible all -m setup -a "filter=ansible_distribution*"
Targeting Hosts
# Single host
ansible host1 -m ping
# Multiple hosts
ansible host1:host2 -m ping
# Host group
ansible webservers -m ping
# All hosts in multiple groups
ansible webservers:databases -m ping
# Exclude hosts
ansible webservers:!databases -m ping
# Intersection of groups
ansible webservers:&staging -m ping
# Pattern matching
ansible web* -m ping
ansible *.example.com -m ping
# Range of hosts
ansible web[1:5] -m ping
ansible-playbook Command
Basic Playbook Execution
# Run playbook
ansible-playbook playbook.yml
# Run with specific inventory
ansible-playbook -i inventory.ini playbook.yml
ansible-playbook -i hosts playbook.yml
# Check syntax
ansible-playbook --syntax-check playbook.yml
# Dry run (check mode)
ansible-playbook --check playbook.yml
# Show differences when changing files
ansible-playbook --check --diff playbook.yml
# Run with verbose output
ansible-playbook -v playbook.yml # Verbose
ansible-playbook -vv playbook.yml # More verbose
ansible-playbook -vvv playbook.yml # Very verbose
ansible-playbook -vvvv playbook.yml # Debug level
Targeting and Limiting
# Limit to specific hosts
ansible-playbook playbook.yml --limit webservers
ansible-playbook playbook.yml --limit host1,host2
ansible-playbook playbook.yml --limit @failed_hosts.txt
# Start at specific task
ansible-playbook playbook.yml --start-at-task="Install nginx"
# Run specific tags
ansible-playbook playbook.yml --tags "configuration,deployment"
# Skip specific tags
ansible-playbook playbook.yml --skip-tags "testing"
# List all tasks (don't execute)
ansible-playbook playbook.yml --list-tasks
# List all tags
ansible-playbook playbook.yml --list-tags
# List all hosts
ansible-playbook playbook.yml --list-hosts
Variables and Extra Vars
# Pass extra variables
ansible-playbook playbook.yml --extra-vars "version=1.2.3"
ansible-playbook playbook.yml -e "env=production"
# Pass multiple variables
ansible-playbook playbook.yml -e "foo=bar baz=qux"
# Load variables from file
ansible-playbook playbook.yml -e "@vars.yml"
ansible-playbook playbook.yml -e "@vars.json"
Privilege Escalation
# Run with sudo
ansible-playbook playbook.yml --become
# Specify sudo user
ansible-playbook playbook.yml --become --become-user=root
# Ask for sudo password
ansible-playbook playbook.yml --become --ask-become-pass
# Ask for SSH password
ansible-playbook playbook.yml --ask-pass
# Use specific connection method
ansible-playbook playbook.yml --connection=local
Step and Interactive
# Step through tasks one by one
ansible-playbook playbook.yml --step
# Set number of parallel forks
ansible-playbook playbook.yml --forks=10
# Timeout for connections
ansible-playbook playbook.yml --timeout=30
Playbook Structure
Basic Playbook Example
---
- name: Configure web servers
hosts: webservers
become: yes
vars:
http_port: 80
max_clients: 200
tasks:
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Start nginx service
service:
name: nginx
state: started
enabled: yes
- name: Copy configuration file
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify: Restart nginx
handlers:
- name: Restart nginx
service:
name: nginx
state: restarted
Multiple Plays
---
- name: Configure databases
hosts: databases
become: yes
tasks:
- name: Install PostgreSQL
apt:
name: postgresql
state: present
- name: Configure web servers
hosts: webservers
become: yes
tasks:
- name: Install nginx
apt:
name: nginx
state: present
Common Modules
Package Management
# APT (Debian/Ubuntu)
- name: Install package
apt:
name: nginx
state: present
update_cache: yes
# YUM (RedHat/CentOS)
- name: Install package
yum:
name: httpd
state: present
# DNF (Fedora)
- name: Install package
dnf:
name: nginx
state: present
# Generic package module
- name: Install package
package:
name: vim
state: present
File Operations
# Copy files
- name: Copy file
copy:
src: /local/path/file.txt
dest: /remote/path/file.txt
owner: user
group: group
mode: '0644'
# Copy with backup
- name: Copy with backup
copy:
src: config.conf
dest: /etc/app/config.conf
backup: yes
# Template files (Jinja2)
- name: Template configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: '0644'
notify: Restart nginx
# Create file
- name: Create file
file:
path: /tmp/myfile
state: touch
mode: '0644'
# Create directory
- name: Create directory
file:
path: /opt/myapp
state: directory
mode: '0755'
# Create symlink
- name: Create symlink
file:
src: /path/to/source
dest: /path/to/link
state: link
# Delete file/directory
- name: Remove file
file:
path: /tmp/oldfile
state: absent
Service Management
# Start service
- name: Start nginx
service:
name: nginx
state: started
# Stop service
- name: Stop nginx
service:
name: nginx
state: stopped
# Restart service
- name: Restart nginx
service:
name: nginx
state: restarted
# Reload service
- name: Reload nginx
service:
name: nginx
state: reloaded
# Enable service at boot
- name: Enable nginx
service:
name: nginx
enabled: yes
# Using systemd module
- name: Restart and enable service
systemd:
name: nginx
state: restarted
enabled: yes
daemon_reload: yes
Command Execution
# Run command
- name: Run command
command: /usr/bin/somecommand arg1 arg2
# Run shell command (with pipes, redirects)
- name: Run shell command
shell: cat /etc/passwd | grep root
# Run script
- name: Run script
script: /local/path/script.sh
# Run command only if file doesn't exist
- name: Initialize database
command: /usr/bin/init-db
args:
creates: /var/lib/db/initialized
# Run command with specific working directory
- name: Build application
command: make build
args:
chdir: /opt/myapp
User and Group Management
# Create user
- name: Create user
user:
name: deploy
state: present
shell: /bin/bash
groups: sudo
append: yes
# Remove user
- name: Remove user
user:
name: olduser
state: absent
remove: yes
# Create group
- name: Create group
group:
name: developers
state: present
# Add SSH key
- name: Add SSH key
authorized_key:
user: deploy
state: present
key: "{{ lookup('file', '/path/to/id_rsa.pub') }}"
Git Operations
# Clone repository
- name: Clone repository
git:
repo: https://github.com/user/repo.git
dest: /opt/myapp
version: main
# Update repository
- name: Update repository
git:
repo: https://github.com/user/repo.git
dest: /opt/myapp
update: yes
force: yes
Inventory Management
INI Format Inventory
# hosts.ini or inventory.ini
# Ungrouped hosts
host1.example.com
192.168.1.10
# Host with custom SSH port
host2.example.com ansible_port=2222
# Groups
[webservers]
web1.example.com
web2.example.com
web[3:5].example.com
[databases]
db1.example.com
db2.example.com
# Group variables
[webservers:vars]
http_port=80
ansible_user=deploy
# Group of groups
[production:children]
webservers
databases
# Variables for group of groups
[production:vars]
env=production
YAML Format Inventory
# inventory.yml
all:
hosts:
host1.example.com:
host2.example.com:
ansible_port: 2222
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
vars:
http_port: 80
ansible_user: deploy
databases:
hosts:
db1.example.com:
db2.example.com:
production:
children:
webservers:
databases:
vars:
env: production
Inventory Commands
# List all hosts
ansible-inventory --list
# Show inventory graph
ansible-inventory --graph
# Show host variables
ansible-inventory --host web1.example.com
# Use specific inventory file
ansible -i inventory.ini all -m ping
ansible-playbook -i inventory.yml playbook.yml
Variables
Variable Precedence (lowest to highest)
- Role defaults
- Inventory file/script group vars
- Inventory group_vars/all
- Playbook group_vars/all
- Inventory group_vars/*
- Playbook group_vars/*
- Inventory file/script host vars
- Inventory host_vars/*
- Playbook host_vars/*
- Host facts
- Play vars
- Play vars_prompt
- Play vars_files
- Role vars
- Block vars
- Task vars
- Extra vars (—extra-vars)
Using Variables
# Define in playbook
- hosts: webservers
vars:
http_port: 80
app_version: "1.2.3"
tasks:
- name: Use variable
debug:
msg: "Port is {{ http_port }}"
# Load from file
- hosts: webservers
vars_files:
- vars/common.yml
- vars/production.yml
tasks:
- name: Show variable
debug:
var: app_version
# Register task output
- name: Check if file exists
stat:
path: /etc/myapp/config
register: config_file
- name: Use registered variable
debug:
msg: "File exists"
when: config_file.stat.exists
# Facts (automatically gathered)
- name: Show OS distribution
debug:
msg: "OS is {{ ansible_distribution }} {{ ansible_distribution_version }}"
Variable Files
# group_vars/webservers.yml
http_port: 80
max_clients: 200
# host_vars/web1.example.com.yml
server_id: 1
Conditionals and Loops
When Conditions
# Simple condition
- name: Install on Ubuntu only
apt:
name: nginx
state: present
when: ansible_distribution == "Ubuntu"
# Multiple conditions (AND)
- name: Install on Ubuntu 20.04
apt:
name: nginx
state: present
when:
- ansible_distribution == "Ubuntu"
- ansible_distribution_version == "20.04"
# Multiple conditions (OR)
- name: Install on Debian or Ubuntu
apt:
name: nginx
state: present
when: ansible_distribution == "Ubuntu" or ansible_distribution == "Debian"
# Check variable defined
- name: Run if variable is defined
debug:
msg: "Running"
when: my_var is defined
# Check boolean
- name: Run if enabled
debug:
msg: "Enabled"
when: feature_enabled | bool
Loops
# Simple loop
- name: Install packages
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- git
- vim
# Loop with variables
- name: Create users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'alice', groups: 'sudo' }
- { name: 'bob', groups: 'developers' }
# Loop with dictionary
- name: Set file permissions
file:
path: "{{ item.key }}"
mode: "{{ item.value }}"
loop: "{{ files | dict2items }}"
vars:
files:
/etc/app/config: "0644"
/opt/app/script.sh: "0755"
# Loop with range
- name: Create numbered directories
file:
path: "/tmp/dir{{ item }}"
state: directory
loop: "{{ range(1, 6) | list }}"
# Loop with until
- name: Wait for service
uri:
url: http://localhost:8080/health
status_code: 200
register: result
until: result.status == 200
retries: 10
delay: 5
Handlers
Basic Handlers
---
- hosts: webservers
tasks:
- name: Update nginx config
copy:
src: nginx.conf
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Update app config
template:
src: app.conf.j2
dest: /etc/app/config.conf
notify:
- Restart nginx
- Clear cache
handlers:
- name: Restart nginx
service:
name: nginx
state: restarted
- name: Clear cache
command: /usr/local/bin/clear-cache
Handler Execution
# Force handlers to run immediately
- name: Update config
copy:
src: config.conf
dest: /etc/app/config.conf
notify: Restart app
- meta: flush_handlers
- name: This runs after handler
debug:
msg: "Handler has executed"
Roles
Role Directory Structure
roles/
webserver/
tasks/
main.yml
handlers/
main.yml
templates/
nginx.conf.j2
files/
index.html
vars/
main.yml
defaults/
main.yml
meta/
main.yml
Using Roles
---
- hosts: webservers
roles:
- common
- webserver
- { role: database, db_type: postgresql }
# With variables
- hosts: webservers
roles:
- role: nginx
vars:
http_port: 8080
# With tags
- hosts: webservers
roles:
- { role: webserver, tags: ['web'] }
# Include role in tasks
- hosts: webservers
tasks:
- include_role:
name: webserver
vars:
http_port: 8080
Creating a Role
# Create role structure
ansible-galaxy init webserver
# Install role from Galaxy
ansible-galaxy install geerlingguy.nginx
# Install from requirements file
ansible-galaxy install -r requirements.yml
requirements.yml
# From Ansible Galaxy
- src: geerlingguy.nginx
version: 3.1.4
# From GitHub
- src: https://github.com/user/ansible-role-name
name: custom-role
version: main
Templates (Jinja2)
Basic Template
{# nginx.conf.j2 #}
server {
listen {{ http_port }};
server_name {{ server_name }};
root {{ document_root }};
{% if ssl_enabled %}
ssl_certificate {{ ssl_cert_path }};
ssl_certificate_key {{ ssl_key_path }};
{% endif %}
{% for location in locations %}
location {{ location.path }} {
proxy_pass {{ location.backend }};
}
{% endfor %}
}
Template Filters
- name: Use template filters
debug:
msg: "{{ 'hello' | upper }}" # HELLO
- debug:
msg: "{{ my_list | join(', ') }}" # Join list items
- debug:
msg: "{{ my_var | default('default') }}" # Default value
- debug:
msg: "{{ '/path/to/file' | basename }}" # file
- debug:
msg: "{{ my_string | regex_replace('old', 'new') }}"
Ansible Vault
Managing Secrets
# Create encrypted file
ansible-vault create secrets.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# Encrypt existing file
ansible-vault encrypt vars.yml
# Decrypt file
ansible-vault decrypt secrets.yml
# View encrypted file
ansible-vault view secrets.yml
# Rekey (change password)
ansible-vault rekey secrets.yml
# Encrypt string
ansible-vault encrypt_string 'secret_password' --name 'db_password'
Using Vault in Playbooks
# Run playbook with vault
ansible-playbook playbook.yml --ask-vault-pass
# Use password file
ansible-playbook playbook.yml --vault-password-file ~/.vault_pass
# Multiple vault IDs
ansible-playbook playbook.yml --vault-id prod@prompt --vault-id dev@~/.vault_dev
Vault in Variables
# Encrypted variable in playbook
db_password: !vault |
$ANSIBLE_VAULT;1.1;AES256
66386439653235336166353036626163...
Configuration
ansible.cfg
[defaults]
# Inventory file
inventory = ./inventory.ini
# Number of parallel processes
forks = 10
# SSH timeout
timeout = 10
# Disable host key checking
host_key_checking = False
# Log file
log_path = /var/log/ansible.log
# Role path
roles_path = ./roles:/usr/share/ansible/roles
# Gathering facts
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 86400
# Callbacks
stdout_callback = yaml
callbacks_enabled = timer, profile_tasks
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False
[ssh_connection]
pipelining = True
ssh_args = -o ControlMaster=auto -o ControlPersist=60s
Configuration Priority
ANSIBLE_CONFIGenvironment variable./ansible.cfg(in current directory)~/.ansible.cfg(in home directory)/etc/ansible/ansible.cfg
Common Use Cases
Deploy Application
---
- name: Deploy web application
hosts: webservers
become: yes
vars:
app_version: "1.2.3"
app_path: /opt/myapp
tasks:
- name: Pull latest code
git:
repo: https://github.com/user/app.git
dest: "{{ app_path }}"
version: "{{ app_version }}"
notify: Restart application
- name: Install dependencies
pip:
requirements: "{{ app_path }}/requirements.txt"
virtualenv: "{{ app_path }}/venv"
- name: Copy configuration
template:
src: config.j2
dest: "{{ app_path }}/config.py"
notify: Restart application
- name: Collect static files
command: "{{ app_path }}/venv/bin/python manage.py collectstatic --noinput"
args:
chdir: "{{ app_path }}"
handlers:
- name: Restart application
systemd:
name: myapp
state: restarted
System Hardening
---
- name: Harden servers
hosts: all
become: yes
tasks:
- name: Update all packages
apt:
upgrade: dist
update_cache: yes
- name: Disable root SSH login
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
notify: Restart sshd
- name: Configure firewall
ufw:
rule: allow
port: "{{ item }}"
loop:
- 22
- 80
- 443
- name: Enable firewall
ufw:
state: enabled
handlers:
- name: Restart sshd
service:
name: sshd
state: restarted
Testing and Debugging
Debug Module
- name: Show variable
debug:
var: my_variable
- name: Show message
debug:
msg: "Value is {{ my_var }}"
- name: Show all variables
debug:
var: vars
- name: Show hostvars
debug:
var: hostvars[inventory_hostname]
Assert Module
- name: Verify conditions
assert:
that:
- ansible_distribution == "Ubuntu"
- ansible_distribution_version is version('20.04', '>=')
fail_msg: "Ubuntu 20.04 or higher required"
success_msg: "OS version check passed"
Molecule (Testing Framework)
# Install Molecule
pip install molecule molecule-docker
# Initialize new role with Molecule
molecule init role my_role
# Test role
cd my_role
molecule test
# Test steps individually
molecule create # Create test instance
molecule converge # Run playbook
molecule verify # Run tests
molecule destroy # Destroy instance
Tips and Best Practices
- Use roles to organize complex playbooks into reusable components
- Tag tasks for selective execution:
--tagsand--skip-tags - Use
--checkmode to dry-run playbooks before execution - Use
--diffmode to see what will change - Store secrets in Ansible Vault, never in plain text
- Use
ansible-lintto check playbook syntax and best practices - Name all tasks for better readability and debugging
- Use handlers for service restarts to avoid unnecessary restarts
- Set
gather_facts: noif you don’t need facts (faster execution) - Use
asyncandpollfor long-running tasks - Keep playbooks idempotent - safe to run multiple times
- Use version control for all playbooks and roles
- Use
delegate_toto run tasks on different hosts - Cache facts to speed up playbook execution
- Use
serialto control rolling updates - Document your playbooks with comments and README files
Quick Reference
# Ad-hoc commands
ansible all -m ping
ansible all -a "command"
ansible all -m module -a "args"
# Playbook execution
ansible-playbook playbook.yml
ansible-playbook playbook.yml --check
ansible-playbook playbook.yml --check --diff
ansible-playbook playbook.yml -vvv
# Inventory
ansible-inventory --list
ansible-inventory --graph
# Vault
ansible-vault create|edit|view|encrypt|decrypt file.yml
# Galaxy
ansible-galaxy init role_name
ansible-galaxy install role_name
ansible-galaxy install -r requirements.yml
# Configuration
ansible-config list
ansible-config dump
ansible-config view