Ansible Configuration

Introduction

Ansible's behavior can be extensively customized through configuration files, environment variables, and command-line options. Understanding the configuration system is essential for optimizing performance, managing authentication, controlling output, and adapting Ansible to your specific environment.

Configuration Precedence (Highest to Lowest):
  1. Command-line options: ansible-playbook -f 50
  2. Environment variables: ANSIBLE_FORKS=50
  3. ansible.cfg (current directory): ./ansible.cfg
  4. User configuration: ~/.ansible.cfg
  5. System configuration: /etc/ansible/ansible.cfg

Finding Your Configuration

View Current Configuration

# Show which config file is being used
ansible --version

# Output shows:
# ansible [core 2.14.0]
#   config file = /etc/ansible/ansible.cfg
#   configured module search path = ['/home/user/.ansible/plugins/modules']

# View all configuration settings
ansible-config dump

# View only changed settings
ansible-config dump --only-changed

# View configuration for specific setting
ansible-config dump | grep -i forks

# List all available settings
ansible-config list

Configuration File Locations

# Check which config file Ansible will use
export ANSIBLE_CONFIG=/path/to/ansible.cfg  # Highest priority
./ansible.cfg                               # Project-specific
~/.ansible.cfg                              # User-specific
/etc/ansible/ansible.cfg                    # System-wide (default)

# Verify active configuration
ansible-config view

# Check if a specific config file is valid
ansible-config view -c /path/to/ansible.cfg

Complete ansible.cfg Reference

[defaults] Section

The [defaults] section contains the most commonly used settings:

[defaults]
# Inventory settings
inventory = ./inventory
# inventory = /etc/ansible/hosts
# Can be file, directory, or comma-separated list

# Roles and collections paths
roles_path = ./roles:/usr/share/ansible/roles
collections_path = ./collections:/usr/share/ansible/collections

# Connection settings
remote_user = ansible
# Default user for SSH connections

timeout = 10
# SSH connection timeout in seconds

host_key_checking = False
# Disable SSH host key checking (useful for dynamic environments)
# Security risk: set to True in production

# Performance tuning
forks = 5
# Number of parallel processes (increase for larger inventories)
# Recommended: CPU cores * 2 to 4

gathering = smart
# Fact gathering: implicit (always), explicit (never unless requested), smart (cache)

fact_caching = jsonfile
# Cache facts to speed up playbook runs: memory, jsonfile, redis, yaml

fact_caching_connection = /tmp/ansible_facts
# Where to store cached facts

fact_caching_timeout = 86400
# Fact cache expiration in seconds (86400 = 24 hours)

# Output and logging
stdout_callback = yaml
# Output format: default, yaml, json, minimal, debug

bin_ansible_callbacks = True
# Use callbacks from collections

log_path = /var/log/ansible.log
# Path to log file (must be writable by user)

display_skipped_hosts = False
# Show tasks that were skipped

display_ok_hosts = True
# Show successful tasks

# Error handling
retry_files_enabled = False
# Create .retry files for failed hosts

retry_files_save_path = ./
# Where to save .retry files

any_errors_fatal = False
# Stop entire playbook on any error

# Module and plugin settings
module_name = command
# Default module for ad-hoc commands

library = /usr/share/ansible/modules
# Additional module search paths

action_plugins = /usr/share/ansible/plugins/action
callback_plugins = /usr/share/ansible/plugins/callback
connection_plugins = /usr/share/ansible/plugins/connection
filter_plugins = /usr/share/ansible/plugins/filter
lookup_plugins = /usr/share/ansible/plugins/lookup
test_plugins = /usr/share/ansible/plugins/test

# Python interpreter
interpreter_python = auto_silent
# How to find Python: auto, auto_legacy, auto_silent, /usr/bin/python3

# Warnings and deprecations
deprecation_warnings = True
command_warnings = True
system_warnings = True

# Vault
vault_password_file = ~/.vault_pass
# Path to file containing vault password

vault_identity_list = dev@~/.vault_pass_dev, prod@~/.vault_pass_prod
# Multiple vault passwords with labels

# Miscellaneous
nocows = 1
# Disable cowsay output

nocolor = 0
# Disable colored output (1 = disable, 0 = enable)

