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.
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
- Describe the old server's current setup as a playbook — packages, configs, services.
- Add the new server to a temporary inventory group, separate from production.
- Apply the playbook to the new server with the
--checkflag — a test run with no real changes. - Apply the playbook for real and compare the new and old server's configuration by hand.
- 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
--check before applying to production servers.Comparing ways to configure a new server
| Method | Repeatability | Speed across ten servers |
|---|---|---|
| Manual setup from instructions | low — easy to skip a step | slow, grows linearly with server count |
| A bash setup script | medium — depends on script quality | fast, but fragile across OS differences |
| An Ansible playbook | high — idempotent by design | fast, 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
| Error | Cause and fix |
|---|---|
| UNREACHABLE! Failed to connect to the host via ssh | Wrong path in ansible_ssh_private_key_file, or the server is not in known_hosts |
| FAILED! Missing sudo password | A 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
- Keep playbooks in git — rolling back configuration is just applying the previous playbook version.
- Before risky changes, take a server snapshot at the VDS panel level, if it is a virtual machine.
- 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 statuslogs 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.