From 67da7cd87048e5b0becc70027c66ddbe1df224d4 Mon Sep 17 00:00:00 2001 From: tiennm99 Date: Sat, 3 Oct 2026 09:58:52 +0700 Subject: [PATCH] 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. --- gitea-mirror/.env.example | 22 ++---------- gitea-mirror/README.md | 76 ++++++++++++++++++++++++--------------- gitea-mirror/compose.yml | 26 ++++++++------ 3 files changed, 66 insertions(+), 58 deletions(-) diff --git a/gitea-mirror/.env.example b/gitea-mirror/.env.example index 06c503e..be06a71 100644 --- a/gitea-mirror/.env.example +++ b/gitea-mirror/.env.example @@ -1,19 +1,3 @@ -COMPOSE_PROJECT_NAME=gitea-mirror -TZ=Asia/Ho_Chi_Minh - -POSTGRES_DB=gitea-mirror -POSTGRES_USER=gitea-mirror -POSTGRES_PASSWORD=gitea-mirror - -USER_UID=1000 -USER_GID=1000 -GITEA_HTTP_PORT=3000 -GITEA_SSH_PORT=8022 -GITEA_ROOT_URL=http://localhost:3000/ -GITEA_SSH_DOMAIN=localhost - -GITEA_MIRROR_PORT=4321 -BETTER_AUTH_SECRET=replace-with-a-random-secret-at-least-32-characters -BETTER_AUTH_URL=http://localhost:4321 -PUBLIC_BETTER_AUTH_URL=http://localhost:4321 -BETTER_AUTH_TRUSTED_ORIGINS=http://localhost:4321 +POSTGRES_PASSWORD=gitea +GITEA_ROOT_URL=https://gitea.example.com/ +GITEA_MIRROR_URL=https://gitea-mirror.example.com diff --git a/gitea-mirror/README.md b/gitea-mirror/README.md index 709f6a8..44f71a1 100644 --- a/gitea-mirror/README.md +++ b/gitea-mirror/README.md @@ -4,40 +4,58 @@ Self-hosted [Gitea](https://about.gitea.com/) backed by PostgreSQL, with [gitea-mirror](https://github.com/RayLabsHQ/gitea-mirror) mirroring GitHub repositories into it. -Every published port binds to `127.0.0.1`, so nothing is reachable from -outside the host. Put a reverse proxy in front for remote access. - ## Services -| Service | Image | Address | -| --- | --- | --- | -| `db` | `postgres:16-alpine` | internal only | -| `gitea` | `gitea/gitea:latest` | `127.0.0.1:3000` (HTTP), `127.0.0.1:2222` (SSH) | -| `gitea-mirror` | `ghcr.io/raylabshq/gitea-mirror:latest` | `127.0.0.1:4321` | +| 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` | -`gitea` waits for `db` to pass its health check before starting. -`gitea-mirror` sets `pull_policy: always`, so every recreate takes the newest -`latest`. +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: + +```sh +docker compose exec db psql -U gitea -c "ALTER USER gitea PASSWORD '';" +``` + +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 , then configure -mirroring at . - -Gitea advertises SSH port `2222`: - -```sh -git clone ssh://git@127.0.0.1:2222//.git -``` - -## Configuration - -`compose.yml` hardcodes everything — database credentials, ports and the Gitea -SSH port are written inline, and it reads no environment variables, so -`.env.example` is not wired up. - -The Postgres credentials are `gitea` / `gitea`. Change them before exposing -this stack beyond localhost. +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 @@ -45,4 +63,4 @@ this stack beyond localhost. | --- | --- | | `db-data` | PostgreSQL data | | `gitea-data` | Repositories, Gitea config and state | -| `gitea-mirror-data` | Mirror job database | +| `gitea-mirror-data` | Mirror job database and generated secrets | diff --git a/gitea-mirror/compose.yml b/gitea-mirror/compose.yml index b1d80e4..509cbc8 100644 --- a/gitea-mirror/compose.yml +++ b/gitea-mirror/compose.yml @@ -3,9 +3,9 @@ services: image: postgres:16-alpine restart: unless-stopped environment: - POSTGRES_DB: gitea + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-gitea} POSTGRES_USER: gitea - POSTGRES_PASSWORD: gitea + POSTGRES_DB: gitea volumes: - db-data:/var/lib/postgresql/data healthcheck: @@ -15,32 +15,38 @@ services: retries: 10 gitea: - image: gitea/gitea:latest + 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__database__PASSWD: gitea - GITEA__server__SSH_PORT: 2222 + GITEA__server__ROOT_URL: ${GITEA_ROOT_URL:?required} + GITEA__server__DISABLE_SSH: "true" volumes: - gitea-data:/data - ports: - - "127.0.0.1:3000:3000" - - "127.0.0.1:2222:22" + 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_URL: ${GITEA_MIRROR_URL:?required} + PUBLIC_BETTER_AUTH_URL: ${GITEA_MIRROR_URL:?required} + BETTER_AUTH_TRUSTED_ORIGINS: ${GITEA_MIRROR_URL:?required} volumes: - gitea-mirror-data:/app/data - ports: - - "127.0.0.1:4321:4321" volumes: db-data: