Pracandy
← Newsroom

Features

In Defence of Boring Technology

Postgres, systemd timers and static files against the current fashion. Where boring wins and where it genuinely holds you back.

19 September 2026

Network Engineering Ashlan Chidester 23
Photo: Cloud899, CC BY-SA 4.0, via Wikimedia Commons

The boring stack is the default

Choosing a boring technology stack is the only rational choice when you are the sole maintainer of several live products. It minimises the surface area for failure and keeps the cognitive load low enough to actually ship features. The current fashion for complex microservices and distributed systems often solves problems that do not exist on a single machine.

Pracandy runs five distinct products from one VPS. The infrastructure is deliberately unglamorous. One Next.js process serves four sites via host-based routing: pracandy.com, flix.pracandy.com, walls.pracandy.com, and the admin panel. Instalaz runs as a separate Node process on port 3050, proxied by Caddy. GamingCap and Invoiceful are static builds served straight from disk by Caddy. They have no server process and no database. This separation is not architectural purity; it is resource management. Processes on one box compete for memory. Isolating the heavy Node app from the static file servers ensures that a spike in traffic to the film publication does not starve the invoice generator of CPU cycles.

Systemd timers over cron

Scheduled work is where many independent developers underestimate the value of the init system. We use systemd oneshot services with timers rather than cron. The reasoning is operational, not ideological. Cron is a time-based trigger. It does not know if the previous run is still executing. If a database backup takes longer than the interval, you get overlapping jobs. Overlapping jobs write to the same files or lock the same tables. The result is corruption or deadlock.

Systemd timers handle this natively. They can wait for the previous instance to finish before starting the next. They also log their output to the journal, which is searchable and persistent. When a scheduled task fails, the error is visible in the system log immediately. With cron, you often have to pipe output to a log file manually, and if the pipe fails, the error vanishes. For a solo developer, visibility is survival. If a backup fails silently, you do not know until you need to restore. A systemd timer that blocks subsequent runs until the previous one succeeds is a feature, not a bug. It forces the system to acknowledge the work is done.

Postgres 16 as the single source of truth

There is one PostgreSQL 16 database shared by the Next.js app and Instalaz. This is a point of contention in modern discourse, where many argue for a database per service. In practice, a single database on a single machine is easier to back up, easier to monitor, and easier to tune. You do not have to manage network latency between services. You do not have to handle distributed transactions. You do not have to reconcile data across multiple stores.

The constraint is that the database must be reliable. Postgres is reliable. It has been for decades. It handles concurrency well. It has a rich ecosystem of tools. The alternative, such as a NoSQL database or a serverless database, introduces complexity that a single VPS cannot justify. The 12GB of RAM on the box is sufficient for the working set of these applications. The 193GB disk is sufficient for the data. The bottleneck is rarely the database engine; it is the application logic that queries it poorly. Optimising the SQL is more effective than splitting the storage layer.

Where boring holds you back

Boring technology is not a panacea. It holds you back when the problem requires scale that a single machine cannot provide. If your user base grows to millions, a single VPS becomes a liability. The static file serving by Caddy is efficient, but it cannot scale horizontally without a load balancer. The systemd timers are reliable, but they are bound to the host. If the host goes down, everything goes down.

For Pracandy, this is an acceptable risk. The products are small enough that the revenue does not justify the cost of a distributed system. The risk of a single point of failure is mitigated by the simplicity of the setup. If something breaks, it is usually easy to diagnose. You do not have