Self-Hosted Deployment Guide
Deploy Systemi on your own infrastructure using Docker. Your data never leaves your network.
License. Use of the self-hosted Software is subject to our End User License Agreement (EULA). © 2024–2026 MDG LLC. Systemi™ is a trademark of MDG LLC.
Overview
Systemi can be deployed on your own infrastructure using Docker. This ensures all data remains within your network. The application is distributed as a compiled Docker image — no source code is included.
Prerequisites
- Docker and Docker Compose installed
- A machine with at least 2 CPU cores and 2 GB RAM
- A signed contract and registry credentials (username + token to pull the image)
- A valid Systemi license key (provided with your contract)
- Network access to your Jira, GitHub, and/or Slack APIs
The Docker image is private. You need registry credentials (provided after contract signing) to pull it. Access is controlled by both the registry token and your license key.
Don't have a contract or credentials yet? Contact sales to get started.
Quick Start
Download the deployment files
Create a directory and download the configuration files:
mkdir systemi && cd systemi
# Download docker-compose.yml and .env template
curl -O https://getsystemi.com/deploy/docker-compose.yml
curl -O https://getsystemi.com/deploy/.env.example
cp .env.example .envOr create the files manually — see the Docker Compose reference below.
Configure environment
Edit .env with your settings:
# Required
POSTGRES_PASSWORD=<generate-a-strong-password>
DATABASE_URL=postgresql://systemi:<your-password>@db:5432/systemi
NEXTAUTH_URL=https://systemi.yourdomain.com
SYSTEMI_LICENSE_KEY=<your-license-key>
ENCRYPTION_KEY=<base64-encoded-32-byte-key>
# Registry (provided with your contract)
GHCR_REGISTRY_USER=<your-registry-username>
GHCR_REGISTRY_TOKEN=<your-registry-token>
# Admin account (created on first run)
SUPERADMIN_EMAIL=admin@yourdomain.com
SUPERADMIN_PASSWORD=<strong-password>
SUPERADMIN_NAME=Admin
# OAuth Integrations (optional — for one-click connect)
# ATLASSIAN_CLIENT_ID=<from-developer.atlassian.com>
# ATLASSIAN_CLIENT_SECRET=
# GITHUB_CLIENT_ID=<from-github.com/settings/developers>
# GITHUB_CLIENT_SECRET=
# SLACK_CLIENT_ID=<from-api.slack.com/apps>
# SLACK_CLIENT_SECRET=
# Optional — Email (Systemi SMTP is used by default)
# SMTP_HOST=smtp.yourdomain.com
# SMTP_PORT=465
# EMAIL=noreply@yourdomain.com
# PASSWORD=<smtp-password>
# Optional — AI (OpenAI or Google Gemini)
# OPENAI_API_KEY=<for-ai-powered-insights>
# GEMINI_API_KEY=<from-aistudio.google.com> # and set AI_PROVIDER=gemini if both keys exist
# Optional — Slack message sync pacing (ms between API pages; eases rate limits)
# SLACK_API_MIN_INTERVAL_MS=600
# Large workspaces: Slack message sync checkpoints by channel (resumes across cron). Tune thread cap / daily cron in Admin → Integrations → Slack.
CRON_SECRET=<random-secret-for-cron-jobs>Note: PostgreSQL is included in the Docker Compose setup — no external database needed. The DATABASE_URL is auto-configured from POSTGRES_PASSWORD. Email works out of the box using Systemi's built-in SMTP relay. AI features work without an API key — they fall back to pre-written insights. Use OPENAI_API_KEY or GEMINI_API_KEY (see AI_PROVIDER in env docs). OAuth variables are only needed for one-click connect; users can always connect integrations via manual API tokens.
Log in to the container registry
Authenticate using the credentials provided with your contract:
echo $GHCR_REGISTRY_TOKEN | docker login ghcr.io -u $GHCR_REGISTRY_USER --password-stdinThis is a one-time step; Docker caches the credentials.
Pull and start the application
docker compose pull
docker compose up -dOn first start, the app applies the database schema and creates the superadmin account from your SUPERADMIN_* env vars — no manual init step needed. On ARM64 (Apple Silicon, Graviton) you may see a platform warning; run with DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose up -d. The provided docker-compose.yml sets platform: linux/amd64 for the app.
Access the application
Open https://systemi.yourdomain.com (or http://localhost:3000 for local testing) and log in with the admin credentials you set in step 2.
Docker Compose Reference
Here is the full docker-compose.yml for reference. You can create this file manually if you prefer not to download it:
version: "3.8"
services:
app:
platform: linux/amd64
image: ghcr.io/mdgart/systemi:latest
ports:
- "3000:3000"
depends_on:
db:
condition: service_healthy
env_file:
- .env
environment:
- DATABASE_URL=postgresql://systemi:${POSTGRES_PASSWORD}@db:5432/systemi
- NODE_ENV=production
restart: unless-stopped
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_USER: systemi
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: systemi
healthcheck:
test: ["CMD-SHELL", "pg_isready -U systemi"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
pgdata:Architecture
┌─────────────────────────────────────────┐
│ Your Network │
│ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ Systemi │────▶│ PostgreSQL │ │
│ │ App │ │ (your DB) │ │
│ │ :3000 │ │ :5432 │ │
│ └────┬─────┘ └──────────────────┘ │
│ │ │
└───────┼─────────────────────────────────┘
│ Outbound only (read-only APIs)
▼
┌────────────┐ ┌──────────┐ ┌───────┐
│ Jira Cloud │ │ GitHub │ │ Slack │
└────────────┘ └──────────┘ └───────┘- All data is stored in your PostgreSQL instance
- Outbound traffic is limited to read-only API calls to Jira, GitHub, and Slack
- No data is sent to Systemi's servers
- The Docker image contains only compiled production code (no source code)
Updating
When a new version is released, pull the latest image and restart. Your data is preserved in the PostgreSQL volume. Ensure you are logged in to the registry (docker login ghcr.io) if your session has expired.
# Pull the latest image
docker compose pull
# Restart with the new version
docker compose up -d
# Apply any database schema changes
docker compose exec app node node_modules/prisma/build/index.js db pushTo pin a specific version instead of latest, edit your docker-compose.yml and change the image tag:
image: ghcr.io/mdgart/systemi:1.2.0If the update doesn't take effect, Docker may be using a cached image. Remove it and pull again (no need to stop containers or reset the database). If you use a versioned tag, replace latest with your tag:
docker rmi ghcr.io/mdgart/systemi:latest
docker compose pull
docker compose up -dReverse Proxy (Production)
For production deployments, place a reverse proxy (nginx, Caddy, Traefik) in front of Systemi:
server {
listen 443 ssl;
server_name systemi.yourdomain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3000;
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;
}
}Backup & Restore
Back up your PostgreSQL database regularly:
docker compose exec db pg_dump -U systemi systemi > backup-$(date +%Y%m%d).sqlRestore from backup:
docker compose exec -T db psql -U systemi systemi < backup-20260309.sqlFirewall Rules
For maximum security, configure your firewall to allow only these connections:
| Direction | Port | Destination | Purpose |
|---|---|---|---|
| Inbound | 443 | Your server | HTTPS access |
| Outbound | 443 | *.atlassian.net | Jira API |
| Outbound | 443 | api.github.com | GitHub API |
| Outbound | 443 | slack.com | Slack API |
| Outbound | 443 | api.openai.com | OpenAI (optional AI features) |
| Outbound | 443 | generativelanguage.googleapis.com | Google Gemini (optional AI features) |
| Internal | 5432 | PostgreSQL | Database |
Managed Single-Tenant Deployment
For customers who prefer not to manage infrastructure, Systemi offers managed single-tenant deployments:
- Dedicated instance: Your own Systemi instance running in an isolated cloud environment
- Dedicated database: Your data is stored in a dedicated PostgreSQL instance (not shared)
- Custom domain: Access via your own subdomain (e.g., systemi.yourdomain.com)
- Managed updates: We handle upgrades, backups, and monitoring
- SLA-backed: Custom SLAs available for enterprise customers
Contact sales for pricing and setup.
Troubleshooting
Can't pull the image
- The image is private — you need registry credentials (provided with your contract)
- Run
echo $GHCR_REGISTRY_TOKEN | docker login ghcr.io -u $GHCR_REGISTRY_USER --password-stdinbefore pulling - Verify
GHCR_REGISTRY_USERandGHCR_REGISTRY_TOKENare set correctly - Contact support if credentials are missing or expired
Application won't start
- Check logs:
docker compose logs app - Verify DATABASE_URL is correct in
.env - Ensure the database is accessible:
docker compose exec app node node_modules/prisma/build/index.js db push
License key errors
- Verify
SYSTEMI_LICENSE_KEYis set in.env - Check expiration date
- Contact support for renewal
Email not working
- By default, Systemi uses its own SMTP relay — no configuration needed. Check logs:
docker compose logs app | grep Email - If using custom SMTP, verify
SMTP_HOST,EMAIL, andPASSWORDin.env - Some SMTP providers require app-specific passwords or allowed sender verification
Need help?
Our team is available to help with deployment, configuration, and ongoing support.
Contact Support