Author: pzin

  • How this site runs

    This blog, the page at pavel-zin.com, and the status page all run on infrastructure I built as a learning project — two small virtual machines. I wanted the whole thing to work the way similar to how real systems work, just at a small scale: everything defined as code, nothing configured by hand, and every layer doing an actual job.

    The path of a request

    When your browser asked for this page, the request resolved through DNS to the public IP of the edge node. Before reaching any software, it passed two independent firewalls: the cloud provider’s network rules, and the host’s own nftables ruleset. Both are default-deny — they drop everything except what is explicitly allowed, and each would hold on its own if the other failed.

    On the edge node, nginx accepted the connection and terminated TLS with a Let’s Encrypt certificate. For the blog, nginx handed the request to a WordPress container over FastCGI. WordPress then needed the database — and that’s where it gets a bit more interesting.

    A private tunnel between nodes

    The database doesn’t live on the edge node. It runs on a second machine, core, which exposes nothing to the internet except SSH. The two nodes talk over a WireGuard tunnel, and the database listens only on its tunnel address. So the query for this post left the WordPress container, traveled encrypted between the two VMs, and hit MariaDB on an interface that simply doesn’t exist from the outside. A Redis container on the edge caches objects so most page loads don’t need the trip at all.

    Everything is code

    Both machines are described entirely by an Ansible repository: packages, SSH hardening, firewall rules, the tunnel, Docker, every container, the TLS certificate lifecycle, even the WordPress installation itself — there was never a browser-based setup step. A single playbook run turns an empty Ubuntu machine into a fully working node.

    Changes go through pull requests. A CI pipeline lints every change, and the deployment to both nodes runs from CI as well.

    Watching it

    The status page is a small Gatus container probing the public sites, the tunnel, and the database, with its monitors defined in the same repository as everything else.