Server Management (Unmanaged)

Mastering Ansible: A Comprehensive Step-by-Step Guide

By the Domain India teamPublished 10 min read
Knowledge base article
Contents (10 sections)

Ansible is an open-source automation tool that configures servers, deploys applications and runs repeatable maintenance from one machine, over plain SSH. You describe the state you want in YAML, and Ansible makes each server match it. This guide takes you from installation to inventories, playbooks, variables, roles and Vault, using current Ansible practice for 2026.

Key takeaways

Install Ansible on your own computer or a management server (with pipx install --include-deps ansible), list your servers in an inventory, and check the connection with ansible all -m ping. Write playbooks in YAML using fully qualified module names such as ansible.builtin.dnf, keep secrets in Ansible Vault, and always run --check --diff before a real change. Ansible needs root or sudo on the target, so it is for your own VPS or server, not for shared hosting.

This guide is for servers you control

Ansible installs packages and edits system files, which needs root or sudo on each target server. Use it on your own VPS or dedicated server. On shared hosting you cannot change server configuration, so Ansible has nothing to manage there.

1. How Ansible works

Ansible is agentless and push-based. You run it on a control node (your laptop, a CI runner or a small management server). It connects to each managed node over SSH (or WinRM for Windows), copies a small Python module across, runs it and removes it. Nothing stays installed on the target except Python, which almost every Linux server already has.

The building blocks:

TermWhat it is
InventoryThe list of servers to manage, grouped (for example web and db)
ModuleOne unit of work, such as installing a package or editing a file
TaskOne call to a module with its arguments
PlaybookA YAML file of plays; each play runs tasks against a group of hosts
HandlerA task that runs only when another task reports a change, such as a service restart
RoleA reusable folder of tasks, handlers, templates and variables
CollectionA distributed bundle of modules and roles, such as ansible.posix or community.general

Most modules are idempotent: they check the current state first and change something only when needed. Running the same playbook twice should report changed=0 the second time.

2. Install Ansible and connect to your servers

Ansible's control node runs on Linux or macOS. On Windows, use it inside WSL. The simplest cross-platform install is through pipx, which keeps Ansible in its own Python environment:

bash
pipx install --include-deps ansible
ansible --version

The ansible package includes ansible-core plus the popular community collections. Distribution packages (sudo dnf install ansible-core on AlmaLinux or Rocky, sudo apt install ansible on Ubuntu) also work, but they are often older.

Ansible logs in with SSH keys. Create a modern key and copy it to each server:

bash
ssh-keygen -t ed25519 -C "ansible"
ssh-copy-id -i ~/.ssh/id_ed25519.pub [email protected]

Use a normal user with sudo rights rather than logging in as root, and once key login works, turn off password login in /etc/ssh/sshd_config on the server.

3. Build your inventory

A static inventory can be INI or YAML. INI is the quickest to read:

ini
# inventory.ini
[web]
web1 ansible_host=203.0.113.10
web2 ansible_host=203.0.113.11

[db]
db1 ansible_host=203.0.113.20

[all:vars]
ansible_user=deploy
ansible_python_interpreter=auto_silent

Test every host:

bash
ansible all -i inventory.ini -m ansible.builtin.ping

A reply of "ping": "pong" means SSH and Python both work. Put group and host variables in group_vars/web.yml and host_vars/web1.yml rather than on the inventory lines, and never store passwords in the inventory; section 7 covers secrets.

For cloud fleets, a dynamic inventory plugin reads hosts from the provider's API instead of a file, for example amazon.aws.aws_ec2 from the amazon.aws collection. The old standalone inventory scripts are replaced by these plugins.

4. Run one-off commands

The ansible command runs a single module across hosts, which is handy for quick checks:

bash
ansible web -i inventory.ini -a "uptime"
ansible web -i inventory.ini -b -m ansible.builtin.dnf -a "name=chrony state=present"

-b means "become" (sudo). For anything you will run twice, write a playbook instead.

5. Write your first playbook

This playbook installs and starts nginx on AlmaLinux or Rocky Linux, and deploys a config file from a template:

yaml
# site.yml
- name: Configure web servers
  hosts: web
  become: true
  vars:
    http_port: 80

  tasks:
    - name: Install nginx
      ansible.builtin.dnf:
        name: nginx
        state: present

    - name: Deploy site config
      ansible.builtin.template:
        src: templates/site.conf.j2
        dest: /etc/nginx/conf.d/site.conf
        mode: "0644"
      notify: Reload nginx

    - name: Start and enable nginx
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: Reload nginx
      ansible.builtin.service:
        name: nginx
        state: reloaded

Run it, dry-run first:

bash
ansible-playbook -i inventory.ini site.yml --check --diff
ansible-playbook -i inventory.ini site.yml

Two habits keep playbooks portable. Use fully qualified collection names (ansible.builtin.template, not template). And when a playbook must run on both Ubuntu and AlmaLinux, use ansible.builtin.package, or pick apt or dnf with when: ansible_facts['os_family'] == "Debian".

6. Variables, facts, conditionals and loops

Variables can live in the play, in group_vars and host_vars, in role defaults or on the command line. When the same name is set in several places, the more specific source wins. In practice: role defaults are the weakest, inventory variables beat them, play variables beat those, and --extra-vars on the command line always wins.

