Self-host Observra with Docker
Run Observra locally or on a Docker-capable server with one Compose file. You do not need Node.js, pnpm, PostgreSQL, Redis, NATS, or Python installed on the host.
Requirements
- Docker Desktop or Docker Engine with Docker Compose support
- Access to the public container registry during the initial image pull
- An available host port for the dashboard (
3000by default)
Pull the Observra image
Pull the public Observra image before starting the services:
docker pull hardik1802/selfhosted-observra:latest
Create docker-compose.yml
Use the following Compose configuration:
services:
observra:
image: hardik1802/selfhosted-observra:latest
ports:
- "3000:3000"
- "8787:8787"
- "8788:8788"
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
nats:
condition: service_started
volumes:
- observra-journal:/app/journal-data
- observra-config:/app/config
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: observra
POSTGRES_USER: observra
POSTGRES_PASSWORD: observra
volumes:
- observra-postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U observra -d observra"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
redis:
image: redis:7-alpine
volumes:
- observra-redis:/data
restart: unless-stopped
nats:
image: nats:2-alpine
restart: unless-stopped
volumes:
observra-config:
observra-journal:
observra-postgres:
observra-redis:
Start Observra
From the folder containing docker-compose.yml, run:
docker compose up -d
docker compose ps
Open the dashboard at http://localhost:3000.
Default first-login credentials:
Email: admin@observra.local
Password: ChangeMe-123!
Change the password immediately after signing in.
On first setup, choose Use bundled local services. Observra runs database migrations, verifies the schema, seeds the initial account, and starts the gateway and worker.
Use the gateway
Create a Gateway API key in the dashboard. Requests use the gateway at http://localhost:8787.
The gateway key authenticates Observra; the provider key is forwarded to the selected AI provider.
Example Gemini request:
import requests
response = requests.post(
"http://localhost:8787/gemini/v1beta/models/gemini-3.6-flash:generateContent",
headers={
"Authorization": "Bearer <GATEWAY_KEY>",
"x-provider-key": "<GEMINI_API_KEY>",
"Content-Type": "application/json",
},
json={
"contents": [
{"role": "user", "parts": [{"text": "Hello from Observra"}]}
]
},
timeout=60,
)
print(response.status_code)
print(response.text)
After a successful request, open Request Explorer to view status, model, tokens, cost, latency, and request timing.
Run on another machine or server
Copy the same docker-compose.yml to the host and run:
docker compose pull
docker compose up -d
On a remote server, allow TCP port 3000 in its firewall and open:
http://SERVER_IP:3000
For production hosting, put the dashboard behind HTTPS and restrict ports 8787 and 8788 to
trusted networks. Keep the Docker volumes so database, configuration, and journal data survive
container restarts.
Logs and shutdown
docker compose logs -f observra
docker compose down
docker compose down preserves named volumes. To permanently remove all bundled data:
docker compose down -v
This deletes the local PostgreSQL, Redis, configuration, and journal volumes.
Troubleshooting
Check service status:
docker compose ps
If Observra reports getaddrinfo EAI_AGAIN postgres, Redis, or NATS, make sure all four Compose
services are defined in the same file and started together. If the dashboard is unavailable, check
that port 3000 is free and inspect:
docker compose logs -f observra postgres redis nats