Docker & DevOps

Automate VPS configuration with Ansible

Install Ansible, write an inventory of your VPSs, run ad-hoc commands, and create a playbook that hardens SSH, installs packages, configures a firewall and deploys Nginx, idempotently.

IntermediateLinux VPS2 min read

Configuring servers by hand works for one VPS, but becomes error-prone at three or more. Ansible describes the desired state in YAML playbooks and applies it over SSH, with no agent on the servers. This guide shows how to automate VPS configuration with Ansible.

Before you start

  • A control machine (your laptop, WSL or a management VPS) with Python.
  • One or more Linux VPSs reachable by SSH with key login and a sudo user. See first steps on a new VPS.

Install Ansible

python3 -m pip install --user ansible

Or use your package manager (sudo apt install ansible), which may be older.

Create an inventory

inventory.ini:

[web]
web01 ansible_host=203.0.113.10
web02 ansible_host=203.0.113.11

[web:vars]
ansible_user=deploy

Test connectivity:

ansible -i inventory.ini web -m ping

Run ad-hoc commands

ansible -i inventory.ini web -b -m apt -a "update_cache=yes upgrade=dist"

-b means become root with sudo.

Write a playbook

site.yml:

- hosts: web
  become: true
  tasks:
    - name: Install packages
      ansible.builtin.apt:
        name: [nginx, ufw, fail2ban]
        state: present
        update_cache: true

    - name: Disable SSH password login
      ansible.builtin.lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^#?PasswordAuthentication'
        line: 'PasswordAuthentication no'
      notify: Restart ssh

    - name: Allow SSH and HTTP(S)
      community.general.ufw:
        rule: allow
        name: "{{ item }}"
      loop: [OpenSSH, 'Nginx Full']

    - name: Enable firewall
      community.general.ufw:
        state: enabled

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

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

The community.general collection ships with the full ansible package; install it with ansible-galaxy collection install community.general if missing.

Run it

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

--check shows what would change. Then run without it. Running again reports ok instead of changed: playbooks are idempotent.

Grow from here

  • Organise tasks into roles (common, web, database).
  • Store secrets with ansible-vault.
  • Use templates (ansible.builtin.template) for Nginx vhosts.
  • Combine with cloud-init for first boot.

Troubleshooting

  • UNREACHABLE: wrong IP, user or key; test plain ssh deploy@IP.
  • Missing sudo password: add -K to prompt, or configure passwordless sudo for the deploy user.
  • couldn't resolve module: install the needed collection.

Frequently asked questions

Do servers need Ansible installed?

No, only Python and SSH, which almost all Linux distributions have.

Ansible or Terraform?

Terraform creates infrastructure (VMs, DNS); Ansible configures what runs inside. They work well together.

Can Ansible manage Windows servers?

Yes, over WinRM or SSH with Windows-specific modules.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.