Sentry self-hosted na VPS

Sentry captura cada exceção da aplicação com stack trace completa, contexto do usuário, variáveis de ambiente e histórico de commits, tudo o que você precisa para reproduzir e corrigir um bug em produção sem depender de logs vagos. Self-hosteado, os dados de erro ficam na sua infraestrutura.

Instalar Sentry self-hosted

O Sentry tem um repositório oficial com docker-compose:

bash
# Requisitos mínimos: 4 vCPUs, 8 GB RAM, 20 GB disco
# (Sentry roda muitos containers internamente)

# Clonar e instalar:
git clone https://github.com/getsentry/self-hosted /opt/sentry
cd /opt/sentry

# Instalar (script interativo):
./install.sh
# O script vai:
# 1. Verificar dependências (Docker, docker-compose)
# 2. Gerar configurações e chaves
# 3. Criar banco de dados
# 4. Criar usuário admin

# Subir após instalação:
docker compose up -d

# Verificar containers rodando (são muitos!):
docker compose ps | grep -v "Exit"

# Porta padrão: 9000 (apenas local)
# Configurar Nginx como proxy:
# server_name sentry.seudominio.com.br → proxy_pass http://127.0.0.1:9000

# Atualizar Sentry:
cd /opt/sentry && git pull && ./install.sh

Integrar com Node.js

Capturar exceções e erros não tratados:

typescript
// npm install @sentry/node @sentry/profiling-node

import * as Sentry from '@sentry/node'
import { nodeProfilingIntegration } from '@sentry/profiling-node'

Sentry.init({
  dsn: 'https://CHAVE@sentry.seudominio.com.br/1',
  environment: process.env.NODE_ENV,
  release: process.env.GIT_COMMIT_SHA,  // ligar erros a releases

  // Performance monitoring:
  tracesSampleRate: 0.1,      // 10% das transações
  profilesSampleRate: 0.1,

  integrations: [
    nodeProfilingIntegration(),
  ],
})

// Express — capturar erros de rotas:
app.use(Sentry.Handlers.requestHandler())
app.use(Sentry.Handlers.tracingHandler())

// ... suas rotas ...

// Sempre depois das rotas:
app.use(Sentry.Handlers.errorHandler())

// Capturar erro manualmente com contexto extra:
try {
  await processarPagamento(pedido)
} catch (err) {
  Sentry.withScope((scope) => {
    scope.setUser({ id: userId, email: userEmail })
    scope.setTag('pedido.id', pedido.id)
    scope.setContext('pagamento', { valor: pedido.valor, metodo: pedido.metodo })
    Sentry.captureException(err)
  })
  throw err
}

Integrar com React (frontend)

Capturar erros do frontend e correlacionar com o backend:

typescript
// npm install @sentry/react

import * as Sentry from '@sentry/react'
import { BrowserTracing } from '@sentry/tracing'

Sentry.init({
  dsn: 'https://CHAVE_FRONTEND@sentry.seudominio.com.br/2',
  environment: import.meta.env.MODE,
  release: import.meta.env.VITE_GIT_COMMIT,
  integrations: [
    new BrowserTracing({
      tracePropagationTargets: ['api.seudominio.com.br'],
    }),
  ],
  tracesSampleRate: 0.1,
  // Ignorar erros conhecidos de extensions do browser:
  ignoreErrors: ['ResizeObserver loop limit exceeded', 'Non-Error promise rejection captured'],
})

// Envolver o App com ErrorBoundary:
root.render(
  <Sentry.ErrorBoundary fallback={<p>Algo deu errado. Nossa equipe foi notificada.</p>}>
    <App />
  </Sentry.ErrorBoundary>
)

// Source maps para ver o stack trace real (TypeScript/minificado):
// vite.config.ts:
import { sentryVitePlugin } from '@sentry/vite-plugin'
export default defineConfig({
  plugins: [
    sentryVitePlugin({
      org: 'minha-org',
      project: 'frontend',
      url: 'https://sentry.seudominio.com.br',
    }),
  ],
  build: { sourcemap: true },
})

