Skip to main content

Automating My VPS Setup with Ansible

Table of Contents
This post documents how I fully automated my VPS setup with Ansible, from Docker and Nginx to SSL, OAuth2, and GitHub Runners with security and reproducibility in mind.

🧩 Infrastructure Overview
#

Here’s a high-level view of the services I run:

  • Docker: Everything is containerized for isolation
  • Nginx: Reverse proxy + TLS termination
  • Certbot: Automatic SSL with Let’s Encrypt
  • OAuth2 Proxy + Keycloak: Centralized authentication
  • Grafana + Prometheus + Node Exporter: Monitoring stack
  • GitHub Actions Runner: Self-hosted CI
  • UFW + Fail2Ban: Firewall and brute-force protection
  • Watchtower: Automatically updates Docker containers

Why Ansible?
#

Using Ansible allows me to:

  • Define everything as code
  • Avoid configuration drift
  • Make re-deployments easy and predictable

All roles are modular and idempotent. I can rebuild the entire server from scratch in minutes.


Attempted Security-First
#

Sed quis custodiet ipsos custodes?

OAuth2 Proxy + Keycloak
#

Sensitive apps are protected via oauth2-proxy in front of containers, authenticating through Keycloak. Each app config includes OAuth toggles:

nginx_apps:
  - domain: subdomain.smikic.com
    port: 69420
    oauth: true

This generates a custom Nginx config with an embedded OAuth2 block. Only authenticated users can reach the app.

Let’s Encrypt + Certbot
#

SSL certificates are automatically requested and renewed using Certbot with the Nginx plugin. Ansible automates this, requiring only a domain and email.

Firewall Rules via UFW
#

UFW is configured dynamically:

  • Allows only required ports
  • OAuth2-protected apps get UFW rules only if enabled
  • Node Exporter listens only to localhost

Fail2Ban is also installed and enabled for SSH brute-force protection.

Monitoring with Grafana & Prometheus
#

Monitoring runs on its own Docker network:

  • Prometheus scrapes data from Node Exporter and itself
  • Grafana visualizes metrics, using Keycloak SSO
  • Node Exporter exposes host metrics with hardened volumes

All of this is deployed via Docker containers with Watchtower watching for updates.

GitHub Actions Runner
#

I added a self-hosted GitHub runner to offload builds from GitHub’s shared runners.

Ansible installs dependencies, configures the runner, and sets it up as a systemd service. Meaning it is ready to go after any reboot or re-provision.

Deployment is a Single Command
#

Once the inventory and vars are set, provisioning the whole VPS is as easy as:

ansible-playbook -i inventory site.yml

It’s safe to re-run this command anytime. Ansible only makes the necessary changes.

📌 What’s Next?
#

  • Add automatic backup/restore routines for volumes and secrets
  • Integrate alerting (Alertmanager?) for Prometheus
  • Extend Monitoring
  • Maybe explore and implementing zero-trust?

There are no articles to list here yet.