Skip to main content
When you choose to self-host, the responsibility for updates, maintenance, and merging future enhancements rests entirely with you.
We highly recommend the Cloud version, unless you have hard requirements to manage your own infrastructure.

Minimum System Requirements

ResourceMinimumRecommended
CPU2 vCPU4 vCPU
RAM2 GB4 GB
Disk20 GB40 GB
Software requirements:
  • Docker 24+ and Docker Compose v2+
  • A domain with DNS A record pointing to your server
  • Ports 80 and 443 open (for web traffic and TLS)

Quick Start

The fastest way to get Sweetr running is with our deploy script. It will guide you through the setup, including creating a GitHub App with the correct permissions.
curl -fsSL https://raw.githubusercontent.com/sweetr-dev/sweetr.dev/main/bin/deploy | bash
The script will:
  1. Check that Docker and Docker Compose are installed
  2. Ask for your domain and GitHub organization handle
  3. Generate a pre-filled URL to create a GitHub App with all required permissions
  4. Collect your GitHub App credentials
  5. Optionally configure Slack integration
  6. Generate docker-compose.yml and .env files
  7. Start the stack
To install a specific version, set the SWEETR_TAG environment variable:
curl -fsSL https://raw.githubusercontent.com/sweetr-dev/sweetr.dev/1.2.0/bin/deploy | SWEETR_TAG=1.2.0 bash

Manual Setup

If you prefer to set things up manually, follow the steps below.

Prerequisites

1

Create a GitHub Application

You’ll need to create a GitHub application.Use our pre-filled link to speed this up — replace YOUR_DOMAIN with your actual domain after opening it.After opening the link, you must also:
  • Uncheck “Expire user authorization tokens”
  • Generate and set a Webhook Secret
  • Submit the form, then generate a Client Secret
  • Generate a Private Key (this downloads a .pem file)
Create the app under your organization account (not your personal account) so it can be installed on the organization directly. Use https://github.com/organizations/YOUR_ORG/settings/apps/new as the base URL.
2

Create a Slack App (Optional)

Create a Slack app at https://api.slack.com/apps/new:
  • Create a Redirect URL: https://your-domain.com/settings/integrations/slack
  • Add the following Bot Token Scopes:
    • app_mentions:read
    • channels:join
    • channels:read
    • chat:write
    • groups:read
    • im:read
    • im:write
    • mpim:read
    • reactions:read
    • users.profile:read
    • users:read
    • users:read.email
3

Create a Caddyfile

Create a Caddyfile for the reverse proxy. Caddy automatically provisions and renews HTTPS certificates via Let’s Encrypt.
your-domain.com {
    @api path /api /api/*
    handle @api {
        uri strip_prefix /api
        reverse_proxy api:8000
    }
    handle {
        reverse_proxy web:80
    }
}
A public domain is required — GitHub cannot deliver webhooks to localhost. For local development, use a tunnel like Cloudflare Tunnel or ngrok and use the tunnel URL as your domain.
4

Create docker-compose.yml

Create a docker-compose.yml file:
services:
  caddy:
    image: caddy:2
    container_name: sweetr-caddy
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - sweetr-caddy-data:/data
      - sweetr-caddy-config:/config
    restart: unless-stopped
    networks:
      - sweetr
    depends_on:
      - api
      - web

  api:
    image: sweetr/api:latest
    container_name: sweetr-api
    env_file: .env
    environment:
      - NODE_ENV=production
      - APP_ENV=production
      - APP_MODE=self-hosted
      - USE_SELF_SIGNED_SSL=false
    restart: unless-stopped
    networks:
      - sweetr
    depends_on:
      postgres:
        condition: service_healthy
      dragonfly:
        condition: service_healthy

  web:
    image: sweetr/web:latest
    container_name: sweetr-web
    environment:
      - API_ENDPOINT=${API_ENDPOINT}
      - AUTH_COOKIE_DOMAIN=${AUTH_COOKIE_DOMAIN}
      - GITHUB_APP=${GITHUB_APP}
      - SENTRY_DSN=${SENTRY_DSN:-}
      - APP_ENV=${APP_ENV:-production}
    restart: unless-stopped
    networks:
      - sweetr
    depends_on:
      - api

  postgres:
    image: postgres:16
    container_name: sweetr-postgres
    env_file: .env
    volumes:
      - sweetr-db:/var/lib/postgresql/data
    restart: unless-stopped
    networks:
      - sweetr
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

  dragonfly:
    image: docker.dragonflydb.io/dragonflydb/dragonfly
    container_name: sweetr-dragonfly
    command: ["--cluster_mode=emulated", "--lock_on_hashtags", "--proactor_threads=2"]
    ulimits:
      memlock: -1
    volumes:
      - sweetr-dragonfly:/data
    restart: unless-stopped
    networks:
      - sweetr
    healthcheck:
      test: ["CMD-SHELL", "redis-cli ping"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  sweetr-db:
  sweetr-dragonfly:
  sweetr-caddy-data:
  sweetr-caddy-config:

networks:
  sweetr:
    driver: bridge
5

Configure environment variables

Create a .env file. See the Environment Variables Reference below for all available options.
# Database
POSTGRES_USER=postgres
POSTGRES_PASSWORD=<generate-a-secure-password>
POSTGRES_DB=sweetr
DATABASE_URL=postgres://postgres:<POSTGRES_PASSWORD>@postgres:5432/sweetr

# API
PORT=8000
FRONTEND_URL=https://your-domain.com
JWT_SECRET=<generate-a-secure-random-string>
REDIS_CONNECTION_STRING=redis://dragonfly:6379

# GitHub App
GITHUB_APP_ID=<your-app-id>
GITHUB_CLIENT_ID=<your-client-id>
GITHUB_CLIENT_SECRET=<your-client-secret>
GITHUB_APP_HANDLE=<your-app-slug>
# Private key: replace newlines with \n and wrap in double quotes
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIE...\n-----END RSA PRIVATE KEY-----\n"
GITHUB_WEBHOOK_SECRET=<your-webhook-secret>

# Web
API_ENDPOINT=https://your-domain.com/api
AUTH_COOKIE_DOMAIN=your-domain.com
GITHUB_APP=<your-app-slug>

# Slack (optional)
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
SLACK_WEBHOOK_SECRET=
6

Start the stack

docker compose up -d
The API container will automatically run database migrations on startup.

Environment Variables Reference

API (sweetr/api)

VariableRequiredDefaultDescription
DATABASE_URLYesPostgreSQL connection string
REDIS_CONNECTION_STRINGYesRedis/Dragonfly connection string
JWT_SECRETYesSecret for signing JWT tokens
FRONTEND_URLYesURL of the web application
PORTNo3000API server port
GITHUB_APP_IDYesGitHub App ID
GITHUB_CLIENT_IDYesGitHub OAuth Client ID
GITHUB_CLIENT_SECRETYesGitHub OAuth Client Secret
GITHUB_APP_HANDLEYesGitHub App slug (from the app URL)
GITHUB_APP_PRIVATE_KEYYesGitHub App private key (PEM format)
GITHUB_WEBHOOK_SECRETYesSecret for verifying GitHub webhooks
GITHUB_OAUTH_REDIRECT_PATHNo/github/callbackOAuth redirect path
APP_MODENoself-hostedself-hosted or saas
NODE_ENVNoproductiondevelopment or production
APP_ENVNoproductiondevelopment, staging, or production
LOG_LEVELNoinfodebug, info, warn, or error
USE_SELF_SIGNED_SSLNofalseUse self-signed SSL certificates
BULLMQ_ENABLEDNotrueEnable background job processing
SLACK_CLIENT_IDNo""Slack Client ID
SLACK_CLIENT_SECRETNo""Slack Client Secret
SLACK_WEBHOOK_SECRETNo""Slack webhook verification secret
STRIPE_API_KEYNo""Stripe API key (cloud billing only)
STRIPE_WEBHOOK_SECRETNo""Stripe webhook secret (cloud billing only)
SENTRY_DSNNo""Sentry DSN for error tracking
LOG_DRAINNoconsoleconsole or logtail
LOGTAIL_TOKENNo""LogTail source token
EMAIL_ENABLEDNofalseEnable transactional emails
RESEND_API_KEYNo""Resend API key for emails
BULLBOARD_PATHNo""URL path to access BullBoard dashboard
BULLBOARD_USERNAMENo""BullBoard login username
BULLBOARD_PASSWORDNo""BullBoard login password
CRON_GITHUB_RETRY_FAILED_WEBHOOKS_EVERY_MINUTESNo30Retry interval for failed webhooks

Web (sweetr/web)

VariableRequiredDefaultDescription
API_ENDPOINTYesFull URL to the API (e.g., https://sweetr.example.com/api)
AUTH_COOKIE_DOMAINYesDomain for auth cookies (e.g., example.com)
GITHUB_APPYesGitHub App slug (same as GITHUB_APP_HANDLE)
SENTRY_DSNNo""Sentry DSN for frontend error tracking
APP_ENVNoproductionEnvironment name for Sentry

Upgrading

To upgrade to a new version:
cd sweetr
docker compose pull
docker compose up -d
Database migrations run automatically on API container startup. To pin a specific version instead of latest, edit the image tags in docker-compose.yml:
services:
  api:
    image: sweetr/api:1.2.0
  web:
    image: sweetr/web:1.2.0

Monitoring (Optional)

Sentry

Add to your API .env:
SENTRY_DSN=https://your-sentry-dsn
For frontend error tracking, also add to your .env:
SENTRY_DSN=https://your-frontend-sentry-dsn
The web container reads this as the SENTRY_DSN environment variable.

LogTail

LOG_DRAIN=logtail
LOGTAIL_TOKEN=your-logtail-token

BullBoard (Job Queue Dashboard)

To enable the BullBoard dashboard for monitoring background jobs:
BULLBOARD_PATH=/bullboard
BULLBOARD_USERNAME=admin
BULLBOARD_PASSWORD=<secure-password>
Access it at https://your-domain.com/api/bullboard.

Troubleshooting

API fails to start

Check the container logs:
docker compose logs api
Common causes:
  • Database connection failed: Ensure Postgres is healthy with docker compose ps. The API waits for migrations to run on startup.
  • Missing environment variables: The API will log which required variables are missing.
  • Redis connection failed: Ensure Dragonfly is healthy. Check that REDIS_CONNECTION_STRING uses the Docker service name (e.g., redis://dragonfly:6379).

Web app shows blank page

Check the browser console for errors. Common causes:
  • API_ENDPOINT is wrong: Make sure it’s the full URL reachable from the browser (not an internal Docker hostname).
  • CORS errors: Ensure FRONTEND_URL on the API matches the URL you’re accessing the web app from.

Database migration errors

If migrations fail on startup, check the API logs. You may need to connect to Postgres directly:
docker compose exec postgres psql -U postgres -d sweetr

Port conflicts

If port 80 or 443 is already in use, either stop the conflicting service or change the Caddy port mappings in docker-compose.yml:
caddy:
  ports:
    - "8080:8080" # Change host port
Then update your Caddyfile to match (e.g., :8080 {) and adjust FRONTEND_URL and API_ENDPOINT in .env accordingly.