neversettledblog.com
A fully self-hosted travel blog for a military family. Built from scratch — no WordPress, no third-party CMS, no managed hosting. Posts are written through a custom admin panel, stored in SQLite, and published as static HTML files served directly by Caddy.
Also includes a full email server (Mailcow) at mail.neversettledblog.com, providing @neversettledblog.com addresses with webmail access.
How publishing works
- Posts are created and edited via the admin panel at
/admin/ - The FastAPI backend handles auth (JWT), post CRUD, and image uploads
- Publishing a post renders it to a static
.htmlfile and rebuildsindex.html - Caddy serves all static files directly — no server-side rendering per request
- Image uploads stored on-disk, served by Caddy alongside post HTML
Infrastructure
- VPS (2 CPU, 8GB RAM) at 76.13.103.159
- Top-level Caddy (havoc-site) handles SSL termination for all domains via Let's Encrypt
- Blog Caddy container on port 8080 routes
/api/*and/admin/*to the FastAPI service and serves static files for everything else - FastAPI/uvicorn runs on port 8000 inside the Docker network
- Mailcow email server at
mail.neversettledblog.com— web UI proxied through Caddy, email ports (25, 587, 465, 993) exposed directly
Stack
Python
FastAPI
SQLite
Caddy
Docker
Mailcow
Let's Encrypt
VPS