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:
Or permanently via .env:
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¶
- Resources — storage, RAM, performance — sizing profiles in detail
- Distribution & reachability
- Security — hardening checklist