Skip to content

Self-hosting overview

Reference for operations tasks around Vesana. If you host Vesana for someone else or maintain a customer instance: the levers live here.

Directory layout

/opt/vesana/
├── docker-compose.prod.yml      # Compose stack
├── .env                         # Secrets + configuration
├── secrets/                     # File secrets (chmod 600)
│   ├── pg_password
│   ├── redis_password
│   ├── secret_key
│   └── field_encryption_key
├── ssl/                         # TLS certs (optional, otherwise self-signed)
│   ├── cert.pem
│   └── key.pem
├── backups/                     # Backups when profile "backup" is active
└── uploads/                     # Wiki attachments etc.

Optional profiles

Compose profiles toggle optional services:

Profile Services When
Default (no profile) postgres, redis, api, receiver, worker, frontend, init Always
ai ollama AI features with local Ollama
backup backup sidecar Daily backup
pgbouncer pgbouncer Connection pool with many API replicas

Activate:

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

Profiles are cumulative — once active, services stay even on up -d without the flag. To remove: explicit down <service>.

Important env variables

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

Required

Variable Meaning
BASE_URL Public URL incl. https://
POSTGRES_PASSWORD Generated
REDIS_PASSWORD Generated
SECRET_KEY JWT signing key, generated
FIELD_ENCRYPTION_KEY AES-256-GCM key for field encryption, generated

Optional / tuning

Variable Default Meaning
WORKER_REPLICAS 1 Number of consumer workers
WORKER_CONCURRENCY 4 Concurrency per worker
WORKER_BATCH_SIZE 100 Batch size per pass
PG_SHARED_BUFFERS 256MB ~25 % of RAM
PG_WORK_MEM 16MB Sort/hash buffer
PG_EFFECTIVE_CACHE 512MB ~50 % of RAM
PG_MAX_CONNECTIONS 200 Connection limit
REDIS_MAXMEMORY 512mb Redis memory limit (noeviction policy)
HTTP_PORT / HTTPS_PORT 80 / 443 When other services use the ports
AI_ENABLED false Turn on AI features
LICENSE_KEY empty License key
VESANA_TESTER_MODE false Tester mode (all features unlocked)

Full list in .env.example. After changes: docker compose up -d to apply.

SSL / TLS

Default: Let's Encrypt from the wizard

If BASE_URL is a domain and port 80 is reachable from outside, the wizard auto-issues a Let's Encrypt cert. Renewal runs in the background.

Custom certificate

sudo cp your-cert.pem /opt/vesana/ssl/cert.pem
sudo cp your-key.pem  /opt/vesana/ssl/key.pem
sudo chmod 600 /opt/vesana/ssl/key.pem

docker compose -f /opt/vesana/docker-compose.prod.yml exec nginx nginx -s reload

Behind your own reverse proxy

If a nginx / Traefik / HAProxy already fronts the server, terminate TLS there and proxy internally to http://vesana-frontend:80. Details: TLS / reverse proxy.

Tester mode

What is tester mode

With VESANA_TESTER_MODE=true in .env, license validation is bypassed — all features are unlocked, the setup wizard skips the license step. The instance registers with the licence portal as a „tester instance" and Lukas / vendor team can revoke updates server-side per instance.

Activate

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

What happens

  • shared/license.py::is_tester_mode() returns True
  • load_license_from_env_or_db() returns a synthetic full-features LicenseInfo
  • API server phones home every 60 minutes to license.vesana.org/api/v1/tester/register with {instance_id, hostname, version}
  • Instance shows up in the licence portal under „tester instances"
  • Per instance, updates can be set to blocked — the updater shows a banner

When to turn it off

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

Updates & backups

Next