unit 2 · Setup
ansible.cfg & config precedence
Four places, first one wins
you may want to read 5 · Installing a control node first — but nothing is locked
tl;dr
- Every run reads ONE config file: ANSIBLE_CONFIG → ./ansible.cfg → ~/.ansible.cfg → /etc/ansible/ansible.cfg.
- First file found wins — the search stops there. Nothing merges.
- Best practice: a project-root ansible.cfg committed to Git, so everyone runs with identical settings.
why it matters Two engineers run the same command and get different inventories, users and behaviour because different ansible.cfg files won — until you know the search order, that looks like magic.
Lesson 5 left you with a working control node. Before you point it at a real machine, you need to know where Ansible gets its settings — because the honest answer is “it depends on the directory you’re standing in”, and that catches people on day one.
Every command in the toolbox — ansible, ansible-playbook,
ansible-inventory — reads its defaults from a single INI file called
ansible.cfg. Which file? Ansible searches four places, in this order, and
stops at the first one it finds:
- Whatever the
ANSIBLE_CONFIGenvironment variable points to ./ansible.cfg— the current working directory~/.ansible.cfg— your home directory/etc/ansible/ansible.cfg— the machine-wide fallback
First found wins, and the search stops dead. Nothing merges. If a project
ships its own ansible.cfg and you run from inside it, your carefully tuned
~/.ansible.cfg contributes exactly nothing to that run.
Put it in the repo
That cwd slot at position 2 is the whole strategy. The best practice is a
project-root ansible.cfg, committed to Git: everyone who clones the repo
and runs from its root gets identical behaviour — same inventory, same
parallelism, same paths — instead of whatever their laptop happens to have in
~/.ansible.cfg. It’s the first file in the standard repo layout you’ll meet
in lesson 36.
Slot 1 exists for the runs that must ignore all of that. Because the environment variable outranks even the project file, a CI job can force a known config no matter what the checkout contains:
ANSIBLE_CONFIG=/opt/ci/ansible.cfg ansible-playbook site.ymlWhat goes in it
A sensible starter, using only settings you’ll actually touch early:
[defaults]
inventory = inventories/dev/ # default inventory (unit 3) — no -i flag on every run
remote_user = ansible # the user Ansible logs in to managed nodes as
forks = 20 # parallelism: how many hosts to work on at once
host_key_checking = False # lab convenience — leave SSH host-key checks on in prod
roles_path = roles # where this repo keeps its roles (lesson 24)Quick tour: inventory sets a default so nobody has to remember an -i flag;
remote_user is the login account on the managed nodes; forks
caps how many hosts Ansible handles in parallel; host_key_checking = False
skips the interactive SSH host-key prompt — fine against throwaway lab VMs,
not something to ship to production.
Other settings live in this same file and you’ll meet each one when its topic
arrives: collections_path (where installed collections go), become
(privilege escalation defaults), gathering and fact caching (lesson 17),
and stdout_callback, which swaps the run output format via a callback
plugin (lesson 14). Resist the urge to tune them now — a small, boring
config that lives in Git beats a clever one that lives on your laptop.
One habit closes this lesson: when Ansible behaves differently on two machines
— or in CI versus your laptop — ask which config file won before you ask
anything else. Check the env var, then look for an ansible.cfg in the
directory you ran from. Nine times out of ten, that’s the whole mystery. Next
lesson, the config starts paying rent: your first ad-hoc command.
at work, this sounds like
- “Just run it from the repo root — the ansible.cfg handles it.”
- The project ships its own config file; running from that directory picks it up, so the inventory and other defaults are preset.
- “Bump the forks if it feels slow.”
- Raise the parallelism setting in ansible.cfg so Ansible works on more hosts simultaneously.
self-check — recall, not a test
1 Name the four places Ansible looks for its config, in order.
2 Why commit an ansible.cfg at the project root?
3 Does this precedence chain decide which value a variable ends up with?