Everything powering awrealty.homes runs on a single N95 Mini PC sitting in my house. No cloud provider, no managed services, no monthly infrastructure bill. Every piece of the application has it's own under privileged assigned users, nothing runs as root. Here's how it all fits together.
The Foundation: Proxmox & Containers
The N95 runs Proxmox with three LXC containers, each purpose-built and resource-constrained so nothing steps on each other's toes:
- Frontend Container (256MB RAM, Alpine Linux) — Holds the static HTML/CSS/JS files, Nginx reverse proxy, and the Cloudflare Tunnel client. This is the first stop for every visitor.
- Backend Container (1GB RAM, Alpine Linux) — Runs the Rust API service and SurrealDB as independent processes side by side. This is where the brain lives.
- Monitoring Container (1GB RAM, Debian) — Runs Uptime Kuma to track the health of both frontend and backend. I wanted this on Alpine too, but it wasn't playing nice. Sometimes compatibility wins over minimalism.
That leaves over half the N95's available RAM on the table in case I need to allocate more. Every container has auto-boot configured in a specific order with staggered delays so things come up cleanly after a restart. There are no race conditions, and no manual intervention.
The Backend: Rust & SurrealDB
The Rust backend is intentionally bare bones. Right now, the only crates I'm pulling in are Axum, Serde, SurrealDB, Tokio, Tower-HTTP, and Tracing for logging. That's it. The only endpoint that exists today is a health check, because we've been focused on publishing content and building SEO momentum before adding complexity. I laid this foundation down early so that when we do need it, whether that's contact forms, listing data, or analytics, the plumbing is already in place and ready to go.
I chose SurrealDB for the database layer because of its schema flexibility. We honestly don't know what we need yet or what shape the data should take. SurrealDB lets us figure that out as we go without being locked into rigid table structures early on. I've also used it in side projects before and genuinely like the project. If me using it here gives them a tiny bit more visibility, that's a bonus.
The Network: Cloudflare Tunnel, Nginx & Tailscale
The networking layer is designed so that nothing is exposed to the public internet directly. When someone visits awrealty.homes, the request flows through a Cloudflare Tunnel which is a secure, invisible bridge that lets Cloudflare talk to the N95 without ever opening ports on my home router or revealing my home IP address. From there, Nginx acts as the traffic cop: it serves static files from disk for maximum speed and only forwards API requests to the Rust backend when needed.
For management, I use Tailscale to create a private, encrypted VPN exclusively for my devices. This lets me SSH into the N95, deploy code, and manage containers from my laptop without exposing SSH to the world. The result is zero inbound ports open to the internet. Everything either goes through the Cloudflare Tunnel (public traffic) or Tailscale (my traffic).
The Pipeline: GitHub Actions & Rsync
I have two separate GitHub Actions pipelines. One for the frontend, one for the backend. Both connect through Tailscale to securely push changes to the N95 via rsync. Push to main, the pipeline builds, connects, and deploys. I don't have to manually touch the server or worry about pulling changes by hand. It just goes.
Resilience & Backups
Keeping the site alive matters more than I'd like to admit. The N95 sits on an uninterruptible power supply so if the power drops, there's a buffer before everything shuts down gracefully. The BIOS is set to auto-boot on power restoration, Proxmox brings the containers back up in order, and the site recovers on its own. I shouldn't have to touch anything.
For monitoring, I run two services. Uptime Kuma watches the frontend and backend from inside my network, but that has a blind spot. If my whole network goes down, I wouldn't know. So I added UptimeRobot as an external monitor that pings the live site. If it goes unreachable, I get an alert on my phone and can address it immediately.
And for worst-case scenarios, a backup script runs every day at 4AM, pushing full system backups to Google Cloud Storage with a 7-day retention window. If something catastrophic happened, I could pull those backups down and restore the entire system relatively quickly.
What I'd Change
If I'm being honest, frontend work isn't my strong suit. I'm a backend guy. I like seeing data move, watching systems respond, getting the result I want. Design doesn't come as naturally. This site has gone through several iterations, and there's not a single part I'm 100% satisfied with. But that's the nature of building things: they evolve when you find better ways of doing them, and I'm okay with that.