Hosting this site on my own hardware: the home server plan

· self-hosting, raspberry-pi, cloudflare, tailscale, homelab

This very site runs on hardware sitting in my home — two Raspberry Pi 4s, no cloud bill, no open ports on my router. Here’s the plan I followed and the architecture that makes it both public and private at the same time.

Goal: run a public portfolio/blog on my own hardware, manage everything privately from anywhere over a VPN, using free services wherever possible.

Hardware: 2× Raspberry Pi 4 (8GB RAM) Domain: luckyganesh.in Total ongoing cost: ₹0/year — the domain was already paid for, and every service below has a free tier.

The core principle

The whole design comes down to one rule:

The public site and the private admin never share a door.

Anyone on the internet can reach the blog. But SSH and the admin dashboards are only reachable by me, over a VPN. Those two paths never touch.

Architecture

                    Internet (anyone)                    Me, from anywhere
                          │                                     │
                  Cloudflare network                      Tailscale app
                  (DDoS + caching)                      (WireGuard VPN)
                          │                                     │
                   outbound-only tunnel                  encrypted mesh
                          │                                     │
   ┌──────────────────────▼─────────────────────────────────────▼──────────┐
   │  HOME NETWORK (no open ports on the router!)                          │
   │                                                                        │
   │   Pi #1  "apollo"                          Pi #2  "vault"              │
   │   ├─ cloudflared (tunnel)                  ├─ Pi-hole (DNS adblock)    │
   │   ├─ Caddy reverse proxy                   ├─ backups (restic)         │
   │   ├─ Astro portfolio+blog (public)         ├─ Uptime Kuma (monitoring) │
   │   └─ admin apps (VPN-only)                 └─ Tailscale (VPN node)     │
   └────────────────────────────────────────────────────────────────────────┘

Two Pis, two jobs

The free-services stack

Everything is open source or has a genuinely free tier:

NeedTool
VPN (access from anywhere)Tailscale
Public exposure (no port forwarding)Cloudflare Tunnel
DNS + CDNCloudflare DNS
Website + blogAstro
Reverse proxy + auto-HTTPSCaddy
ContainersDocker + Compose
Ad-block DNSPi-hole
Monitoring / uptimeUptime Kuma + Glances
Backupsrestic

Why Astro

For the website itself I picked Astro: a static-site generator that’s fast, secure, and uses almost no RAM — ideal for a Raspberry Pi. Publishing a post is just: write Markdown, git push, and the Pi rebuilds the static site automatically.

The publishing workflow

Posting is delightfully boring:

  1. Create a Markdown file under src/content/blog/.
  2. Write the post.
  3. git push.
  4. The Pi pulls, rebuilds, and the new post goes live.

That’s the same flow that published this post. More to come as I build each phase out — next up: getting the tunnel and VPN wired together so the whole thing is reachable (and only by the right people).

← All posts