refactor: rename the gitea-mirror service directory to gitea

This commit is contained in:
tiennm99 committed 2026-10-05 15:54:03 +07:00
1 parent d0eb7c8aa9
commit 5caa497d7f
7 files changed
+7 -7

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
POSTGRES_PASSWORD=gitea
GITEA_ROOT_URL=https://gitea.example.com/
GITEA_CLONE_TIMEOUT=3600
BETTER_AUTH_SECRET=
ENCRYPTION_SECRET=
GITEA_MIRROR_URL=https://gitea-mirror.example.com
+4
View File
@@ -0,0 +1,4 @@
gitea/
gitea-mirror/
.env
purge.py
+76
View File
@@ -0,0 +1,76 @@
# gitea
Self-hosted [Gitea](https://about.gitea.com/) backed by PostgreSQL, with
[gitea-mirror](https://github.com/RayLabsHQ/gitea-mirror) mirroring GitHub
repositories into it.
## Services
| Service | Image | Internal port | Domain |
| --- | --- | --- | --- |
| `db` | `postgres:16-alpine` | 5432 | none |
| `gitea` | `gitea/gitea:28` | 3000 | `GITEA_ROOT_URL` |
| `gitea-mirror` | `ghcr.io/raylabshq/gitea-mirror:latest` | 4321 | `GITEA_MIRROR_URL` |
In Coolify, give `gitea` and `gitea-mirror` each a domain on their internal
port, matching the two URL variables.
`gitea` waits for `db` to pass its health check. `gitea` checks
`/api/healthz`; the `gitea-mirror` image ships its own health check.
## Variables
| Variable | Feeds | Notes |
| --- | --- | --- |
| `POSTGRES_PASSWORD` | `db`, `gitea` | Defaults to `gitea`. |
| `GITEA_ROOT_URL` | Gitea `server.ROOT_URL` | Public URL, with trailing slash. Gitea builds clone URLs and redirects from it. |
| `GITEA_CLONE_TIMEOUT` | Gitea `git.timeout` `MIGRATE` and `MIRROR`; gitea-mirror `BUN_CONFIG_HTTP_IDLE_TIMEOUT` | Seconds a mirror's first clone or a later fetch may run. Defaults to `3600`; at most `14340`. |
| `BETTER_AUTH_SECRET` | gitea-mirror | Signs sessions and encrypts its login keys. Generate with `openssl rand -base64 32`. |
| `ENCRYPTION_SECRET` | gitea-mirror | Encrypts the stored GitHub and Gitea tokens. Generate with `openssl rand -base64 48`. |
| `GITEA_MIRROR_URL` | `BETTER_AUTH_URL`, `PUBLIC_BETTER_AUTH_URL`, `BETTER_AUTH_TRUSTED_ORIGINS` | Public URL of the mirror UI, no trailing slash. |
Behind a reverse proxy, gitea-mirror rejects sign-in with "invalid origin"
unless all three Better Auth variables hold the external URL, so one variable
feeds them all.
Both secrets are set explicitly rather than left to the image, which would
otherwise generate its own into `gitea-mirror-data`. Data encrypted under one
secret is unreadable under another, so moving the data to a new deployment
means carrying the secrets with it. Never change either on an existing
install.
## Choices
- **HTTPS only.** The proxy routes HTTP, not SSH, so Gitea's SSH server is
disabled and the UI offers HTTPS clone URLs only.
- **One-hour clone timeout.** Gitea's defaults (600 s to migrate, 300 s to
fetch) cut off multi-gigabyte repositories mid-clone, leaving empty mirrors
that still hold gigabytes of unreachable packfiles.
- **gitea-mirror waits as long as Gitea clones.** Gitea's migrate API sends
nothing until the clone ends, and Bun's `fetch` drops a connection idle for
5 minutes. gitea-mirror then marks the repository failed while Gitea keeps
cloning; on retry it finds the half-made repository and marks it mirrored.
If that clone later fails, Gitea keeps an empty repository with no mirror
record, which never syncs. `BUN_CONFIG_HTTP_IDLE_TIMEOUT` takes the same
value as the clone timeout so the request outlives the clone. Bun caps it
at 239 minutes, so a larger `GITEA_CLONE_TIMEOUT` stops helping there.
- **`gitea/gitea:28`.** Gitea publishes major tags; the major pin takes
updates without a surprise major upgrade.
- **`gitea-mirror:latest`** with `pull_policy: always`: upstream publishes no
major tag, so every redeploy takes the newest release.
- **`postgres:16-alpine`** stays on 16: a new Postgres major cannot read the
existing data directory without a dump and restore.
## Usage
Complete Gitea's first-run setup at `GITEA_ROOT_URL`, create an access token,
then configure mirroring at `GITEA_MIRROR_URL`. In gitea-mirror, set the Gitea
URL to `http://gitea:3000` so it talks to Gitea over the internal network.
## Storage
| Volume | Holds |
| --- | --- |
| `db-data` | PostgreSQL data |
| `gitea-data` | Repositories, Gitea config and state |
| `gitea-mirror-data` | Mirror job database and generated secrets |
+59
View File
@@ -0,0 +1,59 @@
services:
db:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-gitea}
POSTGRES_USER: gitea
POSTGRES_DB: gitea
volumes:
- db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U gitea -d gitea"]
interval: 5s
timeout: 5s
retries: 10
gitea:
image: gitea/gitea:28
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
GITEA__database__PASSWD: ${POSTGRES_PASSWORD:-gitea}
GITEA__database__DB_TYPE: postgres
GITEA__database__HOST: db:5432
GITEA__database__NAME: gitea
GITEA__database__USER: gitea
GITEA__server__ROOT_URL: ${GITEA_ROOT_URL:?required}
GITEA__server__DISABLE_SSH: "true"
GITEA__git_0X2E_timeout__MIGRATE: ${GITEA_CLONE_TIMEOUT:-3600}
GITEA__git_0X2E_timeout__MIRROR: ${GITEA_CLONE_TIMEOUT:-3600}
volumes:
- gitea-data:/data
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:3000/api/healthz"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
gitea-mirror:
image: ghcr.io/raylabshq/gitea-mirror:latest
restart: unless-stopped
pull_policy: always
environment:
BETTER_AUTH_SECRET: ${BETTER_AUTH_SECRET:?required}
ENCRYPTION_SECRET: ${ENCRYPTION_SECRET:?required}
BETTER_AUTH_URL: ${GITEA_MIRROR_URL:?required}
PUBLIC_BETTER_AUTH_URL: ${GITEA_MIRROR_URL:?required}
BETTER_AUTH_TRUSTED_ORIGINS: ${GITEA_MIRROR_URL:?required}
BUN_CONFIG_HTTP_IDLE_TIMEOUT: ${GITEA_CLONE_TIMEOUT:-3600}
volumes:
- gitea-mirror-data:/app/data
volumes:
db-data:
gitea-data:
gitea-mirror-data: