AboutTheEngineer

This page reveals the human story behind the engineering, showing how I built a high-performance, cost-effective real estate website for my wife using HTML, CSS, JS, Rust and SurrealDB on a $100 N95 Mini PC.

Call Joe
Joe Wennesheimer

About Me

Hi, I'm Joe. I've lived in Green Bay most of my life, surrounded by family, before my wife and I made the jump up to Crivitz a decade back. We moved here for the slower pace and to be closer to the water. I wanted to be able to fish after work without driving an hour, and now I do exactly that.

My path hasn't been a straight line. I started out studying Kinesiology with dreams of athletic training, then spent time in construction learning how to build things with my hands. Eventually, I realized I enjoyed solving complex problems more than anything else, which led me from hammers to keyboards. Today, I run a tight household with two dogs, two cats, a bearded dragon, and about 20 fish. I'm also a dad who loves playing RPGs and base-building games with my daughter, and I'm still grinding on Old-School Runescape after 22 years.

People often describe me as the "rock" of the group. I tend to be the calm one when things get chaotic, though sometimes I solve problems a little too quickly. I have a habit of offering solutions when people just want to vent. That problem-solving mindset extends to everything I do, from fixing cars and doing home repairs to helping my wife navigate business decisions. In fact, our partnership works because I handle the strategy and technical logic while she manages the people and legal side. Seeing her finish her first year in the top 8% of agents in our county is something we're both incredibly proud of.

I'm a pretty direct person. I value honesty and clarity over corporate fluff because I believe we waste enough time already. If there's a problem, I'll tell you plainly what I see and how we can fix it. It's not about being tough; it's about respecting everyone's time and getting to the truth so we can move forward.

At the end of the day, I got into software engineering for a simple reason: I wanted a stable, good-paying job that would fund my life outside of work. I love my job, but I don't want it to be my entire identity. I'd rather put in eight hours of focused effort, go home, lift weights at 5 AM the next morning, and spend my evenings fishing or gaming with my family.

If you're looking for someone who takes ownership, communicates clearly without the noise, and genuinely cares about building things that last—both technically and personally, I think we'd get along well.

Why I Built This

My wife, Alyssa, needed a website when she started her real estate career. Most agents use templated platforms—and honestly, I couldn't stand the idea of her being stuck with something generic, slow, and dependent on someone else's code.

For me, this wasn't just about having a nice-looking page. I didn't want the burden falling on her to debug why something wasn't working, or to figure out design decisions while also running her business. I wanted us to own everything. No licenses, no monthly fees, no waiting on a vendor to fix an issue. Just a system we built ourselves, where every piece could be understood, adjusted, and secured.

There was also a growing frustration in how much of modern web development has become bloated and fragile. We started down the path using Angular, but soon after, a series of supply chain attacks hit the NPM ecosystem hard. I found myself worried about pulling in packages that could compromise the site. The whole thing felt like it was built with toothpicks, and I realized I didn't want to inherit that problem forever.

So I stripped it back. Instead of starting with an entire house, I decided to start with a shed. Build it lean, build it stable, and let it grow naturally from there. Vanilla HTML/CSS/JS for the frontend, Rust for the backend, SurrealDB for the database—all of it hosted locally on hardware I secured myself. Web crawlers prefer simple HTML anyway, and from a business standpoint, faster load times and better SEO mattered more than flashy frameworks.

I spent most of my time laying the foundation: securing the N95 Mini PC, setting up GitHub Actions pipelines so deployments happened automatically, making sure the theme stayed consistent across every screen size. I wanted to build something that could last, not something that just shipped for a pitch deck.

And here's the truth: I've taken off social media because I value my privacy, and most of my friends are from construction. They don't know what it takes to spin up a Proxmox machine, lock down VMs, configure Cloudflare tunnels, configure pipelines, and deploy a full-stack app from scratch. People can see the website, but they can't see the work underneath. If I didn't put this online, nobody would ever know what went into it, and that felt unfair to myself and the effort I put in.

