Installing Ansible and setting up a control node
Install the package or the pip distribution, configure ansible.cfg with a predictable precedence, set up SSH keys and become, install collections, and check connectivity.
Which Ansible to install
# a control node needs Python; the managed nodes need only SSH and Python
python3 -m venv ~/.venvs/ansible
source ~/.venvs/ansible/bin/activate
pip install "ansible-core==2.17.*"
# the community bundle adds hundreds of collections on top of core
pip install "ansible==10.*"
ansible --version
# note the config file path it reports: that is the one it will actually read| Package | Contains | Choose when |
|---|---|---|
ansible-core | The engine, a small set of built-in modules | You install exactly the collections you need |
community bundle | ansible-core plus many collections | You want broad coverage out of the box |
| Distribution package | Whatever version the OS ships | Usually too old for new collections |
- Never install Ansible on the managed nodes. It is agentless by design and pushes modules over SSH at runtime.
ansible-coremoves fast and periodically removes deprecated modules, so pin the version in a requirements file and in CI.- The control node does the work, so its Python version matters more than the targets'.
Configuration and precedence
# ./ansible.cfg in the project directory: the most useful place for it
[defaults]
inventory = ./inventory/hosts.ini
roles_path = ./roles
collections_path = ./collections
host_key_checking = False
retry_files_enabled = False
stdout_callback = yaml
callbacks_enabled = profile_tasks, timer
interpreter_python = auto_silent
forks = 20
[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| Order | Location | Wins |
|---|---|---|
| 1 | ANSIBLE_CONFIG environment variable | Always wins |
| 2 | ansible.cfg in the current directory | The usual choice |
| 3 | ~/.ansible.cfg | User default |
| 4 | /etc/ansible/ansible.cfg | Global default |
ansible --version prints the config file in use. When a setting appears to be ignored, that line is the fastest way to find out why.
SSH, become and a first check
ssh-keygen -t ed25519 -C "ansible-control-node"
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]
ansible all -i inventory/hosts.ini -m ping
ansible web -m setup -a 'filter=ansible_distribution*'
ansible-playbook -i inventory/hosts.ini site.yml --check --diff
# install collections and roles from a pinned requirements file
ansible-galaxy collection install -r requirements.yml -p ./collections
ansible-galaxy role install -r requirements.yml -p ./roles💡
Use a dedicated automation user with a sudo rule rather than logging in as root. Set
host_key_checking = False only in a development config; in production, distribute a known_hosts file so a changed host key fails loudly.FAQ
What if the target has no Python?
The
raw module runs over SSH with no Python at all, so the usual bootstrap is a raw task that installs Python, then gather_facts for everything afterwards.Why is my config file ignored?
Ansible reads the first config it finds in its precedence order, starting from the current working directory. Run
ansible --version from your project directory and check the reported path.Related
Collections, Galaxy and the module ecosystem Inventories and ad-hoc commands
Last refreshed 2026-09-18.