Tired of GitHub going down? Automatically mirror your code on a server you own!
A simple Elysia/Bun server that receives a GitHub organization webhook and, whenever a repository is created, creates a matching pull mirror in a Gitea / Forgejo instance automatically.
-
Install packages
bun install
-
Copy the example env file and fill it in
cp .env.example .env
-
Run it
bun run dev # watch mode bun run start # once
GET /healthreports configuration health:200with{ "ok": true, "configuration": { "valid": true, "errors": [], "warnings": [] } }when the environment is valid, or503with the offending variables listed underconfiguration.errors. Invalid config is logged at startup but does not crash the server, so this endpoint stays reachable to diagnose it.
- Deploy once, and leave it to do it's job!
- Click the button below to configure and deploy to Vercel:
- Docker images are available at cr.mikandev.com.
The webhook only mirrors repos created after it is installed. To back-fill every repo
that already exists in the org(s) named by GITHUB_ORG, run:
bun run seedIt reads the same .env, lists all repositories in each org via the GitHub API, and
mirrors each one with createMirror (identical settings to the webhook). Already-mirrored
repos are reported as exists and skipped, so it is safe to re-run. GITHUB_TOKEN is
required to include private repositories. This may also be useful if the webhook fails to be sent for whatever reason, and a desync occurs.
| Var | Required | Default | Description |
|---|---|---|---|
PORT |
no | 3000 |
Local listen port (Vercel injects its own). |
GITHUB_ORG |
no | — | Owner allowlist. Empty accepts any owner the webhook delivers; comma-separated for several. |
GITHUB_TOKEN |
for private repos | — | PAT (repo scope). Sent to Gitea as the clone auth_token so it can pull private sources. |
GITHUB_WEBHOOK_SECRET |
yes | — | HMAC secret verifying X-Hub-Signature-256. |
GITEA_URL |
yes | — | Base URL, e.g. https://gitea.example.com (no /api/v1). |
GITEA_TOKEN |
yes | — | Gitea/Forgejo API token with repo create rights in GITEA_ORG. |
GITEA_ORG |
yes | — | Destination owner for every mirror. May be an org or a user. |
MIRROR_INTERVAL |
no | 8h0m0s |
Pull-mirror sync cadence. |
MIRROR_LFS |
no | false |
Mirror Git LFS objects. |
MIRROR_PRIVATE |
no | auto |
auto matches the source visibility; true/false forces it. |
LOG_LEVEL |
no | info |
Log verbosity. |
Add the webhook on the organization (Settings → Webhooks):
- Payload URL: your server URL +
/webhook(e.g.https://host/webhook) - Content type:
application/json - Secret: the same value as
GITHUB_WEBHOOK_SECRET - Events: select individual events → Repositories
Create the token under a user that can create repositories in GITEA_ORG (repository
read/write scope). The mirror is created with mirror: true, so Gitea keeps it in sync with
GitHub on the MIRROR_INTERVAL schedule.
