Skip to main content

Ansible: automating server configuration

Migration · 06.02.2025 · 4 min read
Illustration for “Ansible: automating server configuration”

Why Ansible when migrating servers

Ansible lets you configure servers automatically from a description (infrastructure as code). No agents needed — it works over SSH. This is especially valuable for migrations: instead of manually repeating the old server's setup on the new one and inevitably forgetting something, you describe the configuration once and apply it to any number of servers identically.

💡 Ansible's main advantage is idempotency: run the playbook 10 times in a row — the result is always exactly the same.

Installing Ansible

# Ubuntu/Debian
apt install ansible -y

# Check
ansible --version

The inventory file

[webservers]
web1.example.com
web2.example.com

[dbservers]
db1.example.com

[all:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/id_rsa

Migrating configuration to a new server

  1. Describe the old server's current setup as a playbook — packages, configs, services.
  2. Add the new server to a temporary inventory group, separate from production.
  3. Apply the playbook to the new server with the --check flag — a test run with no real changes.
  4. Apply the playbook for real and compare the new and old server's configuration by hand.
  5. Move the new server into the production inventory group only after a successful check.

Sample playbook: installing Nginx

---
- name: Install and configure Nginx
  hosts: webservers
  become: yes
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present
        update_cache: yes

    - name: Start and enable nginx
      systemd:
        name: nginx
        state: started
        enabled: yes

    - name: Deploy config
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: reload nginx

  handlers:
    - name: reload nginx
      systemd:
        name: nginx
        state: reloaded

Running the playbook

# Test (dry run)
ansible-playbook -i inventory.ini setup.yml --check

# Real run
ansible-playbook -i inventory.ini setup.yml
⚠️ Always run with --check before applying to production servers.

Comparing ways to configure a new server

MethodRepeatabilitySpeed across ten servers
Manual setup from instructionslow — easy to skip a stepslow, grows linearly with server count
A bash setup scriptmedium — depends on script qualityfast, but fragile across OS differences
An Ansible playbookhigh — idempotent by designfast, one run covers every server

Checking the result on the new server before switching

# Compare the list of installed packages
ansible webservers -i inventory.ini -a "dpkg -l nginx"

# Check that the service is actually listening on the port
ansible webservers -i inventory.ini -a "ss -tlnp | grep :80"

The ansible ... -a command runs a one-off command on every server in a group without writing a playbook — handy for a quick state check before switching traffic onto the whole new server fleet.

Common errors

ErrorCause and fix
UNREACHABLE! Failed to connect to the host via sshWrong path in ansible_ssh_private_key_file, or the server is not in known_hosts
FAILED! Missing sudo passwordA password is required for become — run with the --ask-become-pass flag
fatal: [host]: FAILED! => {"msg": "no python interpreter found"}The minimal OS image has no Python installed — set ansible_python_interpreter explicitly

Rolling back changes

  1. Keep playbooks in git — rolling back configuration is just applying the previous playbook version.
  2. Before risky changes, take a server snapshot at the VDS panel level, if it is a virtual machine.
  3. If a service fails to come up after a playbook run, revert the last playbook commit and rerun it.

When Ansible does not fit

For a one-off transfer of a single server, writing and debugging a playbook can take longer than configuring everything by hand. Ansible pays off once there are more than a few servers, or when the configuration has to be repeated regularly — for example, when spinning up a new environment for every client. If there are only one or two servers and they change once a year, it is more sensible to write the steps as a plain checklist and run them by hand with a check at every stage.

Checking after applying the playbook

  • Rerun the playbook — an idempotent playbook should show 0 changes (changed=0) on the second run.
  • Compare installed package versions on the new server against the reference in the playbook.
  • Check systemctl status logs for every service brought up by the playbook.

Automated deployment on top of Ansible-configured servers is described in zero-downtime deployment: blue-green and rolling strategies.

Was this article helpful?
← Back to Knowledge Base Ask Support