Will it ever be done? Probably not. That's the engineer in me. There's always room to improve, always something to refine. But Alyssa is genuinely impressed, and I've had other people reach out asking if I can build their sites too. That's validation enough.

Why I Built It This Way

If you strip away the code and talk about values, there are five principles that guided every decision on this project. None of them were flashy — they're just things that matter when you want something to last.

Start Lean, Scale Later

I started hosting on Azure Web Apps because static sites are free there. But once I needed a backend, I hit a wall: I didn't want to risk an infinite loop or something wild and get hit with a $10,000 bill from cloud providers. My next idea was using a Raspberry Pi I had lying around, but then I'd have to deal with ARM architecture quirks. So I landed on the N95 Mini PC, which is reliable enough to boot after power loss, powerful enough for the load, and simple enough that I can manage it myself. No AWS, no GCP, no vendor lock-in. Just hardware I control.

Trust the Compiler, Not Me

I picked Rust because I like the "pay for it upfront" concept. The language trusts the compiler over the developer, and honestly, I trust the compiler more than myself. Am I a Rust expert? Not really. I go through spurts where I'm excited to write in Rust, struggle through building something, and then set it down for a bit. But when it compiles, the chances of it crashing in production is slim. That peace of mind means I don't have to worry about runtime surprises eating into my time off.

Keep It Simple On Purpose

There wasn't one moment where I realized " frameworks are bad." It was smaller things compounding. I do miss some React and Angular conveniences, components are nice. But the supply chain attacks, the endless dependency updates, the feeling that I need to double-check the language rather than having the language double-check me... those added up until it felt easier to start from scratch with vanilla HTML/CSS/JS. Will it go back if there's a need? Maybe. Dioxus might be calling my name down the road. But right now, simplicity wins.

Security Is About Realism, Not Paranoia

I wouldn't call myself paranoid about security. At work, we never dealt with major breaches. And sometimes I think people take it too far. Most people don't have iron bars on their windows. We acknowledge that if someone wants in, they'll find a way. We just try to make it hard enough that they give up before trying. If the security is so heavy that I can't do my own work or access my own systems, it's pointless. This approach came from thought experiments and research, figuring out what actually matters and implementing that, nothing extra.

SEO First, Everything Else Second

Truthfully, SEO was the biggest driver behind choosing vanilla HTML. I spent hours researching how to make SEO work with web applications, and it always seemed overly complicated. With plain HTML, crawlers know what they're looking at immediately. No JavaScript bottlenecks, no rendering delays. I wanted Alyssa to be the first result that pops up when someone searches for real estate in Crivitz. We're leagues away from hitting that goal, but that's the end game. Technology should serve the business, not the other way around.

The takeaway: Every choice here was made for longevity, transparency, and ease of ownership. Not because they're trendy, but because they respect the end user's time and the owner's control.

The Architecture Underneath

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.

LayerTechnologyWhy
FrontendVanilla HTML/CSS/JSZero runtime overhead. Crawler-friendly. Maximum SEO.
BackendRust (Axum + Tokio)Compiles safe, crashes rarely. Peace of mind.
DatabaseSurrealDBSchema-flexible. We define data shapes when we're ready, not before.
Reverse ProxyNginxServes static files instantly. Routes API calls to Rust.
TunnelCloudflare TunnelZero open ports. Home IP stays hidden. SSL handled automatically.
VPNTailscalePrivate access for deploys and management. No public SSH.
InfrastructureN95 Mini PC + Proxmox LXC$100 hardware, full ownership, constrained by design.
OS (App Containers)Alpine LinuxTiny footprint, minimal attack surface, boots fast.
CI/CDGitHub Actions + rsyncPush to deploy. No manual server touches.
MonitoringUptime Kuma + UptimeRobotInternal + external coverage. Alerts to phone.
BackupsDaily to Google Cloud Storage7-day retention. Full system restore capability.
PowerUPS + BIOS auto-bootPower backup and auto-recovery on power return.