Single-node deployment
Run the full Observal stack on a single VM with Docker Compose. Best for teams of up to ~50 users, internal tools, evaluations, and any deployment where simplicity matters more than multi-AZ redundancy.
End state: Observal running behind TLS on one server, with automated backups to S3-compatible storage, surviving reboots, and upgradable in under a minute.
When to use this vs. the Terraform module
Best for
Small/mid teams, internal use, POCs
Enterprise, SLA-bound, high-traffic
Infra
1 VM, any cloud or on-prem
~100 managed AWS resources
Cost
$20–150/mo
~$255/mo
HA
No — single point of failure
Yes — Multi-AZ Postgres, autoscaling ECS
Time to deploy
10 minutes
20–30 minutes
Operational complexity
Low — SSH, docker compose, cron
Medium — Terraform, AWS console, CloudWatch
Scaling
Vertical (bigger VM)
Horizontal (more Fargate tasks)
Architecture
Everything runs as Docker containers on a single host. The nginx LB routes traffic and terminates TLS. Docker's restart policy and systemd keep the stack running across reboots.
Prerequisites
VM
2 vCPU, 4 GB RAM, 40 GB SSD
4 vCPU, 8 GB RAM, 100 GB SSD
OS
Ubuntu 22.04+ / Amazon Linux 2023 / Debian 12
Ubuntu 24.04 LTS
Docker
Engine ≥ 24.0 with Compose v2
Latest stable
Domain (for TLS)
A DNS record pointing to the VM's public IP
—
Firewall
Ports 80, 443 open inbound
—
Sizing guide
1–10 users
t3.medium (2 vCPU / 4 GB)
~$30/mo
10–30 users
t3.large (2 vCPU / 8 GB)
~$60/mo
30–50 users
t3.xlarge (4 vCPU / 16 GB)
~$120/mo
ClickHouse is the memory consumer. If you run out, increase CLICKHOUSE_MEMORY_LIMIT before resizing the VM.
Step 1: Provision the VM
Use any cloud provider or on-prem hypervisor. Example for AWS:
For other clouds:
GCP:
e2-standard-2with 100 GB balanced persistent diskAzure:
Standard_B2mswith 100 GB Premium SSDHetzner:
CPX31(4 vCPU / 8 GB, ~€15/mo)On-prem: any Linux box meeting the specs above
Step 2: Install Docker
SSH into the VM and install Docker:
Step 3: Clone and configure
Edit .env for production. At minimum, change these:
Write them into .env:
SAML SSO, audit logs, and executive dashboards are included in the open-source distribution. See Configuration. For mounted credentials and private keys, use the documented
NAME_FILEinputs instead of placing secret contents in.env.
Step 4: Set up TLS
This guide uses the source Compose stack. Every localhost:80 example below refers to that stack's nginx load balancer. Do not expose its HTTP listener directly to remote clients. For downloadable server-package bindings, see Requirements.
Option A: Caddy (simplest — automatic HTTPS)
Create /etc/caddy/Caddyfile:
Caddy handles Let's Encrypt certificates automatically. No renewal cron needed.
Option B: Certbot + nginx production config
Then use the production compose overlay which configures nginx for TLS:
Set up auto-renewal:
Option C: Behind a cloud load balancer
If your VM sits behind an AWS ALB, GCP HTTPS LB, or Cloudflare, terminate TLS there and proxy to port 80 on the VM. No TLS config on the VM itself.
Step 5: Start the stack
First build takes 3–5 minutes (pulling images, building the API and web containers). Watch the logs:
Wait for:
Verify:
Step 6: Survive reboots
Docker's restart: unless-stopped policy (already set in docker-compose.yml) handles container restarts. To ensure Docker itself starts on boot:
Test it:
Step 7: Set up automated backups
Create a backup script:
Schedule it:
For ClickHouse (weekly, since it's larger):
See Backup and restore for detailed restore procedures.
Step 8: First login
Install the CLI on your local machine:
Log in:
Verify:
Upgrades
The Compose init service applies migrations before API startup. See Upgrades for rollback procedures.
Or use the CLI:
Monitoring
Prometheus and Grafana are optional. Start the core stack with Prometheus only:
Start Prometheus and Grafana:
Access Grafana at http://your-server:3001 when the Grafana profile is enabled.
For basic alerting without Grafana, add a health check cron:
Security hardening
The security assurance case describes the deployment trust boundaries and residual risks.
Before exposing to the internet:
Scaling up
When you outgrow a single node:
API response times increasing
Increase API_WORKERS in .env (default 2), or bump to a bigger VM
ClickHouse queries slow
Increase CLICKHOUSE_MEMORY_LIMIT, move to a bigger VM, or externalize to ClickHouse Cloud
Disk filling up
Reduce DATA_RETENTION_DAYS, add a bigger disk, or move ClickHouse data to a separate volume
Need HA / zero downtime deploys
Migrate to the Terraform module
Next
Configuration — all environment variables
Backup and restore — detailed restore procedures
Upgrades — safe upgrade and rollback flow
Troubleshooting — common issues
Last updated
Was this helpful?