Ansible — Inventory File
A structured YAML inventory file that defines three host groups — webservers, dbservers, and monitoring — with global connection defaults, per-group variables, and per-host overrides for connection settings and application-specific configuration.
Overview
An Ansible inventory defines the hosts and groups that Ansible manages. While the
original INI-style inventory format is still supported, the YAML format is more expressive: it
supports nested group hierarchies, inline variables, and is easier to read and validate.
Use the inventory by passing it with the -i flag:
ansible-playbook -i inventory.yml nginx.yml.
The YAML inventory structure always starts with all, the implicit parent group that
contains every host. Under all, you define global variables in all.vars
and sub-groups in all.children. Each group can have its own hosts,
vars, and children — allowing arbitrarily deep nesting for complex
infrastructure hierarchies. Variables follow a clear inheritance order: host variables beat group
variables, which beat parent group variables, which beat all.vars.
ansible-inventory -i inventory.yml --list to see the
fully-resolved host and variable tree as JSON, or with --graph for a visual hierarchy.
Use ansible all -i inventory.yml -m ping to verify connectivity to all hosts.
Full YAML Copy-paste ready
all:
vars:
ansible_user: ubuntu
ansible_ssh_private_key_file: ~/.ssh/id_rsa
ansible_python_interpreter: /usr/bin/python3
children:
webservers:
hosts:
web1:
ansible_host: 10.0.1.10
web2:
ansible_host: 10.0.1.11
vars:
nginx_port: 80
document_root: /var/www/html
dbservers:
hosts:
db1:
ansible_host: 10.0.2.10
ansible_port: 22
ansible_user: admin
vars:
postgres_version: "16"
postgres_data_dir: /var/lib/postgresql/16/main
monitoring:
hosts:
monitor1:
ansible_host: 10.0.3.10
Key sections explained
all.vars for global defaults
Variables defined under all.vars apply to every host in the inventory. These are the
lowest-priority variables, so any host-level or group-level variable with the same name will override
them. This is the right place for connection defaults that apply across your entire infrastructure:
the SSH user (ansible_user: ubuntu), the SSH key (ansible_ssh_private_key_file),
and the Python interpreter path. Setting these globally avoids repeating them for every group and host.
Connection variables that start with ansible_ are special: Ansible reads them
automatically to control how it connects to each host. The full list includes
ansible_host, ansible_port, ansible_user,
ansible_password, ansible_ssh_private_key_file,
ansible_connection, and many more. Non-prefixed variables like nginx_port
are user-defined and are only meaningful in your playbook tasks and templates.
children for group nesting
The children key under a group defines sub-groups. Here, webservers,
dbservers, and monitoring are all children of all. You can
nest groups further — for example, you could have a production group that contains
webservers and dbservers as children, and a staging group
with its own sub-groups. A host can belong to multiple groups simultaneously, and it will inherit
variables from all of them (with the lowest-priority group losing in case of conflicts).
Group-level variables defined in vars (like nginx_port under
webservers) are available to all hosts in that group. In the Nginx playbook, the
template and file tasks reference {{ nginx_port }} and {{ document_root }}
— which come from the webservers group vars in this inventory, allowing you to
configure different values for a staging webserver group without touching the playbook.
ansible_host for IP mapping
By default, Ansible uses the hostname or alias defined in the inventory (like web1) to
connect to the host via SSH. If web1 is not resolvable via DNS, Ansible will fail to
connect. ansible_host overrides the connection target, letting you use descriptive
logical names in your inventory while still connecting to the correct IP addresses. This is common
in private networks where internal IPs are not registered in DNS, or where you want the inventory
host name to reflect the server's role rather than its hostname.
Host-level variable overrides
The db1 host demonstrates host-level variable overrides: ansible_user: admin
overrides the global ansible_user: ubuntu set in all.vars, because
host-level variables always take priority over group and global variables. This is how you handle
heterogeneous infrastructure — most hosts share the same SSH user and key, but a few special hosts
(like database servers managed by a different team) need different credentials without breaking the
defaults for everyone else.
The ansible_port: 22 on db1 is explicit here for clarity. The default SSH
port is already 22, so this line has no effect — but it serves as documentation. If your database
server exposed SSH on a non-standard port like 2222, setting ansible_port: 2222 at the
host level would override the default for that host only.
ansible_python_interpreter for Python 3
Ansible modules run on the remote host using Python. On older Ubuntu systems, python
might not be in PATH (only python3 is available), which would cause
Ansible to fail with a cryptic error. Setting ansible_python_interpreter: /usr/bin/python3
globally ensures that Ansible always uses Python 3 on all hosts, regardless of whether a
python symlink exists. On modern distributions this is the expected default, but making
it explicit avoids surprises when targeting a mix of old and new servers.
Tips & variations
Use group_vars directories for cleaner organization
Instead of defining group variables inline in the inventory file, you can create a
group_vars/ directory alongside your inventory. Ansible automatically loads
group_vars/webservers.yml (or group_vars/webservers/main.yml) for hosts
in the webservers group. This keeps the inventory focused on host-to-group mapping
while separating configuration into dedicated variable files — easier to review and manage in
version control.
Encrypt sensitive host variables with Ansible Vault
Connection variables like ansible_password or database passwords should not be
committed to version control in plaintext. Use ansible-vault encrypt_string to encrypt
individual values, or ansible-vault encrypt group_vars/dbservers/secrets.yml to
encrypt an entire variable file. Run the playbook with
ansible-playbook --ask-vault-pass or point to a vault password file with
--vault-password-file.
Use a dynamic inventory for cloud environments
For AWS, GCP, Azure, and other cloud providers, Ansible supports dynamic inventories
that query the cloud API at runtime to discover hosts and their metadata. For example,
amazon.aws.aws_ec2 generates an inventory from your EC2 instances, automatically
grouping them by region, VPC, tags, and instance type. This eliminates the need to manually
maintain static IP addresses as your infrastructure scales.
Verify the inventory graph
# Show visual group hierarchy ansible-inventory -i inventory.yml --graph # Show all hosts and variables as JSON ansible-inventory -i inventory.yml --list # Test connectivity to all hosts ansible all -i inventory.yml -m ping