TrieOH

Infrastructure

What runs the TrieOH platform — Caddy, Forgejo, Postgres, rustfs, observability, mail, monitoring, notifications.

One server, plain Docker Compose, no Swarm. Everything lives in TrieOH/infra (shared infra) and TrieOH/deploy/thetree (the product stack); Caddy fronts it all with TLS.

Services

ServiceWhat it isWhere it lives
Caddyreverse proxy + TLS gateway (wildcard *.trieoh.com)infra/caddy
Forgejogit + Actions runner (DinD)infra/forgejo
Moxmail (SMTP/IMAP)infra/mox
ObservabilityGrafana + VictoriaMetrics / VictoriaLogs / VictoriaTracesinfra/observability
Beszelserver monitoringinfra/beszel
ntfypush notifications (phone)infra/ntfy
Postgresthe single databasedeploy/thetree
rustfsS3-compatible object storagedeploy/thetree
The four servicesIdentityX, Univents, Payssage, Informddeploy/thetree

Networks

NetworkScope
caddy-netexternal, shared — anything the public gateway reaches
internalinternal: true — Postgres only, never exposed to the host
obs-netexternal — telemetry scrapes (metrics/logs/traces)

Caddy (gateway + TLS)

  • Wildcard TLS via /etc/caddy/certs/trieoh.com_origin.pem (host bind-mount :ro); mail hosts use Let's Encrypt from /etc/letsencrypt. Certs are not in the repo.
  • API gatewayapi.trieoh.com routes path prefixes to each service: /identityx/*, /univents/*, /payssage/*, /informd/*.
  • Direct subdomainsapi.identityx.com.br, api.univents.com.br, api.payssage.trieoh.com, api.informd.trieoh.com.
  • Auth aliasesauth.univents.com.br, auth.payssage.trieoh.com, auth.identityx.com.br, auth.informd.trieoh.com all → IdentityX.
  • Dashboardsgrafana.trieoh.com (Grafana), metrics/logs/traces.trieoh.com (Victoria*, behind HTTP basic auth), beszel.trieoh.com, ntfy.trieoh.com, git.trieoh.com (Forgejo).
  • Storageapi.storage.trieoh.cloud (:9000) and console.storage.trieoh.cloud (:9001) → rustfs.
  • Mailmail.trieoh.com, mta-sts.trieoh.com, autoconfig.trieoh.com → Mox.
  • Added a service? Join caddy-net, add a block (reverse_proxy <service>:<port>), then just reload-caddy.

Forgejo (git + CI)

  • Git over HTTPS via Caddy; SSH is routed by the host sshd (the git user's shell is forgejo-shell, AuthorizedKeysCommand reads the volume's authorized_keys) — it has to exist before Docker comes up (setup.sh wires it).
  • Actions runner (forgejo-runner, DinD) runs the CI/CD workflows (ci.yml, publish.yml, trivy-scan.yml, deploy-front.yml, publish-ts-sdks.yml). It registers manually once against the instance, then runs as a daemon.
  • The container registry (git.trieoh.com/trieoh/*) is where Deploy pulls the service images from.

Observability

Grafana + the Victoria stack, 7-day retention, all bound to 127.0.0.1 on the host (only Caddy reaches them publicly):

ComponentPort (host)Endpoint
Grafana127.0.0.1:3000grafana.trieoh.com
VictoriaMetrics127.0.0.1:8428metrics.trieoh.com (basic auth)
VictoriaLogs127.0.0.1:9428logs.trieoh.com (basic auth)
VictoriaTraces127.0.0.1:10428traces.trieoh.com (basic auth)

Every backend boots through the shared harness (lib/go/httpserver), which exposes /metrics, /health, and OpenTelemetry — the scrapers are provisioned via infra/observability/scrape.yml and Grafana dashboards live in infra/observability/dashboards.

Host layout

~/infra          # shared infra (this repo): caddy, forgejo, mox, observability, beszel, ntfy
~/deploy/thetree # the product stack: postgres, rustfs, identityx, univents, payssage, informd
  • Setup: just setup (creates caddy-net, starts Caddy + Forgejo, wires git SSH).
  • Edit the Caddyfile? just reload-caddy.
  • The nightly dind-prune and forgejo-restart crons live in the server crontab (not in git).

Ports (prod vs dev)

ServiceProdDev (docker compose up in TheTree)
Postgresinternal network only5432
rustfsvia Caddy9000, 9001
identityxvia Caddy8080 (+ 6060 pprof)
univentsvia Caddy8081 (+ 6061)
payssagevia Caddy8082 (+ 6062)
informdvia Caddy8083 (+ 6063)

On this page