Self-Hosting

Self-Hosting

Run Tindra on your own infrastructure. One binary, one Postgres database.

Requirements

  • Docker 20.10+
  • 512 MB RAM minimum, 1 GB recommended

Install script

The fastest way to get up and running. Run this on the server you want to host Tindra on:

bash -c "$(curl -sSL https://install.tindra.sh)"

The script asks a few questions, then writes a docker-compose.yml, pulls the images, and optionally starts the stack:

Tindra  self-hosted install

→  Checking prerequisites
   ✓  docker found
   ✓  docker compose found

→  Install directory
   Path [/opt/tindra]:

→  Public URL
   URL (e.g. https://tindra.example.com): https://tindra.yourcompany.com

→  Host port
   Port [8080]:

→  First account
   Email: you@yourcompany.com
   Name: Your Name
   Password: (hidden)
   Confirm: (hidden)

→  Generating database password
   ✓  48-character random password generated

→  Writing docker-compose.yml
   ✓  Written to /opt/tindra/docker-compose.yml

→  Pulling images
→  Starting
→  Creating your account
   ✓  Account created: you@yourcompany.com

   Tindra is running.
   Open https://tindra.yourcompany.com and log in.

The database password is auto-generated and written into docker-compose.yml. There is no sign-up page. The installer creates your admin account directly via the CLI.

Reverse proxy: The installer binds Tindra to port 8080 by default. It does not configure a reverse proxy or TLS for you. See Reverse proxy below.

Manual install

If you prefer to set things up yourself, or need to integrate with existing infrastructure:

# docker-compose.yml
services:
  postgres:
    image: postgres:18-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: tindra
      POSTGRES_USER: tindra
      POSTGRES_PASSWORD: 26a676d924141700f615f0b381c84f5e
    volumes:
      - postgres_data:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U tindra -d tindra"]
      interval: 5s
      timeout: 5s
      retries: 5

  tindra:
    image: ghcr.io/blendbyte/tindra:latest
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      DATABASE_URL: "postgres://tindra:26a676d924141700f615f0b381c84f5e@postgres:5432/tindra?sslmode=disable"
      PUBLIC_URL: https://your-hostname.example.com
      BIND_ADDR: ":8080"
      DATA_DIR: /data
      COOKIE_SECURE: "true"
    volumes:
      - tindra_data:/data
    depends_on:
      postgres:
        condition: service_healthy

volumes:
  postgres_data:
  tindra_data:
docker compose up -d

Migrations run automatically on startup. Once the container is healthy, create your first account:

docker compose exec tindra /tindra users create \
  --email you@example.com \
  --name "Your Name" \
  --password yourpassword

There is no sign-up page. The first account created automatically receives all admin permissions.

Environment variables

Required

Variable Description
DATABASE_URL Postgres connection string
PUBLIC_URL The public URL of your Tindra instance (used in emails and DSN generation)

Optional

Variable Default Description
BIND_ADDR 0.0.0.0:8080 Listen address
DATA_DIR /data Directory for attachments and other file storage
RETENTION_DAYS 90 How long to keep events
COOKIE_SECURE false Set to true when serving over HTTPS
LOG_FORMAT text Set to json for structured logging
DISABLE_VERSION_CHECK false Set to true to disable the periodic check for new Tindra versions. When enabled, the server contacts https://www.tindra.sh/version-update-check every 6 hours and shows a notice in Settings > Overview. Useful for air-gapped environments.

Email

Set EMAIL_PROVIDER to one of: smtp, postmark, brevo, ahasend, lettermint, cloudflare.

Each provider requires its own set of additional variables. See Authentication for OAuth-related email settings and Configuration for the full variable reference.

Reverse proxy

Run Tindra behind nginx or Caddy for TLS termination. Pass the X-Forwarded-Proto and X-Forwarded-For headers so Tindra sees real client IPs.

If you prefer a Unix socket over a TCP port, set BIND_ADDR=unix:/run/tindra/tindra.sock and point your proxy at the socket path instead.

Caddy

your-hostname.example.com {
    reverse_proxy localhost:8080
}

Caddy handles TLS automatically.

nginx

server {
    listen 443 ssl;
    server_name your-hostname.example.com;

    location / {
        proxy_pass http://localhost:8080;
        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;
    }
}

Updating

docker compose pull
docker compose up -d

Migrations run on startup. Downtime is typically under a second.

Next steps