force_color = 0
# Force colored output even when not in TTY

ansible_managed = Ansible managed: {file} modified on %Y-%m-%d %H:%M:%S by {uid} on {host}
# Header for templates to show they're managed by Ansible

jinja2_extensions = jinja2.ext.do,jinja2.ext.i18n
# Additional Jinja2 extensions

# Task execution
poll_interval = 15
# How often to poll for async task status

internal_poll_interval = 0.001
# Internal task polling interval

# Variable handling
hash_behaviour = replace
# How to merge hashes: replace or merge (replace is recommended)

# Inventory plugins
enable_plugins = host_list, script, auto, yaml, ini, toml
# Which inventory plugins to enable

[privilege_escalation] Section

Settings for privilege escalation (sudo, su, etc.):

[privilege_escalation]
become = True
# Enable privilege escalation by default

become_method = sudo
# Method: sudo, su, pbrun, pfexec, doas, dzdo, ksu, runas, machinectl

become_user = root
# User to become (usually root)

become_ask_pass = False
# Prompt for privilege escalation password

become_flags = -H -S -n
# Additional flags for become command

# Method-specific settings
[sudo_become_plugin]
flags = -H -S -n
# Sudo-specific flags

[pbrun_become_plugin]
flags = -l
# Pbrun-specific flags

[ssh_connection] Section

SSH connection optimization:

[ssh_connection]
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
# SSH arguments for connection multiplexing
# -C: compression
# ControlMaster: reuse connections
# ControlPersist: keep connections alive

control_path = %(directory)s/ansible-ssh-%%h-%%p-%%r
# Path for SSH control socket
# %%h = hostname, %%p = port, %%r = remote user

pipelining = True
# Enable SSH pipelining (huge performance boost)
# Requires requiretty disabled in /etc/sudoers

scp_if_ssh = smart
# When to use SCP vs SFTP: smart, True, False

transfer_method = smart
# How to transfer files: smart, sftp, scp, piped

retries = 3
# Number of SSH connection retries

timeout = 10
# SSH connection timeout in seconds

ssh_executable = /usr/bin/ssh
# Path to SSH binary

sftp_batch_mode = True
# Disable confirmation prompts in SFTP

[persistent_connection] Section

Settings for persistent network connections:

[persistent_connection]
connect_timeout = 30
# Timeout for establishing connection

connect_retry_timeout = 15
# Timeout before retrying connection

command_timeout = 30
# Timeout for commands on persistent connection

[colors] Section

Customize output colors:

[colors]
highlight = white
verbose = blue
warn = bright purple
error = red
debug = dark gray
deprecate = purple
skip = cyan
unreachable = red
ok = green
changed = yellow
diff_add = green
diff_remove = red
diff_lines = cyan

[selinux] Section

SELinux-specific settings:

[selinux]
special_context_filesystems = fuse, nfs, vboxsf, ramfs, 9p, vfat
# Filesystems that require special SELinux handling

libvirt_lxc_noseclabel = yes
# Don't set SELinux labels on libvirt LXC containers

Environment Variables

Common Environment Variables

# Configuration file location
export ANSIBLE_CONFIG=/path/to/ansible.cfg

# Connection settings
export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_REMOTE_USER=ansible
export ANSIBLE_REMOTE_PORT=22
export ANSIBLE_TIMEOUT=10

# Performance
export ANSIBLE_FORKS=50
export ANSIBLE_GATHERING=smart
export ANSIBLE_CACHE_PLUGIN=jsonfile
export ANSIBLE_CACHE_PLUGIN_CONNECTION=/tmp/facts_cache
export ANSIBLE_CACHE_PLUGIN_TIMEOUT=86400

# Pipelining (requires requiretty disabled)
export ANSIBLE_PIPELINING=True
export ANSIBLE_SSH_PIPELINING=True

# Inventory
export ANSIBLE_INVENTORY=/path/to/inventory
export ANSIBLE_INVENTORY_ENABLED=host_list,script,auto,yaml,ini

# Output and logging
export ANSIBLE_STDOUT_CALLBACK=yaml
export ANSIBLE_LOG_PATH=/var/log/ansible.log
export ANSIBLE_DISPLAY_SKIPPED_HOSTS=False
export ANSIBLE_DISPLAY_OK_HOSTS=True
export ANSIBLE_CALLBACK_WHITELIST=timer,profile_tasks

