4 min read

Self-Hosting My Repositories and Sites

Table of Contents

Choosing a Host for My Open Repositories settled the why: self-hosted Forgejo, one instance per area, on infrastructure I run rather than a seat rented on someone else’s. This is the how — written before I have finished building it, so it can be checked against what actually happens rather than tidied up afterward.

Should the Site Be Self-Hosted Too?

The forge decision was about the working repository — where commits land, where CI runs, where releases are cut. The site is a different question, and it does not get answered by the same reasoning automatically.

None of these sites are live yet, so this is not a migration — there is nothing running on Cloudflare Pages to move away from. That changes the question: not whether the cost of moving a working site is worth paying, but which one to build in the first place.

The case for Cloudflare Pages anyway: it is free, it is proven, and Wrangler already means the repository does not have to sit where Cloudflare can see it — only the deploy target needs the API token. Building against it first and revisiting later is the smaller effort today.

The case for self-hosting from the start: building a static file server once, alongside the forge, costs less than building it for Cloudflare first and rebuilding it later — and it finishes the sovereignty argument rather than leaving it half-applied for however long “later” turns out to be: the working repository under my own address, the site it produces served from someone else’s edge in the meantime.

Decision: launch both together. Nothing is live yet, so there is no migration cost to weigh against the sovereignty argument — only the cost of building the static server once instead of twice. A CDN caching in front of it, rather than publishing, solves the latency problem from day one — which CDN is a separate decision, not yet made.

What Has to Get Built

One Forgejo instance per area — sharing a host, a reverse proxy, and one backup regime, so what multiplies with each new area is configuration rather than infrastructure. Forgejo derives every clone and web URL from a single root, so the address an instance answers to becomes canonical for everything inside it: repositories, issues, releases, CI runs.

The site served from day one behind a CDN, not Cloudflare Pages — the static build launches on infrastructure I hold rather than on Cloudflare’s edge. Wrangler never enters the deploy pipeline; a CDN configured to cache rather than to publish sits in front of the origin instead, solving the latency problem without hosting it — Cloudflare’s free tier is the obvious candidate, but which CDN is not decided yet. Serving it is not a new problem — the RAD Stack’s ops layer should cover it without needing the application layer a static site has no use for: Caddy for the reverse proxy and automatic HTTPS, a Cloudflare Tunnel for ingress with no inbound port to expose, systemd managing the process. Untested for this specific case, but nothing about serving static files asks more of that layer than it is already designed to give.


💬

If you run a per-project forge like this and know where it actually breaks, I would rather hear it now than discover it later. Leave a comment below, or get in touch. Follow my RSS feed for the rest of this series as the decisions land.