Introduction

The ansible.cfg file is Ansible's primary configuration file, controlling everything from SSH connection behavior to module paths and output formatting. One of the most impactful recent changes affecting Ansible users is the deprecation of the SCP protocol in OpenSSH 9.0 (shipped with RHEL 9, Ubuntu 22.04+, and Fedora 36+). If your playbooks suddenly fail with file transfer errors after an OS upgrade, this is likely the cause.

This guide covers the ansible.cfg SSH settings you need to understand, how to handle the SCP deprecation, and best practices for optimal SSH performance.

ansible.cfg File Locations

Ansible searches for configuration in this order (first found wins):

  1. ANSIBLE_CONFIG environment variable
  2. ./ansible.cfg (current directory)
  3. ~/.ansible.cfg (home directory)
  4. /etc/ansible/ansible.cfg (global)

Best practice: Keep ansible.cfg in your project directory alongside your playbooks and commit it to version control.

# Check which config file Ansible is using
ansible --version | grep "config file"

The SCP Deprecation in OpenSSH 9.0

What Changed

Starting with OpenSSH 9.0 (RHEL 9, Ubuntu 22.04+):

  • The scp command now uses SFTP protocol internally by default
  • The legacy SCP protocol can be restored with the -O flag
  • Future OpenSSH releases will remove SCP protocol support entirely

Impact on Ansible

Ansible uses file transfer for modules, facts, and the copy/fetch/template modules. If your ansible.cfg explicitly set transfer_method = scp, file transfers may fail on systems running OpenSSH 9.0+:

fatal: [host]: FAILED! => {"msg": "scp transfer failed"}

The Fix

Option 1: Use SFTP (Recommended)

Remove any explicit transfer_method setting or set it to smart:

[ssh_connection]
transfer_method = smart

The smart method (default) tries SFTP first, then falls back to SCP. This works on both old and new OpenSSH versions.

Option 2: Keep SCP with -O flag (Temporary)

If you must use SCP (e.g., for compatibility with very old systems):

[ssh_connection]
transfer_method = scp
scp_extra_args = -O

The -O flag forces the legacy SCP protocol. However, this is a temporary solution — the -O flag may be removed in future OpenSSH releases.

Option 3: Force SFTP only

[ssh_connection]
transfer_method = sftp

Complete ansible.cfg Reference for SSH

[defaults]
# Number of parallel processes
forks = 20
# Default connection type
transport = ssh
# Disable host key checking (use with caution)
host_key_checking = False
# Timeout for SSH connection
timeout = 30

[ssh_connection]
# SSH arguments for ControlMaster multiplexing
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no

# File transfer method: smart (default), sftp, scp
transfer_method = smart

# Enable pipelining (significant performance improvement)
pipelining = True

# Extra arguments for SCP (if using SCP transfer)
scp_extra_args = -O

# Extra arguments for SFTP
sftp_extra_args =

# Extra arguments for SSH
ssh_extra_args =

# ControlPath for SSH multiplexing
control_path_dir = /tmp/.ansible/cp
control_path = %(directory)s/%%h-%%r-%%p

# Retries for SSH connections
retries = 3

Key Settings Explained

ssh_args and ControlMaster

ssh_args = -o ControlMaster=auto -o ControlPersist=60s
  • ControlMaster=auto: Enables SSH connection multiplexing — the first SSH connection to a host creates a control socket, and subsequent connections reuse it
  • ControlPersist=60s: Keeps the control socket alive for 60 seconds after the last connection closes

This dramatically reduces SSH handshake overhead when running multiple tasks against the same host.

pipelining

pipelining = True

When enabled, Ansible sends the module code through the SSH pipe instead of copying it as a file. This eliminates one SFTP/SCP transfer per task, significantly improving performance.

Requirement: The remote user must not have requiretty set in /etc/sudoers. Check with:

grep requiretty /etc/sudoers

If found, comment it out or add an exception:

Defaults:ansible_user !requiretty

transfer_method

ValueBehavior
smartTry SFTP first, fall back to SCP (default, recommended)
sftpUse SFTP only
scpUse SCP only (requires -O on OpenSSH 9.0+)

forks

forks = 20

Controls how many hosts Ansible manages in parallel. Default is 5, which is conservative. For large inventories, increase to 20-50 depending on your control node's resources.

Performance-Optimized ansible.cfg

A production-ready configuration for maximum SSH performance:

[defaults]
forks = 30
host_key_checking = False
timeout = 30
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts
fact_caching_timeout = 3600
stdout_callback = yaml

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=600s -o PreferredAuthentications=publickey
transfer_method = smart
pipelining = True
control_path_dir = /tmp/.ansible/cp
retries = 3

Key improvements:

  • ControlPersist=600s: 10-minute persistence for long playbook runs
  • PreferredAuthentications=publickey: Skip password auth attempts
  • pipelining=True: Major speed improvement
  • fact_caching: Cache facts for 1 hour to skip repeated gathering

Environment-Specific Configurations

Development

[defaults]
forks = 5
host_key_checking = False
deprecation_warnings = True
stdout_callback = debug

Production

[defaults]
forks = 30
host_key_checking = True
log_path = /var/log/ansible/ansible.log
no_log = True
stdout_callback = yaml

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=600s -o StrictHostKeyChecking=yes
pipelining = True
retries = 3

Network Devices

[defaults]
forks = 10
timeout = 60

[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o KexAlgorithms=+diffie-hellman-group14-sha1
pipelining = False  # Often required for network devices

CVE-2020-15778: SCP Vulnerability

The SCP protocol has known security vulnerabilities. CVE-2020-15778 allows remote code execution through crafted file names during SCP transfers. This is one of the primary reasons OpenSSH deprecated SCP:

# Vulnerable: SCP protocol
transfer_method = scp

# Secure: SFTP protocol
transfer_method = sftp

Recommendation: Always use SFTP unless you have a specific compatibility requirement.

Troubleshooting SSH Issues

Connection Timeout

[defaults]
timeout = 60  # Increase from default 10

[ssh_connection]
ssh_args = -o ConnectTimeout=30 -o ServerAliveInterval=15 -o ServerAliveCountMax=3

SSH Key Issues

# Test SSH connection manually
ssh -vvv user@host

# Specify key in ansible.cfg
[defaults]
private_key_file = ~/.ssh/ansible_key

ControlMaster Socket Errors

If you see stale socket errors:

# Clean up stale control sockets
rm -rf /tmp/.ansible/cp/*

Conclusion

The ansible.cfg file is the control center for Ansible's behavior, and getting SSH settings right is critical for both performance and security. With the SCP deprecation in OpenSSH 9.0+, the key takeaway is: use transfer_method = smart (or sftp), enable pipelining, and configure ControlMaster for connection multiplexing. These three settings alone can cut playbook execution time by 50% or more while keeping your file transfers secure.