A small, deliberately constrained self-hosting environment built around a single Raspberry Pi: an exercise in running real services on modest hardware, with privacy and simplicity treated as first-class design choices.
Introduction
The Infrastructure Lab is the name I use for a small personal hosting environment that runs on a single Raspberry Pi at home. It serves a handful of websites, a few internal tools, and one Tor hidden service. The project began as a way to host my own work without depending on managed platforms, and it has grown into a long-running exercise in disciplined engineering.
This page documents the lab as a coherent project rather than a pile of side experiments. It describes the architecture, the trade-offs, and the small set of design principles that I have learned on the fly that have been proven to be useful.
Project philosophy
A few principles shape almost every decision in the lab.
- Run real things. Toy deployments hide the questions that matter. I prefer to operate the same kinds of services I would want to use in production, even at modest scale.
- Constraints are a feature. A modest Pi forces clarity about what each service actually needs. When resources are scarce, indulgences are exposed quickly.
- Prefer durable, simple tools. Plain-text configuration, well-known daemons, stable Linux primitives. I treat trendy abstractions with skepticism.
- Privacy is part of the architecture. It is not a feature added at the end, but a principle that shapes which services exist and how they are maintained.
The lab is quiet by design. It is not optimized for maximum throughput or for showing off. It is optimized for being understandable, repairable, and slow to rot.
Raspberry Pi as the primary server
The lab runs on a Raspberry Pi 3 Model B with 1 GB of RAM. The operating system is a stripped-down Debian-based distribution with most desktop and graphical packages removed. A microSD card holds working data and database files.
This is not a powerful machine, but it gets the job done. Besides, the Pi has become my favorite environment for learning precisely because nothing can hide on it.
Hosting multiple websites and services
Several services run side by side on the Pi:
- A handful of small static personal websites.
- A few Flask applications powering utilities and small APIs.
- A couple of WordPress installations, kept lean with caching and a minimal plugin set.
- Internal tools for monitoring, log review, and backup verification.
- A Tor hidden service, described in a later section.
Each service runs as its own systemd unit under a dedicated unprivileged user. The aim is not to maximize the count of services, but to keep the set small enough that I can reason about all of them at once.
nginx and reverse proxy architecture
A single nginx process sits in front of everything on the Pi. It terminates TLS, dispatches requests by hostname, applies common security headers, and forwards traffic to the appropriate upstream: Flask via gunicorn over a Unix socket, WordPress via PHP-FPM, static sites served directly from disk.
This design has several practical advantages on a small machine. There is exactly one TLS implementation to keep current. There is one place to apply rate limits, redirects, and request-size limits. Each application can be moved, restarted, or replaced behind the proxy without disturbing the others.
Cloudflare and networking
Public services are reachable through Cloudflare. The Pi’s origin address is never published. Cloudflare’s edge handles DNS, terminates TLS for clients, caches static assets, and absorbs unwanted traffic. nginx on the Pi enforces an additional TLS layer between Cloudflare and the origin, so the path is encrypted end to end.
The benefits are huge. The origin sees a fraction of total traffic because the edge caches aggressively. DNS changes propagate quickly when I move things around. None of this requires elaborate configuration: the lab uses Cloudflare’s free tier and a short list of page rules.
Resource optimization
With 1 GB of RAM and a modest CPU, every megabyte spent has to justify itself. A few habits keep the system comfortable under normal load:
- nginx and PHP-FPM are tuned with conservative worker counts and an
ondemandconfig; I would rather queue briefly than thrash. - Flask applications run under gunicorn with a small fixed pool of workers, sized to the actual traffic each app sees.
- WordPress sits behind caching, so PHP runs only when a page genuinely changes.
- Logs are rotated tightly and shipped off the device for longer retention.
- Background jobs are scheduled so they do not collide with one another or with backups.
Tor hidden service and privacy
One of the lab’s services is published as a Tor hidden service. The Tor daemon runs locally and exposes the service over a Unix socket; nginx handles it like any other virtual host. The hidden service has no public IP exposure, no DNS footprint, and no dependence on Cloudflare.
I run this for two reasons:
- The engineering fascinates me. Hidden services have different threat models, different reachability characteristics, and different operational quirks than ordinary websites.
- Personal philosophy about privacy. I think the broader web benefits from having more ordinary, well-behaved services reachable over Tor (not only the controversial ones). A boring
.onionsite is my small contribution to that.
Vanity address generation
The hidden service uses a v3 onion address with a chosen prefix. v3 addresses are derived from an Ed25519 public key, so “choosing” a prefix actually means generating keys until one happens to encode the desired characters. I used mkp224o to do the search offline on a more capable machine: there was no need to use the Pi (which is already running at full capacity) for this vanity task.
I named it after myself, it took my machine about three hours to find it. You can check it out at:
albertovyf26uzm5wyd4ihhsyku5wcwn56vocble2k5pxtggmta2c5yd.onion
To be honest, I would’ve loved to add an x at the end, just for aesthetic reasons: albertox{etc}.onion. But every additional character multiplies the work by 32. The idea of using around 3 × 32 = 96 continuous hours of computing time just for the sake of vanity (pun intended) didn’t really appeal to me. alberto is enough.
Minimal anonymous contact form
My onion site includes a contact form. It is deliberately minimal: a single HTML page, styled with a small amount of CSS, with no JavaScript at all. The form posts to a tiny server-side handler that validates input, writes the message to disk, and returns a static thank-you page.
For a service whose entire point is anonymity and minimal trust, that simplicity is itself a feature.
Lessons learned
A few things have stuck with me from operating this lab.
- Real services teach faster than tutorials. A thirty-minute problem in production is worth a week of reading; the lab has been a steady source of those small, instructive failures.
- Constraints encourage good taste. A 1 GB machine makes me question every dependency before I add it, and the resulting systems are easier to understand months later.
- Boring tools age well. nginx, systemd, Tor, and a small set of Python and PHP applications have outlasted several waves of fashionable replacements. I expect the same to be true of the next several waves.
- Privacy is operational. It is not an
on/offsetting, but rather a series of small decisions about what to log, what to expose, and what to depend on.
The Infrastructure Lab will keep changing in small ways, but its shape is settled: a small machine, well-understood software, a few services I actually use, and enough discipline and time to keep it that way.