Automating VPS Setup with Ansible: Inventory and First Playbook | INTROSERV
EUR
european

EUR

usa

USD

English En
Ex. VAT Ex. VAT 0%

Automating VPS Setup with Ansible: Inventory and First Playbook

Introduction

Ansible is an open source automation tool used for configuration management, application deployment, and infrastructure provisioning. It connects to servers over SSH and does not require any agent installation on remote machines, which makes it simple and safe to use. Common use cases include automating server setup, keeping configurations consistent, and deploying applications across multiple systems at once.

In this tutorial, you set up Ansible on your local machine and use it to automate configuration of multiple VPS instances. Instead of configuring each server manually, you define tasks once and apply them everywhere. You create an inventory, write your first playbook, and deploy a working web application stack.

Understanding Ansible Core Concepts

You are not writing a script that runs commands one by one. You are describing what your servers should look like after the playbook finishes.

In this tutorial, you use only a few core components. The inventory file defines your VPS servers and how Ansible connects to them. The playbook is where you describe the desired state of your servers. Inside the playbook, tasks define individual pieces of that desired state, such as installed packages, running services, or configuration files.

The most important concept here is declarativeness. Instead of writing exact commands like you would in a shell script, you describe the result you want. For example, you do not tell Ansible to run a command to install Nginx. You define that Nginx must be installed. You do not tell it to start a service manually. You define that the service must be running and enabled. Ansible then decides what actions are needed to achieve that state.

This is different from a traditional approach where you would manually run commands in a specific order. In such scripts, you need to handle every possible situation yourself. With Ansible, the logic is built into the modules you use, such as package management, service control, file management, and HTTP checks.

Another key concept is idempotency. This means that running the same playbook multiple times does not cause unnecessary changes. If the system already matches the desired state, Ansible leaves it unchanged. For example, if Nginx is already installed, it will not reinstall it. If a configuration file already matches what you defined, it will not be rewritten.

Because of declarativeness and idempotency, you can safely run the playbook multiple times. On the first run, Ansible installs and configures everything. On subsequent launches, it only checks the system state and changes it if necessary.

Prerequisites

  • Target audience: Beginner system administrators
  • Estimated time: ~40–60 minutes
  • Operating system: Debian 13 on local PC and all VPS nodes
  • VPS nodes:
    • ans0: 192.168.10.10
    • ans1: 192.168.10.11
    • ans2: 192.168.10.12
  • Access:
    • SSH access to all VPS instances
    • A user with sudo privileges on each VPS
  • Network:
    • Port 22 open for SSH
    • Port 80 open for HTTP
  • Local machine:
    • Python 3 installed
    • Internet access
  • End goal: By the end of this tutorial, you will automatically configure multiple VPS servers, install Nginx, deploy PocketBase, and make it accessible through a web server.

Step 1: Install Ansible on Local Machine

Ansible runs on your local machine and connects to remote servers. You only install it once.

Update package lists:

sudo apt update

Install Ansible:

sudo apt install ansible -y

Check installation:

ansible --version

Expected result: You see version information. This confirms Ansible is installed and ready.

Step 2: Prepare SSH Access

Ansible uses SSH to connect to servers. To avoid typing passwords every time, you use SSH keys.

Generate SSH key:

ssh-keygen

Press Enter to accept defaults. This creates a key pair:

  • Private key stays on your PC
  • Public key is copied to servers

Copy key to VPS:

ssh-copy-id <YOUR_USERNAME>@192.168.10.10

ssh-copy-id <YOUR_USERNAME>@192.168.10.11

ssh-copy-id <YOUR_USERNAME>@192.168.10.12

Test access:

ssh <YOUR_USERNAME>@192.168.10.10

Expected result: You log in without entering a password.

Step 3: Create Ansible Project and Inventory

Ansible uses an inventory file to know which servers to manage.

Create project directory:

mkdir ~/ansible-vps

cd ~/ansible-vps

Create inventory file:

nano inventory.ini

Insert the following content into the inventory file:

[vps] ans0 ansible_host=192.168.10.10 ans1 ansible_host=192.168.10.11 ans2 ansible_host=192.168.10.12 [vps:vars] ansible_user=<YOUR_USERNAME> ansible_python_interpreter=/usr/bin/python3

Explanation:

  • [vps] is a group name
  • ans0, ans1, ans2 are logical names
  • ansible_host defines real IP addresses
  • ansible_user tells Ansible which user to log in as

Test connectivity:

ansible -i inventory.ini vps -m ping

Expected result: Each server returns "pong".

Step 4: Create Your First Playbook

A playbook is a file where you describe tasks you want to run on servers.

Create file:

nano playbook.yml

Insert the following content into the playbook file:

