diff --git a/.env.example b/.env.example index fcfba003..1b16ba67 100644 --- a/.env.example +++ b/.env.example @@ -10,3 +10,10 @@ POSTGRES_PASSWORD=changeme # YC_REGISTRY_ID= # IMAGE_TAG=latest # NEXT_PUBLIC_API_BASE_URL=https://your-domain.example.ru + +# GlitchTip (errors.gendsgn.ru) +GLITCHTIP_DB_PASS= +GLITCHTIP_SECRET= +# DSN-ы из GlitchTip UI после первого старта (→ .env.runtime или backend/.env) +GLITCHTIP_DSN= +NEXT_PUBLIC_GLITCHTIP_DSN= diff --git a/Caddyfile b/Caddyfile index 5c52cc04..4b43b2ed 100644 --- a/Caddyfile +++ b/Caddyfile @@ -44,6 +44,18 @@ obsidian.gendsgn.ru { } } +# GlitchTip — self-hosted error tracking (Sentry-compatible). +# DNS: A-record errors.gendsgn.ru → IP VPS. +errors.gendsgn.ru { + encode zstd gzip + + reverse_proxy glitchtip-web:8080 + + log { + output file /var/log/caddy/errors.gendsgn.ru.log + } +} + # Plain HTTP by IP — kept for ssh-tunnel / debugging. # Caddy issues no TLS here (no hostname). :80 { diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 90632581..e48c9b99 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -121,6 +121,46 @@ services: condition: service_healthy command: ["celery", "-A", "app.workers.celery_app", "beat", "--loglevel=info"] + glitchtip-web: + image: glitchtip/glitchtip:latest + container_name: glitchtip-web + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + environment: + DATABASE_URL: postgres://glitchtip:${GLITCHTIP_DB_PASS}@postgres:5432/glitchtip + REDIS_URL: redis://redis:6379/2 + SECRET_KEY: ${GLITCHTIP_SECRET} + PORT: "8080" + EMAIL_URL: dummy:// + GLITCHTIP_DOMAIN: https://errors.gendsgn.ru + DEFAULT_FROM_EMAIL: errors@gendsgn.ru + ENABLE_USER_REGISTRATION: "false" + ENABLE_ORGANIZATION_CREATION: "false" + CELERY_WORKER_AUTOSCALE: "1,3" + restart: always + mem_limit: 256m + networks: [default] + + glitchtip-worker: + image: glitchtip/glitchtip:latest + container_name: glitchtip-worker + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_started + command: ./bin/run-celery-with-beat.sh + environment: + DATABASE_URL: postgres://glitchtip:${GLITCHTIP_DB_PASS}@postgres:5432/glitchtip + REDIS_URL: redis://redis:6379/2 + SECRET_KEY: ${GLITCHTIP_SECRET} + restart: always + mem_limit: 256m + networks: [default] + caddy: image: caddy:2 restart: unless-stopped diff --git a/scripts/bootstrap_glitchtip.sh b/scripts/bootstrap_glitchtip.sh new file mode 100644 index 00000000..18450a24 --- /dev/null +++ b/scripts/bootstrap_glitchtip.sh @@ -0,0 +1,108 @@ +#!/usr/bin/env bash +# bootstrap_glitchtip.sh +# One-shot bootstrap for GlitchTip on the VPS. +# +# Run ONCE manually after merging feat/204-glitchtip-infra. +# Do NOT add to deploy.yml — this is idempotent setup, not a recurring step. +# +# Usage (on VPS via SSH): +# cd /opt/gendesign +# # Ensure GLITCHTIP_DB_PASS and GLITCHTIP_SECRET are set in .env +# bash scripts/bootstrap_glitchtip.sh +# +# After running: +# 1. docker compose -p gendesign -f docker-compose.prod.yml exec glitchtip-web ./manage.py createsuperuser +# 2. Log in to https://errors.gendsgn.ru → create org "gendesign" +# 3. Create projects: "backend", "frontend" +# 4. Copy DSNs → add to /opt/gendesign/backend/.env (GLITCHTIP_DSN) +# and /opt/gendesign/frontend/.env or .env.runtime (NEXT_PUBLIC_GLITCHTIP_DSN) +# 5. Recreate affected containers: +# docker compose -p gendesign -f docker-compose.prod.yml up -d --force-recreate --no-deps backend + +set -euo pipefail + +COMPOSE_FILE="docker-compose.prod.yml" +COMPOSE_PROJECT="gendesign" +COMPOSE="docker compose -p $COMPOSE_PROJECT -f $COMPOSE_FILE" + +# ── Load .env.runtime for GLITCHTIP_DB_PASS / POSTGRES_* ────────────────── +if [ -f ".env" ]; then + set -a; source .env; set +a +fi +if [ -f "backend/.env.runtime" ]; then + set -a; source backend/.env.runtime; set +a +fi + +: "${GLITCHTIP_DB_PASS:?GLITCHTIP_DB_PASS not set — add to .env or export}" +: "${POSTGRES_USER:?POSTGRES_USER not set}" +: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD not set}" +: "${POSTGRES_DB:?POSTGRES_DB not set}" + +echo "==> Ensuring postgres service is healthy..." +for i in $(seq 1 30); do + if $COMPOSE exec -T postgres pg_isready -U "$POSTGRES_USER" -q; then + break + fi + echo " Waiting for postgres... ($i/30)" + sleep 2 +done + +# ── Create glitchtip DB + user (idempotent) ──────────────────────────────── +echo "==> Creating glitchtip database and user (idempotent)..." +$COMPOSE exec -T postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" \ + -v ON_ERROR_STOP=on < Pulling glitchtip image..." +$COMPOSE pull glitchtip-web glitchtip-worker + +echo "==> Starting glitchtip-web and glitchtip-worker..." +$COMPOSE up -d glitchtip-web glitchtip-worker + +# ── Wait for glitchtip-web to become healthy ─────────────────────────────── +echo "==> Waiting for glitchtip-web to become healthy (up to 60s)..." +for i in $(seq 1 30); do + if $COMPOSE exec -T glitchtip-web curl -fsS http://localhost:8080/healthz/ >/dev/null 2>&1; then + echo " glitchtip-web is healthy." + break + fi + echo " Waiting... ($i/30)" + sleep 2 +done + +echo "" +echo "==> Bootstrap complete." +echo "" +echo "Next steps:" +echo " 1. Create superuser:" +echo " $COMPOSE exec glitchtip-web ./manage.py createsuperuser" +echo "" +echo " 2. Log in to https://errors.gendsgn.ru" +echo " - Create organization: gendesign" +echo " - Create project: backend (Platform: Python)" +echo " - Create project: frontend (Platform: JavaScript / Browser)" +echo "" +echo " 3. Copy DSNs from each project's Settings → DSN" +echo " - Add GLITCHTIP_DSN= to /opt/gendesign/backend/.env" +echo " - Add NEXT_PUBLIC_GLITCHTIP_DSN= to /opt/gendesign/backend/.env or .env" +echo "" +echo " 4. Recreate services to pick up new DSNs:" +echo " $COMPOSE up -d --force-recreate --no-deps backend" +echo " $COMPOSE up -d --force-recreate --no-deps worker beat" +echo "" +echo " 5. Verify: trigger a test exception and confirm it appears in GlitchTip."