Inventories and ad-hoc commands
Describe your machines in an inventory, connect over SSH without installing an agent, and run one-off tasks from the command line.
The inventory
Ansible is agentless: it copies a small Python program over SSH, runs it on the target, and removes it. The inventory is the list of hosts it may talk to, grouped, and optionally annotated with variables.
# inventory.ini
[web]
web1.example.com
web2.example.com ansible_user=deploy
[database]
db1.example.com
[prod:children] # a group of groups
web
database
[prod:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_ssh_private_key_file=~/.ssh/prod_ed25519| Pattern | Matches |
|---|---|
all | Every host in the inventory |
web | The group named web |
web:db1.example.com | Union of a group and a single host |
prod:!database | Everything in prod except the database group |
web:&prod | Hosts that are in both web and prod |
web[0] | The first host of the group |
Ad-hoc commands
Anything you would run once on one machine, you can run on a hundred. The shape is always ansible <pattern> -m <module> -a <arguments>.
# is the connection and the remote Python working?
ansible all -i inventory.ini -m ping
# run a command and print its output
ansible web -i inventory.ini -m shell -a 'df -h /'
# discover facts about the machines
ansible prod -i inventory.ini -m setup -a 'filter=ansible_distribution*'
# copy a file, then confirm it landed
ansible web -i inventory.ini -m copy -a 'src=./app.conf dest=/etc/app.conf mode=0644'
# install a package (needs privilege escalation)
ansible web -i inventory.ini -b -m apt -a 'name=nginx state=present'-iselects the inventory; without it Ansible falls back to/etc/ansible/hosts.-mnames the module (ping,copy,apt,service) and-apasses its arguments.-benablesbecome(sudo) for that run;--become-usernames the target user.-f 20raises the number of parallel forks above the default of five.--limit web2narrows any pattern further, which is how you test a change safely.
Configuration and safety
# ansible.cfg — keep it beside your playbooks
[defaults]
inventory = ./inventory.ini
host_key_checking = True
forks = 20
retry_files_enabled = False
[privilege_escalation]
become = True
become_method = sudo
become_ask_pass = FalseAnsible reads ansible.cfg from the current directory first, then ~/.ansible.cfg, then /etc/ansible/ansible.cfg. Keeping one beside the playbooks makes a repository behave the same on every machine.
⚠️
Ad-hoc commands are not idempotent by default:
shell and command run every time they are invoked. Use modules with a state argument for anything that must be safe to repeat, and keep shell for genuinely one-off work.FAQ
Do I need to install anything on the managed hosts?
No agent. You need SSH access and a Python interpreter. If a host has no Python at all, a small subset of modules can still run through
raw.How do I try a command without changing anything?
Add
--check for a dry run and --diff beside it to see which lines would change. Both require the module you use to support check mode.Related
Playbooks and modules Roles, Vault and idempotency
Last refreshed 2026-09-18.