The Sovereign Replit
Deployment Stack
This is the full formula — not just code backup, but a complete self-hosted CI/CD pipeline with a CDN edge layer. Built by WellSpr.ing after GitHub suspended 32 civic AI repositories without warning on April 18, 2026. Documented here as a gift. Freely given, so freely given.
— Lesson from the WellSpr.ing migration, April 2026
The four-layer stack
Each layer is independent. Add them in order — each one makes you meaningfully harder to disrupt.
# Layer 1 — Git (sovereignty) git.yourname.org Forgejo on Railway ~$5/mo └─mirror→ codeberg.org (nonprofit backup) └─mirror→ github.com (discovery — optional) # Layer 2 — CI builds (speed) Hetzner cx23 2 vCPU / 4GB €5/mo Forgejo act_runner → Go builds in ~45s, Node in ~3min vs. Replit shared CPU → 15-minute deploys # Layer 3 — Edge (resilience) Fly.io proxy 2 regions ~free tier → points to Replit deployment URL → Bunny DNS health-checks both; fails over in <30s # Layer 4 — CDN (performance + IP hygiene) Bunny CDN anycast edge ~$1/mo Clean IP in front of Replit's shared egress Zone pull from Fly.io (not directly from Replit)
Total cost: ~$11/mo for a production-grade, platform-independent deployment. Replit stays as your development environment. You stop being single-homed on any single vendor.
— Anurag Vishwakarma, April 11 · 147k impressions
The Replit situation
Replit connects your project to GitHub automatically. That's useful for discoverability and backup — until GitHub decides, with no warning and no explanation, that your account is suspended. At that point your project's remote becomes unreachable. If you haven't pushed locally, or if Replit's sync was the only copy, you've lost the history.
The good news: Replit projects are almost always small. The median project fits comfortably under 10 MB. Adding a second remote — one that isn't GitHub — takes two commands and zero dollars.
Path A — Codeberg only (recommended for most users)
Codeberg is a nonprofit, community-governed Forgejo instance hosted in Berlin. Free for open source. No IP bans on record. Run by a German non-profit (Codeberg e.V.) under German law. Likely the best GitHub exit for the majority of Replit users.
git remote add codeberg https://codeberg.org/YOURUSERNAME/YOURREPO.git git push codeberg --all
git push origin && git push codeberg# Add to ~/.bashrc in your Replit alias gpa='git push origin && git push codeberg'
Path B — Self-hosted Forgejo as primary (power users)
If you're running an AI agent pipeline, a civic project, or anything that makes dozens of API calls to GitHub per day, you want Forgejo as your primary — not just a mirror. This is the full three-mirror architecture documented at notgit.org/formula.
# Your sovereign primary — no rate limits, no ban risk, no TOS scrutiny git.yourname.org (Forgejo on Railway, Hetzner, Fly.io) └─push-mirror→ codeberg.org/you/repo (community discovery, nonprofit) └─push-mirror→ github.com/you/repo (commercial discovery — optional)
The Railway Forgejo template gets you a running instance in about ten minutes. Full walkthrough: notgit.org/push-mirror-setup. Once it's running, configure your Replit to push to Forgejo instead of GitHub, and let the push-mirrors handle downstream propagation automatically.
Railway Forgejo cookbook — what actually works
Forgejo on Railway is the fastest path to a self-hosted primary. Three things that will save you hours if you know them going in:
/data/git, not /data/data/git and creates the git user there. If you mount a Railway volume at the root /data, the entrypoint sees an empty, root-owned directory and Forgejo fails to start. Mount at /data/git — the entrypoint handles the rest.
# Railway volume: Mount Path /data/git ✓ correct — entrypoint chowns this /data ✗ breaks entrypoint (root-owned, empty)
FORGEJO__repository__ROOT to the git subpath/data/repositories. But the entrypoint only creates and chowns /data/git/repositories. If you don't override this env var, Forgejo writes repos to a root-owned path and every push fails with permission denied.
FORGEJO__repository__ROOT=/data/git/repositories ✓ # NOT /data/repositories — that path is root-owned
auto_init: true when creating repos via APIauto_init: true exists in the database but has no git objects on disk. It looks healthy in the UI but every API call that touches its contents returns 404 or an empty tree. Always init — especially if you're using a provisioner to create many repos.
# POST /api/v1/user/repos { "name": "my-repo", "auto_init": true, ← required "default_branch": "main" }
auto_init: true. There is no in-place repair.
Layer 2 — CI builds on a €5 Hetzner server
Replit's 15-minute deploy is a shared-CPU bottleneck on the containerized build. The same Vite + TypeScript compile that takes 15 minutes on Replit takes 2–4 minutes on a dedicated Hetzner cx23 (2 vCPU / 4 GB, €4.99/mo). Go binaries build in 30–45 seconds instead of never-completing cross-compiles.
The mechanism is Forgejo Actions — the self-hosted equivalent of GitHub Actions — running on a dedicated act_runner process on the Hetzner box.
# cx23: 2 vCPU / 4 GB RAM / €4.99/mo — best value for CI curl -X POST https://api.hetzner.cloud/v1/servers \ -H "Authorization: Bearer $HETZNER_CLOUD_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "myproject-builder", "server_type": "cx23", "image": "ubuntu-24.04", "location": "nbg1", "ssh_keys": [YOUR_SSH_KEY_ID] }'
HETZNER_CLOUD_TOKEN. This call returns a public IP in under 30 seconds.
user_data in the server creation payload to run the setup script on first boot. Key installs:
# Go 1.22 (for cross-compiled binaries) wget https://go.dev/dl/go1.22.3.linux-amd64.tar.gz tar -C /usr/local -xzf go1.22.3.linux-amd64.tar.gz # Node.js 20 LTS (for Vite/npm builds) curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt install -y nodejs # Forgejo act_runner v0.4.1 curl -fsSL https://gitea.com/gitea/act_runner/releases/download/v0.4.1/act_runner-0.4.1-linux-amd64 \ -o /usr/local/bin/act_runner && chmod +x /usr/local/bin/act_runner
dl.gitea.com/act_runner/latest/ path returns 404. Use the direct Gitea release URL above.
git.yourname.org/-/admin), expand Actions → Runners in the sidebar — the feature is already enabled in Forgejo 10.x. Click "Create Runner" to get a registration token, then on the Hetzner server:
# Run as the runner user on the Hetzner box act_runner register \ --no-interactive \ --instance https://git.yourname.org \ --token YOUR_REGISTRATION_TOKEN \ --name myproject-hetzner \ --labels ubuntu-latest:docker://node:20-bullseye-slim
# .forgejo/workflows/release.yml name: Release on: push: tags: ['v*'] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build Linux run: | GOOS=linux GOARCH=amd64 CGO_ENABLED=0 \ go build -ldflags "-s -w" -o myapp-linux . - name: Create Release uses: actions/forgejo-release@v2 with: direction: upload release-dir: . release-notes: "Binary release"
v1.0.0 tag and the runner picks it up, builds cross-platform binaries, and attaches them to the Forgejo release — all on your €5 server, not Replit's shared pool.
Layer 3 — Edge resilience with Fly.io + Bunny DNS
Replit's deployment gives you a single *.replit.app endpoint on shared infrastructure with a shared IP pool. Two problems: (1) shared IPs occasionally get flagged by spam filters or rate-limited by APIs, and (2) a Replit outage takes your app down with no fallback. The edge layer solves both.
# server.js — the entire Fly.io app const http = require('http'); const { createProxyMiddleware } = require('http-proxy-middleware'); const TARGET = process.env.UPSTREAM_URL; // e.g. https://myapp.yourusername.repl.co http.createServer( createProxyMiddleware({ target: TARGET, changeOrigin: true }) ).listen(8080);
fly launch from your Replit shell — it creates a Fly.io app with a dedicated IPv4 and routes traffic to Replit. Your custom domain (via CNAME to myapp.fly.dev) now has a clean IP address.
bunny.net) costs $1–2/month for CDN pull zones and gives you anycast DNS with sub-30-second failover. Point your domain's A record at the Fly.io IP. Configure a health check on both the Fly.io proxy and your Replit deployment URL. If Fly goes down, Bunny reroutes to Replit directly. If Replit goes down, you know in 30 seconds.
# Bunny DNS zone — your domain A @ FLY_APP_IP TTL 60 # primary (clean IP) A @ REPLIT_IP TTL 60 # fallback (health-check gated)
Full cost table
| Layer | Service | Cost | What it does |
|---|---|---|---|
| Git primary | Railway (Forgejo) | $5/mo | Self-hosted git host, API, push mirrors to Codeberg |
| CI runner | Hetzner cx23 | €5/mo | Forgejo act_runner — 45s Go builds, 3min Node builds |
| CDN / Edge | Bunny CDN | ~$1/mo | Anycast IP, pull zone, DNS failover, DDoS absorption |
| Proxy | Fly.io | free tier | Clean dedicated IP, geo-proxy, Replit abstraction layer |
| Code mirror | Codeberg | free | Nonprofit backup, community discovery |
| Dev environment | Replit | existing | AI-assisted development, hot reload, always-on URL |
| Total added | ~$11/mo | Full sovereign deployment stack |
This entire cookbook was built in a 35-minute compute sprint by a Replit AI agent after GitHub suspended the WellSpr.ing account. The same agent that lost its GitHub access built the infrastructure that makes losing GitHub access irrelevant. The recipe is the proof.— WellSpr.ing, April 2026
NotGit.org runs on exactly this architecture. The source lives at git.wellspr.ing/wellspring/notgit — self-hosted Forgejo on Railway, mirrored to Codeberg. Deployments are built by a Forgejo act_runner on Hetzner. The domain sits behind Bunny CDN with a Fly.io proxy as the primary endpoint. We wouldn't publish a cookbook we don't eat from.
Why Replit users are specifically at risk
| Factor | Risk |
|---|---|
| AI-assisted coding at speed | Replit's AI agent can commit and push faster than a developer working alone. Rapid automated commits match GitHub's suspension trigger patterns. |
| GitHub as the only remote | Replit's sync button pushes to GitHub only. One GitHub suspension = complete loss of remote access. |
| "Sign in with GitHub" dependencies | If your app uses GitHub OAuth, a ban cuts off your users too — not just your code. |
| No warning, no appeal SLA | The pattern documented at notgit.org/incident/2026-04-18 — suspension with no notice, appeal replies taking days or never arriving. |
The five rules for AI-era Replit development
repo scope only — not admin:org, not delete_repo. Broad tokens making many calls per minute match the detection pattern."GitHub is still the best place to collaborate and be discoverable. Nothing wrong with using it. The problem is using it as the only copy."— Anurag Vishwakarma, on the lesson his account suspension taught him