type: decision
status: active
timestamp: 2026-06-28
tags: [decision, mirror, insurance, git-host, backup, multi-platform, disaster-recovery, radicle, notabug, gitgud, rocketgit]

Mirror repos/own/* to 9 popular GitHub alternatives — weekly cron from the umbrella repo

Mirror repos/own/* to 9 free Git hosts via GH Actions

Mirror repos/own/* to 9 popular GitHub alternatives

Decision

One GitHub Actions workflow (.github/workflows/mirror-all.yml) on the chirag127/workspace umbrella repo pushes every repos/own/* submodule to 9 free, no-self-host GitHub-alternative hosts on a weekly schedule. All state lives in the workflow + chirag127 org-level secrets and variables — zero local runner, zero card.

WorkflowScheduleScopeHosts
mirror-all.ymlFriday 03:30 IST (Thu 22:00 UTC)20 repos/own/* submodules from .gitmodulesAll 9
codeberg-mirror.ymlDaily 08:30 IST (03:00 UTC)Same scopeCodeberg only (daily DR)

The 9 hosts

All free, no card, no self-hosting. Eight are managed git hosts; Radicle is a P2P seed-node network.

#HostFree modelPush methodEnv var(s)
1GitLab.comUnlimited public reposHTTPS PAT (api + write_repository)MIRROR_GITLAB_TOKEN, MIRROR_GITLAB_USERNAME
2Codeberg.orgFOSS non-profit, ForgejoHTTPS token (write:repository)MIRROR_CODEBERG_TOKEN, MIRROR_CODEBERG_USERNAME
3Bitbucket CloudUnlimited public + private (5 users)Workspace Access TokenMIRROR_BITBUCKET_API_TOKEN, MIRROR_BITBUCKET_USERNAME
4Azure DevOpsUnlimited repos, 5 free usersOrg-scoped PAT (Code: Manage)MIRROR_AZURE_DEVOPS_TOKEN, MIRROR_AZURE_DEVOPS_ORG, MIRROR_AZURE_DEVOPS_PROJECT
5GitFlic.ruFree + pull-mirror featurePersonal tokenMIRROR_GITFLIC_TOKEN, MIRROR_GITFLIC_USERNAME
6NotABug.orgFree, Gogs-basedHTTPS access tokenMIRROR_NOTABUG_TOKEN, MIRROR_NOTABUG_USERNAME
7GitGud.ioGitLab + Sapphire, unlimited free public + privateHTTPS PATMIRROR_GITGUD_TOKEN, MIRROR_GITGUD_USERNAME
8RocketGit.comUnlimited public + private, freeHTTPS API tokenMIRROR_ROCKETGIT_TOKEN, MIRROR_ROCKETGIT_USERNAME
9RadicleFree P2P, public seed radicle.gardenrad CLI + restored keypairMIRROR_RADICLE_KEYPAIR_TAR_B64, MIRROR_RADICLE_PASSPHRASE

Two hosts added 2026-06-28

HostWhy added
GitGud.ioGitLab + Sapphire; unlimited free public + private; managed; another GitLab-fabric mirror under a different operator (trust-sphere diversity).
RocketGitNiche but stable git-only host, unlimited public + private free, no card; adds non-GitLab/non-Gitea fabric for max code-host diversity. No public REST API for repo creation — pre-create manually if push 404s.

Rejected (kept here, won’t be added)

PlatformWhy not
Framagit42-project cap per user — too tight for future scale even though we have 20 today
AWS CodeCommitAWS halted onboarding mid-2024; not in 2026 rankings
SourceHut (sr.ht)€4+/month — violates no-card-on-file
Google Cloud Source ReposClosed to new users since 2024-06-17
Gitee (gitee.com)Requires Chinese phone number
HeptapodMercurial-first; git support via hg-git bridge, no clean git push --mirror
PijulNot git — different patch model
Projectlocker1 project / 50 MB — won’t hold 20 repos
Savannah (GNU + non-GNU)Manual approval per project; FOSS-only
Gitea Cloud30-day trial only
GitVerse.ruRussian-niche; GitFlic already covers that hedge
LaunchpadUbuntu-ecosystem only

Architecture

GitHub repo: chirag127/workspace
+-- .github/workflows/mirror-all.yml  (the only state)

Friday 22:00 UTC (Friday 03:30 IST)
+-- Job: discover (parse repos/own/* from .gitmodules ? 20-repo matrix)
+-- Job: mirror (matrix × 8 HTTPS hosts:
¦     GitLab, Codeberg, Bitbucket, GitFlic, Azure, NotABug,
¦     GitGud, RocketGit)
+-- Job: mirror-radicle (separate — installs rad CLI, restores keypair, syncs)
+-- Job: weekly-digest (Telegram 9-host summary)

All credentials live as org-level GitHub Secrets under chirag127 (the org that owns the umbrella chirag127/workspace repo running the cron). ENABLE flags live as org-level Variables so each host can be flipped 0?1 without touching credentials.

Radicle identity bootstrap (one-time)

The runner needs a Radicle keypair to push. Generate it once locally and store as a base64 tarball in MIRROR_RADICLE_KEYPAIR_TAR_B64:

# Local one-time
curl -sSfL -H "Accept: text/plain" https://radicle.xyz/install | sh
rad auth                                          # creates ~/.radicle/keys
tar czf - -C ~/.radicle keys | base64 -w0 \
  | gh secret set MIRROR_RADICLE_KEYPAIR_TAR_B64 --org chirag127 --visibility all
gh secret set MIRROR_RADICLE_PASSPHRASE --org chirag127 --visibility all

Workflow then unpacks ~/.radicle/keys, configures radicle.garden as the preferred seed, and runs rad init (idempotent) + rad sync --announce.

RPO / RTO

Cost ceiling

All 9 hosts free without card-on-file (verified 2026-06-28). Zero ongoing cost.

Cross-refs


Edit on GitHub · Back to index