Skip to Content
DocumentationGuidesCustomize Companion Hub compose and Traefik config

Customize Companion Hub compose and Traefik config

Change how the Hub stack publishes ports and how Traefik routes traffic. This page covers what Hub applies today and what it doesn’t, because several older ways of customizing the stack no longer take effect.

This guide is for operators who already know Docker and Traefik. Broken changes can take the Hub offline, and support may not be able to recover a customized main stack for you.

What doesn’t work in the current release:

  • A user-config/hub-compose.yml override isn’t applied when you start the stack with cihub up or the desktop app. Hub reads it only when it builds its own log commands. It never changes the running containers.
  • Hub rewrites state/traefik/config/traefik.yml every time the Hub container starts, so an edit lasts only until the next restart. The Persist Traefik config setting and persistTraefikConfig in settings.json don’t change this.
  • Traefik’s dashboard and API stay disabled (insecure: false), by design. Hub turns them on only for source development.

What Hub generates

Your Hub data root (ROOT_FOLDER_HOST) holds the files that configure the stack. Find its path with cihub doctor.

          • traefik.yml
          • dynamic.yml
        • acme_storage.json
      • settings.json
    • docker-compose.prod.yml
    • .env.dev
FileWritten bySafe to edit?
state/traefik/config/traefik.ymlHub, on every Hub startNo — overwritten on restart
state/traefik/dynamic/dynamic.ymlHub, the desktop app, and `cihub up`, on startNo — overwritten on restart
Other files in state/traefik/dynamic/You, using names other than hub.yml, apps.yml, and port-expose.ymlYes — Traefik watches the folder
state/traefik/acme_storage.jsonTraefik, as it issues certificatesNo
docker-compose.prod.ymlThe desktop app, copied from its bundle on every launchNo — the desktop app overwrites it
.env.dev (.env on Windows)The CLI, and the desktop app on every launchOnly for a Hub you start with cihub up
What writes each stack file under ROOT_FOLDER_HOST, and whether your changes last.

Change the published ports

Hub publishes these ports on your machine. On a Hub you start with cihub up, set the variable in your env file — .env.dev in the data root on Linux and macOS, .env on Windows — then restart the stack.

The desktop app rewrites the env file every time it starts. It keeps only its own values, such as ROOT_FOLDER_HOST, the generated secrets, TAILSCALE_AUTHKEY, and TAILSCALE_SERVE_USER_DISABLED, and its port manager picks the port variables below afresh on each launch. On the desktop app, changes to this file don’t last. This section, and the Let’s Encrypt email below, apply to a Hub that you start with cihub up.

PortServiceVariable
5002Hub dashboard and APIAPI_PORT
80 (8880 in the Linux desktop app)Traefik, HTTPHTTP_PORT
443 (8443 in the Linux desktop app)Traefik, HTTPSHTTPS_PORT
8080Traefik dashboard portTRAEFIK_DASHBOARD_PORT
6543PostgreSQL, on 127.0.0.1 onlyPOSTGRES_PORT
5001RabbitMQ, on 127.0.0.1 onlyRABBITMQ_PORT
cihub down cihub up --detached

If a port is busy when the stack starts, the CLI picks a free one and writes it to the env file for you. See Hub stack won’t start.

Set the Let’s Encrypt email

Hub writes ACME_EMAIL into traefik.yml at startup. If you don’t set it, Hub uses admin@localhost. Set it in the env file to receive certificate expiry notices at a real address:

ACME_EMAIL=you@example.com

On Linux, only root can open ports below 1024, so the desktop app publishes Traefik on 8880 and 8443. cihub up on rootful Docker uses 80 and 443 when they are free and otherwise moves to 8880 and 8443; under rootless Docker it always uses those two. Public Web through Cloudflare doesn’t depend on these host ports.

Restart the Hub for the change to apply.

dynamic.yml holds the TLS 1.2 floor, the forward-auth middleware that passes Hub’s signed identity headers to your apps, the middleware that strips forwarding headers a visitor sets, and the <app> is starting… page Hub shows when an exposed app answers 502 or 504. It points at the Hub container, ci-hub.

Add your own Traefik routes

Traefik watches state/traefik/dynamic/ and reloads a file when it changes, with no restart. Hub writes dynamic.yml, hub.yml, apps.yml, and port-expose.yml there, so use other file names and your files survive restarts. Use a separate file for routers, services, middlewares, and TLS options.

For example, this routes printer.example.lan through the Hub’s Traefik to a device on your network. Save it as state/traefik/dynamic/printer.yml:

http: routers: printer: rule: Host(`printer.example.lan`) entryPoints: - web service: printer services: printer: loadBalancer: servers: - url: http://192.168.1.50:80

Dynamic configuration can’t change Traefik’s static settings, such as entry points, certificate resolvers, and the log level. Those live in traefik.yml, which Hub rewrites.

Read Traefik’s logs

Traefik logs JSON at INFO level. Read them with Docker:

docker logs traefik

See the Log viewer for the rest of the stack.

Customize one app instead

To add environment values or host mounts to a single app, use the per-app override files in user-config/. See Customize app config.

Last updated on