Skip to main content

Installation & Setup

Installation Methods

# Install Ansible
pip install ansible

# Upgrade Ansible
pip install --upgrade ansible

# Install specific version
pip install ansible==6.0.0

# Install with additional collections
pip install ansible[azure,aws,gcp]

Using Package Managers

Ubuntu/Debian

# Update package index
sudo apt update

# Install software-properties-common
sudo apt install software-properties-common

# Add Ansible PPA
sudo add-apt-repository --yes --update ppa:ansible/ansible

# Install Ansible
sudo apt install ansible

CentOS/RHEL/Fedora

# CentOS/RHEL 8
sudo dnf install epel-release
sudo dnf install ansible

# CentOS/RHEL 7
sudo yum install epel-release
sudo yum install ansible

# Fedora
sudo dnf install ansible

macOS

# Using Homebrew
brew install ansible

# Using MacPorts
sudo port install py39-ansible

Using Docker

# Pull Ansible image
docker pull ansible/ansible

# Run Ansible in container
docker run -it --rm -v $(pwd):/ansible ansible/ansible

# Create alias for easier use
alias ansible-docker='docker run -it --rm -v $(pwd):/ansible ansible/ansible'

Initial Configuration

Configuration File Locations

# System-wide configuration
/etc/ansible/ansible.cfg

# User-specific configuration
~/.ansible.cfg

# Project-specific configuration
./ansible.cfg

# Check current configuration
ansible-config view
ansible-config dump

Basic ansible.cfg

[defaults]
# Inventory file location
inventory = ./inventory

# Default user for SSH connections
remote_user = ansible

# SSH key file
private_key_file = ~/.ssh/id_rsa

# Disable SSH key checking
host_key_checking = False

# Default module path
library = /usr/share/ansible

# Roles path
roles_path = ./roles

# Retry files
retry_files_enabled = False

# Gathering facts
gathering = smart
fact_caching = memory

# Logging
log_path = ./ansible.log

# Output format
stdout_callback = yaml
bin_ansible_callbacks = True

[ssh_connection]
# SSH timeout
timeout = 30

# SSH retries
retries = 3

# Pipelining (faster execution)
pipelining = True

# Control persist
control_path = ~/.ansible/cp/ansible-ssh-%%h-%%p-%%r

Environment Variables

# Configuration file
export ANSIBLE_CONFIG=./ansible.cfg

# Inventory file
export ANSIBLE_INVENTORY=./inventory

# Roles path
export ANSIBLE_ROLES_PATH=./roles

# Library path
export ANSIBLE_LIBRARY=./library

# SSH args
export ANSIBLE_SSH_ARGS='-o ControlMaster=auto -o ControlPersist=60s'

# Disable host key checking
export ANSIBLE_HOST_KEY_CHECKING=False

# Remote user
export ANSIBLE_REMOTE_USER=ansible

# Become user
export ANSIBLE_BECOME_USER=root

# Logging
export ANSIBLE_LOG_PATH=./ansible.log

SSH Configuration

SSH Key Setup

# Generate SSH key
ssh-keygen -t rsa -b 4096 -C "ansible@example.com"

# Copy public key to target hosts
ssh-copy-id -i ~/.ssh/id_rsa.pub user@target-host

# Add key to SSH agent
ssh-add ~/.ssh/id_rsa

# Test SSH connection
ssh user@target-host

SSH Config File

# ~/.ssh/config
Host ansible-host-*
User ansible
IdentityFile ~/.ssh/ansible_key
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
ControlMaster auto
ControlPath ~/.ssh/ansible-%r@%h:%p
ControlPersist 60s

Host production-*
User root
IdentityFile ~/.ssh/production_key
Port 2222

Host staging-*
User deploy
IdentityFile ~/.ssh/staging_key
ProxyJump bastion-host

SSH with Bastion/Jump Host

# SSH config for bastion
Host bastion
HostName bastion.example.com
User bastion-user
IdentityFile ~/.ssh/bastion_key

Host production-server
HostName 10.0.1.100
User ansible
IdentityFile ~/.ssh/production_key
ProxyJump bastion

User Management

Create Ansible User

# Create ansible user on target hosts
sudo useradd -m -s /bin/bash ansible

# Add to sudo group
sudo usermod -aG sudo ansible

# Set up passwordless sudo
echo "ansible ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ansible

# Set up SSH key
sudo -u ansible mkdir -p /home/ansible/.ssh
sudo -u ansible touch /home/ansible/.ssh/authorized_keys
sudo -u ansible chmod 700 /home/ansible/.ssh
sudo -u ansible chmod 600 /home/ansible/.ssh/authorized_keys

# Add public key
echo "ssh-rsa AAAAB3NzaC1yc2E... ansible@controller" | sudo -u ansible tee -a /home/ansible/.ssh/authorized_keys

Ansible User Playbook

---
- name: Setup Ansible user
hosts: all
become: yes
vars:
ansible_user: ansible
ansible_ssh_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"

