Skip to content

How to Deploy GlitchTip on a VPS

Updated Sep 2026

verified on Ubuntu 26.04 · Sep 2026
We earn commissions when you shop through the links below. Full disclosure →

Self-host GlitchTip, the Sentry-compatible error tracker, on a small VPS with the official Docker Compose file. Covers the secret key, closed signup, a loopback port behind Caddy, retention and Postgres backups.

Before you start
  • A small VPS — 1 vCPU / 1 GB RAM is enough to start
  • A fresh Ubuntu 24.04 or 26.04 server with root/sudo SSH access
  • A domain you can point at the server — SDK DSNs embed it
  • Docker Engine + Compose installed (see the base guide below)
Need a box for this guide? Kamatera's free tier lets you spin one up now.Start free on Kamatera → (opens in new tab)

What GlitchTip is

GlitchTip is an open-source error tracker that speaks Sentry's ingestion protocol. Your applications keep using the official Sentry SDKs. You change only the DSN, and the exceptions, stack traces and alerts arrive at your own server instead of sentry.io. It is a Django application backed by PostgreSQL, with optional Valkey (a Redis fork) for its task queue and cache. Recent versions also include uptime monitoring and log ingestion.

It aims to be the lighter option: it covers the core of error tracking without the full Sentry self-hosted stack. GlitchTip vs Sentry covers what that trade leaves out. Bugsink vs GlitchTip compares it with an even smaller alternative.

Server sizing

GlitchTip's install docs give these numbers:

  • Recommended: 512 MB RAM, x86 or arm64.
  • Minimum: 256 MB RAM in the all-in-one setup, or 128 MB plus swap with careful configuration. The compose file lists the knobs: disable Valkey, log ingestion and uptime monitoring.
  • Disk: as a rough guide from the same docs, 30 GB for about a million events a month. Event size varies a lot with stack depth and breadcrumbs, so treat that as an order of magnitude.

In our install check (GCP e2-standard-2, Ubuntu 26.04, September 2026), the default stack of GlitchTip all-in-one, Postgres and Valkey idled at about 181 MB of RAM and about 1.8 GB of Docker disk. A 1 GB VPS leaves room for Caddy and headroom for traffic spikes.

Put it on a box separate from the apps that report to it. An error tracker that goes down with your application can't tell you why it went down.

Prepare the server

This guide assumes Docker Engine and the Compose plugin are installed. If not, work through Docker & Compose on Ubuntu first. Open SSH and the reverse-proxy ports only:

sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw --force enable
sudo ufw status verbose

GlitchTip's own port (8000) will be bound to 127.0.0.1. Docker-published ports bypass ufw, so the loopback bind is what keeps it private.

Where to host itaffiliate disclosure
Hetzner Cloudrun it on
2 vCPU · 4 GB RAM · 80 GB SSD · $23.59/mo
Get Hetzner Cloud (opens in new tab)
Kamaterafree trial
1 vCPU · 1 GB RAM · 20 GB SSD · $4.00/mo
Start free on Kamatera → (opens in new tab)
DigitalOceanalso works on
1 vCPU · 1 GB RAM · 25 GB SSD · $6.00/mo
Deploy on DigitalOcean → (opens in new tab)

Paid link — we earn a commission if you shop through it.

Download and edit the compose file

GlitchTip publishes a sample compose file. Its install docs say to save it as compose.yml and edit the environment section:

mkdir -p ~/glitchtip && cd ~/glitchtip
[ -f compose.yml ] || curl -fsSL -o compose.yml https://glitchtip.com/assets/compose.sample.yml
grep -n 'image:\|SECRET_KEY\|GLITCHTIP_DOMAIN\|"8000:8000"' compose.yml

The file defines three services. postgres runs Postgres 18, valkey runs Valkey 9, and web runs glitchtip/glitchtip:6 with SERVER_ROLE: all_in_one, so one container serves both the web app and the background worker. The shared settings sit in an x-environment block at the top.

Now make the edits, each one idempotent so you can re-run the block:

cd ~/glitchtip
# 1. A real secret key — the sample ships a placeholder
sed -i "s|SECRET_KEY: change_me_to_something_random|SECRET_KEY: $(openssl rand -hex 32)|" compose.yml
# 2. Your public URL — DSNs and email links are built from it
sed -i 's|GLITCHTIP_DOMAIN: https://glitchtip.example.com|GLITCHTIP_DOMAIN: https://errors.example.com|' compose.yml
# 3. Loopback-only port — Caddy is the public entry point
sed -i 's|- "8000:8000"|- "127.0.0.1:8000:8000"|' compose.yml
# 4. No public self-signup, and only the hostnames you serve
grep -q ENABLE_USER_REGISTRATION compose.yml || \
  sed -i '/ENABLE_ADMIN:/i\  ENABLE_USER_REGISTRATION: "False"\n  ALLOWED_HOSTS: errors.example.com,127.0.0.1,localhost' compose.yml
grep -n 'SECRET_KEY\|GLITCHTIP_DOMAIN\|127.0.0.1:8000\|ENABLE_USER_REGISTRATION\|ALLOWED_HOSTS' compose.yml | sed 's/SECRET_KEY: .*/SECRET_KEY: (set)/'

Replace errors.example.com with your real domain in both places. Here is what each edit does:

  • SECRET_KEY signs sessions and tokens. The sample value is public, so never run with it.
  • GLITCHTIP_DOMAIN must include the scheme. The DSN each project shows is built from it, so a wrong value hands your SDKs a wrong ingest URL.
  • ENABLE_USER_REGISTRATION: "False" follows the docs' definition: self- signup is disabled after the first user is registered. Anyone else must be created by a superuser, and organisation invitations can only go to existing users. Leave it at the default True and anyone who finds the URL can make an account.
  • ALLOWED_HOSTS. Without it, GlitchTip logs a warning at startup that ALLOWED_HOSTS is the wildcard default and should be restricted in production.

EMAIL_URL stays consolemail://, which prints emails to the container log. Before inviting teammates or relying on alert emails, set it to your SMTP server in the form smtp://user:password@host:port, and set DEFAULT_FROM_EMAIL to match. The sample's Postgres uses trust authentication on the internal Compose network. It isn't published to the host, but the sample's own comment suggests setting a password for anything long-lived.

Start GlitchTip

cd ~/glitchtip
docker compose up -d
for i in $(seq 1 60); do
  [ "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8000/_health/)" = 200 ] && break
  sleep 3
done
curl -s http://127.0.0.1:8000/_health/; echo
docker compose ps

Database migrations run automatically on start. _health/ answering ok means the web process is up and serving.

Create the admin account

With self-signup closed, create the first account yourself. Django's createsuperuser command runs non-interactively when the password comes from the environment. This generates one and saves it to ~/glitchtip/admin-password:

cd ~/glitchtip
[ -f admin-password ] || openssl rand -base64 18 > admin-password
chmod 600 admin-password
docker compose exec -T -e DJANGO_SUPERUSER_PASSWORD="$(cat admin-password)" web \
  ./manage.py createsuperuser --noinput --email admin@example.com 2>&1 | tail -1
curl -s http://127.0.0.1:8000/api/settings/ | grep -o '"enableUserRegistration": [a-z]*'

"enableUserRegistration": false confirms public signup is off. Use your own email. It is the login. Once you're signed in, create an organisation and then a project for each application. Each project shows its DSN.

HTTPS + domain

Point an A record for errors.example.com at the server and put Caddy in front of the loopback port:

errors.example.com {
    reverse_proxy 127.0.0.1:8000
}

GlitchTip's docs recommend a proxy that buffers requests and handles chunked transfer encoding, and their nginx example raises the body limit to 40 MB so large event payloads and source-map uploads aren't rejected. Caddy sets no request-body limit by default, so this works as is.

Point an application at it

In each app, keep the Sentry SDK and swap the DSN for the one from the GlitchTip project page. It looks like https://<key>@errors.example.com/<project-id>. For example, in Python:

import sentry_sdk
sentry_sdk.init(dsn="https://<key>@errors.example.com/1")

Trigger a test exception from the app, and it appears in the project's issue list, grouped with any repeats.

Retention

GlitchTip cleans up old data automatically. GLITCHTIP_RETENTION_DAYS (default 90) is the master setting. Per-type overrides exist for events, transactions, logs, uptime checks and files, plus GLITCHTIP_RELEASE_RETENTION_DAYS (default 365). Recent events stay in Postgres for GLITCHTIP_EVENT_HOT_DAYS (default 30). Older ones can move to an optional cold-storage archive, enabled with GLITCHTIP_ENABLE_DUCKDB. On a small disk, lower the master value in the x-environment block and recreate the containers.

Backups

Postgres holds everything: users, organisations, projects and events. Dump it with the stack running:

cd ~/glitchtip
docker compose exec -T postgres pg_dump -U postgres postgres | gzip > glitchtip-$(date +%F).sql.gz
ls -lh glitchtip-*.sql.gz

Also keep compose.yml, which holds your SECRET_KEY, and the uploads volume if you upload source maps or debug files. Copy all of it off the box. To restore, bring up an empty stack with the same compose.yml and pipe the dump into psql in the postgres container before starting web.

Upgrades

The docs' procedure is pull, stop, start. Migrations run automatically:

cd ~/glitchtip
docker compose pull
docker compose stop
docker compose up -d

The glitchtip/glitchtip:6 tag follows the 6.x line. A new major version means editing the tag, and the sample's comment points to the GlitchTip blog for those announcements. The Postgres tag is a separate decision. A major Postgres upgrade needs a dump and restore, not just a new image. Take a dump before either.

Troubleshooting

The UI loads but SDK events never arrive. Check GLITCHTIP_DOMAIN. The DSN is built from it, so if it still says glitchtip.example.com, every SDK sends to the wrong host. Fix it, recreate the containers, and copy the DSN again.

"Bad Request (400)" through the domain. The hostname isn't in ALLOWED_HOSTS. Add it (comma-separated) and recreate web.

No alert or invite emails. EMAIL_URL is still consolemail://, so the emails went to docker compose logs web. Configure SMTP.

