Skip to content

Self-hosting overview

This page is the reference for operational tasks around Vesana. If you host Vesana for others, or maintain an instance at a customer's site: here are the levers.

Directory structure

On the host itself, /opt/vesana/ only contains two things:

/opt/vesana/
├── docker-compose.prod.yml      # compose stack definition
└── .env                         # secrets + configuration (plain environment variables)

Everything else — SSL certificates, backups, agent/collector binaries, uploads, icon assets, avatars — lives in named Docker volumes, not as a directory under /opt/vesana. That has the advantage that a docker compose down (without -v) can never accidentally drag along data from a host directory.

To look inside a volume or copy something out, use a throwaway container:

# Example: list a volume's contents
docker run --rm -v vesana_backup-data:/data alpine ls -la /data

# Example: copy a file out of a volume
docker run --rm -v vesana_backup-data:/src -v $(pwd):/dst alpine \
  sh -c 'cp /src/some-file /dst/'

(Volume names usually carry the compose project prefix, e.g. vesana_backup-data — check with docker volume ls if your prefix differs.)

Optional compose profiles

Two optional profiles turn on additional services:

Profile Service When
Default (no profile) postgres, redis, api, receiver, worker, worker-scheduler, nginx, init Always
ai ollama AI features with local Ollama
agent-gateway agent-gateway A separate port serving only agent/collector endpoints (so the web UI can be locked down by firewall) — see Distribution & reachability

Backups are no longer a profile — the built-in DR backup system (see Backup & Disaster Recovery) always runs, without a separate sidecar.

Enable:

docker compose -f docker-compose.prod.yml --profile ai up -d

Or permanently via .env:

COMPOSE_PROFILES=ai,agent-gateway

Important environment variables

The .env is generated by the setup script. Important variables:

Required

Variable Meaning
BASE_URL Public URL including https://
POSTGRES_PASSWORD Generated
REDIS_PASSWORD Generated
SECRET_KEY Signing key for login tokens, generated
FIELD_ENCRYPTION_KEY AES-256-GCM key for field encryption, generated

Optional / tuning

Variable Default Meaning
WORKER_REPLICAS 1 Number of consumer worker containers
WORKER_CONCURRENCY 4 Parallelism per worker
WORKER_BATCH_SIZE 100 Batch size per DB insert pass
DB_POOL_SIZE 10 Size of the DB connection pool
DB_MAX_OVERFLOW 20 Extra connections beyond the pool, as needed
PG_SHARED_BUFFERS 256MB Postgres buffer, ~25% of RAM as a rule of thumb
PG_WORK_MEM 16MB Sort/hash buffer per operation
PG_EFFECTIVE_CACHE 512MB Postgres planner assumption, ~50% of RAM
PG_MAX_CONNECTIONS 200 Connection limit
PG_MAINTENANCE_WORK_MEM 256MB Memory cap for vacuum/index maintenance — without this, the automatic Postgres tuning logic derives the value from the host's total RAM, which can cause OOM on small machines
REDIS_MAXMEMORY 512mb Redis memory limit (noeviction policy — Redis rejects new data instead of evicting old data)
CHECK_RESULTS_RETENTION_DAYS 90 Starting value for metrics retention (later changeable under Resources → Storage)
LOG_RETENTION_DAYS 30 Starting value for log retention
HTTP_PORT / HTTPS_PORT 80 / 443 If other services occupy those ports
AGENT_GATEWAY_PORT 8443 Only relevant with the agent-gateway profile active
AI_ENABLED false Enable AI features
LICENSE_KEY empty License key
VESANA_TESTER_MODE false Tester mode (all features unlocked)

The four sizing profiles (Small/Medium/Large/XL) under Resources → Performance set WORKER_REPLICAS, WORKER_CONCURRENCY, PG_SHARED_BUFFERS, PG_EFFECTIVE_CACHE, PG_WORK_MEM, PG_MAINTENANCE_WORK_MEM, PG_MAX_CONNECTIONS, DB_POOL_SIZE/DB_MAX_OVERFLOW, and REDIS_MAXMEMORY in one go — easier for most setups than tuning individual variables by hand.

Full list of available variables in the bundled .env.example. After changes: docker compose up -d to apply.

SSL / TLS

Default: automatic self-signed certificate

On first start, Vesana automatically generates a self-signed certificate — that way the setup wizard always runs over HTTPS, even with no domain or certificate of your own at all. Your browser will show a certificate warning for this until you install a real certificate.

There is no built-in automatic Let's Encrypt issuance — issuing and renewing a public certificate is something you organize yourself (e.g. with certbot on the host, or via a reverse proxy in front, see below).

Installing your own certificate

The certificate and key live inside the container at /etc/nginx/ssl/fullchain.pem and /etc/nginx/ssl/privkey.pem — that's a named Docker volume, not a host directory. Copy your own certificate in like this:

docker run --rm \
  -v vesana_ssl:/etc/nginx/ssl \
  -v /path/to/your/cert:/src:ro \
  alpine sh -c 'cp /src/fullchain.pem /src/privkey.pem /etc/nginx/ssl/'

docker compose -f /opt/vesana/docker-compose.prod.yml restart nginx

As long as valid files exist under those two names in the volume, Vesana won't overwrite them with a new self-signed certificate on restart — renewal (e.g. every 90 days with Let's Encrypt) is something you repeat yourself via a cron job (same command as above, then nginx -s reload instead of a full restart).

Behind your own reverse proxy

If the server already sits behind your own nginx / Traefik / HAProxy, terminate TLS there and proxy internally to the Vesana web server container. Details on reverse-proxy specifics (SSE buffering, WebSocket upgrade): Distribution & reachability.

Tester mode

What is tester mode

With VESANA_TESTER_MODE=true in .env, license checking is bypassed — all features are unlocked, and the setup wizard skips the license step. The instance registers itself with the licence portal as a "tester instance" and can be excluded from updates there, server-side.

Enabling it

echo "VESANA_TESTER_MODE=true" | sudo tee -a /opt/vesana/.env
docker compose -f /opt/vesana/docker-compose.prod.yml up -d

What happens

  • The license check always returns a full-featured license info internally
  • The API server checks in with the licence portal hourly as a tester instance (instance ID, hostname, version)
  • The instance appears under "Tester instances" in the licence portal
  • Updates can be blocked there per instance — the updater then shows a banner

When to turn tester mode off

Before handing off to a real customer: remove VESANA_TESTER_MODE from .env, add a license key, restart the stack.

Updates & backups

  • Updates — GUI updater, online + offline + emergency CLI, no auto-rollback
  • Backup & restore — built-in DR system, multiple schedules, disaster drill

Next