Ansible for the Modern Sysadmin: Installation, Configuration,Vaults and Automation.
Ansible is a powerful automation and orchestration tool that lets you manage servers consistently and securely over SSH. This guide explains what Ansible is, why it matters, and how to structure a clean, real-world Ansible project.
Ansible is an open-source automation platform designed to simplify IT operations at scale. It enables system administrators and engineers to manage configuration, deploy applications, and orchestrate infrastructure using clear, human-readable code. By eliminating manual, repetitive tasks, Ansible ensures consistency and reduces errors while allowing teams to manage hosts seamlessly, whether they are located in the same data center or distributed worldwide across regions such as the United States, Japan, and beyond.
This tutorial introduces Ansible from a system administrator's perspective. We will cover what Ansible is, why it is used, how orchestration works, and how to build a minimal but correct project using secure SSH access and Ansible Vault.
A simple two-host study case will tie everything together.
What is Ansible?
Ansible is an open-source automation platform built to streamline and standardize IT operations at scale. It allows system administrators and engineers to manage configuration, deploy applications, and orchestrate infrastructure using simple, human-readable code. You define the desired system state in YAML files called playbooks and apply them to remote hosts over SSH. By replacing manual and repetitive tasks with automation, Ansible improves consistency, reduces operational risk, and enables teams to manage hosts efficiently—whether they reside in a single data center or are distributed globally across regions such as the United States, Japan, and beyond.
Key characteristics:
- Agentless (no agent or additional software is required on managed hosts; Ansible connects remotely using SSH)
- Uses SSH
- Declarative, not procedural (you tell Ansible what the system should be, and it figures out how to get there.)
- Designed for simplicity and readability
Why Use Ansible?
Ansible is commonly used to:
- Provision servers – set up new machines automatically.
- Configure operating systems and applications – ensure software and settings are consistent.
- Enforce security baselines – apply and maintain security policies across hosts.
- Deploy applications – install or update software reliably.
- Orchestrate multi-host workflows – coordinate tasks across multiple servers in the correct order.
Advantages (Pros)
- Agentless: Nothing to install on target hosts
- Idempotent: Safe to run repeatedly
- Simple syntax: YAML is easy to read and review
- Secure: Native support for secrets via Ansible Vault
- Scalable: Works for 2 servers or 2,000
- Extensible: Large ecosystem of modules and roles
Ansible and Orchestration
Orchestration goes beyond configuration management. It involves coordinating actions across multiple systems in the correct order.
With Ansible, orchestration can include:
- Updating development servers before production
- Restarting services only when configurations change
- Running database migrations before application restarts
- Managing dependencies between hosts and roles
Ansible playbooks make orchestration simple by clearly defining which hosts to act on, in what order, and under what conditions tasks should run. This ensures complex workflows are executed reliably and consistently across your infrastructure.
Ensuring Ansible Is Fully Installed
(Including Vault)
Ansible Vault is included by default with Ansible packages.
The key is ensuring a recent and complete installation.
1. Install Ansible (Controller)
macOS
$ brew update
$ brew install ansible
Ubuntu (Server)
$ sudo apt update
$ sudo apt install -y ansible
Verify:
ansible --version
ansible-vault --version
2. Create SSH Key Pair (Controller)
Create multiple hosts with different keys for clarity.
# For host.1 (development):
ssh-keygen -t ed25519 -f ~/.ssh/host.1_id -N "" -C "ansible-host_1"
# For host.2 (production):
ssh-keygen -t ed25519 -f ~/.ssh/host.2_id -N "" -C "ansible-host_2"- Passphrase: NO (convenience)
What it does:
- Creates SSH keypair using modern ed25519 algorithm
- Saves as:
~/.ssh/host.1_id(private key - keep secret)~/.ssh/host.1_id.pub(public key - share)-N ""passphrase:NO (convenience)
- Labels it with comment "ansible-host_1" for identification
For Ansible: Use this key for automation instead of your personal SSH key. More secure to revoke/rotate.
Result:
~/.ssh/host.1_id
~/.ssh/host.1_id.pub
Set permissions (very important):
$ chmod 600 ~/.ssh/host.1_id
$ chmod 644 ~/.ssh/host.1_id.pub
3. Copy SSH Key to Target Hosts
Run once per host:
$ ssh-copy-id -i ~/.ssh/host.1_id.pub -p 1024 user@192.168.1.10
$ ssh-copy-id -i ~/.ssh/host.2_id.pub -p 1025 user@192.168.1.11
Verify manual SSH:
$ ssh -i ~/.ssh/host.1_id -p 1024 user@192.168.1.10
$ ssh -i ~/.ssh/host.2_id -p 1025 user@192.168.1.11
You should be able to log in without a password.
If this fails, Ansible will not be able to connect and playbooks will fail.
Action: Fix SSH access first—ensure the private key matches the public key on the host and that permissions are correct (chmod 600 ~/.ssh/host.1_id).
4. Project Layout (Minimal but Correct)
Here's a canonical, well-structured form:
~/ansible-projects/
├── ansible.cfg
├── inventories/
│ └── hosts
├── playbooks/
├── roles/
└── group_vars/
└── all/
└── vault.yml
5. Configure ansible.cfg
This avoids typing flags repeatedly.ansible.cfg with detailed comments on each line:
# MAIN DEFAULT SETTINGS SECTION
[defaults]
# Where to find your inventory files
inventory = inventories/
# Where Ansible looks for roles
roles_path = roles/
# Where Ansible looks for collections
collections_path = collections/
# Don't ask to verify new SSH host keys (useful for automation)
host_key_checking = False
# Don't create .retry files when playbooks fail
retry_files_enabled = False
# Default output format (human-readable)
stdout_callback = default
# How to format results (yaml is clean and readable)
result_format = yaml
# Hide annoying deprecation warnings
deprecation_warnings = False
# Automatically find Python on target hosts
interpreter_python = auto_silent
# Enable useful callbacks: profile_tasks shows timing, timer adds total time
callback_whitelist = profile_tasks, timer
# Enable callbacks even for ansible binaries (ansible, ansible-playbook, etc)
bin_ansible_callbacks = True
# Add this to [defaults] for better security:
# force_handlers = True # Always run handlers even on failure
# error_on_undefined_vars = True # Catch typos in variable names
# PRIVILEGE ESCALATION SECTION (sudo/root access)
[privilege_escalation]
# Automatically use 'become' (sudo) for all tasks
become = True
# How to become root: sudo, su, doas, etc.
become_method = sudo
# Which user to become (usually root)
become_user = root
# Don't prompt for sudo password (assumes passwordless sudo or SSH key)
become_ask_pass = False
# INVENTORY PLUGIN CONFIGURATION
[inventory]
# Which inventory plugins to enable
enable_plugins = ini, yaml, toml
# - ini: Traditional .ini files (most common)
# - yaml: YAML format inventory
# - toml: TOML format inventory
# PERSISTENT SSH CONNECTIONS (performance optimization)
[persistent_connection]
# How long to wait for SSH connection (seconds)
connect_timeout = 30
# How long to wait for command to complete (seconds)
command_timeout = 60
# SSH CONNECTION OPTIMIZATIONS
[ssh_connection]
# SSH arguments for better performance:
# - ControlMaster: Reuse SSH connections (massive speedup)
# - ControlPersist: Keep connection alive for 60 seconds
# - ServerAliveInterval: Send keepalive every 30 seconds
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ServerAliveInterval=30
# Where to store SSH control socket files (unique per host/user/port)
control_path = ~/.ssh/ansible-%%r@%%h:%%p
# %%r = remote username
# %%h = host
# %%p = port
# Add this to [ssh_connection] for MacOS:
# pipelining = True # Faster execution (reduces SSH roundtrips)
# scp_if_ssh = True # Use SCP for file transfers when possibleVerify Ansible is using it:
$ ansible --version
You should see:
config file = /Users/.../ansible-projects/ansible.cfg
6. Define Inventory (SSH-Aware)
inventories/hosts
# SECTION: VARIABLES FOR ALL HOSTS
[all:vars]
# Tell Ansible to use Python 3 on ALL target servers
# Default would be /usr/bin/python (Python 2)
ansible_python_interpreter = /usr/bin/python3
# SECTION: DEVELOPMENT ENVIRONMENT HOSTS
[development]
# Development server named "host.1"
# Real IP: 192.168.1.10, SSH port: 1024 (not default 22)
host.1 ansible_host=192.168.1.10 ansible_port=1024
# SECTION: PRODUCTION ENVIRONMENT HOSTS
[production]
# Production server named "host.2"
# Real IP: 192.168.1.11, SSH port: 1025 (different from dev)
host.2 ansible_host=192.168.1.11 ansible_port=1025
# ELLIPSIS: Could add more hosts here...
...
..
.No SSH details here. Inventory stays clean.
Check inventory structure:
$ ansible-inventory --graph
out:
# @all:
# |--@development:
# | |--host.1
# |--@production:
# | |--host.2
# |--@webservers:
# | |--@development:
# | |--@production:
#
#
#
#7. Ansible Vault (Store SSH Details Securely)
Ansible Vault is a security feature in Ansible that let you encrypt sensitive information such as passwords, API tokens, or SSH keys, so they can be stored in your playbooks and inventories without exposing them in plain text, while still being usable during automation runs.
Create Vault for Each Host
host.1
$ mkdir -p inventories/host_vars/host.1
$ ansible-vault create inventories/host_vars/host.1/vault.yml
vault.yml
add
ansible_user: host.1
ansible_ssh_private_key_file: ~/.ssh/host.1_id
ansible_port: 1024
ansible_become_password: "STRONG_PASSWORD_HERE"
*Always use quotes for passwords.
host.2
$ mkdir -p inventories/host_vars/host.2
$ ansible-vault create inventories/host_vars/host.2/vault.yml
vault.yml
add
ansible_user: host.2
ansible_ssh_private_key_file: /Users/yannickcoffi/.ssh/host.2_id
ansible_port: 1025
ansible_become_password: "STRONG_PASSWORD_HERE"
*Always use quotes for passwords.
Each host now has:
- Its own SSH key
- Its own port
- Its own sudo password
- All encrypted
8. Test Connection (Verbose Debug)
Test one host at a time:
# Test octopus specifically
ansible host.1 -m ping --ask-vault-pass -vvv
# Test all production hosts
ansible host.2 -m ping --ask-vault-pass -vvv
# Test all hosts
ansible all -m ping --ask-vault-pass -vvv--ask-vault-pass ="Ask For Locker Password" 🔑
Basically prompts you: "Hey, what's the password to unlock your vault/secrets?"
-vvv = DEBUG MODE - connection details
Expected:
host.1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
host.2 | SUCCESS => {
"changed": false,
"ping": "pong"
}9. Useful ANSIBLE Commands
ansible all --list-hosts -i inventories/hosts --ask-vault-pass
WHAT IT DOES:
"Show me ALL hosts in my inventory, but first unlock the vault"
hosts (2):
host.1
host.2ansible-inventory -i inventories/hosts --list --ask-vault-pass
WHAT IT DOES:
"Show me EVERYTHING about my inventory - hosts, groups, variables"
{
"all": {
"children": ["development", "production", "webservers"]
},
"development": {
"hosts": ["host.1"],
"vars": {"ansible_port": 1024}
},
"production": {
"hosts": ["host.2"],
"vars": {"ansible_port": 1025}
}
}ansible all -a "date" --ask-vault-pass
WHAT IT DOES:
"Run the date command on ALL my servers"
host.1 | CHANGED | rc=0 >>
SAT Jan 3 22:30:45 UTC 2026
host.2 | CHANGED | rc=0 >>
SAT Jan 3 22:30:45 UTC 2026Ansible ad-hoc commands
ansible all -a "uptime" --ask-vault-pass
WHAT IT DOES:
"Run the uptime command on ALL my servers"
host.1 | CHANGED | rc=0 >>
22:31:10 up 15 days, 3:12, 1 user, load average: 0.08, 0.03, 0.01
host.2 | CHANGED | rc=0 >>
22:31:11 up 7 days, 1:45, 2 users, load average: 1.50, 1.25, 1.10ansible all -a "setup" --ask-vault-pass
WHAT IT DOES:
"Collect ALL information about ALL my servers"
Example Oput: *MASSIVE - shows 100+ lines per server
host.1 | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "Ubuntu",
"ansible_distribution_version": "22.04",
"ansible_memory_mb": {
"total": 4096,
"free": 2048
},
"ansible_processor": ["Intel Xeon"],
"ansible_all_ipv4_addresses": ["192.168.1.10"],
"ansible_devices": {
"sda": {"size": "50G"},
"sdb": {"size": "100G"}
}
// ... 100+ more facts!
}
}TELLS YOU EVERYTHING ABOUT SERVER:
- OS version
- Memory/RAM
- CPU/processors
- Disk space
- Network IPs
- Installed packages
- ...and much more!
Setting up Ansible gives you a solid foundation for consistent, repeatable, and secure system management. By properly structuring inventories and handling credentials—such as with Ansible Vault—you gain better visibility and control over changes while reducing operational risk. Once in place, Ansible makes automation predictable, scalable, and far easier to maintain over time.
This guide focused on core concepts and hands-on examples to help you get started quickly. For anything beyond that, the official Ansible documentation at https://docs.ansible.com remains the authoritative reference. Good documentation is the backbone of Ansible and a daily resource in real-world environments—even for experienced teams.
We hope this post helps you take control of your infrastructure with confidence. Stay tuned for upcoming articles where we’ll dive deeper into more advanced techniques for automating, managing, and scaling systems with Ansible.