Ansible Tutorial: Agentless Config Management

Ansible automates server configuration, app deployment, and orchestration over plain SSH - no agents to install on the machines you manage.

Get started - freeLive cloud workspace in your browser · nothing to install
#ansible#configuration-management#devops#automation

What is Ansible?

Ansible is an open-source automation tool used for configuration management, application deployment, and orchestration across fleets of servers. Instead of logging into each machine and running commands by hand, you describe the desired state of your systems in YAML files called playbooks, then run them against an inventory of hosts. Ansible connects to each host, figures out what needs to change, and makes only those changes.

Its defining trait is that it is agentless. Tools like Puppet and Chef traditionally run a persistent agent on every managed node. Ansible instead connects over standard SSH (or WinRM for Windows targets), pushes small modules to the remote machine, executes them with the remote Python interpreter, and cleans up afterward. The only requirements on a target are SSH access and Python. This keeps the attack surface small and makes Ansible easy to adopt on machines you do not fully control.

Ansible is also declarative and idempotent. You declare that a package should be present, a config file should contain certain content, or a service should be running and enabled. Running the same playbook twice does not double-apply the change - if the system already matches the desired state, Ansible reports "ok" and moves on. That property is what makes it safe to run playbooks repeatedly as your source of truth.

How Ansible works (key concepts)

A handful of concepts cover most of what you will use day to day:

Installing Ansible

Ansible runs on Python 3. On modern Linux distributions that enforce PEP 668, installing into the system Python with pip is blocked, so use pipx for an isolated, globally available install. This is the cleanest method on Ubuntu, Debian, and Fedora.

# Install pipx, then Ansible (includes ansible-core + community collections)
sudo apt update
sudo apt install -y pipx
pipx ensurepath
pipx install ansible

# Confirm the install
ansible --version

If you prefer a minimal footprint, or want to manage the Python environment yourself, install into a virtual environment. You can install the full ansible package or just ansible-core:

python3 -m venv ~/ansible-venv
source ~/ansible-venv/bin/activate

# Full distribution (engine + bundled collections)
pip install ansible

# Or the engine only (add ==<version> to pin a specific release)
pip install ansible-core

On Ubuntu you can also use the official PPA, which tracks the full ansible package:

sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible

Hands-on: configure a web server with a playbook

Start with an inventory file describing your hosts. Create inventory.ini:

[webservers]
web1 ansible_host=192.0.2.10
web2 ansible_host=192.0.2.11

[webservers:vars]
ansible_user=ubuntu
ansible_python_interpreter=/usr/bin/python3

Before writing a playbook, verify connectivity with an ad-hoc command. The ping module does not use ICMP - it confirms SSH login and a working Python interpreter on each host:

ansible webservers -i inventory.ini -m ansible.builtin.ping

Now write site.yml to install nginx, copy in a config from a template, and ensure the service is running. The template task expects a Jinja2 file at templates/site.conf.j2 next to the playbook - put your nginx server block there. The handler restarts nginx only when the rendered config changes, which is the idempotent pattern you want:

---
- name: Configure web servers
  hosts: webservers
  become: true

  tasks:
    - name: Install nginx
      ansible.builtin.apt:
        name: nginx
        state: present
        update_cache: true

    - name: Deploy nginx site config
      ansible.builtin.template:
        src: templates/site.conf.j2
        dest: /etc/nginx/sites-available/default
        owner: root
        group: root
        mode: "0644"
      notify: Restart nginx

    - name: Ensure nginx is running and enabled
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

  handlers:
    - name: Restart nginx
      ansible.builtin.service:
        name: nginx
        state: restarted

Run it with the inventory you defined. Use --check first for a dry run that reports what would change without touching the hosts:

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

The first real run shows tasks as changed. Run the same command again and the same tasks report ok with nothing changed - that is idempotency in action, and it shows your playbook can serve as a reliable source of truth.

When to use Ansible

Ansible works best when you need to bring many machines to a known, repeatable state without running an agent on each one. Typical fits include provisioning a set of identical web or database servers, rolling out application deployments, applying security baselines and patches across a fleet, and orchestrating multi-step releases that touch several tiers in order. Because it is push-based and agentless, it is a good fit for environments where you cannot or do not want to maintain persistent daemons on every target.

It is less suited to scenarios that demand continuous enforcement of state without an operator triggering a run - a pull-based agent model or a dedicated drift-detection loop fits those better. For provisioning cloud infrastructure itself, a declarative infrastructure-as-code tool like Terraform is usually the better primary choice, with Ansible handling the in-instance configuration afterward. A common and effective pattern is to pair the two: Terraform creates the servers, then Ansible configures what runs on them.

Frequently asked questions

What is Ansible?

Ansible is an open-source automation tool for configuration management, application deployment, and orchestration. It connects to managed nodes over SSH (or WinRM for Windows) and applies declarative YAML playbooks. It is agentless, so the only requirements on a target are SSH access and Python.

Is Ansible agentless?

Yes. Ansible pushes small modules to managed nodes over SSH, runs them with Python, and removes them when finished. There is no long-running daemon or agent to install, patch, or secure on the targets - only the control node needs Ansible installed.

What is the difference between ansible and ansible-core?

ansible-core is the engine: the CLI, the execution model, and a small set of built-in modules. The ansible package bundles ansible-core plus dozens of community collections. Install ansible-core if you want a minimal footprint and add collections yourself.

What language are Ansible playbooks written in?

Playbooks are written in YAML and use Jinja2 templating for variables and expressions. You do not write imperative scripts - you declare the desired state of files, packages, and services, and Ansible figures out the changes needed.

Do real production work, free. Live cloud workspaces in your browser - every project you complete lands on your portfolio.

Get started - free
Get started - free