tasks:
- name: Create ansible user
user:
name: '{{ ansible_user }}'
group: '{{ ansible_user }}'
createhome: yes
shell: /bin/bash
state: present

- name: Add ansible user to sudo group
user:
name: '{{ ansible_user }}'
groups: sudo
append: yes

- name: Set up passwordless sudo
lineinfile:
path: /etc/sudoers.d/ansible
line: '{{ ansible_user }} ALL=(ALL) NOPASSWD:ALL'
create: yes
validate: 'visudo -cf %s'

- name: Create .ssh directory
file:
path: '/home/{{ ansible_user }}/.ssh'
state: directory
owner: '{{ ansible_user }}'
group: '{{ ansible_user }}'
mode: '0700'

- name: Add SSH key
authorized_key:
user: '{{ ansible_user }}'
key: '{{ ansible_ssh_key }}'
state: present

Testing Installation

Basic Tests

# Check Ansible version
ansible --version

# Test local connection
ansible localhost -m ping

# Test inventory
ansible-inventory --list

# Test configuration
ansible-config dump --only-changed

Connection Tests

# Test all hosts
ansible all -m ping

# Test specific host
ansible webservers -m ping -i inventory

# Test with different user
ansible all -m ping -u ansible

# Test with become
ansible all -m ping -b

# Test with custom key
ansible all -m ping --private-key ~/.ssh/custom_key

Directory Structure

Project Structure

ansible-project/
├── ansible.cfg
├── inventory/
│ ├── production
│ ├── staging
│ └── group_vars/
│ ├── all.yml
│ ├── webservers.yml
│ └── databases.yml
├── playbooks/
│ ├── site.yml
│ ├── deploy.yml
│ └── maintenance.yml
├── roles/
│ ├── common/
│ ├── webserver/
│ └── database/
├── files/
├── templates/
├── vars/
└── vault/

Best Practices Structure

project/
├── ansible.cfg
├── requirements.yml
├── inventories/
│ ├── production/
│ │ ├── hosts
│ │ └── group_vars/
│ └── staging/
│ ├── hosts
│ └── group_vars/
├── playbooks/
│ ├── site.yml
│ ├── common.yml
│ └── roles/
│ ├── requirements.yml
│ └── internal/
├── collections/
└── logs/

Troubleshooting

Common Issues

# SSH connection issues
ansible all -m ping -vvv

# Permission denied
ansible all -m ping -u root --ask-pass

# Host key verification failed
export ANSIBLE_HOST_KEY_CHECKING=False

# Module not found
ansible-galaxy collection install community.general

# Python interpreter issues
ansible all -m ping -e ansible_python_interpreter=/usr/bin/python3

Debug Commands

# Verbose output
ansible-playbook playbook.yml -v
ansible-playbook playbook.yml -vv
ansible-playbook playbook.yml -vvv

# Dry run
ansible-playbook playbook.yml --check

# Show differences
ansible-playbook playbook.yml --check --diff

# Step through playbook
ansible-playbook playbook.yml --step

# Start from specific task
ansible-playbook playbook.yml --start-at-task="Task name"

Log Configuration

# ansible.cfg
[defaults]
log_path = /var/log/ansible.log
display_skipped_hosts = False
display_ok_hosts = False

# Custom callback plugins
stdout_callback = yaml
callback_whitelist = profile_tasks, timer

Security Considerations

SSH Security

# Disable SSH password authentication
# /etc/ssh/sshd_config
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin no

# Use SSH agent forwarding carefully
ForwardAgent no

# Restrict SSH access
AllowUsers ansible

File Permissions

# Secure private keys
chmod 600 ~/.ssh/id_rsa

# Secure ansible.cfg
chmod 600 ansible.cfg

# Secure inventory files
chmod 600 inventory/*

# Secure vault files
chmod 600 vault/*

Network Security

# Use jump hosts for production
# ansible.cfg
[ssh_connection]
ssh_args = -o ProxyJump=bastion-host

# Use VPN for remote access
# Custom SSH config for VPN
Host vpn-*
ProxyCommand nc -X connect -x vpn-proxy:1080 %h %p

Performance Optimization

Parallelism

# ansible.cfg
[defaults]
forks = 20
host_key_checking = False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 3600

[ssh_connection]
pipelining = True
control_path = ~/.ansible/cp/ansible-ssh-%%h-%%p-%%r

Fact Caching

# Redis fact caching
[defaults]
fact_caching = redis
fact_caching_connection = localhost:6379:0
fact_caching_timeout = 3600

# JSON file caching
[defaults]
fact_caching = jsonfile
fact_caching_connection = /tmp/ansible_facts_cache
fact_caching_timeout = 3600

Connection Optimization

# Use persistent connections
[ssh_connection]
pipelining = True
control_path = ~/.ansible/cp/ansible-ssh-%%h-%%p-%%r
control_path_dir = ~/.ansible/cp

# SSH multiplexing
ssh_args = -o ControlMaster=auto -o ControlPersist=60s