Skip to main content

Docker Compose Deployment

The fastest way to self-host Sentro. Runs the entire platform on a single machine using Docker Compose, with an automatic-HTTPS reverse proxy in front.

Prerequisites​

  • Docker 24+ (or Podman 4+)
  • Docker Compose v2+
  • 2 CPU cores, 4 GB RAM minimum
  • An x86-64 Linux server (Ubuntu 22.04+, Debian 12+, or any Docker-compatible OS). ARM hosts are not supported — the images are published for x86-64 only.

Quick Start​

Option 1: Automated install​

curl -fsSL https://sentro.dev/install.sh | bash

Or, without the short domain:

bash <(curl -fsSL https://raw.githubusercontent.com/sentro-dev/self-hosted/main/install.sh)

This will:

  1. Check system requirements
  2. Download the deployment bundle
  3. Generate secure passwords and secrets
  4. Start all services
  5. Print your admin credentials

Everything is installed into ~/sentro by default. Use --dir /opt/sentro to install elsewhere, and --no-start to generate the configuration without booting the stack.

Option 2: Manual setup​

1. Download the deployment files:

mkdir -p ~/sentro && cd ~/sentro

BASE=https://raw.githubusercontent.com/sentro-dev/self-hosted/main
curl -fsSL $BASE/docker-compose.yml -o docker-compose.yml
curl -fsSL $BASE/Caddyfile -o Caddyfile
curl -fsSL $BASE/.env.example -o .env.example
curl -fsSL $BASE/prometheus.yml -o prometheus.yml
curl -fsSL $BASE/server.mjs -o server.mjs

2. Configure your environment:

cp .env.example .env

Then fill in every value marked REQUIRED:

# Generate the secrets
openssl rand -hex 32 # AUTH_SECRET
openssl rand -hex 32 # ENCRYPTION_KEY (must be exactly 64 hex characters)
openssl rand -hex 32 # ADMIN_SESSION_SECRET
openssl rand -hex 16 # POSTGRES_PASSWORD
openssl rand -hex 16 # REDIS_PASSWORD

Also set your domains, and keep AUTH_URL in sync with DOMAIN_APP:

DOMAIN_APP=app.yourdomain.com
DOMAIN_ADMIN=admin.yourdomain.com
DOMAIN_API=api.yourdomain.com
AUTH_URL=https://app.yourdomain.com
warning

AUTH_URL must be the exact URL your users open the dashboard on, including the scheme. If it disagrees with DOMAIN_APP, sign-in redirects will break.

3. Start the services:

docker compose up -d

4. Wait for services to be ready (about 30 seconds):

docker compose ps        # all services should report "healthy"
docker compose logs -f # follow logs

5. Access your instance:

Once DNS for your domains points at the server, the bundled Caddy proxy obtains HTTPS certificates automatically:

ServiceURL
Dashboardhttps://app.yourdomain.com
Admin Panelhttps://admin.yourdomain.com
REST APIhttps://api.yourdomain.com

Every service is also published on the loopback interface, which is handy before DNS is ready and for local evaluation:

ServiceURL
Dashboardhttp://localhost:3001
Admin Panelhttp://localhost:3002
REST APIhttp://localhost:4000
API healthhttp://localhost:4000/health
App healthhttp://localhost:3001/api/health

Services​

The default stack starts these containers:

ContainerImagePortPurpose
sentro-caddycaddy:2-alpine80, 443Reverse proxy + automatic HTTPS
sentro-appsentro-app3001User dashboard
sentro-adminsentro-admin3002Admin panel
sentro-apisentro-api4000REST API
sentro-workersentro-worker9464 (metrics)Monitor check engine
sentro-postgrespostgres:16-alpine5432Database
sentro-redisredis:7-alpine6379Job queue
sentro-migratesentro-app—Runs DB migrations (exits after)

Changing host ports​

If a port is already taken on your machine, override it in .env — nothing else needs to change:

CADDY_HTTP_PORT=8080
CADDY_HTTPS_PORT=8443
APP_HOST_PORT=13001
ADMIN_HOST_PORT=13002
API_HOST_PORT=14000
POSTGRES_HOST_PORT=15432
REDIS_HOST_PORT=16379

Optional Profiles​

Profiles are additive — combine them freely.

Documentation portal​

docker compose --profile docs up -d

Serves this documentation site locally on http://localhost:3003, and on DOMAIN_DOCS if you set one.

Sandbox (mock endpoints + email capture)​

docker compose --profile sandbox up -d

Adds a mock HTTP target you can point test monitors at, plus MailHog so outgoing email is captured instead of delivered:

To route real application email through MailHog, set SMTP_HOST=mailhog and SMTP_PORT=1025 in .env.

For production, configure a real SMTP relay instead:

SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your-sendgrid-api-key
SMTP_FROM=alerts@yourdomain.com

Monitoring stack (Prometheus + Grafana)​

docker compose --profile monitoring up -d

Prometheus is pre-configured to scrape the worker's metrics endpoint — no scrape config to write.

HTTPS and Reverse Proxy​

The stack ships with Caddy and handles certificates for you. Point the DNS records for DOMAIN_APP, DOMAIN_ADMIN, and DOMAIN_API at the server, make sure ports 80 and 443 reach it, and certificates are issued on first request.

Using your own proxy instead​

If you already run nginx, Traefik, or a cloud load balancer, disable Caddy and proxy to the loopback ports directly:

docker compose up -d --scale caddy=0

Then forward each hostname to the matching local port:

server {
listen 443 ssl http2;
server_name app.yourdomain.com;

ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

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

Repeat for admin.yourdomain.com → 127.0.0.1:3002 and api.yourdomain.com → 127.0.0.1:4000.

warning

Whatever proxy you use, the hostname users type must appear in DOMAIN_APP (or APP_HOSTNAMES). Requests arriving on an unrecognised hostname are treated as custom status-page domains and will return "Status page not found".

Data & Backups​

Back up PostgreSQL​

# Create backup
docker exec sentro-postgres pg_dump -U sentro sentro > backup-$(date +%Y%m%d).sql

# Restore from backup
cat backup-20260101.sql | docker exec -i sentro-postgres psql -U sentro sentro

Back up volumes​

# Stop services first
docker compose down

# Back up the data volumes
tar czf sentro-backup-$(date +%Y%m%d).tar.gz \
$(docker volume inspect sentro_postgres_data --format '{{ .Mountpoint }}') \
$(docker volume inspect sentro_redis_data --format '{{ .Mountpoint }}')

# Restart
docker compose up -d
danger

Back up your .env too, and keep it somewhere safe. ENCRYPTION_KEY cannot be regenerated — losing it makes every encrypted field in the database permanently unreadable.

Automated backups​

# /etc/cron.d/sentro-backup
0 3 * * * root cd /root/sentro && docker exec sentro-postgres pg_dump -U sentro sentro | gzip > /backups/sentro-$(date +\%Y\%m\%d).sql.gz

Troubleshooting​

Services won't start​

docker compose logs -f      # check logs
docker stats # check resource usage
docker compose config # verify .env is loaded and valid

A port conflict on 80, 443, 3001, 3002, 4000, 5432, or 6379 is the most common cause — see Changing host ports.

Database connection issues​

docker exec sentro-postgres pg_isready -U sentro
docker compose logs migrate

"Status page not found" when opening the dashboard​

The hostname you used is not recognised as an app hostname. Set DOMAIN_APP to that hostname (or add it to APP_HOSTNAMES), keep AUTH_URL in sync, and restart.

Worker not processing checks​

docker compose logs -f worker
docker exec sentro-redis redis-cli -a YOUR_REDIS_PASSWORD ping

Reset everything​

# Stop and remove all containers + volumes (DATA LOSS!)
docker compose down -v

# Start fresh
docker compose up -d