Sentry Self-Hosted Error Tracking Installation
Sentry is an open-source error tracking and performance monitoring platform that captures exceptions, slowdowns, and crashes in real time, helping developers reproduce and fix issues faster. This guide covers deploying self-hosted Sentry with Docker, setting up projects, integrating SDKs, configuring alert rules, and tracking releases.
Prerequisites
- Ubuntu 20.04+ or CentOS 8+ / Rocky Linux 8+
- Docker and Docker Compose
- 16 GB RAM minimum (Sentry's self-hosted stack is resource-intensive)
- 50 GB disk space
- A domain name with DNS pointing to your server (for email and HTTPS)
Installing Self-Hosted Sentry
Sentry provides an official self-hosted installation script:
# Clone the self-hosted repository
git clone https://github.com/getsentry/self-hosted.git
cd self-hosted
# Check out the latest stable release
git checkout $(git tag --sort=version:refname | tail -1)
# Run the installation script
# This installs Docker, creates config files, and runs migrations (~10 minutes)
sudo ./install.sh
# The install script will prompt you to create an admin user
# Enter your email and password when asked
After installation completes:
# Start all services
docker compose up -d
# Check that all containers are healthy
docker compose ps
# Key services running:
# sentry-web - Web UI and API (port 9000)
# sentry-worker - Background task processing
# postgres - Database
# redis - Caching and message broker
# clickhouse - Error event storage (newer versions)
# kafka - Event ingestion queue
# snuba - Query layer for ClickHouse
Wait 5-10 minutes for all services to fully start. Check health:
curl http://localhost:9000/_health/
Initial Setup
Access Sentry at http://your-server:9000. Log in with the admin credentials you created during installation.
Configure a reverse proxy with TLS (required for production and SDK integrations):
# /etc/nginx/sites-available/sentry
server {
listen 80;
server_name sentry.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name sentry.example.com;
ssl_certificate /etc/letsencrypt/live/sentry.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/sentry.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:9000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
client_max_body_size 100M;
}
}
Configure the Sentry URL in .env:
# In self-hosted/.env
SENTRY_URL=https://sentry.example.com
Configure email notifications in .env:
SENTRY_EMAIL_HOST=smtp.gmail.com
SENTRY_EMAIL_PORT=587
SENTRY_EMAIL_USE_TLS=true
[email protected]
SENTRY_EMAIL_PASSWORD=your-app-password
[email protected]
After editing .env, restart:
docker compose restart web worker
Creating Projects and Getting DSNs
- In Sentry, go to Settings → Projects → Create Project
- Select your platform (Python, Node.js, React, Go, etc.)
- Name the project (e.g., "production-api")
- Click Create Project
The DSN (Data Source Name) is displayed. It looks like:
https://[email protected]/1234
For self-hosted, the DSN format is:
https://{public_key}@sentry.example.com/{project_id}
Find your project's DSN:
- Settings → Projects → select project → SDK Setup → DSN
SDK Integration
Python:
pip install sentry-sdk
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration # or FastApiIntegration
sentry_sdk.init(
dsn="https://[email protected]/1",
integrations=[DjangoIntegration()],
traces_sample_rate=0.1, # 10% of transactions for performance
profiles_sample_rate=0.1, # 10% profiling
environment="production",
release="[email protected]",
send_default_pii=False, # Don't send IP, username, etc.
)
# Test: this will send a test event
# with sentry_sdk.push_scope() as scope:
# scope.set_tag("test", True)
# raise Exception("Test exception")
Node.js / Express:
npm install @sentry/node @sentry/profiling-node
// instrument.js (require before anything else)
const Sentry = require("@sentry/node");
const { nodeProfilingIntegration } = require("@sentry/profiling-node");
Sentry.init({
dsn: "https://[email protected]/1",
integrations: [nodeProfilingIntegration()],
tracesSampleRate: 0.1,
profilesSampleRate: 0.1,
environment: process.env.NODE_ENV || "production",
release: process.env.npm_package_version,
});
// Express error handler (add after routes)
const app = require("express")();
app.use(Sentry.Handlers.requestHandler());
// ... your routes ...
app.use(Sentry.Handlers.errorHandler());
React (frontend):
npm install @sentry/react
// index.js
import * as Sentry from "@sentry/react";
Sentry.init({
dsn: "https://[email protected]/1",
integrations: [Sentry.browserTracingIntegration()],
tracesSampleRate: 0.1,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
environment: "production",
release: "[email protected]",
});
Go:
go get github.com/getsentry/sentry-go
package main
import (
"log"
"time"
"github.com/getsentry/sentry-go"
)
func main() {
err := sentry.Init(sentry.ClientOptions{
Dsn: "https://[email protected]/1",
TracesSampleRate: 0.1,
Environment: "production",
Release: "[email protected]",
})
if err != nil {
log.Fatalf("sentry.Init: %s", err)
}
defer sentry.Flush(2 * time.Second)
// Capture manually:
sentry.CaptureException(fmt.Errorf("something went wrong"))
}
Alert Rules and Notifications
Create alert rules in Alerts → Create Alert Rule:
Error alert example:
- Type: Issues
- Conditions:
An issue is seen more than 10 times in 1h - Filter: Environment: production
- Action: Send email to team, post to #alerts Slack channel
Performance alert example:
- Type: Metric Alert
- Metric: Transaction duration P95
- Threshold: > 2000ms
- Time window: 5 minutes
- Action: Notify on-call
Configure Slack integration:
- Settings → Integrations → Slack → Add to Slack
- Authorize Sentry to post to your workspace
- In alert rules, select Slack as the notification channel
Configure PagerDuty:
- Settings → Integrations → PagerDuty
- Enter your PagerDuty integration key
- Select services to map to PagerDuty services
Release Tracking and Source Maps
Tag events with release versions to track when bugs were introduced:
# Create a release via the Sentry CLI
# Install the CLI
curl -sL https://sentry.io/get-cli/ | bash
# For self-hosted, set the URL:
export SENTRY_URL=https://sentry.example.com
export SENTRY_AUTH_TOKEN=your-auth-token # Settings → Auth Tokens
export SENTRY_ORG=your-org-slug
export SENTRY_PROJECT=your-project-slug
# Create release, upload source maps, finalize
sentry-cli releases new "[email protected]"
sentry-cli releases files "[email protected]" upload-sourcemaps ./dist
sentry-cli releases finalize "[email protected]"
sentry-cli releases deploys "[email protected]" new -e production
In your CI/CD pipeline (GitHub Actions):
- name: Create Sentry Release
env:
SENTRY_URL: https://sentry.example.com
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SENTRY_ORG: myorg
SENTRY_PROJECT: my-app
run: |
sentry-cli releases new ${{ github.sha }}
sentry-cli releases set-commits --auto ${{ github.sha }}
sentry-cli releases files ${{ github.sha }} upload-sourcemaps ./dist
sentry-cli releases finalize ${{ github.sha }}
sentry-cli releases deploys ${{ github.sha }} new -e production
Performance Monitoring
Sentry captures transaction traces automatically with the SDK. View them under Performance:
- Duration histogram and P50/P95/P99 breakdowns
- Slow DB Queries - automatically detected slow queries
- N+1 Issues - detected ORM query problems
- Transaction waterfall - full span breakdown
Add custom spans to trace business logic:
import sentry_sdk
with sentry_sdk.start_transaction(op="task", name="process_order"):
with sentry_sdk.start_span(op="db.query", description="fetch order"):
order = db.fetch_order(order_id)
with sentry_sdk.start_span(op="http.client", description="payment gateway"):
result = payment_api.charge(order)
Troubleshooting
Services failing to start:
cd self-hosted
docker compose logs --tail=50 web
docker compose logs --tail=50 worker
# Common: insufficient RAM, PostgreSQL not ready
Events not appearing in Sentry:
# Check if events are being received
docker compose logs relay | tail -20
# Relay handles inbound SDK events
# Test with sentry-cli
sentry-cli send-event -m "Test event" --logfile /dev/stdin <<< "test"
Disk space filling up:
# Check storage usage
docker system df
du -sh self-hosted/
# Adjust retention in Settings → Admin → General Settings
# Default: 90 days for events
Email notifications not working:
# Send a test email
docker compose run --rm web sentry sendtestemail --to [email protected]
Sentry is slow:
# Check resource usage
docker stats
# ClickHouse is the main memory consumer
# Increase Docker memory limit or add more RAM
Conclusion
Self-hosted Sentry provides enterprise-grade error tracking and performance monitoring with full data ownership and no per-event pricing. The SDK integrations for Python, Node.js, React, Go, and dozens of other platforms capture errors automatically with full stack traces, request context, and breadcrumbs. Combined with release tracking and source maps, Sentry correlates production errors to specific code changes and developers, dramatically reducing time to resolution. Plan for at least 16 GB RAM and provision SSD storage for the best performance.

