Quick Start (Self-Hosted)¶
Deploy SerOps on your own Docker host in about 5 minutes.
What this ships¶
Only what SerOps is — the SerOps application:
- frontend — React SPA
- backend — Django API + Celery worker + beat
- postgres — application database (Postgres 16)
- redis — cache + Celery broker
- caddy — single reverse proxy on ports 80 / 443, automatic HTTPS via Let's Encrypt
SerOps is the AI layer that sits on top of the observability stack you already run. It does not bundle Elasticsearch, Loki, Prometheus, or any log/metric shipper. Supported providers you connect from the UI after signing in:
- Logs: Elasticsearch, OpenSearch, Grafana Loki, Splunk, Datadog, AWS CloudWatch, Google Cloud Logging, Azure Log Analytics
- Metrics: Prometheus, VictoriaMetrics, Grafana Mimir, Datadog, AWS CloudWatch, Google Cloud Monitoring, Azure Monitor
- SCM + CI/CD: GitLab, GitHub, Bitbucket, Azure DevOps, Jenkins
Prerequisites¶
- Linux host with Docker 24+ and Docker Compose v2 or newer (
docker compose, not the legacydocker-compose) - 2 GB RAM, 1 vCPU, 10 GB disk for a single-project evaluation. Production sizing starts higher — see System Requirements
- An API key for one of: Anthropic, Google Gemini, OpenAI, or DeepSeek — or Ollama for fully on-prem inference with no key. You add it in the SerOps UI after signing in, not in a config file
- (Optional) A DNS name pointing at your host if you want automatic HTTPS
Step 1: Get the compose files¶
The quick-start compose file and its supporting configuration live in
deploy/quick-start/ of the repository:
Step 2: Configure¶
Open .env and set the required values:
| Variable | How to generate |
|---|---|
DJANGO_SECRET_KEY |
python3 -c "import secrets; print(secrets.token_urlsafe(64))" |
POSTGRES_PASSWORD |
openssl rand -hex 24 |
REDIS_PASSWORD |
openssl rand -hex 24 |
AI provider keys do not go in .env
SerOps reads AI keys from the database, per organisation — never from the environment. You will add yours in Settings → AI Providers → API Keys at Step 5, after the stack is running.
This is deliberate: on a multi-tenant self-host a shared env-var
key would pool quota and billing across every organisation, and
the onboarding wizard could no longer tell "no key yet" apart from
"key rejected by the provider". Setting ANTHROPIC_API_KEY in
.env has no effect.
For a real hostname with automatic HTTPS:
Point that DNS name at your host's public IP before starting Caddy — otherwise the Let's Encrypt HTTP-01 challenge fails and Caddy retries on its own timer.
For a purely local install, leave SEROPS_DOMAIN=localhost. Caddy then
serves https://localhost with a certificate from its own local
authority, so your browser shows a certificate warning the first time —
accept it to continue. http://localhost redirects there.
Replace every change-me-… value
The .env.example file ships with placeholder text
(change-me-…). Compose refuses to start if a required password is
missing, and the backend refuses to start while any secret still
contains change-me — its log names the variables to fix.
Use the hex commands above: the Redis password is embedded in a
redis:// URL, and a / (common in base64 output) breaks it.
See Configuration Reference for the full list of environment variables.
Step 3: Start the stack¶
Five containers come up: serops-postgres, serops-redis,
serops-backend, serops-frontend, serops-caddy. Only Caddy
exposes ports (80 and 443) to the host — everything else is reachable
only inside the internal serops Docker network.
Step 4: Create the first admin¶
The backend applies database migrations itself on every start, so the
schema is ready once serops-backend reports healthy
(docker compose ps). Create the first admin account — it gets its own
organisation:
Once this organisation exists, the public sign-up page closes
automatically: invite teammates from Settings → Team instead (a
sign-up would create a separate organisation). To let other teams create
their own organisations on this instance, set REGISTRATION_ENABLED=True
in .env.
Step 5: Add an AI provider key¶
Sign in with the superuser you just created. The Onboarding Wizard starts automatically on first login and walks you through the remaining steps; you can also do them manually.
Go to Settings → AI Providers, pick your provider, and paste the key. Keys are stored per organisation and encrypted at rest.
Supported: Anthropic (Claude), Google (Gemini), OpenAI, DeepSeek, and Ollama for fully on-prem inference with no key at all.
Step 6: Connect your observability stack¶
Go to Integrations and connect at least one of the supported observability providers so SerOps has real logs and metrics to analyse. See Integrations Overview for the full list and per-provider setup guides.
Step 7: Tag your telemetry¶
Skip this and your batches will be empty
This is the single most common reason a new install analyses nothing. SerOps finds your data by querying the provider for specific field values — if your logs don't carry them, the query matches zero documents and every batch comes back empty.
Your log shipper (Fluent Bit, Vector, Promtail, the OTel Collector, a Datadog Agent…) must stamp these fields on every record:
| Field | Example | What it maps to |
|---|---|---|
organisation_name |
acme-cloud |
Your SerOps organisation |
project_name |
checkout-api |
A SerOps project |
service_name |
checkout |
A service inside that project |
environment |
production |
The environment being analysed |
log_level |
ERROR |
Severity, used by Sentinel triage |
Common aliases are accepted automatically — OpenTelemetry's
service.name, Datadog's service / env, Kubernetes' app label,
and level / severity / status for the level field.
Configure Data Collection has copy-pasteable configuration for each shipper, plus the equivalent label and tag setup for metrics.
Step 8: Create your first project¶
With a key, a provider, and tagged telemetry in place, create a project and link a service. First Project walks through it.
Common operations¶
Update to a new release
Images are pinned by version, not floating on latest. Pulling
without changing the version re-pulls the tag you already have, so
set the new version first:
# 1. Back up the database — always, before any upgrade
docker compose exec postgres pg_dump -U serops serops > backup-$(date +%F).sql
# 2. Set the release you want in .env (see the releases page), e.g.
# SEROPS_VERSION=1.1.0
# 3. Pull and restart — the backend applies migrations on start
git pull
docker compose pull
docker compose up -d
SEROPS_VERSION is the only knob for upgrades. The
SEROPS_BACKEND_IMAGE / SEROPS_FRONTEND_IMAGE overrides in
.env.example exist only for pulling from your own registry mirror.
See Upgrading for the version compatibility matrix and the full backup checklist.
View logs
Back up Postgres
Stop everything (keep data)
Wipe everything including data
Networking + exposed ports¶
By design only Caddy exposes ports to the host:
| Port | Service |
|---|---|
| 80 | Caddy (HTTP + Let's Encrypt challenge) |
| 443 | Caddy (HTTPS) |
Postgres and Redis are reachable only from inside the serops Docker
network. For a psql session, run it inside the container:
Security posture¶
- Every service that accepts a password is required to have one — the
compose file refuses to start if
POSTGRES_PASSWORDorREDIS_PASSWORDisn't set. - No default credentials anywhere — the
.env.examplefile is a template, not a working config. - Postgres runs with data-checksums on,
pg_stat_statementsenabled for query-level observability. - Redis requires auth (
requirepass) and caps memory at 256 MB with an LRU eviction policy. - Caddy adds HSTS,
X-Frame-Options: DENY,X-Content-Type-Options: nosniffon every response.
Using your own reverse proxy¶
If you already run nginx / Traefik / a cloud load balancer, remove the
caddy service from docker-compose.yml and point your ingress at:
serops-frontend:3000for everything by defaultserops-backend:8000for/api/*and/images/*
See config/caddy/Caddyfile
for the exact routing rules.
Troubleshooting¶
Backend keeps restarting
Almost always a database credential mismatch. Check the logs:
Verify POSTGRES_PASSWORD in .env matches what the postgres
container was initialised with. If you started with a wrong password
and want to reset:
Caddy stuck on cert issuance
The Let's Encrypt HTTP-01 challenge requires port 80 to be reachable
from the internet at the exact SEROPS_DOMAIN you configured. Confirm
DNS points at your host and the host firewall allows port 80.
AI analyses aren't producing issues
Either no AI provider key is configured, or the org has no observability integration wired. Check Settings → AI Providers for the provider key, and Integrations to connect at least one of the supported log or metric providers.
Next steps¶
- First project setup
- Onboarding Wizard walk-through
- Integrations Overview — connect your observability stack
- Production Deployment — SSL/TLS, backups, monitoring
- Configuration Reference — every environment variable