About This Site
No cloud providers, no open ports β just a Mac Mini on a shelf serving static files through a Cloudflare tunnel.
The Stack
This site is a statically exported Next.js 15 application built with React 19 and TypeScript. At build time, every page becomes a plain HTML file β no server-side rendering, no API routes, no Node.js runtime in production. Just flat files.
Tailwind CSS 4 handles all styling through utility classes and CSS custom properties. The entire design system β colors, typography, spacing β lives in a single globals.css file. No component library, no CSS-in-JS.
Typography uses Instrument Serif for display headings and DM Sans for body text, loaded through next/font/google with automatic subsetting and self-hosting. The language switcher and scroll-triggered animations are the only pieces of client-side interactivity.
The Server
This site runs on a Mac Mini Late 2012, a machine that spent years as a desktop before being retired to a shelf and given a second life as a home server. The hardware is modest: a dual-core Intel i5, upgraded to 16 GB of RAM and a 1 TB SSD. It draws about 10 watts at idle.
The machine runs Ubuntu Server headless β no display, no keyboard, managed entirely over SSH. It hosts this site alongside a few other containers and personal projects.
The entire setup costs about $2/month in electricity. No cloud bills, no subscriptions, no usage tiers.
How It Gets to You
The site is packaged as a Docker container using a multi-stage build: Node 22 builds the static files, then just the output gets copied into a tiny Nginx Alpine image (under 25 MB). Deploys are a single command that rebuilds and restarts the container in about 30 seconds.
Caddy sits in front of all containers as a reverse proxy, handling automatic TLS certificates via Let's Encrypt. Each container runs its own web server (Nginx), keeping apps self-contained and portable, while Caddy routes traffic by domain name.
A Cloudflare Tunnel creates an outbound-only connection from the server to Cloudflare's edge β no ports are open on the home network, no port forwarding, no dynamic DNS. It even works behind CGNAT, so you don't need a public IP address. Cloudflare handles DNS, DDoS protection, and edge caching on top.
Want to build something like this?
I wrote a detailed step-by-step guide covering everything from scaffolding the Next.js project to setting up the Cloudflare tunnel. It's aimed at beginners β if you can open a terminal, you can follow along.
Read the guide β