Facts are details Ansible gathers from each host at the start of a play: OS family, IP addresses, memory and more. Read them through ansible_facts:

yaml
- name: Show the OS
  ansible.builtin.debug:
    msg: "{{ inventory_hostname }} runs {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}"

Conditionals and loops combine naturally:

yaml
- name: Install base packages on RHEL-family hosts
  ansible.builtin.dnf:
    name: "{{ item }}"
    state: present
  loop:
    - git
    - curl
    - firewalld
  when: ansible_facts['os_family'] == "RedHat"

For a package list, passing the whole list to name: in one task is faster than a loop.

7. Keep secrets in Ansible Vault

Vault encrypts files or single values with a password, so you can commit them to Git safely:

bash
ansible-vault create group_vars/db/vault.yml
ansible-vault edit group_vars/db/vault.yml
ansible-playbook -i inventory.ini site.yml --ask-vault-pass

A common pattern is to keep vault_db_password in the encrypted file and reference it from a plain vars.yml as db_password: "{{ vault_db_password }}", so you can still search for variable names. For automation, read the vault password from a file outside the repository (--vault-password-file), and add no_log: true to any task that would print a secret.

8. Organise with roles and collections

Once a playbook grows past a page, split it into roles:

bash
ansible-galaxy role init roles/nginx

This creates tasks/, handlers/, templates/, files/, defaults/, vars/ and meta/. Your playbook then becomes a short list of roles. Pin external roles and collections in a requirements.yml and install them with ansible-galaxy install -r requirements.yml, so every machine uses the same versions.

9. Test, debug and run safely

Dry run
--check --diff shows what would change, and the file differences, without changing anything.
Lint
ansible-lint flags deprecated syntax, missing names and risky patterns before you run a playbook.
Verbose output
Add -v up to -vvvv to see connection details and module arguments.
Limit the blast radius
--limit web1 runs on one host; serial: 1 in a play updates one server at a time.
Handle failures on purpose
Use block/rescue or failed_when rather than a blanket ignore_errors: true.
Test roles
Molecule runs a role in a throwaway container or VM and checks the result.

Common errors: "Permission denied (publickey)" means the key or user is wrong; "Missing sudo password" needs --ask-become-pass or passwordless sudo for the deploy user; "couldn't resolve module" usually means a collection is not installed.

For a web interface, scheduling and access control, AWX is the free upstream project (installed on Kubernetes with the AWX Operator), and Red Hat Ansible Automation Platform is the supported commercial product that replaced Ansible Tower. You do not need either to start.

10. Running Ansible with Domain India

Ansible fits a Domain India VPS: KVM virtualisation, full root access and a choice of Linux distribution, so every example above runs as written. The VPS is self-managed, which is exactly where Ansible earns its keep: your server setup lives in Git and can be rebuilt quickly. To combine Ansible with Terraform, see Infrastructure as Code on a Domain India VPS: Terraform and Ansible.

On shared hosting (cPanel, DirectAdmin, Webuzo), jailed SSH is available on every plan but off by default; ask support to enable it for your account. It is a restricted shell with key-only login, so Ansible cannot install packages or change server settings there. For shared hosting, deploy your site with Git or SFTP instead; see enabling and accessing jailed SSH.

VPS Starter
₹552.65/mo + GST
  • 1 vCPU
  • 2 GB DDR4 RAM
  • 64 GB NVMe SSD Storage
  • 2 TB Monthly Bandwidth
See plan details
VPS Basic
₹1,105.30/mo + GST
  • 2 vCPU
  • 4 GB DDR4 RAM
  • 128 GB NVMe SSD Storage
  • 3 TB Monthly Bandwidth
See plan details

Prices on the cards are live Domain India list prices and exclude 18% GST.

Is Ansible free?

Yes. Ansible and ansible-core are open source. Red Hat sells Ansible Automation Platform, a supported product with a web interface and extra tooling, but you do not need it to use Ansible.

Do I need to install anything on the servers Ansible manages?

No agent is needed. Each managed Linux server needs SSH access and Python, which most distributions include. Ansible copies its modules over SSH, runs them and removes them.

What is the difference between ansible and ansible-core?

ansible-core is the engine and the ansible.builtin modules. The ansible package installs ansible-core plus a curated set of community collections, such as community.general and ansible.posix.

Why should I use names like ansible.builtin.dnf instead of dnf?

Fully qualified collection names say exactly which module runs, avoid clashes between collections, and are what ansible-lint expects. Short names still work for built-in modules but are discouraged.

How do I test a playbook without changing my servers?

Run ansible-playbook with --check --diff. It reports what would change and shows file differences without applying anything. Some tasks, such as shell commands, cannot predict their result in check mode.

Can I use Ansible on Domain India shared hosting?

Not to manage the server. Shared hosting gives you a jailed, key-only SSH shell on request, with no root access, so Ansible cannot install packages or change configuration. Use it on a Domain India VPS, where you have full root access.

Does Ansible manage Windows servers?

Yes, over WinRM or SSH, using the ansible.windows collection for tasks such as installing features, managing services and running updates.

Ready to automate? Compare VPS plans, then follow the Terraform and Ansible guide to keep your whole server setup in Git.

Automate your own server

KVM VPS with full root access and your choice of Linux distribution, ready for Ansible.

See VPS plans

Ready when you are

Get VPS from ₹552.65/mo + GST

See plans

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app