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
PackageContainsChoose when
ansible-coreThe engine, a small set of built-in modulesYou install exactly the collections you need
community bundleansible-core plus many collectionsYou want broad coverage out of the box
Distribution packageWhatever version the OS shipsUsually 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-core moves 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
OrderLocationWins
1ANSIBLE_CONFIG environment variableAlways wins
2ansible.cfg in the current directoryThe usual choice
3~/.ansible.cfgUser default
4/etc/ansible/ansible.cfgGlobal 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 deploy@web1.example.com

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.

Collections, Galaxy and the module ecosystem Inventories and ad-hoc commands

Last refreshed 2026-09-18.