Ansible
Comprehensive Ansible cheatsheet covering playbooks, inventories, roles, tasks, variables, handlers, ad-hoc commands, modules, and configuration options.
Ansible is a powerful automation tool for configuration management, application deployment, and orchestration. This cheatsheet provides quick reference guides for common Ansible tasks, modules, and best practices to help you get started and work efficiently with Ansible.
No commands found
Try adjusting your search term
Getting Started
Installation & Setup
Install Ansible and configure basic settings
Install Ansible on Ubuntu
sudo apt updatesudo apt install -y ansibleInstall Ansible via pip
pip install ansiblepip install ansible==2.10.7Verify Ansible Installation
Displays installed Ansible version and configuration details
ansible --versionansible 2.10.7 config file = /etc/ansible/ansible.cfg configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3/dist-packages/ansible executable location = /usr/bin/ansible python version = 3.10.12- Version should be 2.9+
- Python 3.6+ required
Ansible Configuration File
Main configuration file setup at ansible.cfg
Create Basic ansible.cfg
[defaults]inventory = ./hostsremote_user = ubuntuprivate_key_file = ~/.ssh/id_rsahost_key_checking = Falsegather_facts = TrueConfigure Parallel Execution
forks increases parallelism for faster execution
[defaults]forks = 10timeout = 30retries = 3- Default forks value is 5
- Higher forks = more parallelism = higher memory usage
First Playbook Run
Execute your first Ansible playbook
Simple Hello World Playbook
Basic playbook that prints a debug message
---- name: Hello World hosts: all tasks: - name: Print Hello debug: msg: "Hello from Ansible"PLAY [Hello World] *****TASK [Print Hello] *****ok: [localhost] => { "msg": "Hello from Ansible"}PLAY RECAP *****localhost : ok=1 changed=0 failed=0- Playbooks must be valid YAML
- [object Object]
Test Host Connectivity
Verify connectivity to managed hosts
Ping All Hosts
Tests connectivity to all hosts without running tasks
ansible all -i hosts -m pingwebserver01 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong"}database01 | SUCCESS => { "ping": "pong"}- ping module requires Python on remote
- SUCCESS indicates host is reachable
Inventory Management
Inventory Formats
Different ways to define managed hosts
INI Format Inventory
INI format with groups and variables
[webservers]web1 ansible_host=192.168.1.10web2 ansible_host=192.168.1.11
[databases]db1 ansible_host=192.168.1.20db2 ansible_host=192.168.1.21
[all:vars]ansible_user=ubuntuansible_ssh_private_key_file=~/.ssh/id_rsa- Groups defined with [groupname]
- [all:vars] applies to all hosts
YAML Format Inventory
YAML format for complex hierarchies
all: children: webservers: hosts: web1: ansible_host: 192.168.1.10 web2: ansible_host: 192.168.1.11 databases: hosts: db1: ansible_host: 192.168.1.20 vars: ansible_user: ubuntu- Better for nested groups
- More readable for complex inventories
Host Patterns
Select specific hosts or groups
Target Specific Groups
webservers targets group, !web2 excludes host
ansible webservers -i hosts -m pingansible databases -i hosts -m pingansible 'webservers:!web2' -i hosts -m pingweb1 | SUCCESS => {"ping": "pong"}web2 | SUCCESS => {"ping": "pong"}- webservers selects entire group
- negates selection
Wildcard and Range Patterns
Wildcards match patterns, [1:2] matches range
ansible 'web*' -i hosts -m pingansible 'db[1:2]' -i hosts -m pingansible 'webservers[0]' -i hosts -m ping- * matches any characters
- [1:2] includes indexes 1 and 2
Dynamic Inventory
Generate inventory from external sources
EC2 Dynamic Inventory
AWS EC2 plugin pulls instances from AWS
plugin: aws_ec2regions: - us-east-1filters: tag:Environment: productionkeyed_groups: - key: placement.region_name prefix: aws_region- Requires boto3 library
- Cache results for performance
Custom Inventory Script
Custom script outputs JSON inventory format
#!/bin/bashcat << EOF{ "webservers": { "hosts": ["web1", "web2"] }}EOF- Script must be executable
- Output must be valid JSON
Host Variables & Priorities
Set variables at different levels
Host-Level Variables
Variables specific to individual hosts
all: children: webservers: hosts: web1: ansible_host: 192.168.1.10 http_port: 80 server_role: primary- Host variables override group variables
- Highest precedence level
Group Variables File
Load variables from files by host/group name
group_vars/webservers.ymlgroup_vars/webservers/main.ymlhost_vars/web1.yml- group_vars/groupname.yml for entire group
- host_vars/hostname.yml for single host
Ad-Hoc Commands
Basic Syntax
Run single tasks without playbook
Run Adhoc Command
Execute shell command on all hosts
ansible all -i hosts -m shell -a "uptime"web1 | CHANGED | rc=0 >> 10:45:23 up 5 days, 3:21, 2 users, load average: 0.05, 0.10, 0.08web2 | CHANGED | rc=0 >> 10:45:24 up 3 days, 1:15, 1 user, load average: 0.02, 0.06, 0.05- -m specifies module
- -a passes arguments
Use copy Module
Copy file from control node to remote
ansible webservers -i hosts -m copy -a "src=/etc/hosts dest=/tmp/hosts"web1 | CHANGED => { "changed": true, "checksum": "5d41402abc4b2a76b9719d911017c592", "dest": "/tmp/hosts", "gid": 0, "mode": "0644", "owner": "root", "size": 158, "src": "/tmp/ansible.87a8vz/hosts", "state": "file"}- src path on control node
- dest path on remote
Common Ad-Hoc Modules
Frequently used modules for ad-hoc tasks
Package Management
Install nginx package
ansible webservers -i hosts -m apt -a "name=nginx state=present"web1 | CHANGED => { "changed": true, "stderr": "", "stdout": "Reading package lists..."}- apt for Debian/Ubuntu
- yum for Red Hat/CentOS
Service Management
Start nginx service and enable on boot
ansible webservers -i hosts -m service -a "name=nginx state=started enabled=yes"web1 | CHANGED => { "changed": true, "enabled": true, "name": "nginx", "state": "started"}- [object Object]
- enabled=yes enables service on boot
File Permissions
Set file permissions and ownership
ansible all -i hosts -m file -a "path=/tmp/test.txt mode=0644 owner=root"web1 | CHANGED => { "changed": true, "mode": "0644", "owner": "root", "path": "/tmp/test.txt"}- mode in octal format
- owner and group can be specified
Parallelism & Forks
Control how many hosts execute simultaneously
Limit Concurrent Execution
Execute on 2 hosts at a time instead of default
ansible all -i hosts -m ping -f 2- -f or --forks sets parallelism
- Lower for safety, higher for speed
Serial Execution
Execute one at a time (serial)
ansible all -i hosts -m shell -a "systemctl restart app" -f 1- Useful for rolling restarts
- Prevents service downtime
Playbooks
Playbook Structure
Create and organize playbooks
Basic Playbook Structure
Complete playbook with all major sections
---- name: Deploy Web Application hosts: webservers become: yes vars: app_port: 8080 app_user: www-data tasks: - name: Install dependencies apt: name: python3-pip state: present - name: Start application command: /opt/app/start.sh- --- indicates YAML document start
- [object Object]
- [object Object]
Multiple Plays in Single Playbook
Multiple plays execute sequentially
---- name: Configure Databases hosts: databases tasks: - debug: msg="Setting up database"
- name: Configure Web Servers hosts: webservers tasks: - debug: msg="Setting up web server"- Each play is independent
- Plays execute in order
Playbook Execution
Run playbooks with various options
Run Basic Playbook
Execute playbook against specified inventory
ansible-playbook playbook.yml -i hostsPLAY [Deploy Web Application] *****TASK [Install dependencies] *****ok: [web1]ok: [web2]TASK [Start application] *****changed: [web1]changed: [web2]PLAY RECAP *****web1 : ok=2 changed=1 failed=0web2 : ok=2 changed=1 failed=0- ok = task already in desired state
- changed = task made changes
Check Mode (Dry Run)
Preview changes without executing
ansible-playbook playbook.yml -i hosts --check- Shows what would change
- Useful before production runs
Run with Extra Variables
Pass variables from command line
ansible-playbook playbook.yml -i hosts -e "env=production app_version=2.0"- -e or --extra-vars for variables
- Overrides defaults in playbook
Verbose Output
Show detailed execution information
ansible-playbook playbook.yml -i hosts -vvv- -v = info, -vv = debug, -vvv = extra debug
Conditionals
Execute tasks based on conditions
Simple When Condition
Skip task if condition false
- name: Install nginx if not exists apt: name: nginx state: present when: ansible_distribution == "Ubuntu"TASK [Install nginx if not exists] *****skipped: [web1] => (item=centos)ok: [web2] => (item=ubuntu)- Conditions use when keyword
- Access facts with ansible_variablename
Multiple Conditions
All conditions must be true (AND logic)
- name: Restart service service: name: nginx state: restarted when: - ansible_os_family == "Debian" - ansible_distribution_version >= "20.04"- List format uses AND logic
- [object Object]
Tasks & Handlers
Task Structure
Define and organize tasks
Basic Task Definition
Task with module, arguments, and tags
- name: Install web server apt: name: nginx state: present become: yes tags: - webserver - packages- [object Object]
- [object Object]
Register Task Output
Save task output in variable for later use
- name: Get service status command: systemctl status nginx register: nginx_status changed_when: false
- name: Display status debug: msg: "{{ nginx_status.stdout }}"- register stores full result
- Access with variable name
Handlers
Run tasks on change events
Basic Handler
Handler executes if task notifies it
- name: Deploy application hosts: webservers tasks: - name: Copy app config copy: src: app.conf dest: /etc/app/app.conf notify: restart app handlers: - name: restart app service: name: app state: restarted- Handlers only run if task changed
- Run at end of play by default
Multiple Handlers
Single task can notify multiple handlers
tasks: - name: Update config template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: - reload nginx - log config changehandlers: - name: reload nginx service: name: nginx state: reloaded - name: log config change command: logger "nginx config updated"- Handlers run in defined order
- Duplicate handler calls only run once
Loops
Repeat tasks with different variables
Loop Over List
Item variable changes per loop iteration
- name: Install multiple packages apt: name: "{{ item }}" state: present loop: - nginx - php-fpm - mysql-clientTASK [Install multiple packages] *****ok: [web1] => (item=nginx)ok: [web1] => (item=php-fpm)ok: [web1] => (item=mysql-client)- [object Object]
- item is implicit variable name
Loop Over Dict
Loop over dictionary structures
- name: Create users user: name: "{{ item.name }}" uid: "{{ item.uid }}" state: present loop: - { name: 'alice', uid: 1001 } - { name: 'bob', uid: 1002 }- Access dict items with dot notation
- Useful for complex configurations
Variables & Facts
Variable Definition
Define and use variables
Play-Level Variables
Define variables at play scope
- name: My playbook hosts: all vars: db_host: localhost db_port: 3306 db_name: myapp env: production tasks: - name: Connect to database debug: msg: "Connecting to {{ db_host }}:{{ db_port }}"- Accessible in all tasks
- {{ }} for variable substitution
Task-Level Variables
Variables local to specific task
- name: Configure service service: name: nginx state: started vars: nginx_user: www-data nginx_workers: 4- Only available in this task's context
Gathering Facts
Collect system information from hosts
Auto-Gather Facts
Facts gathered by default unless disabled
- name: Display fact hosts: all tasks: - name: Show OS debug: msg: "OS: {{ ansible_os_family }}, Memory: {{ ansible_memtotal_mb }}"TASK [Show OS] *****ok: [web1] => { "msg": "OS: Debian, Memory: 4096"}- ansible_* variables are facts
- [object Object]
Custom Facts
Define custom facts in JSON files
/etc/ansible/facts.d/custom.fact{ "app_version": "2.1.0", "deployment_date": "2026-01-15"}- Store in /etc/ansible/facts.d/
- Extension must be .fact
Variable Precedence
Order of variable resolution
Precedence Levels
Variables override based on source location
# Lowest to highest precedence:# 1. defaults/main.yml in role# 2. group_vars/all# 3. group_vars/groupname# 4. host_vars/hostname# 5. vars in playbook# 6. vars_files# 7. task vars# 8. -e extra vars (highest)- Command line (-e) always wins
- Host vars override group vars
Override with Extra Vars
Extra vars override all others
ansible-playbook playbook.yml -e "db_host=newhost db_port=5432"- -e highest precedence
- Useful for overriding defaults
Variable Templating
Template and manipulate variable values
Jinja2 Filters
Transform variables with filters
- name: Use filters debug: msg: | Uppercase: {{ service_name | upper }} Lowercase: {{ domain | lower }} Default: {{ undefined_var | default('localhost') }} List join: {{ servers | join(',') }}TASK [Use filters] *****ok: [localhost] => { "msg": "Uppercase: NGINX\nLowercase: example.com\nDefault: localhost\nList join: web1,web2,web3"}- | for multiline strings
- | filters modify variable values
Roles
Role Structure
Organize code with roles
Role Directory Structure
Standard role directory structure
roles/webserver/├── tasks/│ └── main.yml├── handlers/│ └── main.yml├── vars/│ └── main.yml├── defaults/│ └── main.yml├── files/├── templates/└── meta/ └── main.yml- tasks/ contains main task execution
- defaults/ provides variable defaults
Role Definition
Define tasks in role
---- name: Install web server apt: name: nginx state: present become: yes
- name: Copy config template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf notify: restart nginx- Include handler definitions
- Keep role single-purpose
Role Options & Includes
Include and configure roles
Include Role in Playbook
Include multiple roles
- name: Deploy web application hosts: webservers roles: - webserver - php - mysql- Roles execute in order
- Most common role usage
Role with Variables
Pass variables to roles
- name: Deploy web application hosts: webservers roles: - role: webserver vars: nginx_port: 8080 nginx_workers: 8 - role: php when: "'php' in group_names"- Vars override role defaults
- when can conditionally include roles
Role Dependencies
Manage role dependencies
Declare Dependencies
Specify required roles
---dependencies: - role: webserver - role: database vars: db_type: mysql- Dependencies execute first
- Can pass variables to dependencies
Modules
System Modules
System administration modules
User Management
Create system user with specified properties
- name: Create user user: name: appuser uid: 2000 home: /opt/app shell: /bin/bash state: presentok: [web1] => { "changed": false, "comment": "", "home": "/opt/app", "name": "appuser", "shell": "/bin/bash", "uid": 2000}- [object Object]
- uid specifies numeric user id
File Management
Create directory with permissions
- name: Create directory file: path: /opt/app/data state: directory mode: '0755' owner: appuser recurse: yeschanged: [web1] => { "changed": true, "mode": "0755", "owner": "appuser", "path": "/opt/app/data", "state": "directory"}- [object Object]
- [object Object]
Package Management
Install and manage packages
APT Package Manager
Install multiple packages with cache update
- name: Install packages apt: name: - curl - wget - git state: present update_cache: yes- update_cache updates apt database
- [object Object]
PIP Package Manager
Install Python packages in virtualenv
- name: Install Python packages pip: name: - django==3.2 - requests>=2.25 virtualenv: /opt/app/venv- virtualenv creates/uses virtualenv
- Version pinning with == or >=
Command Execution
Execute commands on remote hosts
Command Module (Preferred)
Execute command without shell processing
- name: Get nginx version command: nginx -v register: nginx_version changed_when: falseok: [web1] => { "cmd": ["nginx", "-v"], "rc": 0, "stderr": "nginx version: nginx/1.18.0", "stdout": ""}- No shell expansion (*, |, &)
- More predictable
Shell Module
Execute with shell processing
- name: Check if file exists shell: | if [ -f /opt/app/config.yml ]; then echo "exists" else echo "missing" fi register: config_check- Supports pipes, redirects
- Less secure, use with care
Web & Net Modules
HTTP and network operations
HTTP Request
Make HTTP request and validate response
- name: Health check uri: url: http://localhost:8080/health method: GET status_code: 200 register: health_checkok: [web1] => { "changed": false, "content": "{\"status\":\"ok\"}", "status": 200}- status_code validates response
- body can parse JSON response
Advanced Features
Blocks & Error Handling
Group tasks and handle errors
Block with Error Handling
Block groups tasks with error handling
- name: Database operations block: - name: Connect to database debug: msg="Connecting" - name: Run migrations command: /opt/app/migrations.sh rescue: - name: Rollback on error command: /opt/app/rollback.sh always: - name: Cleanup file: path: /tmp/app.lock state: absent- [object Object]
- [object Object]
- [object Object]
Validate Task Results
Control when task is marked failed/changed
- name: Run test shell: npm test failed_when: "npm_test.rc != 0" changed_when: false register: npm_test- failed_when override failure detection
- changed_when override change detection
Asynchronous Execution
Run long-running tasks in background
Async with Polling
Run 1-hour task, check every 10 seconds
- name: Long running task shell: /opt/app/long-job.sh async: 3600 poll: 10 register: long_jobASYNC OK on web1 (job_id=123456789.12345)- [object Object]
- [object Object]
Fire and Forget
Start task and don't wait for completion
- name: Start background service shell: /opt/app/service.sh async: 0 poll: 0- async: 0 and poll: 0 for fire-and-forget
Advanced Variable Usage
Complex variable patterns
Access Host Variables
Access variables from other hosts
- name: Reference another host debug: msg: "Database host: {{ hostvars['db1']['ansible_default_ipv4']['address'] }}"- hostvars dict contains all host info
- Useful in multi-host plays
Nested Variable Access
Access deeply nested structures
vars: services: web: port: 8080 workers: 4 db: port: 5432 replicas: 3tasks: - debug: msg="Web port {{ services.web.port }}"- Dot notation for nested access
- Bracket notation also works
Plugins & Extensions
Extend Ansible functionality
Custom Filters
Apply custom filter plugins
- name: Use custom filter debug: msg: "{{ 'hello' | custom_uppercase }}"- Place filters in filter_plugins/
- Extend Jinja2 capabilities
Lookup Plugins
Use lookup plugins for dynamic data
- name: Read file content set_fact: file_content: "{{ lookup('file', '/etc/config.yml') }}"
- name: Get environment variable debug: msg: "{{ lookup('env', 'HOME') }}"- file, env, pipe lookups common
- Results available mid-playbook
Vault & Security
Vault Basics
Encrypt sensitive data
Create Vault File
Create encrypted YAML file
ansible-vault create secrets.yml# Enter password, then edit:# db_password: "secret123"# api_key: "abc123xyz"New Vault password:Confirm New Vault password:- Creates .yml with encrypted content
- Prompts for password
View Vault Content
Decrypt and display vault file
ansible-vault view secrets.yml# Password prompt- Requires vault password
- Doesn't save decrypted content
Edit Vault File
Edit encrypted vault file safely
ansible-vault edit secrets.yml- Opens in editor
- Re-encrypts on save
Using Vault in Playbooks
Reference vault variables in playbooks
Include Vault Variables
Load vault variables in playbook
- name: Deploy app hosts: webservers vars_files: - secrets.yml tasks: - name: Configure database template: src: db.conf.j2 dest: /etc/app/db.conf vars: db_password: "{{ vault_db_password }}"- [object Object]
- Automatic decryption on run
Run Playbook with Vault
Run playbook requiring vault password
ansible-playbook playbook.yml -i hosts --ask-vault-passVault password:PLAY [Deploy app] *****TASK [Configure database] *****ok: [web1]- --ask-vault-pass prompts for password
- --vault-password-file for automation
Encrypt Individual Files
Encrypt specific files or variables
Encrypt Single Variable
Encrypt individual secret for playbook
ansible-vault encrypt_string --ask-vault-pass 'mypassword'Reading plaintext input from stdin.New Vault password:Confirm New Vault password:!vault | $ANSIBLE_VAULT;1.1;AES256 66386...- Generates encrypted string
- Paste into playbook vars
Encrypt Specific Files
Encrypt individual variable files
ansible-vault encrypt host_vars/prod.yml- Encrypts existing file in place
Vault Best Practices
Security practices with vault
Password File Not in Repo
Store vault password file locally, not in git
.gitignore:.vault_pass
Run playbook:ansible-playbook playbook.yml --vault-password-file ~/.vault_pass- Keep .vault_pass outside repository
- Use --vault-password-file for automation
Different Vaults for Environments
Separate encrypted files per environment
group_vars/prod/secrets.yml (encrypted)group_vars/dev/secrets.yml (encrypted)group_vars/staging/secrets.yml (encrypted)- Different passwords per environment
- Enhanced security isolation
You might also enjoy
Check out some of our other posts on similar topics
6 related posts
