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.
This commit is contained in:
tiennm99 committed 2026-10-03 09:58:52 +07:00
1 parent b9042fb191
commit 67da7cd870
3 files changed
+66 -58

No files matched your search

+3 -19
View File
@@ -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
+47 -29
View File
@@ -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 '<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 <http://127.0.0.1:3000>, then configure
mirroring at <http://127.0.0.1:4321>.
Gitea advertises SSH port `2222`:
```sh
git clone ssh://[email protected]:2222/<owner>/<repo>.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 |
+16 -10
View File
@@ -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: