> ## Documentation Index
> Fetch the complete documentation index at: https://controlplanecorporation-majid-docs-content-expansion.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# GlitchTip

> Deploy GlitchTip on Control Plane using the Template Catalog. Open-source, Sentry-compatible error tracking with a stateless web tier, a background worker, a Redis/Sentinel queue and a highly available PostgreSQL backend. Covers the prerequisite auth secret, database and queue modes, closed registration, backups, and upgrading from template version 1.0.x.

## Overview

GlitchTip is open-source, Sentry-API-compatible error tracking — applications report crashes and exceptions with standard Sentry SDKs pointed at a GlitchTip DSN, and GlitchTip groups them into issues with alerting. It is fully MIT-licensed with nothing feature-gated; there is no paid tier. This template deploys GlitchTip backed by a highly available PostgreSQL cluster and a Redis/Sentinel queue by default. The web UI and SDK event-ingest endpoint are served on one public HTTPS endpoint, and self-signup is closed by default.

The Django signing key and the initial superuser login are not template values. They come from a dictionary secret you create before installing, so they never pass through Helm and never land in the release.

<Warning>
  **Template version 1.1.0 is a breaking change.** `django.secretKey`, `admin.email` and `admin.password` moved into a prerequisite secret, and `resources.cpu` / `resources.memory` / `worker.resources.cpu` / `worker.resources.memory` were renamed. An install or upgrade that still sets any of them fails at render. If you are running 1.0.x, read [Upgrading From Earlier Versions](#upgrading-from-earlier-versions) first.
</Warning>

### Architecture

* **GlitchTip web** — A stateless standard workload (default 1 replica, `replicas` knob for more) serving the UI, API, and SDK event ingest on port `8000`.
* **GlitchTip worker** — A single-replica standard workload running the background task worker and scheduler; it also runs database migrations and the superuser bootstrap at boot. It is a fixed singleton and is not scaled.
* **PostgreSQL (HA, default)** — The [postgres-highly-available](/template-catalog/templates/postgres-highly-available) template as a subchart: 3× Patroni PostgreSQL, 3× etcd, and a HAProxy leader-routing endpoint GlitchTip connects through. Holds all issue and event data.
* **PostgreSQL (dev/lightweight, optional)** — The single-instance [postgres](/template-catalog/templates/postgres) template instead, for lighter non-HA deployments.
* **Redis + Sentinel (default, optional)** — The [redis](/template-catalog/templates/redis) template in Sentinel mode: the task queue, cache, and sessions. Disable it to run those on PostgreSQL instead (a lighter dev shape).

### What Gets Created

* **Standard GlitchTip Web Workload** — (`RELEASE_NAME-glitchtip`): the stateless web tier serving the UI, API, and SDK event ingest on port `8000` (`replicas` controls its scale).
* **Standard GlitchTip Worker Workload** — (`RELEASE_NAME-glitchtip-worker`): a single-replica worker plus scheduler that runs migrations and the admin bootstrap at boot.
* **Database Workloads** — HA mode: a stateful Patroni PostgreSQL workload, a stateful etcd workload, and a standard HAProxy leader-routing workload. Single mode: one stateful PostgreSQL workload.
* **Redis Workloads** *(default)* — A master-replica Redis deployment with Sentinel for failover. Omitted when `redis.enabled` is `false`.
* **Volume Sets** — The database subchart's persistent volumes (10 GiB per replica by default), plus Redis persistence when enabled. The GlitchTip web and worker tiers have no volumes of their own.
* **Secrets** — Two start scripts, plus the database and Redis credentials from the subcharts. The template creates **no credential secret of its own**: the signing key and admin login come from the secret you create.
* **Identity & Policy** — A shared identity for the web and worker workloads and a least-privilege policy granting it `reveal` on exactly the secrets it uses, including your auth secret by name and the optional email secret when configured.

<Note>
  This template does not create a GVC. You must deploy it into an existing GVC.
</Note>

## Upgrading From Earlier Versions

Template version 1.0.x carried the Django signing key and the superuser login as plain Helm values, with published defaults for both. Each removed or renamed key is rejected at render with a message naming its replacement, so a failing upgrade leaves the running release untouched. There are no compatibility fallbacks.

| Removed or renamed in 1.0.x                        | 1.1.0                                                    |
| -------------------------------------------------- | -------------------------------------------------------- |
| `django.secretKey`                                 | `secretKey` key in the prerequisite auth secret          |
| `admin.email`                                      | `adminEmail` key in the same secret                      |
| `admin.password`                                   | `adminPassword` key in the same secret                   |
| `resources.cpu` / `resources.memory`               | `resources.maxCpu` / `resources.maxMemory`               |
| `worker.resources.cpu` / `worker.resources.memory` | `worker.resources.maxCpu` / `worker.resources.maxMemory` |

<Warning>
  **Put your existing `secretKey` into the secret rather than generating a new one.** It signs live sessions and tokens: a new value logs every user out and invalidates password-reset links already in flight. Nothing is corrupted, but everyone has to sign in again.

  If your install is still carrying the published 1.0.x default, its sessions and tokens are signed with a value printed in a public repository. Rotating it is the fix and the cost is exactly that one forced sign-out, so plan the upgrade for a quiet window rather than skipping it. Change the admin password in the UI at the same time.
</Warning>

The resource keys were renamed because both blocks expose a reservation as well as a limit, and a bare `cpu` sitting next to `minCpu` does not say which one it is. `maxCpu` and `maxMemory` map onto the platform's `cpu` and `memory` fields.

## Prerequisites

**One secret must exist before you install.** Its values never pass through Helm, so they never land in the release. Secrets are org-level, so no GVC flag is involved.

<Steps>
  <Step title="Create the auth secret">
    A [dictionary secret](/guides/create-secret/dictionary) holding exactly three keys:

    ```bash theme={null}
    cpln secret create-dictionary --name my-glitchtip-auth \
      --entry secretKey="$(openssl rand -hex 32)" \
      --entry adminEmail=admin@example.com \
      --entry adminPassword="$(openssl rand -hex 24)"
    ```

    Set `auth.secretName` to the name you used. Nothing else is required for a default install.

    | Key                            | What it is                                                                                                                                     |
    | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- |
    | `secretKey`                    | Django's `SECRET_KEY` — signs sessions and tokens. Keep it for the life of the install: changing it logs every user out.                       |
    | `adminEmail` / `adminPassword` | The initial superuser, seeded on first boot only. Afterwards manage accounts in the UI; editing the secret does not change the existing login. |
  </Step>

  <Step title="Read the secret back later">
    The `-o yaml` is required — plain `cpln secret reveal` prints only a summary table, not the values:

    ```bash theme={null}
    cpln secret reveal my-glitchtip-auth -o yaml
    ```
  </Step>

  <Step title="Optional: create the email secret">
    For member invites, alert notifications, and password-reset mail, create an [opaque secret](/guides/create-secret/opaque) with encoding `plain` whose payload is a full email URL — for example `smtp://user:password@smtp.example.com:587`. Set `email.secretName` to its name before installing. Leave it empty to run without outbound email.
  </Step>

  <Step title="Optional: set up backup storage">
    Only if you plan to enable database backups — see [Backing Up](#backing-up).
  </Step>
</Steps>

<Warning>
  **Create the auth secret before installing.** A name pointing at a secret that does not exist installs "successfully" and then wedges **both** workloads: every resource reports created, neither becomes ready, and **`cpln logs` returns zero lines** because no container ever starts. The only diagnostic is `status.versions[].message`:

  ```bash theme={null}
  cpln workload get-deployments RELEASE_NAME-glitchtip --gvc GVC_NAME -o yaml
  ```

  It names the missing secret: `The secret <name> no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed.` The command is `get-deployments` — plain `cpln workload get` has no `versions` key at all. Creating the secret recovers the workloads on their own: **poll for 5.5 to 10.5 minutes rather than time-boxing it.** `cpln workload force-redeployment RELEASE_NAME-glitchtip --gvc GVC_NAME` cuts that to roughly 90 seconds; the worker needs the same treatment.
</Warning>

## Installation

To install, follow the instructions for your preferred method:

<CardGroup cols={2}>
  <Card title="UI" href="/template-catalog/install-manage/ui" icon="laptop">
    Browse, install, and manage templates visually
  </Card>

  <Card title="CLI" href="/template-catalog/install-manage/cli" icon="terminal">
    Manage templates from your terminal
  </Card>

  <Card title="Terraform" href="/template-catalog/install-manage/terraform" icon={<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill-rule="evenodd"><path d="M77.941 44.5v36.836L46.324 62.918V26.082zm0 0" fill="#5c4ee5"/><path d="M81.41 81.336l31.633-18.418V26.082L81.41 44.5zm0 0" fill="#4040b2"/><path d="M11.242 42.36L42.86 60.776V23.941L11.242 5.523zm0 0M77.941 85.375L46.324 66.957v36.82l31.617 18.418zm0 0" fill="#5c4ee5"/></g></svg>}>
    Declare templates in your Terraform configurations
  </Card>

  <Card
    title="Pulumi"
    href="/template-catalog/install-manage/pulumi"
    icon={<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" id="Pulumi-Icon--Streamline-Svg-Logos" height="24" width="24">
    <desc>
        Pulumi Icon Streamline Icon: https://streamlinehq.com
    </desc>
    <path fill="#f26e7e" d="M4.683025 13.3318c0.869125 -0.5018 0.870575 -2.1264 0.003225 -3.62865s-2.27504 -2.313275 -3.1441725 -1.811475C0.672945 8.3935 0.6715 10.0181 1.53885 11.52035c0.86735 1.502275 2.27505 2.313275 3.144175 1.81145Zm0.0052 3.2167c0.86735 1.502275 0.865925 3.126875 -0.003225 3.628675 -0.86915 0.5018 -2.2768275 -0.309225 -3.144175 -1.81145 -0.8673525 -1.50225 -0.8659075 -3.126875 0.003225 -3.628675 0.8691325 -0.5018 2.276825 0.309225 3.144175 1.81145Zm5.922875 3.4243c0.86735 1.50225 0.8659 3.126775 -0.003225 3.62875 -0.869125 0.501775 -2.27685 -0.309325 -3.1442 -1.81155 -0.867325 -1.50225 -0.865875 -3.12685 0.00325 -3.628675 0.869125 -0.5018 2.276825 0.309225 3.144175 1.811475Zm-0.001925 -6.845275c0.86735 1.50225 0.8659 3.12685 -0.003225 3.628675 -0.869125 0.5018 -2.276825 -0.309225 -3.144175 -1.811475 -0.86735 -1.50225 -0.8659 -3.12685 0.003225 -3.62865 0.869125 -0.501825 2.276825 0.3092 3.144175 1.81145Z" stroke-width="0.25"></path>
    <path fill="#8a3391" d="M22.45775 11.524125c0.86725 -1.502225 0.865925 -3.12685 -0.003225 -3.62865 -0.869125 -0.501825 -2.276825 0.3092 -3.144175 1.811475 -0.86735 1.50225 -0.8659 3.126825 0.003225 3.62865 0.869125 0.501825 2.276825 -0.3092 3.144175 -1.811475Zm0.000175 3.2151c0.869075 0.5018 0.870625 2.1264 0.003225 3.62865 -0.86735 1.50225 -2.27505 2.313275 -3.144175 1.81145 -0.869125 -0.5018 -0.870575 -2.126425 -0.003225 -3.62865 0.86735 -1.50225 2.27505 -2.313275 3.144175 -1.81145ZM16.536225 18.157875c0.86915 0.501825 0.8706 2.126425 0.00325 3.628675 -0.86735 1.502125 -2.275075 2.313225 -3.1442 1.81145 -0.869125 -0.50175 -0.870575 -2.126425 -0.003225 -3.62865 0.867375 -1.502275 2.27505 -2.3133 3.144175 -1.811475Zm-0.003325 -6.843775c0.869125 0.5018 0.870575 2.126425 0.003225 3.628675s-2.27505 2.313275 -3.1442 1.811475c-0.869125 -0.501825 -0.870575 -2.126425 -0.003225 -3.628675 0.86735 -1.502275 2.27505 -2.313275 3.1442 -1.811475Z" stroke-width="0.25"></path>
    <path fill="#f7bf2a" d="M15.138225 2.06721c0 1.003615 -1.40625 1.817215 -3.14095 1.817215 -1.7347 0 -3.14095 -0.8136 -3.14095 -1.817215C8.856325 1.06359 10.262575 0.25 11.997275 0.25c1.7347 0 3.14095 0.81359 3.14095 1.81721ZM9.2166 5.482375c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172s1.40625 -1.817225 3.14095 -1.817225c1.7347 0 3.14095 0.8136 3.14095 1.817225Zm8.71005 1.8172c1.7347 0 3.14095 -0.813575 3.14095 -1.8172s-1.40625 -1.817225 -3.14095 -1.817225c-1.7347 0 -3.14095 0.8136 -3.14095 1.817225s1.40625 1.8172 3.14095 1.8172Zm-2.788425 1.605625c0 1.003625 -1.40625 1.8172 -3.14095 1.8172 -1.7347 0 -3.14095 -0.813575 -3.14095 -1.8172 0 -1.0036 1.40625 -1.8172 3.14095 -1.8172 1.7347 0 3.14095 0.8136 3.14095 1.8172Z" stroke-width="0.25"></path>
    </svg>}
  >
    Declare templates in your Pulumi programs
  </Card>
</CardGroup>

## Choosing a Database Mode

Exactly one of the two database modes must be enabled — the chart enforces this at render and fails the install with a clear message otherwise.

|                      | `postgresHA` (default)                                  | `postgres`                             |
| -------------------- | ------------------------------------------------------- | -------------------------------------- |
| What runs            | 3× Patroni PostgreSQL, 3× etcd, HAProxy leader endpoint | One single-replica PostgreSQL workload |
| Database failover    | Automatic (Patroni leader election)                     | None                                   |
| First-boot readiness | About 6 minutes 20 seconds for the full stack           | Under a minute                         |
| Best for             | Production                                              | Development and lightweight installs   |

<Note>
  **The HA stack takes about six and a half minutes to converge, and it looks broken while it does.** The worker crash-loops throughout with `django.db.utils.OperationalError: pool error: ... Connection reset by peer` while Patroni elects a leader and the HAProxy endpoint waits for Patroni to answer. This is expected and self-correcting — do not treat it as a failed install, and do not start changing values in the middle of it. If it has not settled after roughly ten minutes, check the worker logs first, not the web logs.
</Note>

## Choosing a Queue Mode

By default the [redis](/template-catalog/templates/redis) template is deployed and GlitchTip runs its task queue, cache, and sessions through Redis Sentinel. Set `redis.enabled: false` to run those on PostgreSQL instead — a lighter shape with no Redis workloads, at lower throughput. Both modes are supported upstream.

## Configuration

The default `values.yaml` for this template:

```yaml theme={null}
image: glitchtip/glitchtip:6.2.2

replicas: 1 # web tier — stateless; set 2+ for high availability (state lives in PostgreSQL/Redis)

resources: # web workload
  minCpu: 250m
  minMemory: 512Mi
  maxCpu: 1000m
  maxMemory: 1Gi

# ─── Background Worker ────────────────────────────────────────────────────────
# Processes events, alerts, emails, and scheduled jobs; also runs database
# migrations and admin bootstrap at boot. Single replica (scheduler singleton).
worker:
  resources:
    minCpu: 250m
    minMemory: 512Mi
    maxCpu: 1000m
    maxMemory: 1Gi
  concurrency: 20 # async tasks processed in parallel (VTASKS_CONCURRENCY)

# ─── Authentication ───────────────────────────────────────────────────────────
auth:
  # REQUIRED PREREQUISITE SECRET — CREATE IT BEFORE YOU INSTALL. If it does not
  # exist the deployment WEDGES silently and looks like a platform fault.
  # A `dictionary` secret holding exactly three keys:
  #   secretKey      — Django session/token signing key; rotating it logs every
  #                    user out, so keep it for the life of the install
  #   adminEmail     — the initial superuser login, seeded on first boot; this
  #                    login form sits on the public endpoint
  #   adminPassword  — its password
  # See README Prerequisites for the exact command.
  secretName: my-glitchtip-auth

registration:
  enabled: false # open self-signup on the endpoint; admin-created users and invites work regardless

# ─── Email (optional) ─────────────────────────────────────────────────────────
email:
  secretName: "" # name of a pre-created opaque secret whose payload is an EMAIL_URL, e.g. smtp://user:pass@smtp.example.com:587 (create BEFORE install; empty = outbound email off)
  fromAddress: glitchtip@example.com # DEFAULT_FROM_EMAIL — used only when secretName is set

# ─── Access ───────────────────────────────────────────────────────────────────
domain: "" # full URL used in DSNs and email links (e.g. https://errors.example.com); empty = canonical *.cpln.app endpoint
publicAccess:
  enabled: true # UI + SDK event ingest (DSN) on the canonical *.cpln.app HTTPS endpoint

internalAccess: # internal firewall scope (in-GVC SDK callers)
  type: same-gvc # options: none, same-gvc, same-org, workload-list
  workloads: [] # used with workload-list
  # workloads:
  #   - //gvc/GVC_NAME/workload/WORKLOAD_NAME

# ─── Task Queue / Cache: Redis (default) ──────────────────────────────────────
# Deploys the redis template (master-replica + Sentinel); GlitchTip connects
# through Sentinel. Disable to run tasks/cache/sessions on PostgreSQL instead
# (lighter dev shape, lower throughput).
redis:
  enabled: true
  redis:
    replicas: 2
    auth:
      password:
        enabled: true
        value: change-me-glitchtip-redis # change before installing (any characters OK — the boot script percent-encodes it)
    firewall:
      internal_inboundAllowType: same-gvc
    persistence:
      enabled: true
  sentinel:
    replicas: 3
    firewall:
      internal_inboundAllowType: same-gvc
    persistence:
      enabled: true

# ─── Database: Highly Available PostgreSQL (default) ──────────────────────────
# Deploys the postgres-highly-available template: 3 Patroni replicas, 3 etcd
# replicas, and an HAProxy leader-routing endpoint GlitchTip connects to.
postgresHA:
  enabled: true
  config:
    # Name of the dictionary secret this chart creates and the bundled
    # postgres-highly-available reads. One secret feeds whichever store
    # is enabled, built from postgres.credentials.* above.
    credentialsSecretName: my-glitchtip-db-credentials
  replicas: 3
  volumeset:
    capacity: 10 # initial capacity in GiB per replica (minimum is 10)

  backup: # optional database backups — see README storage setup
    enabled: false
    mode: logical # logical or wal-g
    resources:
      cpu: 100m
      memory: 128Mi
    logical:
      image: ghcr.io/controlplane-com/backup-images/postgres-backup:17.1.0
      schedule: "0 2 * * *"
    walg:
      intervalSeconds: 21600
    provider: aws # options: aws, gcp, minio
    aws:
      bucket: my-glitchtip-backup-bucket
      region: us-east-1
      cloudAccountName: my-s3-cloud-account
      policyName: my-glitchtip-backup-policy
      prefix: postgres/backups
    gcp:
      bucket: my-glitchtip-backup-bucket
      cloudAccountName: my-gcs-cloud-account
      prefix: postgres/backups
    minio:
      endpoint: http://my-minio-workload:9000
      bucket: my-glitchtip-backup-bucket
      accessKey: my-minio-username
      secretKey: my-minio-password
      prefix: postgres/backups

# ─── Database: Single-instance PostgreSQL (dev/lightweight) ───────────────────
# Enable this and disable postgresHA for a lighter non-HA deployment.
postgres:
  enabled: false
  credentials: # the chart writes these into the secret named below — nothing for you to create
    username: glitchtip
    password: change-me-glitchtip-db # change before installing
    database: glitchtip
  config:
    credentialsSecretName: my-glitchtip-db-credentials # secret names are org-wide — give each release its own
  volumeset:
    capacity: 10 # initial capacity in GiB (minimum is 10)

  backup: # optional database backups (Postgres 17+) — see README storage setup
    enabled: false
    image: ghcr.io/controlplane-com/backup-images/postgres-backup:18.1.0
    schedule: "0 2 * * *"
    resources:
      cpu: 100m
      memory: 128Mi
    provider: aws # options: aws, gcp, minio
    aws:
      bucket: my-glitchtip-backup-bucket
      region: us-east-1
      cloudAccountName: my-s3-cloud-account
      policyName: my-glitchtip-backup-policy
      prefix: postgres/backups
    gcp:
      bucket: my-glitchtip-backup-bucket
      cloudAccountName: my-gcs-cloud-account
      prefix: postgres/backups
    minio:
      endpoint: http://my-minio-workload:9000
      bucket: my-glitchtip-backup-bucket
      credentialsSecretName: my-glitchtip-minio-credentials # dictionary secret holding accessKey + secretKey
      prefix: postgres/backups
```

### GlitchTip

* `image` — The GlitchTip container image, used by both the web and worker workloads.
* `replicas` — Web-tier replica count. The web tier is stateless (all state is in PostgreSQL and Redis), so scaling to `2` or more gives high availability. The default `1` is the proven single-replica shape.
* `resources` — Reservation and limit for the web container (`minCpu` / `maxCpu` / `minMemory` / `maxMemory`).
* `worker.resources` — The same four keys for the worker container.
* `worker.concurrency` — Number of async tasks the worker processes in parallel (`VTASKS_CONCURRENCY`).
* `auth.secretName` — Name of the prerequisite dictionary secret holding `secretKey`, `adminEmail` and `adminPassword`. It must exist before you install.
* `registration.enabled` — Open self-signup on the endpoint. Default `false` (closed) — admin-created users and invites still work either way. See [Onboarding Users](#onboarding-users).

### Email

* `email.secretName` — Name of your pre-created opaque secret whose payload is an `EMAIL_URL` (see [Prerequisites](#prerequisites)). Empty (default) turns outbound email off. Member invites, alert notifications, and password-reset mail all require it.
* `email.fromAddress` — The `From` address on outbound mail; applied only when `email.secretName` is set.

### Access

* `publicAccess.enabled` — Serve the UI and SDK event ingest (the DSN endpoint) on the canonical `*.cpln.app` HTTPS endpoint.
* `domain` — Full URL (for example `https://errors.example.com`) embedded in DSNs and email links. Empty (default) uses the canonical endpoint, derived automatically at boot.
* `internalAccess.type` — Internal firewall scope of the web workload:

| Type            | Description                                                            |
| --------------- | ---------------------------------------------------------------------- |
| `none`          | No internal access.                                                    |
| `same-gvc`      | Allow access from all workloads in the same GVC (default).             |
| `same-org`      | Allow access from all workloads in the same organization.              |
| `workload-list` | Allow access only from workloads listed in `internalAccess.workloads`. |

<Note>
  **Public access is on by default, deliberately.** Browser SDKs and applications outside the GVC have to reach the ingest endpoint or they cannot report anything, and both the legacy store API and the modern envelope API are proven to accept events from outside the GVC against this template. Self-signup is closed by default, and after 1.1.0 there is no published default credential to protect against.

  Set `publicAccess.enabled: false` for in-GVC reporters only, and reach the UI with `cpln port-forward RELEASE_NAME-glitchtip 8000:8000 --gvc GVC_NAME`. A firewall change takes roughly **30 seconds to 5 minutes** to propagate, so re-test rather than trusting the first response.
</Note>

### Task Queue and Cache

* `redis.enabled` — Deploy the Redis subchart in Sentinel mode for the task queue, cache, and sessions (default). Set to `false` to carry those on PostgreSQL instead — see [Choosing a Queue Mode](#choosing-a-queue-mode).
* `redis.redis.replicas` — Redis master-replica count.
* `redis.redis.auth.password.value` — The Redis password. Required when Redis is enabled (the chart enforces it). **Change it before installing** — any characters are fine, the boot script percent-encodes it into the connection URL.
* `redis.sentinel.replicas` — Number of Sentinel instances. Sentinel authentication must stay disabled — GlitchTip cannot send a Sentinel password; the same-GVC firewall is the boundary there.
* `redis.redis.persistence.enabled` / `redis.sentinel.persistence.enabled` — Persistent storage for Redis and Sentinel.
* `redis.redis.firewall.internal_inboundAllowType` / `redis.sentinel.firewall.internal_inboundAllowType` — Internal firewall scope of the Redis and Sentinel workloads.

### Database

Enable exactly one of `postgresHA` (production, default) or `postgres` (dev/lightweight) — see [Choosing a Database Mode](#choosing-a-database-mode). GlitchTip is wired to the active database automatically: the HAProxy leader endpoint in HA mode, or the single instance directly in dev mode.

Both database passwords are bundled plumbing — the database serves GlitchTip only and is unreachable from outside the GVC — but they are used as-is, so **change `postgres.credentials.password` or `postgres.credentials.password` before installing**. The shipped `change-me-glitchtip-db` is a published placeholder.

If you run more than one release of this template in the same organization, give each its own `postgres.config.credentialsSecretName`. Secret names are organization-wide, so a second release left on the default name is **refused at install** and creates nothing — the first release is unaffected.

<Warning>
  **Template version `1.0.0` did not compact the etcd cluster inside the bundled highly available database**, so etcd's backend grows with time alone and goes read-only once it reaches its 2 GiB quota — after roughly 110 days — taking PostgreSQL failover with it. Only installs running the HA database are affected (`postgresHA.enabled`, the default here); see [etcd History Compaction](/template-catalog/templates/postgres-highly-available#etcd-history-compaction) for the mechanism and the symptoms. Version `1.0.1` and later turn compaction on: that stops further growth but cannot shrink a backend that has already grown, and a cluster that has already raised a `NOSPACE` alarm needs operator recovery rather than an upgrade.
</Warning>

## Onboarding Users

Registration is closed by default (`registration.enabled: false`) — an override of GlitchTip's upstream open-signup default. With registration closed, **invites only work for accounts that already exist**: create teammate accounts first through the Django admin at `https://<canonical>.cpln.app/admin/` (log in with the superuser account), then invite them to your organization. Invite, alert, and password-reset emails require `email.secretName` to be set. To allow open self-signup instead, set `registration.enabled: true`.

## Connecting

| What                               | Value                                                                                                                        |
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| UI (public)                        | `https://<canonical>.cpln.app` — `status.canonicalEndpoint` of `RELEASE_NAME-glitchtip`                                      |
| Local access (public access off)   | `cpln port-forward RELEASE_NAME-glitchtip 8000:8000 --gvc GVC_NAME`, then `http://localhost:8000`                            |
| SDK DSN                            | Copy from the UI: project → Settings → DSN (it embeds the public endpoint)                                                   |
| Internal (same GVC)                | `http://RELEASE_NAME-glitchtip.GVC_NAME.cpln.local:8000`                                                                     |
| Login                              | The `adminEmail` / `adminPassword` keys of your auth secret                                                                  |
| Django admin (user management)     | `https://<canonical>.cpln.app/admin/`                                                                                        |
| PostgreSQL (internal, HA mode)     | `RELEASE_NAME-postgres-ha-proxy.GVC_NAME.cpln.local:5432`, credentials in the `RELEASE_NAME-postgres-config` secret          |
| PostgreSQL (internal, single mode) | `RELEASE_NAME-postgres.GVC_NAME.cpln.local:5432`, credentials in the secret named by `postgres.config.credentialsSecretName` |

### Reporting Errors

Point any Sentry SDK at your project's DSN. The DSN is issued in the UI under **project → Settings → DSN** and embeds the public endpoint, so no extra configuration is needed. Existing `@sentry/*` SDK setups keep working — only the DSN changes. SDKs running inside the same GVC can send events to the internal endpoint per `internalAccess`.

## Backing Up

Database backups are optional and disabled by default. They cover the PostgreSQL database — the issues, events, and users that make up your GlitchTip instance. Enable them with `postgresHA.backup.enabled` or `postgres.backup.enabled` (matching your database mode), and complete the storage setup for your provider **before** installing. The values below are shown under `backup.*` — set them within the enabled database block.

<Tabs>
  <Tab title="AWS S3">
    <Steps>
      <Step title="Create a bucket">
        Create an S3 bucket. Set `backup.aws.bucket` and `backup.aws.region` to match.
      </Step>

      <Step title="Set up a Cloud Account">
        If you do not have one, [create a Cloud Account](https://docs.controlplane.com/guides/create-cloud-account) for your AWS account. Set `backup.aws.cloudAccountName` to its name.
      </Step>

      <Step title="Create a bucket-scoped IAM policy">
        Create an AWS IAM policy with the JSON below (replace `YOUR_BUCKET`), then set `backup.aws.policyName` to the policy's name:

        ```json theme={null}
        {
          "Version": "2012-10-17",
          "Statement": [{
            "Effect": "Allow",
            "Action": [
              "s3:ListBucket",
              "s3:GetBucketLocation",
              "s3:GetObject",
              "s3:GetObjectVersion",
              "s3:PutObject",
              "s3:DeleteObject",
              "s3:DeleteObjectVersion",
              "s3:AbortMultipartUpload"
            ],
            "Resource": [
              "arn:aws:s3:::YOUR_BUCKET",
              "arn:aws:s3:::YOUR_BUCKET/*"
            ]
          }]
        }
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="Google Cloud Storage">
    <Steps>
      <Step title="Create a bucket">
        Create a GCS bucket. Set `backup.gcp.bucket` to its name.
      </Step>

      <Step title="Set up a Cloud Account">
        If you do not have one, [create a Cloud Account](https://docs.controlplane.com/guides/create-cloud-account) for your GCP project. Set `backup.gcp.cloudAccountName` to its name — access is keyless (no stored credentials).
      </Step>
    </Steps>

    <Warning>
      Grant the `Storage Admin` role (or `roles/storage.objectAdmin` scoped to the bucket) to the GCP service account created for the Cloud Account.
    </Warning>
  </Tab>

  <Tab title="S3-compatible (MinIO, R2, Wasabi)">
    <Steps>
      <Step title="Create a bucket">
        Create your bucket on the server. Set `backup.minio.bucket` to its name.
      </Step>

      <Step title="Set the endpoint">
        Set `backup.minio.endpoint` to the S3 API address including port. For the `minio` marketplace template deployed in the same GVC, this is `http://WORKLOAD_NAME:9000`.
      </Step>

      <Step title="Set credentials">
        The two backing stores take these differently. In HA mode (`postgresHA`), set `backup.minio.accessKey` and `backup.minio.secretKey` to credentials with access to the bucket. In single-instance mode (`postgres`), those two values were removed: create a [dictionary secret](/guides/create-secret/dictionary) holding the keys `accessKey` and `secretKey`, and set `backup.minio.credentialsSecretName` to its name — see [MinIO backup prerequisites](/template-catalog/templates/postgres#minio) for the exact command.
      </Step>
    </Steps>
  </Tab>
</Tabs>

In HA mode, `backup.mode` selects `logical` (scheduled `pg_dump` via a cron workload) or `wal-g` (continuous WAL archiving). The single-instance mode takes scheduled logical dumps.

## Important Notes

* The auth secret must exist **before** you install. Without it both workloads wedge with no log output at all; see [Prerequisites](#prerequisites) for the one diagnostic that names it.
* **The HA database takes about six and a half minutes to converge on a fresh install**, with the worker crash-looping on `Connection reset by peer` throughout. It is self-correcting and indistinguishable from a failed install — wait it out.
* **Rotating `secretKey` logs every user out** and invalidates password-reset links in flight. Nothing is corrupted, but do it deliberately.
* **Change the database password and the Redis password before installing** — both are bundled plumbing used as-is.
* **Do not scale the worker** — it is a fixed singleton (scheduler plus boot-time migrations). Web `replicas` is the scaling knob; a worker outage pauses processing but ingest keeps accepting events and catches up when the worker returns.
* **First boot: the web tier stays not-ready until the worker finishes migrations.** If it seems stuck, check the worker logs first, not the web logs.
* **With registration closed (default), invites only work for accounts that already exist** — create teammate accounts first at `/admin/`, then invite them. Invite and alert emails require `email.secretName`. See [Onboarding Users](#onboarding-users).
* Editing the auth secret after first boot does not change the existing superuser account — it is seeded once. Change the password in the UI.
* **The first Helm upgrade after an install re-applies resources** even with identical values, which can briefly bounce the bundled datastores. Later upgrades are clean.
* **DSNs embed the endpoint URL** — if you add a custom domain later, set `domain`, run a Helm upgrade, and update the DSNs in your apps.
* **Source-map / artifact uploads are ephemeral** (local disk) — lost on restart and not shared across web replicas. Error ingest itself is unaffected; events go to PostgreSQL.
* **Uninstall deletes the database volume sets** — all issues, events, and users. Enable backups if the data matters.

## External References

<CardGroup cols={2}>
  <Card title="GlitchTip Documentation" icon="book" href="https://glitchtip.com/documentation">
    Official GlitchTip documentation
  </Card>

  <Card title="Installation Reference" icon="gear" href="https://glitchtip.com/documentation/install">
    Installation and configuration reference
  </Card>

  <Card title="Sentry SDKs" icon="code" href="https://docs.sentry.io/platforms/">
    Client setup for the Sentry SDKs GlitchTip is compatible with
  </Card>

  <Card title="GlitchTip 6 Release Notes" icon="rocket" href="https://glitchtip.com/blog/2026-02-03-glitchtip-6-released/">
    What changed in the GlitchTip 6 release line
  </Card>

  <Card title="GlitchTip Backend Source" icon="gitlab" href="https://gitlab.com/glitchtip/glitchtip-backend">
    Upstream GlitchTip backend source
  </Card>

  <Card title="GlitchTip Template" icon="github" href="https://github.com/controlplane-com/templates/tree/main/glitchtip">
    View the source files, default values, and chart definition
  </Card>
</CardGroup>
