Overview
This site is self-hosted on a Raspberry Pi 5 sitting on a desk at home. Traffic routes through a Cloudflare Tunnel — no ports are forwarded, the public IP is never exposed, and HTTPS is handled automatically. Total cost: ~$10/year for the domain. The Pi is hardwired to the switch (no Wi-Fi) and runs off a UPS, so a brief power blip or brownout won’t drop the site or risk an SD-card corruption mid-write.
| Component | Detail |
|---|---|
| Hardware | Raspberry Pi 5 |
| Network | Wired Ethernet — USW port 13 (static 10.0.0.20) |
| Power | UPS-backed (ride-through on outages) |
| OS | Raspberry Pi OS (Debian/arm64) |
| Web Server | Nginx |
| Tunnel | Cloudflare Tunnel (cloudflared) |
| Domain | the-arcanum.com (Cloudflare Registrar) |
| SSL/TLS | Cloudflare Edge (automatic) |
| Site Type | Static HTML/CSS/JS — no frameworks |
| Port Forwarding | None required |
Step 1 — Install Nginx
# On the Pi
sudo apt install nginx -y
sudo mkdir -p /var/www/yoursite
sudo chown $USER:$USER /var/www/yoursite
Edit the Nginx config to point at your site folder:
sudo nano /etc/nginx/sites-available/default
# Change the root line to:
root /var/www/yoursite;
sudo systemctl restart nginx
Step 2 — Domain & Cloudflare
- Create a free account at
dash.cloudflare.com - Buy a domain through Cloudflare Registrar (~$10/year for a .com)
- DNS is automatically configured when you buy through Cloudflare
Step 3 — Install cloudflared
# Download for ARM64 (Pi 5)
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb -o cloudflared.deb
sudo dpkg -i cloudflared.deb
# Verify
cloudflared --version
Step 4 — Authenticate & Create Tunnel
# Opens a browser URL to authorize
cloudflared tunnel login
# Create the tunnel (note the UUID it returns)
cloudflared tunnel create my-tunnel
Step 5 — Route DNS
# Points your domain at the tunnel
cloudflared tunnel route dns my-tunnel yourdomain.com
Step 6 — Configuration
nano ~/.cloudflared/config.yml
tunnel: YOUR-TUNNEL-UUID
credentials-file: /home/youruser/.cloudflared/YOUR-TUNNEL-UUID.json
ingress:
- hostname: yourdomain.com
service: http://localhost:80
- service: http_status:404
Step 7 — Test
cloudflared tunnel run my-tunnel
Visit https://yourdomain.com — if the site loads, proceed to make it permanent.
Step 8 — Install as Service
# Copy config to system path
sudo mkdir -p /etc/cloudflared
sudo cp ~/.cloudflared/config.yml /etc/cloudflared/config.yml
sudo cp ~/.cloudflared/*.json /etc/cloudflared/
# Install and enable
sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
The tunnel now runs in the background and survives reboots.
Step 9 — Deploy
From your local machine:
scp your-files/* [email protected]:/var/www/yoursite/
Optional — SSH Keys (No Password)
# Generate a key (give it a unique name)
ssh-keygen -t ed25519 -f ~/.ssh/id_mysite
# Copy to the Pi
ssh-copy-id -i ~/.ssh/id_mysite [email protected]
Add to ~/.ssh/config:
Host yourpi.local
IdentityFile ~/.ssh/id_mysite
User youruser
Now scp and ssh never ask for a password.
Result
- ✅ Site live at
https://yourdomain.com - ✅ Free HTTPS — Cloudflare handles certificates
- ✅ Public IP completely hidden
- ✅ No ports opened on your router
- ✅ Works behind CGNAT or dynamic IPs
- ✅ Survives reboots
- ✅ Total cost: ~$10/year (domain only)