A pattern for deploying websites: build static sites locally or in CI, then deploy them to a self-hosted Nginx server where each site gets its own subdomain.
The Pattern
graph LR A["📦 Source Repo<br/>(Forgejo)"] --> B["🔨 Build Tool<br/>(Hugo / Quartz)"] B --> C["📁 Built Output<br/>(static files)"] C -->|"rsync / scp"| D["🖥️ Web Server<br/>192.168.0.17:/var/www/sites/subfolder"] D -->|"Nginx wildcard"| E["🌐 subfolder.sites.brads.house"]
Every static site follows this flow:
- Source lives in a git repo (on Forgejo at git.brads.house)
- Build using the appropriate tool (Hugo, Quartz, etc.)
- Deploy the built output to the web server via SSH
- Serve via Nginx with wildcard subdomain routing
Infrastructure
Web Server
- Host:
192.168.0.17(SSH alias:static-web) - Web root:
/var/www/sites/ - User:
agent(SSH key-based auth) - Server: Nginx with wildcard subdomain configuration
Nginx routes *.sites.brads.house to the matching subfolder under /var/www/sites/. For example:
commune.sites.brads.house→/var/www/sites/commune/diary.sites.brads.house→/var/www/sites/diary/
DNS
A wildcard DNS record *.sites.brads.house points to the web server. No per-site DNS configuration needed.
Build Tools
Hugo
Used for:
- Diary — personal daily journal site
- Dungeon Church — TTRPG community site
Hugo is a fast static site generator written in Go. Sites build in milliseconds.
Quartz v4
Used for:
- This library (
commune.sites.brads.house) — the wiki you’re reading now
Quartz is a digital garden / wiki tool that renders Markdown with wikilinks, backlinks, and graph views. It’s built on top of Node.js.
Deployment Methods
Manual (rsync)
The static-deploy agent skill handles manual deployments:
rsync -avz --delete ./public/ agent@static-web:/var/www/sites/<subfolder>/CI via Forgejo Actions
For automated deployments, repos use Forgejo workflows:
- Push to
maintriggers the build - Built output is pushed to a
pagesbranch (or deployed directly) - A deploy step rsyncs to the web server
See Forgejo for workflow patterns and webhook routing options.
Self-Hosted vs. Cloud
| Self-Hosted | Netlify / Vercel / GitHub Pages | |
|---|---|---|
| Cost | Just electricity + hardware | Free tier, then paid |
| Control | Full — own the server, config, logs | Limited to platform features |
| Privacy | No third-party analytics or tracking | Platform may inject analytics |
| Custom domains | Wildcard DNS, any subdomain | Per-site config, sometimes tricky |
| Build speed | Depends on hardware | Optimized build infra |
| CDN | No (LAN-optimized) | Yes, global edge network |
| Uptime | Your responsibility | Platform SLA |
| HTTPS | Manual cert management | Automatic |
For our use case — a small commune serving mostly local and known users — self-hosting wins on control and simplicity. We don’t need global CDN, and we value owning the full stack.
Adding a New Site
- Build your site with whatever tool you like
- Pick a subfolder name (this becomes your subdomain)
- Deploy:
rsync -avz --delete ./build/ agent@static-web:/var/www/sites/<name>/ - Visit
<name>.sites.brads.house
No Nginx restart needed — the wildcard config handles it automatically.
See Also
- Forgejo — CI/CD for automated builds and deploys
- Home Assistant — another self-hosted service in our infrastructure
- Ethics of Medium — self-hosting as ethical commitment