# server-infra Shared Docker services for the Hetzner server: nginx proxy manager, umami analytics, Gitea + Actions runner. ## Services | Service | Port (host) | Description | |---------|-------------|-------------| | nginx proxy manager | 80, 443, 81 (admin) | Reverse proxy + SSL termination | | umami | internal | Web analytics | | gitea | 127.0.0.1:3100 → nginx, 2222 (SSH) | Self-hosted git at `git.padelnomics.io` | | act_runner | — | Gitea Actions CI runner | ## Directory layout ``` /opt/server-infra/ # this repo (owned by infra_service) ├── gitea/docker-compose.yml ├── reverse-proxy/docker-compose.yml # recovered from running container ├── umami/docker-compose.yml # recovered from running container ├── setup.sh # phase 1: user + dirs + uv └── bootstrap.sh # phase 2: recover compose files, start Gitea /data/server-infra/ ├── gitea/ # Gitea data volume └── act_runner/ # Runner data volume ``` ## Setup (new server) ### Phase 1 — user, dirs, uv ```bash ssh root@ 'bash -s' < setup.sh ``` Creates `infra_service` system user (docker group), `/opt/server-infra/`, `/data/server-infra/`, installs uv. ### Phase 2 — sync repo + recover ```bash rsync -av --chown=infra_service:infra_service \ ~/Projects/server-infra/ root@:/opt/server-infra/ ssh root@ 'bash -s' < bootstrap.sh ``` Recovers `umami/docker-compose.yml` and `reverse-proxy/docker-compose.yml` from running containers, creates data dirs, sets ownership. ### Phase 3 — start Gitea ```bash ssh hetzner_root 'sudo -u infra_service docker compose \ -f /opt/server-infra/gitea/docker-compose.yml up -d' ``` Web installer at `http://:3100`. Set ROOT_URL to `https://git.padelnomics.io`. After setup, add a proxy host in nginx proxy manager → `127.0.0.1:3100`. ### Phase 4 — start act_runner 1. Generate a runner token in Gitea: Site Administration → Actions → Runners → Create runner token 2. Create `/opt/server-infra/gitea/.env`: ``` GITEA_RUNNER_TOKEN= ``` 3. Restart with the env file: ```bash ssh hetzner_root 'sudo -u infra_service docker compose \ -f /opt/server-infra/gitea/docker-compose.yml up -d' ``` ## DNS `git.padelnomics.io` must be DNS-only (grey cloud) in Cloudflare — **not** proxied — so that SSH on port 2222 reaches the server directly. ## Secrets The `infra_service` user owns all compose files. Secrets (runner token) go in `/opt/server-infra/gitea/.env` — never committed.