# Privilege escalation
export ANSIBLE_BECOME=True
export ANSIBLE_BECOME_METHOD=sudo
export ANSIBLE_BECOME_USER=root
export ANSIBLE_BECOME_ASK_PASS=False

# Python interpreter
export ANSIBLE_PYTHON_INTERPRETER=/usr/bin/python3

# Vault
export ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass
export ANSIBLE_VAULT_IDENTITY_LIST=dev@~/.vault_dev,prod@~/.vault_prod

# Roles and collections
export ANSIBLE_ROLES_PATH=./roles:/usr/share/ansible/roles
export ANSIBLE_COLLECTIONS_PATH=./collections:~/.ansible/collections

# Module paths
export ANSIBLE_LIBRARY=/usr/share/ansible/modules
export ANSIBLE_MODULE_UTILS=/usr/share/ansible/module_utils

# Plugin paths
export ANSIBLE_ACTION_PLUGINS=/path/to/action_plugins
export ANSIBLE_CALLBACK_PLUGINS=/path/to/callback_plugins
export ANSIBLE_CONNECTION_PLUGINS=/path/to/connection_plugins
export ANSIBLE_FILTER_PLUGINS=/path/to/filter_plugins
export ANSIBLE_LOOKUP_PLUGINS=/path/to/lookup_plugins
export ANSIBLE_TEST_PLUGINS=/path/to/test_plugins

# Error handling
export ANSIBLE_RETRY_FILES_ENABLED=False
export ANSIBLE_ANY_ERRORS_FATAL=False

# Debugging
export ANSIBLE_DEBUG=False
export ANSIBLE_VERBOSE_TO_STDERR=False

# Miscellaneous
export ANSIBLE_NOCOWS=1
export ANSIBLE_NOCOLOR=0
export ANSIBLE_FORCE_COLOR=0
export ANSIBLE_DEPRECATION_WARNINGS=True
export ANSIBLE_COMMAND_WARNINGS=True

Setting Environment Variables Temporarily

# For a single command
ANSIBLE_FORKS=50 ansible-playbook playbook.yml

# For current shell session
export ANSIBLE_FORKS=50
ansible-playbook playbook.yml

# In playbook
- name: Set environment for tasks
  hosts: all
  environment:
    ANSIBLE_DEBUG: True
  tasks:
    - name: Debug task
      debug:
        msg: "Debugging enabled"

Configuration Examples

Development Environment

[defaults]
inventory = ./inventory/dev
roles_path = ./roles
collections_path = ./collections

# Speed up development with these settings
host_key_checking = False
gathering = explicit  # Don't gather facts unless needed
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_dev
retry_files_enabled = False

# Verbose output for debugging
stdout_callback = yaml
display_skipped_hosts = False
callbacks_enabled = timer, profile_tasks

# Performance
forks = 10
timeout = 10

# Python
interpreter_python = auto_silent

