---
title: "Deploy Gitea Mirror | (Just Updated) GitHub to Gitea and Forgejo Backup, Admin Preset, Data Survives Redeploys"
description: "Gitea Mirror: back up GitHub repos to Gitea or Forgejo, admin preset"
category: "Storage"
url: https://railway.com/deploy/gitea-mirror-or-just-updated-github-to-g
---

# Deploy Gitea Mirror | (Just Updated) GitHub to Gitea and Forgejo Backup, Admin Preset, Data Survives Redeploys

Gitea Mirror: back up GitHub repos to Gitea or Forgejo, admin preset

**[Deploy Gitea Mirror | (Just Updated) GitHub to Gitea and Forgejo Backup, Admin Preset, Data Survives Redeploys on Railway](https://railway.com/template/gitea-mirror-or-just-updated-github-to-g)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/gitea-mirror-or-just-updated-github-to-g/manifest.json

- **Creator:** SuperSlowSloth
- **Category:** Storage

## Template content

### gitea-mirror

- **Image:** ghcr.io/bon5co/gitea-mirror-railway:3.51.7@sha256:85478a63ad492af3d883fad4a6750da422f180c72729e22bf7afbfd1c8e604ed
- **Health check:** /api/health
- **Public domain:** Yes

## Documentation

# Deploy and Host Gitea Mirror on Railway

**Built for an LLM agent to deploy and use.** The deploy form has no fields to fill, and the admin account is created for you at first boot, so nobody can claim the instance by opening the page first. Gitea Mirror is an open-source, self-hosted service that backs up GitHub repositories, organisations and starred repositories into your own Gitea or Forgejo server and keeps them in sync on a schedule.

## About Hosting Gitea Mirror

This template runs one service, **gitea-mirror**: a Bun and Astro web app with its SQLite database and generated secrets on a volume mounted at `/app/data`. You connect a GitHub token and a Gitea or Forgejo token on its Configuration page (or through the API), pick what to mirror, and it keeps the copies current.

**Admin preset.** Upstream lets the first visitor register and become the only admin, so a fresh public deploy belongs to whoever finds the URL first, and an agent has no login to use. This template generates `ADMIN_EMAIL` and `ADMIN_PASSWORD` per deploy and creates that account at first boot; upstream then refuses every further sign-up. Redeploys keep the account, the database and the secrets because they live on the volume.

**Using it.** Sign in at your domain with the two variables, or use the API: sign in once, create an API key (`gm_` prefix), and send it in the `x-api-key` header on every call. Keys can be read only or full access, and a key cannot mint more keys.

### Agent contract

- Public URL: `https://RAILWAY_PUBLIC_DOMAIN` (the generated domain of the `gitea-mirror` service; also in the variable `BETTER_AUTH_URL`)
- Private URL: `http://gitea-mirror.railway.internal:8080`
- Credentials: `ADMIN_EMAIL` and `ADMIN_PASSWORD` (generated; the API key is created from them)
- Auth: sign in with `POST /api/auth/sign-in/email` (JSON body, an `Origin` header equal to `BETTER_AUTH_URL`), create a key with `POST /api/auth/api-key/create` using that session cookie, then send the key as the `x-api-key` header; a call without a key or with a wrong key answers `401`
- Health: `GET /api/health` returns 200

```bash
#!/bin/sh
# needs: BETTER_AUTH_URL, ADMIN_EMAIL, ADMIN_PASSWORD (variables of the gitea-mirror service); also curl
J="Content-Type: application/json"
curl -s -w "\nhealth: %{http_code}\n" "$BETTER_AUTH_URL/api/health" | tail -n 1
curl -s -o /dev/null -w "sign-in: %{http_code}\n" -c /tmp/gm.jar -X POST -H "$J" -H "Origin: $BETTER_AUTH_URL" -d "{\"email\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASSWORD\"}" "$BETTER_AUTH_URL/api/auth/sign-in/email"
KEY=$(curl -s -b /tmp/gm.jar -X POST -H "$J" -H "Origin: $BETTER_AUTH_URL" -d '{"name":"agent"}' "$BETTER_AUTH_URL/api/auth/api-key/create" | sed -n 's/.*"key":"\([^"]*\)".*/\1/p')
curl -s -o /dev/null -w "read with key: %{http_code}\n" -H "x-api-key: $KEY" "$BETTER_AUTH_URL/api/dashboard"
curl -s -o /dev/null -w "read without key: %{http_code}\n" "$BETTER_AUTH_URL/api/dashboard"
curl -s -o /dev/null -w "write without key: %{http_code}\n" -X POST -H "$J" -d '{"owner":"octocat","repo":"hello-world"}' "$BETTER_AUTH_URL/api/sync/repository"
curl -s -o /dev/null -w "write with wrong key: %{http_code}\n" -X POST -H "$J" -H "x-api-key: gm_wrong" -d '{"owner":"octocat","repo":"hello-world"}' "$BETTER_AUTH_URL/api/sync/repository"
curl -s -o /dev/null -w "sign-up after admin: %{http_code}\n" -X POST -H "$J" -H "Origin: $BETTER_AUTH_URL" -d '{"email":"x@example.com","password":"password12345","name":"x"}' "$BETTER_AUTH_URL/api/auth/sign-up/email"
```

A fresh deploy prints `health: 200`, `sign-in: 200`, `read with key: 200`, `read without key: 401`, `write without key: 401`, `write with wrong key: 401` and `sign-up after admin: 403`. To mirror a repository, add your GitHub and Gitea tokens on the Configuration page, then `POST /api/sync/repository` with the key.

## Why Deploy Gitea Mirror on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Gitea Mirror on Railway, you are one step closer to supporting a complete full-stack application with minimal burden. Host your servers, databases, AI agents, and more on Railway.

- **Agent-ready** - no deployer fields, a contract block and one script that proves health, sign-in, API keys and the refusals.
- **Not claimable by a stranger** - the admin exists before the first visitor, and sign-up is closed.
- **Data survives redeploys** - database, admin and secrets sit on a volume at `/app/data`.
- **Pinned** - the upstream image is pinned by digest.
- **Your own copy of your code** - GitHub repositories, forks and stars land on a Gitea or Forgejo server you control.

## Common Use Cases

- **Backing up GitHub** - keep a current copy of every repository and organisation on your own server.
- **Leaving GitHub gradually** - mirror first, switch remotes when ready.
- **Archiving starred repositories** - keep projects that may be taken down.
- **Feeding a self-hosted CI** - build from Gitea or Forgejo copies of public repositories.

## Dependencies for Gitea Mirror Hosting

- The gitea-mirror service with a volume, created by the template. A Gitea or Forgejo server to mirror into, and a GitHub token, are yours to supply.

### Deployment Dependencies

- [Gitea Mirror repository](https://github.com/RayLabsHQ/gitea-mirror)
- [Official Docker image](https://github.com/RayLabsHQ/gitea-mirror/pkgs/container/gitea-mirror)
- [Wrapper image source](https://github.com/bon5co/gitea-mirror-railway)


## Similar templates

- [RustFS | (Just Updated) S3 Object Store, Public URL and Keys Set](https://railway.com/deploy/rustfs-or-just-updated-s3-object-store-p) — S3-compatible object store, keys and public URL preset, volume kept
- [TimescaleDB](https://railway.com/deploy/timescaledb-railway-template) — A PostgreSQL-based time-series database for analytics on Railway.
- [Neo4j 2026.10 Community](https://railway.com/deploy/neo4j-202610-community) — Neo4j graph database with APOC, Browser, Bolt TCP proxy and a volume

Open this page in a browser: https://railway.com/deploy/gitea-mirror-or-just-updated-github-to-g
