Observability — SigNoz (OpenTelemetry)
Self-hosted SigNoz on Coolify collects traces from all four treeper apps via
OTLP. Everything is env-gated: with no OTEL_EXPORTER_OTLP_ENDPOINT (or
VITE_/--dart-define equivalent) the instrumentation is a complete no-op.
Topology
Section titled “Topology”| Service | Coolify domain | Port | Notes |
|---|---|---|---|
| SigNoz UI | https://signoz.itssatya.in | 8080 → 443 | dashboards, traces, alerts |
| Otel Collector (HTTP) | https://otelcollectorhttp.itssatya.in | 4318 → 443 | OTLP/HTTP ingest (/v1/traces) |
Cloudflare-proxied serving must be on 443. Set the Coolify service domains
without a port (https://signoz.itssatya.in, not :8080) — Coolify/Traefik
routes 443 → the container port. A domain with an explicit non-standard port
(:8080, :4318) makes Cloudflare’s proxy return 502/000 because it only
speaks 443/80 to the origin. After changing a domain, restart the service —
Traefik’s loadbalancer.server.port label doesn’t regenerate on its own.
How the apps export
Section titled “How the apps export”- backend / workers (server-side): point at the collector over Coolify’s
internal predefined network — no Cloudflare round-trip:
OTEL_EXPORTER_OTLP_ENDPOINT=http://<otel-collector-container>:4318 - web / mobile (client-side): must use the public collector:
https://otelcollectorhttp.itssatya.in(browser/mobile POST OTLP directly, hence the CORS requirement below).
All exporters use OTLP/HTTP (/v1/traces is appended automatically).
Collector config — CORS (required for browser + mobile)
Section titled “Collector config — CORS (required for browser + mobile)”Browsers (and the mobile app’s cross-origin POST) need CORS on the HTTP
receiver. In the collector config (otel-collector-config.yaml, the file passed
via --config), under receivers.otlp.protocols.http:
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 cors: allowed_origins: - "https://treeper.itssatya.in" - "https://*.itssatya.in" - "http://localhost:5173" # local web dev (optional) allowed_headers: - "*" max_age: 7200To apply in Coolify: edit the mounted collector config file → restart the otel-collector container (config is read at startup).
Verify
Section titled “Verify”# UI loads:curl -sI https://signoz.itssatya.in | head -1 # 200
# Receiver healthy (GET is not a valid OTLP verb → 404/405, NOT 502):curl -sI https://otelcollectorhttp.itssatya.in/v1/traces | head -1 # 405
# CORS preflight (browser/mobile gate):curl -i -X OPTIONS https://otelcollectorhttp.itssatya.in/v1/traces \ -H "Origin: https://treeper.itssatya.in" \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: content-type"# → 204 + access-control-allow-origin: https://treeper.itssatya.inPer-app env
Section titled “Per-app env”| App | Variable | Where | Value |
|---|---|---|---|
| backend | OTEL_EXPORTER_OTLP_ENDPOINT | Coolify env | internal collector http://…:4318 |
| workers | OTEL_EXPORTER_OTLP_ENDPOINT | Coolify env | internal collector http://…:4318 |
| web | VITE_OTEL_EXPORTER_OTLP_ENDPOINT | Coolify build arg | https://otelcollectorhttp.itssatya.in |
| mobile | OTEL_EXPORTER_OTLP_ENDPOINT | --dart-define at build | https://otelcollectorhttp.itssatya.in |
Optional everywhere: OTEL_SERVICE_NAME (defaults: treeper-backend,
treeper-workers, treeper-web, treeper-mobile).
Code: backend apps/backend/src/tracing.ts, workers
apps/workers/src/treeper_workers/telemetry.py (+ obs.py spans), web
apps/web/src/telemetry.ts, mobile apps/mobile/lib/core/telemetry/telemetry.dart.