Files
composes/gitea-mirror
tiennm99 67da7cd870 feat(gitea-mirror): serve gitea and gitea-mirror through the proxy
Drop the localhost-bound ports, read the database password and both
public URLs from the environment, pin gitea to its major tag, add a gitea
health check and disable gitea's SSH server.
2026-10-03 09:58:52 +07:00
..

gitea-mirror

Self-hosted Gitea backed by PostgreSQL, with 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_MIRROR_URL BETTER_AUTH_URL, PUBLIC_BETTER_AUTH_URL, BETTER_AUTH_TRUSTED_ORIGINS Public URL of the mirror UI, no trailing slash.

Postgres sets the password only when it first initialises db-data. Changing POSTGRES_PASSWORD later breaks Gitea's connection until the role is altered to match:

docker compose exec db psql -U gitea -c "ALTER USER gitea PASSWORD '<new>';"

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. Its BETTER_AUTH_SECRET and ENCRYPTION_SECRET are left unset: the image generates both on first start and keeps them in gitea-mirror-data.

Choices

  • HTTPS only. The proxy routes HTTP, not SSH, so Gitea's SSH server is disabled and the UI offers HTTPS clone URLs only.
  • 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