[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 -o StrictHostKeyChecking=no

Production Environment

[defaults]
inventory = /etc/ansible/inventory/production
roles_path = /etc/ansible/roles:/usr/share/ansible/roles
collections_path = /etc/ansible/collections

# Security
host_key_checking = True
private_key_file = /etc/ansible/.ssh/ansible_rsa

# Performance optimization
forks = 50
gathering = smart
fact_caching = redis
fact_caching_connection = localhost:6379:0
fact_caching_timeout = 3600

# Logging
log_path = /var/log/ansible/ansible.log
display_skipped_hosts = False
display_ok_hosts = False

# Error handling
retry_files_enabled = True
retry_files_save_path = /var/log/ansible/retries/
any_errors_fatal = False

# Callbacks for monitoring
callbacks_enabled = timer, profile_tasks, profile_roles, log_plays

# Output
stdout_callback = default
bin_ansible_callbacks = True

# Python
interpreter_python = /usr/bin/python3

# Vault
vault_identity_list = prod@/etc/ansible/.vault_pass_prod

[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=3600s
control_path = /tmp/ansible-ssh-%%h-%%p-%%r
scp_if_ssh = smart
transfer_method = smart
retries = 5
timeout = 30

High-Performance Configuration

[defaults]
# Maximize parallelism
forks = 100
strategy = free  # Don't wait for all hosts between tasks

# Optimize fact gathering
gathering = smart
fact_caching = redis
fact_caching_connection = localhost:6379:0
fact_caching_timeout = 86400

# Minimal output
stdout_callback = minimal
display_skipped_hosts = False
display_ok_hosts = False

# No retry files
retry_files_enabled = False

# Performance callbacks
callbacks_enabled = profile_tasks, profile_roles

[ssh_connection]
# Enable pipelining (biggest performance boost)
pipelining = True

# Optimize SSH multiplexing
ssh_args = -o ControlMaster=auto -o ControlPersist=3600s -o PreferredAuthentications=publickey
control_path = %(directory)s/ssh-%%C

# Use SFTP for file transfers
transfer_method = sftp
sftp_batch_mode = True

# Connection pooling
retries = 3
timeout = 30

Security-Focused Configuration

[defaults]
# Strict security
host_key_checking = True
private_key_file = /secure/path/ansible_rsa

# Logging and audit trail
log_path = /var/log/ansible/ansible.log
callbacks_enabled = log_plays, syslog

# No caching of sensitive data
fact_caching = memory
gathering = explicit

# Vault for all secrets
vault_identity_list = main@/secure/path/.vault_pass

# No retry files (may contain sensitive data)
retry_files_enabled = False

# Strict variable handling
hash_behaviour = replace
inject_facts_as_vars = False

[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = True  # Always prompt for password

[ssh_connection]
# Secure SSH settings
ssh_args = -o StrictHostKeyChecking=yes -o UserKnownHostsFile=/etc/ansible/known_hosts
pipelining = False  # Disabled if requiretty is enforced
timeout = 10
retries = 1

Per-Project Configuration

Project Directory Structure

project/
├── ansible.cfg           # Project-specific configuration
├── inventory/
│   ├── production
│   ├── staging
│   └── development
├── group_vars/
├── host_vars/
├── roles/
├── collections/
└── playbooks/

# ansible.cfg in project root
[defaults]
inventory = ./inventory
roles_path = ./roles
collections_path = ./collections
retry_files_enabled = False
host_key_checking = False

Environment-Specific Configs

# Run with specific config file
ansible-playbook -c ./configs/ansible-dev.cfg playbook.yml
ANSIBLE_CONFIG=./configs/ansible-prod.cfg ansible-playbook playbook.yml

# configs/ansible-dev.cfg
[defaults]
inventory = ./inventory/dev
forks = 10
gathering = explicit

# configs/ansible-prod.cfg
[defaults]
inventory = ./inventory/prod
forks = 50
gathering = smart

Debugging Configuration Issues

Troubleshooting Commands

# Show active configuration
ansible-config dump --only-changed

# Test configuration
ansible --version
ansible-config view

# Verify inventory configuration
ansible-inventory --list
ansible-inventory --graph

# Test connection with configuration
ansible all -m ping -vvv

# Check specific setting
ansible-config dump | grep forks

# Validate configuration file
ansible-config view -c ./ansible.cfg

# Show all settings and their origins
ansible-config dump -v

# List all configuration options
ansible-config list | less

Common Configuration Problems

Common Issues:
  • Wrong config file loaded: Check with ansible --version
  • Pipelining not working: Disable requiretty in /etc/sudoers
  • SSH key issues: Verify private_key_file path and permissions
  • Slow performance: Increase forks, enable pipelining, use fact caching
  • Permission denied: Check become settings and SSH user
  • Module not found: Verify library and plugin paths
  • Fact caching not working: Check cache plugin connection and timeout

Best Practices

Configuration Best Practices:
  • Use project-local configs: Keep ansible.cfg in project root
  • Version control: Commit ansible.cfg to git (except sensitive data)
  • Document settings: Add comments explaining non-obvious settings
  • Environment-specific: Use different configs for dev/staging/prod
  • Test changes: Always test configuration changes in dev first
  • Security first: Enable host_key_checking in production
  • Optimize gradually: Start with defaults, tune based on needs
  • Monitor performance: Use timer and profile_tasks callbacks
  • Keep it simple: Only change settings you understand
  • Regular reviews: Periodically review and update configuration

Next Steps