Deploying Qarote
Qarote ships as a self-contained application. Pick the deployment method that fits your environment — all three give you the same dashboard.
| Method | Best for | | --------------------------------- | ----------------------------------------------------------------------- | | Binary | Minimal footprint, existing PostgreSQL, VMs or bare metal | | Docker Compose | Containerised setup, everything bundled including Postgres | | Dokku | Git-push deploys, automatic HTTPS, Heroku-style PaaS on your own server |
All deployments start with the free tier (core monitoring). Premium features — workspaces, alerting, integrations — unlock when you activate a license key in Settings → License. No restart needed.
Prerequisites
- Binary: PostgreSQL 17+ with the TimescaleDB extension and TimescaleDB Toolkit already running (no Docker or Node.js needed)
- Docker Compose: Docker and Docker Compose installed (a TimescaleDB + Toolkit PostgreSQL is bundled)
- Dokku: Dokku installed on your server (its Postgres must ship TimescaleDB + Toolkit — see below)
- Minimum 2 GB RAM, 10 GB disk space
⚠️ PostgreSQL must ship TimescaleDB and the TimescaleDB Toolkit. Qarote stores time-series data in TimescaleDB hypertables and derives throughput rates at read time with the Toolkit's
counter_agg/rate(). Both are server-side extensions that must be present in your Postgres image/package — Qarote activates them (CREATE EXTENSION) but cannot install them, so a missing extension fails the migration on first boot. Usetimescale/timescaledb-ha(the Docker Compose setup bundles it) or install thetimescaledb-2-postgresql-17andtimescaledb-toolkit-postgresql-17packages.timescaledb-toolkithas no Homebrew formula — on macOS use a Docker/Linux Postgres.
Binary
The binary embeds both the API and the frontend. Drop it on any Linux or macOS host that already has PostgreSQL — nothing else required.
1. Set up PostgreSQL
If PostgreSQL isn't already running:
# macOS
brew install postgresql@17
# Ubuntu / Debian / WSL2
sudo apt install postgresql
Create a dedicated database user:
sudo -u postgres psql -c "CREATE USER qarote WITH PASSWORD 'your-secure-password';"
sudo -u postgres psql -c "CREATE DATABASE qarote OWNER qarote;"
# Recommended: set idle connection timeouts
sudo -u postgres psql -c "ALTER SYSTEM SET idle_session_timeout = '30min';"
sudo -u postgres psql -c "ALTER SYSTEM SET idle_in_transaction_session_timeout = '5min';"
sudo -u postgres psql -c "SELECT pg_reload_conf();"
Your connection URL will be: postgresql://qarote:your-secure-password@localhost:5432/qarote
2. Download the binary
# Auto-detects your OS and architecture
PLATFORM="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/x64/' | sed 's/aarch64/arm64/')"
curl -L "https://github.com/getqarote/Qarote/releases/latest/download/qarote-${PLATFORM}.tar.gz" | tar xz --strip-components=1
Or download a specific build from GitHub Releases:
| Platform | File |
| ------------------- | ---------------------------- |
| Linux x64 | qarote-linux-x64.tar.gz |
| Linux ARM64 | qarote-linux-arm64.tar.gz |
| macOS Apple Silicon | qarote-darwin-arm64.tar.gz |
| macOS Intel | qarote-darwin-x64.tar.gz |
Windows
Run the binary inside WSL2. Native Windows is not supported.
3. Run the setup wizard
./qarote setup
The wizard will:
- Ask for your PostgreSQL URL and verify the connection
- Create an admin account (written directly to the database — no sign-up flow needed)
- Let you disable public registration (recommended for private deployments)
- Generate
JWT_SECRETandENCRYPTION_KEY - Write a
.envfile in the current directory
Tip
Say Yes to creating an admin account and No to public registration. You can invite team members later from inside the app.
4. Start Qarote
./qarote
The server starts on http://localhost:3000. Database migrations run automatically on first boot. The migrations/ directory must stay alongside the binary.
To run the background workers, start each in a separate terminal or as a systemd service:
./qarote worker # alert evaluation (required for alerts)
./qarote notification-worker # transactional emails (required if email is enabled)
With a Developer or Enterprise license, three additional workers unlock premium features:
./qarote digest-worker # weekly digest emails
./qarote metrics-worker # queue metrics collection (run exactly 1 — multiple replicas write duplicate snapshot rows)
./qarote firehose-worker # message tracing (run exactly 1 — multiple replicas create duplicate consumers)
Running as a system service (Linux)
To keep Qarote running across reboots, create a systemd unit for each process. This assumes the binary lives at /opt/qarote/qarote and the .env at /opt/qarote/.env.
/etc/systemd/system/qarote.service
[Unit]
Description=Qarote RabbitMQ Dashboard
After=network.target postgresql.service
[Service]
Type=simple
User=qarote
WorkingDirectory=/opt/qarote
EnvironmentFile=/opt/qarote/.env
ExecStart=/opt/qarote/qarote
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Create one unit per worker with the same template, changing Description and ExecStart:
| Unit file | ExecStart |
| ------------------------------------ | ---------------------------------------- |
| qarote-alert-worker.service | /opt/qarote/qarote worker |
| qarote-notification-worker.service | /opt/qarote/qarote notification-worker |
Then reload and enable:
sudo systemctl daemon-reload
sudo systemctl enable --now qarote qarote-alert-worker qarote-notification-worker
Manual setup (without the wizard)
If you prefer flags over the interactive wizard:
# Requires openssl to generate secrets (installed by default on macOS and most Linux distros)
./qarote \
--database-url postgresql://qarote:password@localhost/qarote \
--jwt-secret $(openssl rand -hex 64) \
--encryption-key $(openssl rand -hex 64)
CLI reference
| Flag | Description |
| -------------------------------- | ------------------------------------------- |
| ./qarote setup | Interactive setup wizard (generates .env) |
| ./qarote worker | Start the alert worker process |
| ./qarote notification-worker | Start the notification worker process |
| ./qarote digest-worker | Start the digest worker (EE) |
| ./qarote metrics-worker | Start the metrics worker (EE) |
| ./qarote firehose-worker | Start the firehose worker (EE) |
| --database-url <url> | PostgreSQL connection URL |
| --jwt-secret <secret> | JWT signing secret (min 32 chars) |
| --encryption-key <key> | Encryption key (min 32 chars) |
| -p, --port <port> | Server port (default: 3000) |
| -h, --host <host> | Server host (default: localhost) |
| --enable-email <bool> | Enable email features (default: false) |
| --smtp-host <host> | SMTP server hostname |
| --smtp-port <port> | SMTP server port (default: 587) |
| --smtp-user <user> | SMTP username |
| --smtp-pass <pass> | SMTP password |
| --smtp-service <name> | SMTP service for OAuth2 (e.g. gmail) |
| --smtp-oauth-client-id <id> | OAuth2 client ID |
| --smtp-oauth-client-secret <s> | OAuth2 client secret |
| --smtp-oauth-refresh-token <t> | OAuth2 refresh token |
Updating (binary)
# Back up the current binary before replacing it
cp qarote qarote.backup
# Stop the running instance
kill $(pgrep -f './qarote') 2>/dev/null || true
# Download latest release
PLATFORM="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/x64/' | sed 's/aarch64/arm64/')"
curl -L "https://github.com/getqarote/Qarote/releases/latest/download/qarote-${PLATFORM}.tar.gz" | tar xz --strip-components=1
# Restart — migrations run automatically
./qarote
Your .env file is preserved. To roll back, restore the backup: mv qarote.backup qarote && ./qarote
Docker Compose
The Docker Compose setup bundles PostgreSQL, the backend, the alert worker, the notification worker, and the frontend. One command starts everything.
1. Clone the repository
git clone https://github.com/getqarote/Qarote.git qarote
cd qarote
2. Generate configuration
./setup.sh
This creates a .env file with secure random secrets. Alternatively, copy .env.selfhosted.example and fill in the values manually.
Key variables:
# Security — generate with: openssl rand -hex 64
JWT_SECRET=...
ENCRYPTION_KEY=...
# Ports
POSTGRES_PORT=5432
BACKEND_PORT=3000
FRONTEND_PORT=8080
# Frontend API URL (baked at build time — must match BACKEND_PORT)
# Changing this after the initial build requires rebuilding the frontend container:
# docker compose -f docker-compose.selfhosted.yml build frontend && docker compose ... up -d
VITE_API_URL=http://localhost:3000
3. Start services
docker compose -f docker-compose.selfhosted.yml up -d
This starts five containers:
| Container | Purpose |
| ---------------------------- | ----------------------------------- |
| qarote_postgres | PostgreSQL 17 database |
| qarote_backend | API server on port 3000 |
| qarote_alert_worker | Alert evaluation worker |
| qarote_notification_worker | Transactional emails (auth, Stripe) |
| qarote_frontend | React frontend on port 8080 |
EE workers (licensed features)
With a Developer or Enterprise license, uncomment digest-worker,
metrics-worker, and firehose-worker in docker-compose.selfhosted.yml to
enable weekly digests, queue metrics, and message tracing. Keep
metrics-worker and firehose-worker at exactly 1 replica — Docker
Compose already enforces this; do not add deploy.replicas for these
services.
4. Run database migrations
docker exec qarote_backend pnpm run db:migrate
5. Open the dashboard
Navigate to http://localhost:8080. Use the sign-up page to create your first account — this becomes the admin account. After that, you can disable public registration and invite team members via the Settings → Members page.
Ports
Frontend is served on FRONTEND_PORT (default 8080). The backend API is on
BACKEND_PORT (default 3000). Both are configurable in .env.
Updating (Docker Compose)
git pull origin main
docker compose -f docker-compose.selfhosted.yml up -d --build
docker exec qarote_backend pnpm run db:migrate
Viewing logs
docker compose -f docker-compose.selfhosted.yml logs -f
Production: TLS with a reverse proxy
The Docker Compose stack listens on plain HTTP. For production, put a TLS-terminating reverse proxy in front of the stack. Caddy is the simplest option — it fetches and renews Let's Encrypt certificates automatically.
/etc/caddy/Caddyfile
your-domain.com {
reverse_proxy localhost:8080
}
api.your-domain.com {
reverse_proxy localhost:3000
}
After setting up the proxy, update VITE_API_URL in .env to your API domain and rebuild the frontend container:
docker compose -f docker-compose.selfhosted.yml build frontend
docker compose -f docker-compose.selfhosted.yml up -d
Tip
Bind the Docker Compose ports to localhost only so the services aren't
directly reachable from the internet. In docker-compose.selfhosted.yml,
change "${FRONTEND_PORT}:80" to "127.0.0.1:${FRONTEND_PORT}:80" (and
similarly for the backend port).
Dokku
Dokku gives you git-push deploys, automatic HTTPS via Let's Encrypt, and managed PostgreSQL — on a server you control.
Why Dokku?
Dokku is a lightweight self-hosted PaaS. Push your code with git push dokku main and it rebuilds and redeploys automatically. The Postgres plugin handles
backups and linking. Let's Encrypt via the dokku-letsencrypt plugin handles
SSL.
1. Install Dokku
Follow the Dokku installation guide to set up Dokku on your server.
2. Create the app and database
# On your server (or via SSH)
ssh dokku@your-server apps:create qarote
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git postgres
dokku postgres:create qarote-db
dokku postgres:link qarote-db qarote
DATABASE_URL is set automatically when you link the database.
3. Set environment variables
dokku config:set qarote \
JWT_SECRET=$(openssl rand -hex 64) \
ENCRYPTION_KEY=$(openssl rand -hex 64) \
TZ=UTC \
ENABLE_EMAIL=false
4. Deploy
From your local machine:
git remote add dokku dokku@your-server:qarote
git push dokku main
Dokku builds the app from the Procfile, runs the release phase (migrations), and starts the web, alert-worker, and notification-worker processes.
5. Run database migrations
dokku run qarote pnpm run db:migrate
6. Enable HTTPS (optional but recommended)
dokku domains:set qarote your-domain.com
dokku letsencrypt:enable qarote
Scale the workers
dokku ps:scale qarote alert-worker=1 notification-worker=1
alert-worker— alert evaluation. Required for alerts to fire.notification-worker— transactional emails (password reset, invitations, Stripe receipts). Required ifENABLE_EMAIL=true.
With a Developer or Enterprise license, scale these additional workers to enable premium features:
dokku ps:scale qarote digest-worker=1 metrics-worker=1 firehose-worker=1
digest-worker— weekly digest emails.metrics-worker— queue metrics collection. Run as exactly 1 replica — multiple replicas write duplicate snapshot rows.firehose-worker— message tracing. Run as exactly 1 replica — multiple replicas create duplicate consumers.
Updating (Dokku)
# Push latest — triggers rebuild and redeploy automatically
git push dokku main
# Apply any new migrations
dokku run qarote pnpm run db:migrate
SMTP configuration
Email features (password reset, invitations) are disabled by default. To enable them, set ENABLE_EMAIL=true and provide SMTP credentials.
SMTP can be configured three ways, in priority order:
- Admin UI — Settings → Email Settings (takes effect immediately, no restart)
- Setup wizard —
./qarote setup(binary) or./setup.shfollowed by editing.env(Docker Compose) - Environment variables /
dokku config:set
Common providers
Gmail (app password)
ENABLE_EMAIL=true
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password # Not your Google password — generate at myaccount.google.com/apppasswords
SendGrid
ENABLE_EMAIL=true
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your-sendgrid-api-key
Mailgun
ENABLE_EMAIL=true
SMTP_HOST=smtp.mailgun.org
SMTP_PORT=587
SMTP_USER=postmaster@your-domain.mailgun.org
SMTP_PASS=your-mailgun-smtp-password
Amazon SES
ENABLE_EMAIL=true
SMTP_HOST=email-smtp.us-east-1.amazonaws.com # replace region as needed
SMTP_PORT=587
SMTP_USER=your-ses-smtp-username
SMTP_PASS=your-ses-smtp-password
Use OAuth2 for production
Gmail and Office 365 support OAuth2 authentication, which is more secure than app passwords and doesn't require storing credentials directly. See the Nodemailer OAuth2 guide for setup instructions.
Test your SMTP configuration
# Binary
./qarote test:smtp
./qarote test:smtp -- --send admin@yourcompany.com
# Docker Compose
docker exec qarote_backend pnpm run test:smtp
docker exec qarote_backend pnpm run test:smtp -- --send admin@yourcompany.com
# Dokku
dokku run qarote pnpm run test:smtp -- --send admin@yourcompany.com
SSO configuration
Qarote supports Single Sign-On via OIDC and SAML 2.0. SSO can be configured through the Admin UI (Settings → SSO Settings), the setup wizard (./qarote setup), or environment variables.
Key variables
| Variable | Description | Default |
| ------------------------ | --------------------------------------------------------------------------- | ----------------------- |
| SSO_ENABLED | Enable SSO | false |
| SSO_TYPE | Protocol: oidc or saml | oidc |
| SSO_OIDC_DISCOVERY_URL | OIDC discovery endpoint — must end with /.well-known/openid-configuration | — |
| SSO_OIDC_CLIENT_ID | OIDC client ID | — |
| SSO_OIDC_CLIENT_SECRET | OIDC client secret | — |
| SSO_SAML_METADATA_URL | SAML IdP metadata URL | — |
| API_URL | Backend URL — used for the SSO callback | http://localhost:3000 |
| FRONTEND_URL | Frontend URL — used for the post-login redirect | http://localhost:8080 |
| SSO_BUTTON_LABEL | Login button text | Sign in with SSO |
Register these URLs in your identity provider (Keycloak, Okta, Azure AD, Auth0, Google Workspace, etc.):
- OIDC callback URL:
{API_URL}/sso/callback - SAML ACS URL:
{API_URL}/sso/acs
Binary
Pass SSO flags at startup, or run ./qarote setup to configure interactively:
./qarote \
--sso-enabled true \
--sso-oidc-discovery-url https://your-idp.com/.well-known/openid-configuration \
--sso-oidc-client-id qarote \
--sso-oidc-client-secret your-client-secret \
--api-url https://api.your-domain.com \
--frontend-url https://your-domain.com
Docker Compose
Add SSO variables to .env, then uncomment the SSO block in docker-compose.selfhosted.yml and restart the backend:
SSO_ENABLED=true
SSO_TYPE=oidc
SSO_OIDC_DISCOVERY_URL=https://your-idp.com/.well-known/openid-configuration
SSO_OIDC_CLIENT_ID=qarote
SSO_OIDC_CLIENT_SECRET=your-client-secret
API_URL=https://api.your-domain.com
FRONTEND_URL=https://your-domain.com
Dokku
dokku config:set qarote \
SSO_ENABLED=true \
SSO_TYPE=oidc \
SSO_OIDC_DISCOVERY_URL=https://your-idp.com/.well-known/openid-configuration \
SSO_OIDC_CLIENT_ID=qarote \
SSO_OIDC_CLIENT_SECRET=your-client-secret \
API_URL=https://api.your-domain.com \
FRONTEND_URL=https://your-domain.com
Troubleshooting
"Exec format error" (binary only)
You downloaded the wrong architecture binary. Check your platform:
uname -m # x86_64 → use -x64 | aarch64 → use -arm64
Re-download the correct variant — your .env is preserved.
Tip
Multipass VMs on Apple Silicon are ARM64. Use linux-arm64, not linux-x64.
Database connection refused
- Verify PostgreSQL is running:
systemctl status postgresqlordocker compose ps postgres - Check the
DATABASE_URLformat:postgresql://user:password@host:port/database - Make sure migrations have been run
- For Docker Compose, wait for the health check to pass before the backend starts
Message rate charts are blank
Your RabbitMQ rates_mode is set to basic (the default), which doesn't retain sample history.
Fix it in rabbitmq.conf:
management.rates_mode = detailed
Or apply at runtime without restarting:
rabbitmqctl eval 'application:set_env(rabbitmq_management, rates_mode, detailed).'
Services not starting (Docker Compose)
docker compose -f docker-compose.selfhosted.yml logs
Common causes: missing .env values, port conflicts on 3000/5432/8080, or insufficient disk space.
License or premium features not activating
- Go to Settings → License and re-enter your key
- Check that the key hasn't expired
- Check backend logs for validation errors
- Contact support@qarote.io if the issue persists
License activation
Premium features are activated through the UI — no env vars or restarts needed.
- Purchase a license at the Customer Portal
- Copy your license key (a signed JWT string)
- In Qarote, go to Settings → License
- Paste the key and click Activate
Features unlock immediately. Validation is cryptographic and offline — no network call to Qarote's servers.