Configurar alertas e notificações

Alertar no Slack, email ou Telegram quando erros novos aparecem:

bash
# No Sentry — Settings → Integrations

# Integrar com Slack:
# 1. Settings → Integrations → Slack → Install
# 2. Configurar webhook ou app OAuth

# Alertas automáticos — Settings → Alerts → Create Alert Rule:
# Condição: "An issue is seen for the first time"
# Condição: "The issue count exceeds 100 in 1 hour"
# Ação: "Send a Slack notification" ou "Send an email"

# Integração com Telegram via webhook customizado:
# Settings → Integrations → Webhooks → Add
# URL: https://seu-servidor.com.br/sentry-webhook
# Eventos: issue.created, issue.resolved, issue.assigned

# Handler do webhook no Node.js:
app.post('/sentry-webhook', express.json(), async (req, res) => {
  const { action, data } = req.body
  if (action === 'created') {
    const { issue } = data
    await enviarTelegram(
      `🐛 Novo erro no Sentry:\n${issue.title}\n${issue.culprit}\n${issue.permalink}`
    )
  }
  res.sendStatus(200)
})

Source maps e releases

Ligar erros minificados ao código fonte real via releases:

yaml
# Configurar releases no CI/CD para ligar erros a commits:

# No GitHub Actions — após o deploy:
      - name: Criar release no Sentry
        env:
          SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
          SENTRY_ORG: minha-org
          SENTRY_PROJECT: minha-api
          SENTRY_URL: https://sentry.seudominio.com.br
        run: |
          npx @sentry/cli releases new ${{ github.sha }}
          npx @sentry/cli releases files ${{ github.sha }} \
            upload-sourcemaps ./dist --url-prefix "~/dist"
          npx @sentry/cli releases finalize ${{ github.sha }}
          npx @sentry/cli releases deploys ${{ github.sha }} new \
            -e production

# Resultado no Sentry:
# - Stack trace mostra TypeScript original (não o JS minificado)
# - "Introduced in commit abc123 by João Silva"
# - "Resolved in release 1.2.3"
# - Ver % de usuários afetados por cada erro

Não quer configurar manualmente?

Implante o VPS em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

Sentry Cloud Free: 5.000 erros/mês, 1 usuário, sem retenção histórica longa. Sentry Cloud Team: $26/mês, 50k erros/mês, 90 dias retenção. Self-hosted: gratuito ilimitado mas requer VPS com 8+ GB RAM (~R$200/mês). Para times pequenos: Cloud Team pode ser mais econômico. Para dados sensíveis ou volume alto: self-hosted. Alternativa leve: GlitchTip (2 GB RAM).

Sim, GlitchTip é um substituto open-source do Sentry compatível com o SDK do Sentry, mas muito mais leve (roda com 2 GB RAM). Limitações: sem performance monitoring (APM), sem profiling, sem algumas features avançadas. Para captura de erros básica com stack trace: GlitchTip é excelente. Instale com docker-compose do repositório oficial do GlitchTip.

Por padrão: sim, o SDK envia tudo o que você passa em setUser() e o contexto das requisições. Para compliance LGPD: configure Sentry.init({ beforeSend: (event) => { delete event.user?.email; return event; } }) para remover campos sensíveis. O Sentry self-hosted mantém os dados na sua infra, o que já resolve a questão de soberania de dados.

Sentry tem Cron Monitors, você cria um monitor no painel e faz check-in no início e fim do job. Se o check-in não acontecer no tempo esperado: alerta. No Node.js: const checkIn = Sentry.captureCheckIn({ monitorSlug: "backup-diario", status: "in_progress" }); // ... executar job ...; Sentry.captureCheckIn({ checkInId, monitorSlug: "backup-diario", status: "ok" }).

Configure data retention em Settings → Admin → General: Events: 30 dias, Attachments: 7 dias. Para limpeza manual: docker compose run --rm web sentry cleanup --days 30. Monitore o uso do Postgres e Redis que crescem com os eventos. Regra prática: 5 GB de SSD por mês para APIs com tráfego médio.