# Deploying FlexHub customisations These notes cover **updating an already-running** FlexHub. If you're standing up Forgejo from scratch on a new host, follow the operator-internal runbook at `_github/infra/forgejo/DEPLOY.md` in the `ai-lab` repo first, then come back here for the rebrand layer. All paths below are on `nullstone` (the host running the Forgejo container). The container is named `forgejo`. Host UID 1000 owns the data tree. --- ## Layout on nullstone ``` /opt/docker/forgejo/ └── docker-compose.yml ← image tag, env, traefik labels /home/docker/forgejo/ ├── data/ │ └── gitea/ │ └── custom/ ← Forgejo "override" tree │ ├── conf/app.ini ← APP_NAME, DEFAULT_THEME, THEMES │ ├── templates/ │ │ └── home.tmpl ← homepage (mirror of this repo) │ └── public/assets/ │ ├── css/theme-flexhub.css │ └── img/ ← logos + favicons └── config/ ← Forgejo-managed; don't hand-edit ``` `custom/` is the only path you ever edit by hand. Everything in this repo maps 1:1 into that tree. --- ## Update the homepage template Edit `templates/home.tmpl` here, then on `nullstone`: ```bash ssh nullstone bash <<'EOF' sudo cp /tmp/home.tmpl /home/docker/forgejo/data/gitea/custom/templates/home.tmpl sudo chown 1000:1000 /home/docker/forgejo/data/gitea/custom/templates/home.tmpl EOF ``` Forgejo hot-reloads templates — no container restart needed. Hit and hard-refresh (Ctrl+Shift+R) to confirm. If the page renders blank, check the Forgejo log for a template parse error: ```bash ssh nullstone 'docker logs --tail 50 forgejo 2>&1 | grep -i template' ``` The wrapping `{{template "base/head" .}}` and `{{template "base/footer" .}}` calls are mandatory — drop them and you get a half-page. --- ## Update the theme CSS Edit `public/assets/css/theme-flexhub.css`, copy to nullstone: ```bash ssh nullstone bash <<'EOF' sudo cp /tmp/theme-flexhub.css \ /home/docker/forgejo/data/gitea/custom/public/assets/css/theme-flexhub.css sudo chown 1000:1000 \ /home/docker/forgejo/data/gitea/custom/public/assets/css/theme-flexhub.css EOF ``` CSS is served static — no reload needed. The theme is selected per-user via `DEFAULT_THEME = flexhub` in `app.ini` (see next section) and is overridable in user settings. The brand palette is **orange `#FF9000` / black `#000` / white `#FFF`**. Don't drift. --- ## Bump APP_NAME or theme list `app.ini` lives at `/home/docker/forgejo/data/gitea/custom/conf/app.ini` on nullstone (Forgejo merges custom values over its built-in defaults). The relevant keys: ```ini APP_NAME = FlexHub DEFAULT_THEME = flexhub THEMES = forgejo-auto,forgejo-light,forgejo-dark,flexhub,veilor ``` After editing `app.ini` you **must restart the container** — env-style INI is read at boot only: ```bash ssh nullstone 'cd /opt/docker/forgejo && docker compose restart forgejo' ``` Watch the log come back clean: ```bash ssh nullstone 'docker logs -f --tail 30 forgejo' ``` You're good when you see `Listen: http://0.0.0.0:3000`. The web UI should now show the new title bar / theme list. --- ## Add a new template override Forgejo template hierarchy: . The general flow: 1. Find the upstream template in the Forgejo source tree (`templates/...`). 2. Copy its full content into `custom/templates/.tmpl` on nullstone, owned `1000:1000`. 3. Edit your override. 4. Mirror the file into this repo under `templates/.tmpl` so the repo stays the source of truth. Hot-reload applies — no container restart. If the override stops rendering after a Forgejo version bump, diff your override against the new upstream template — base layout slots sometimes get renamed across major versions. --- ## Add a new image asset ```bash scp my-asset.png nullstone:/tmp/ ssh nullstone bash <<'EOF' sudo cp /tmp/my-asset.png \ /home/docker/forgejo/data/gitea/custom/public/assets/img/my-asset.png sudo chown 1000:1000 \ /home/docker/forgejo/data/gitea/custom/public/assets/img/my-asset.png EOF ``` Reachable at `https://flexhub.s8n.ru/assets/img/my-asset.png`. No container restart. When replacing favicons specifically, also clear the browser cache — favicons are aggressively cached. --- ## Traefik routing for `flexhub.s8n.ru` The FlexHub-branded hostname is wired in via a **file-provider** router (`/opt/docker/traefik/config/dynamic.yml` on nullstone), not via the docker-provider labels on the Forgejo compose file. This is intentional: - `git.s8n.ru` — docker-provider router, `no-guest@file` middleware. - `flexhub.s8n.ru` — file-provider router, public, rate-limit only. The file-provider router defines its **own** service (`flexhub-svc`) pointing at `http://forgejo:3000` directly, rather than referencing `forgejo@docker`. This works around a startup race where file-provider routers can resolve before docker-provider services are populated, leaving the router permanently broken with `the service "forgejo@docker" does not exist`. If you change the Forgejo container name or move it off the `proxy` network, update `flexhub-svc.loadBalancer.servers[0].url` in `dynamic.yml` to match. --- ## Rollback The customisations are pure overlay files. To revert FlexHub branding: ```bash ssh nullstone bash <<'EOF' sudo mv /home/docker/forgejo/data/gitea/custom /home/docker/forgejo/data/gitea/custom.disabled EOF ssh nullstone 'cd /opt/docker/forgejo && docker compose restart forgejo' ``` Forgejo falls back to vanilla theme + homepage. Nothing in the data store changes. Restore by renaming `custom.disabled` back to `custom`.