Memory is tight on a 512 MB box. Use the sample file's own low-RAM options: set VALKEY_URL: "" to use Postgres for the queue and cache, remove the valkey service, and turn off GLITCHTIP_ENABLE_LOGS and GLITCHTIP_ENABLE_UPTIME if you don't use them.

Verification + next steps

You're done when https://errors.example.com loads over a valid certificate, you can sign in as the admin while the signup page is refused to everyone else, a test exception from a real app shows up as an issue, and a Postgres dump sits off the box.

Next: configure SMTP so alerts reach people, create one project per service, and add GlitchTip's uptime monitors for your public endpoints. For dedicated uptime monitoring and status pages, see Uptime Kuma.

Next steps

How to self-host GlitchTip →Automatic HTTPS with Caddy →Run Claude Code with Ollama on Your Own VPS →Deploy Coolify on a VPS →How to Deploy Actual Budget on a VPS →How to Deploy AnythingLLM on a VPS →How to Deploy Appwrite on a VPS →How to Deploy Audiobookshelf on a VPS →How to Deploy Authelia on a VPS →How to Deploy authentik on a VPS →How to Deploy Baserow on a VPS →How to Deploy Beszel on a VPS →How to Deploy Bitwarden on a VPS →How to Deploy BookStack on a VPS →How to Deploy CapRover on a VPS →How to Deploy Checkmate on a VPS →How to Deploy Directus on a VPS →How to Deploy docker-mailserver on a VPS →How to Deploy Docmost on a VPS →How to Deploy Dokku on a VPS →How to Deploy Dokploy on a VPS →How to Deploy Firefly III on a VPS →How to Deploy Forgejo on a VPS →How to Deploy Gatus on a VPS →How to Deploy Ghostfolio on a VPS →How to Deploy Gitea on a VPS →How to Deploy GitLab on a VPS →How to Deploy Grafana on a VPS →How to Deploy Graylog on a VPS →How to Deploy Headscale on a VPS →How to Deploy Healthchecks on a VPS →How to Deploy Home Assistant on a VPS →How to Deploy Immich on a VPS →How to Deploy Jan on a VPS →How to Deploy Jellyfin on a VPS →How to Deploy Karakeep on a VPS →How to Deploy Keycloak on a VPS →How to Deploy Leantime on a VPS →How to Deploy LibreChat on a VPS →How to Deploy Linkwarden on a VPS →How to Deploy LocalAI on a VPS →How to Deploy Mailcow on a VPS →How to Deploy Mailu on a VPS →How to Deploy Matomo on a VPS →How to Deploy Mattermost on a VPS →How to Deploy Meilisearch on a VPS →How to Deploy Memos on a VPS →How to Deploy n8n on a VPS →How to Deploy Navidrome on a VPS →How to Deploy NetBird on a VPS →How to Deploy Netdata on a VPS →How to Deploy Nextcloud on a VPS →How to Deploy Next.js to a VPS →How to Deploy Nginx Proxy Manager on a VPS →How to Deploy NocoDB on a VPS →How to Deploy ntfy on a VPS →How to Deploy Ollama on a VPS →How to Deploy Open WebUI on a VPS →How to Deploy OpenHands on a VPS →How to Deploy OpenObserve on a VPS →How to Deploy OpenProject on a VPS →How to Deploy Outline on a VPS →How to Deploy Pangolin on a VPS →How to Deploy Paperless-ngx on a VPS →How to Deploy Passbolt on a VPS →How to Deploy Plane on a VPS →How to Deploy Plausible Analytics on a VPS →How to Deploy Pocket ID on a VPS →How to Deploy PocketBase on a VPS →How to Deploy Prometheus on a VPS →How to Deploy Psono on a VPS →How to Deploy Radarr on a VPS →How to Deploy Rocket.Chat on a VPS →How to Deploy SigNoz on a VPS →How to Deploy Sonarr on a VPS →How to Deploy Stalwart on a VPS →How to Deploy Stirling-PDF on a VPS →How to Deploy Supabase on a VPS →How to Deploy Synapse on a VPS →How to Deploy Taiga on a VPS →How to Deploy TeamPass on a VPS →How to Deploy Tinyauth on a VPS →How to Deploy Traefik on a VPS →How to Deploy Trilium on a VPS →How to Deploy Twenty CRM on a VPS →How to Deploy Umami on a VPS →How to Deploy Uptime Kuma on a VPS →How to Deploy Vaultwarden on a VPS →How to Deploy Vikunja on a VPS →How to Deploy wg-easy on a VPS →How to Deploy Wiki.js on a VPS →How to Deploy Zabbix on a VPS →How to Deploy Zitadel on a VPS →How to Deploy Zulip on a VPS →Docker & Compose on Ubuntu 26.04 →Building AI Workflows with n8n →Install Open WebUI with Ollama →Adding AI-Powered Insights to Plausible Analytics →Building AI-Powered Apps with Supabase and pgvector →

We use analytics cookies (Google Analytics, PostHog) to see which guides are useful. No ad networks, no cross-site tracking. See our privacy policy.