- name: Configure VPS nodes hosts: vps become: true tasks: - name: Test connectivity ping: - name: Update apt cache apt: update_cache: yes - name: Upgrade packages apt: upgrade: dist - name: Install Nginx apt: name: nginx state: present - name: Ensure Nginx is running service: name: nginx state: started enabled: true - name: Test HTTP connectivity uri: url: http://127.0.0.1/ return_content: no - name: Create directory for PocketBase file: path: /opt/pocketbase/pb_public state: directory - name: Install unzip apt: name: unzip state: present - name: Download PocketBase get_url: url: https://github.com/pocketbase/pocketbase/releases/download/v0.36.7/pocketbase_0.36.7_linux_amd64.zip dest: /opt/pocketbase/pocketbase.zip - name: Unpack PocketBase unarchive: src: /opt/pocketbase/pocketbase.zip dest: /opt/pocketbase/ remote_src: yes - name: Create Pocketbase index.html copy: dest: /opt/pocketbase/pb_public/index.html content: | <h1>Pocketbase</h1> - name: Create systemd service copy: dest: /etc/systemd/system/pocketbase.service content: | [Unit] Description=PocketBase Service After=network.target [Service] Type=simple ExecStart=/opt/pocketbase/pocketbase serve --http=127.0.0.1:8090 Restart=always [Install] WantedBy=multi-user.target - name: Reload systemd command: systemctl daemon-reexec - name: Enable and start PocketBase service: name: pocketbase enabled: true state: started - name: Configure Nginx site copy: dest: /etc/nginx/sites-available/pocketbase content: | server { listen 80; server_name _; location / { proxy_pass http://127.0.0.1:8090; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } - name: Enable Nginx site file: src: /etc/nginx/sites-available/pocketbase dest: /etc/nginx/sites-enabled/pocketbase state: link - name: Remove default site file: path: /etc/nginx/sites-enabled/default state: absent - name: Restart Nginx service: name: nginx state: restarted - name: Check PocketBase availability uri: url: http://127.0.0.1:8090/_/ return_content: no

Explanation:

  • hosts: vps means all servers in the group
  • become: true runs tasks with elevated privileges
  • Each task describes one action
  • Modules like apt, service, file are built into Ansible

Step 5: Run the Playbook

ansible-playbook -i inventory.ini playbook.yml

Expected result: Tasks execute on all nodes without errors.

Info

First run may take several minutes depending on network speed.

Verification

Check web server:

curl http://192.168.10.10/

Expected result: HTTP response is returned.

Open in browser: http://192.168.10.10/_/

Expected result: PocketBase interface loads.

Repeat for other nodes.

Reverting Changes

sudo systemctl stop pocketbase

sudo systemctl disable pocketbase

sudo rm /etc/systemd/system/pocketbase.service

sudo rm -rf /opt/pocketbase

sudo apt remove nginx unzip -y

Reload systemd:

sudo systemctl daemon-reload

Troubleshooting

  • SSH fails: check keys and user
  • Ansible ping fails: ensure network connection between hosts
  • Nginx issues: systemctl status nginx
  • PocketBase issues: journalctl -u pocketbase

Conclusion

You installed Ansible automation tool, created an inventory, and wrote your first playbook. You automated deployment of Nginx and PocketBase across multiple servers.

Next steps:

  • Use roles for better structure
  • Add variables and templates
  • Configure HTTPS

VAT

  • Other

    Ex. VAT

    0%
  • austria

    Austria

    20%
  • Belgium

    Belgium

    21%
  • Bulgaria

    Bulgaria

    20%
  • Croatia

    Croatia

    25%
  • Cyprus

    Cyprus

    19%
  • Czech Republic

    Czech Republic

    21%
  • Denmark

    Denmark

    25%
  • Estonia

    Estonia

    22%
  • France

    France

    20%
  • Finland

    Finland

    24%
  • Germany

    Germany

    19%
  • Greece

    Greece

    24%
  • Hungary

    Hungary

    27%
  • Ireland

    Ireland

    23%
  • Italy

    Italy

    22%
  • Latvia

    Latvia

    21%
  • Lithuania

    Lithuania

    21%
  • Luxembourg

    Luxembourg

    17%
  • Malta

    Malta

    18%
  • Netherlands

    Netherlands

    21%
  • Poland

    Poland

    23%
  • Portugal

    Portugal

    23%
  • Romania

    Romania

    19%
  • Slovakia

    Slovakia

    20%
  • Slovenia

    Slovenia

    22%
  • Spain

    Spain

    21%
  • Sweden

    Sweden

    25%
  • USA

    USA

    0%
european
states
  • germany
  • Español
  • Italiano
  • Poland
  • Русский
  • Slovenski
  • Türkçe
  • ukraine
  • kingdom
  • French
  • Hrvatska
  • Other
  • Austria
  • Belgium
  • Bulgaria
  • Croatia
  • Cyprus
  • Czech Republic
  • Denmark
  • Estonia
  • Finland
  • France
  • Germany
  • Greece
  • Hungary
  • Ireland
  • Italy
  • Latvia
  • Lithuania
  • Luxembourg
  • Malta
  • Netherlands
  • Poland
  • Portugal
  • Romania
  • Slovakia
  • Slovenia
  • Spain
  • Sweden
  • USA