195 lines
6.8 KiB
Markdown
195 lines
6.8 KiB
Markdown
# Light Alternative: GlitchTip
|
||
|
||
This document describes **GlitchTip** as a much lighter alternative to the
|
||
self-hosted Sentry stack in `infra/sentry/`. GlitchTip is **NOT** the
|
||
default observability backend — it lacks Performance/Tracing, Session
|
||
Replay, and OTLP ingest. Use it only when one of the following applies:
|
||
|
||
- The Sentry host is severely RAM-constrained (< 8 GB available)
|
||
- A throw-away preview deployment needs an error sink in < 5 minutes
|
||
- You want a backend on the cheapest possible Hetzner instance for a
|
||
side-project that only cares about error aggregation
|
||
|
||
For the full Sentry stack, see
|
||
[`sentry-selfhost.md`](./sentry-selfhost.md).
|
||
|
||
## At a glance
|
||
|
||
| Item | GlitchTip | Self-Hosted Sentry |
|
||
| --- | --- | --- |
|
||
| Error events | yes | yes |
|
||
| Performance / tracing | no | yes |
|
||
| Session replay | no | yes |
|
||
| Profiling | no | yes |
|
||
| OTLP ingest | no | yes (via Relay) |
|
||
| Sentry-SDK compatibility | yes (errors only) | yes (all features) |
|
||
| Container count | 4 | ~10 |
|
||
| RAM | 1–2 GB | 12–16 GB |
|
||
| Disk (90 d) | 5–10 GB | 40–60 GB |
|
||
| Upstream image pin | `glitchtip/glitchtip:v6.1.6` | `getsentry/self-hosted` @ `25.12.1` |
|
||
|
||
## SDK compatibility note
|
||
|
||
GlitchTip implements a subset of the Sentry HTTP ingest API — **errors only**.
|
||
The official Sentry SDKs (`@sentry/node`, `@sentry/react`, etc.) work
|
||
without modification for plain error reporting:
|
||
|
||
```ts
|
||
Sentry.init({
|
||
dsn: process.env.GLITCHTIP_DSN, // looks like a Sentry DSN
|
||
});
|
||
Sentry.captureException(new Error("hello"));
|
||
```
|
||
|
||
**Do not** enable `tracesSampleRate`, `replaysSessionSampleRate`, or
|
||
`profilesSampleRate` — those payloads are rejected. If you call
|
||
`Sentry.startTransaction(...)`, GlitchTip silently drops the span data;
|
||
nothing breaks, but you also do not see traces.
|
||
|
||
For OpenTelemetry ingest (Phase 02 task #33) GlitchTip is **not** a
|
||
viable backend.
|
||
|
||
## Compose (light, 4-container)
|
||
|
||
The following Compose file runs on Coolify exactly like the Sentry stack
|
||
but with 4 services instead of 10. Save under
|
||
`infra/glitchtip/docker-compose.yml` (NOT committed today; this is the
|
||
reference document so we can stand it up quickly if needed).
|
||
|
||
```yaml
|
||
version: "3.8"
|
||
|
||
networks:
|
||
default:
|
||
name: glitchtip-net
|
||
coolify:
|
||
external: true
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:15-alpine
|
||
environment:
|
||
POSTGRES_DB: ${GLITCHTIP_DB:-glitchtip}
|
||
POSTGRES_USER: ${GLITCHTIP_DB_USER:-glitchtip}
|
||
POSTGRES_PASSWORD: ${GLITCHTIP_DB_PASSWORD:?must be set in .env}
|
||
volumes:
|
||
- /data/coolify/services/glitchtip/postgres-data:/var/lib/postgresql/data
|
||
healthcheck:
|
||
test: ["CMD", "pg_isready", "-U", "${GLITCHTIP_DB_USER:-glitchtip}"]
|
||
interval: 10s
|
||
retries: 6
|
||
|
||
valkey:
|
||
# GlitchTip 6.x uses Valkey (Redis fork) as cache + broker. Pin to v7
|
||
# to match Coolify's existing Redis container ABI.
|
||
image: valkey/valkey:7-alpine
|
||
volumes:
|
||
- /data/coolify/services/glitchtip/valkey-data:/data
|
||
healthcheck:
|
||
test: ["CMD", "valkey-cli", "ping"]
|
||
interval: 10s
|
||
retries: 6
|
||
|
||
web:
|
||
image: glitchtip/glitchtip:v6.1.6
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
valkey:
|
||
condition: service_healthy
|
||
environment:
|
||
DATABASE_URL: postgres://${GLITCHTIP_DB_USER:-glitchtip}:${GLITCHTIP_DB_PASSWORD}@postgres:5432/${GLITCHTIP_DB:-glitchtip}
|
||
REDIS_URL: redis://valkey:6379/0
|
||
SECRET_KEY: ${GLITCHTIP_SECRET_KEY:?generate with python -c "import secrets; print(secrets.token_urlsafe(50))"}
|
||
GLITCHTIP_DOMAIN: ${GLITCHTIP_BASE_URL:-https://glitchtip.boiler.saas-ctrl.com}
|
||
DEFAULT_FROM_EMAIL: ${GLITCHTIP_FROM_EMAIL:-glitchtip@boiler.saas-ctrl.com}
|
||
ENABLE_USER_REGISTRATION: "false" # invite-only, matches Sentry hardening
|
||
ENABLE_ORGANIZATION_CREATION: "false"
|
||
CELERY_WORKER_AUTOSCALE: "1,3"
|
||
volumes:
|
||
- /data/coolify/services/glitchtip/uploads:/code/uploads
|
||
networks:
|
||
- default
|
||
- coolify
|
||
labels:
|
||
- "traefik.enable=true"
|
||
- "traefik.docker.network=coolify"
|
||
- "traefik.http.routers.glitchtip.rule=Host(`glitchtip.boiler.saas-ctrl.com`)"
|
||
- "traefik.http.routers.glitchtip.entrypoints=https"
|
||
- "traefik.http.routers.glitchtip.tls=true"
|
||
- "traefik.http.routers.glitchtip.tls.certresolver=letsencrypt"
|
||
- "traefik.http.services.glitchtip.loadbalancer.server.port=8000"
|
||
|
||
worker:
|
||
image: glitchtip/glitchtip:v6.1.6
|
||
command: ./bin/run-celery-with-beat.sh
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
valkey:
|
||
condition: service_healthy
|
||
environment:
|
||
DATABASE_URL: postgres://${GLITCHTIP_DB_USER:-glitchtip}:${GLITCHTIP_DB_PASSWORD}@postgres:5432/${GLITCHTIP_DB:-glitchtip}
|
||
REDIS_URL: redis://valkey:6379/0
|
||
SECRET_KEY: ${GLITCHTIP_SECRET_KEY}
|
||
GLITCHTIP_DOMAIN: ${GLITCHTIP_BASE_URL:-https://glitchtip.boiler.saas-ctrl.com}
|
||
CELERY_WORKER_AUTOSCALE: "1,3"
|
||
volumes:
|
||
- /data/coolify/services/glitchtip/uploads:/code/uploads
|
||
```
|
||
|
||
Note: this Compose includes an implicit `migrate` step. The `web`
|
||
service of the GlitchTip image runs Django migrations automatically on
|
||
startup; no separate `migrate` command is required. If you want an
|
||
explicit one-shot, override with `command: ./manage.py migrate`.
|
||
|
||
## `.env` template
|
||
|
||
```dotenv
|
||
GLITCHTIP_BASE_URL=https://glitchtip.boiler.saas-ctrl.com
|
||
|
||
# Postgres
|
||
GLITCHTIP_DB=glitchtip
|
||
GLITCHTIP_DB_USER=glitchtip
|
||
GLITCHTIP_DB_PASSWORD=replace-me-strong
|
||
|
||
# Django secret — generate with `python -c "import secrets; print(secrets.token_urlsafe(50))"`
|
||
GLITCHTIP_SECRET_KEY=replace-me-50-chars-urlsafe
|
||
|
||
# Optional: outbound mail. GlitchTip needs this for invitation flows
|
||
# even though we disable self-signup.
|
||
GLITCHTIP_FROM_EMAIL=glitchtip@boiler.saas-ctrl.com
|
||
EMAIL_URL=smtp://smtp.mailjet.net:587/?_user=...&_password=...
|
||
```
|
||
|
||
## Bootstrap
|
||
|
||
```bash
|
||
# 1. DNS: glitchtip.boiler.saas-ctrl.com -> 46.225.5.93
|
||
# 2. Fill .env, then:
|
||
docker compose up -d
|
||
# 3. First-superuser:
|
||
docker compose exec web ./manage.py createsuperuser
|
||
# 4. Log in, create projects, copy DSNs into apps' Coolify secrets.
|
||
```
|
||
|
||
## When to choose which
|
||
|
||
| Scenario | Recommendation |
|
||
| --- | --- |
|
||
| Default production observability | **Sentry** self-hosted |
|
||
| OpenTelemetry traces required | **Sentry** (GlitchTip cannot ingest OTLP) |
|
||
| Replay / Performance / Profiling required | **Sentry** |
|
||
| Throw-away preview environment | GlitchTip |
|
||
| < 8 GB RAM available | GlitchTip |
|
||
| EU-only data residency on a budget VPS | GlitchTip (both work, but GlitchTip's resource footprint is dramatically smaller) |
|
||
|
||
## Migration paths
|
||
|
||
- **Sentry → GlitchTip:** swap the DSN in app `.env`s. Historical events
|
||
are not migrated (different schema). Decommission the Sentry stack
|
||
after a 7-day overlap window.
|
||
- **GlitchTip → Sentry:** same swap, opposite direction. Historical
|
||
GlitchTip events also do not migrate. Sentry can ingest the GlitchTip
|
||
DSN format directly.
|