TGViewer
r/SelfHosted r/SelfHosted @r_selfhosted · 969 subscribers
Post #53976 24
Started self-hosting bootstrapped projects on Mac Mini (and moved away from AWS)

I've been running my side projects on AWS for a while and the bill kept creeping up. Every new idea meant another EC2 instance with its own monthly bill (full disclaimer: this was probably not the most efficient setup). So I bought a Mac mini M6 (24GB/512GB) and moved everything home. Both apps run from my living room now and the EC2 instances are off.

Here's roughly how it's set up:

* Cloudflare Tunnel (free plan) so nothing on my network is exposed. The mini connects out to Cloudflare, no open ports, and my home IP stays hidden.
* One Caddy instance in front of everything, routing by hostname.
* Docker Desktop with one Compose project per app, each with its own Postgres, Redis and Celery workers.
* Nightly backups with restic to Backblaze B2, plus a Sentry check-in so I find out if one fails.
* SSH and Screen Sharing only over Tailscale.

The part I spent the most time on was the networking. Only the web/frontend containers join a shared "edge" network with cloudflared and Caddy. The databases, Redis and workers stay on each project's private network, and nothing publishes a port on the host:

Visitor ─► Cloudflare ─► tunnel (outbound from the mini)
│
┌─ edge (shared) ───────────▼──────────────────┐
│ cloudflared ──► Caddy (routes by hostname) │
│ │ │ │
│ app1-web app2-web │
└────────────────────┼───────────────┼─────────┘
│ │
┌─ app1 private ─────┴──┐ ┌─ app2 private ────┴┐
│ Postgres, Redis, │ │ Postgres, Redis, │
│ workers │ │ workers │
└───────────────────────┘ └────────────────────┘

Since Caddy talks to containers by name, two projects can both use port 8000 and I don't have to keep track of ports anymore. Adding a new project is basically copying a template folder and adding a few lines of config.

It's not perfect, and I made some trade-offs on purpose. FileVault is off so the mini can come back on its own after a power outage (the offsite backups are encrypted, at least). Both web apps share the edge network, so if one got compromised it could reach the other's web container, though not its database. I'm fine with that since both apps are mine. It's also obviously a single point of failure, so a UPS is on the way. And Cloudflare's free plan cuts requests off at 100 seconds, so anything slow has to run as a background job.

This is really meant for early-stage projects. If one of them ever takes off, it's the same containers, so moving back to the cloud shouldn't be a big deal.

I wrote up the whole thing in more detail here, with the configs and some security stuff I learned along the way: \[[LINK](https://medium.com/@jjacosta37/i-turned-a-mac-mini-m6-into-my-personal-server-and-left-aws-behind-63e29f8bd1fb)\]

Thinking of open-sourcing the edge network setup as a template. Let me know if you'd be interested!

Would also love to hear your thoughts on the setup. Are any of you self-hosting your own projects, and what are you doing differently?

https://redd.it/1x1lo1s
@r_SelfHosted
Medium I Turned a Mac Mini M6 Into My Personal Server and Left AWS Behind The bill that kept growing
More from @r_selfhosted
  1. Oct 10, 2026Built a wordle plugin for Claude Code Ever felt like you don't know what to do when Claude…
  2. Oct 10, 2026My browser Gaming Server setup! https://youtu.be/uUlEZznbYzY https://redd.it/1x1za34 @r_Se…
  3. Oct 10, 2026How do you backup your home lab? Hey Guys, So i got 3 mini pc, 2 which i wanna use for stu…
  4. Oct 9, 2026Filestash iOS client? I found Filestash for my file management on my small server, but I w…
  5. Oct 9, 2026information. 8. Low administrative overhead. If the system requires us to manually log eve…
  6. Oct 9, 2026Building a self-hosted “boat management system” Baserow or something else? Looking for an…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →