Skip to content

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.

ServiceCoolify domainPortNotes
SigNoz UIhttps://signoz.itssatya.in8080 → 443dashboards, traces, alerts
Otel Collector (HTTP)https://otelcollectorhttp.itssatya.in4318 → 443OTLP/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.

  • 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: 7200

To apply in Coolify: edit the mounted collector config file → restart the otel-collector container (config is read at startup).

Terminal window
# 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.in
AppVariableWhereValue
backendOTEL_EXPORTER_OTLP_ENDPOINTCoolify envinternal collector http://…:4318
workersOTEL_EXPORTER_OTLP_ENDPOINTCoolify envinternal collector http://…:4318
webVITE_OTEL_EXPORTER_OTLP_ENDPOINTCoolify build arghttps://otelcollectorhttp.itssatya.in
mobileOTEL_EXPORTER_OTLP_ENDPOINT--dart-define at buildhttps://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.