Onyx (formerly Danswer) is an open-source enterprise search / AI answer engine that connects to your data sources (Slack, Confluence, Google Drive, etc.) and provides a chat/search interface over them. Unlike faster-whisper or Piper, it's a multi-container application (web frontend, API server, background workers, Postgres, Vespa search engine, Redis, MinIO/S3-compatible storage, nginx), so it's deployed via Docker Compose rather than a single service.
1. Choose and size the VPS
Onyx is heavy to run — Vespa (its search backend) alone wants real memory.
| Use case | Recommended RamNode plan specs |
|---|---|
| Small team / evaluation | 4 vCPU, 16 GB RAM, 100 GB disk |
| Production, moderate document volume | 8 vCPU, 32 GB RAM, 200+ GB SSD |
Recommended OS: Ubuntu 24.04 LTS. Use a plan with SSD/NVMe storage — Vespa indexing is disk-I/O sensitive.
2. Initial server setup
apt update && apt -y upgrade
apt -y install ca-certificates curl gnupg ufw git
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable3. Install Docker Engine and Compose plugin
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable --now docker
docker --version
docker compose versionOptional: add a non-root deploy user to the docker group so you don't have to sudo every command:
adduser onyx
usermod -aG docker onyx4. Pull down the Onyx repo
su - onyx -s /bin/bash
git clone https://github.com/onyx-dot-app/onyx.git
cd onyx/deployment/docker_composeThe deployment/docker_compose directory contains the compose files Onyx maintains for self-hosting (docker-compose.dev.yml for a quick eval setup, and a prod-oriented compose file with nginx included — check the repo's current README, since filenames occasionally change between releases).
5. Configure environment variables
Copy the example env file and edit it:
cp env.prod.template .env
nano .envAt minimum, set:
# LLM provider — Onyx needs at least one configured to answer questions
GEN_AI_API_KEY=your_openai_or_other_provider_key
GEN_AI_MODEL_PROVIDER=openai
# Auth — set a real secret, don't leave the default
SECRET=$(openssl rand -hex 32)
# Domain Onyx will be served from
WEB_DOMAIN=https://onyx.example.com
# Postgres credentials (used by the postgres container in the same compose file)
POSTGRES_USER=onyx
POSTGRES_PASSWORD=$(openssl rand -hex 16)Onyx supports self-hosted/local LLMs too (via Ollama or a compatible OpenAI-style endpoint) if you don't want to send data to a third-party API — set GEN_AI_MODEL_PROVIDER and the corresponding host/key variables accordingly. Check the current env.prod.template in the repo for the full, up-to-date variable list, since Onyx adds new connectors/settings frequently.
6. Bring the stack up
docker compose -f docker-compose.prod.yml up -dThis starts, at minimum: web_server, api_server, background, relational_db (Postgres), index (Vespa), cache (Redis), minio, and nginx. First startup is slow — Vespa needs to initialize its index and the model server needs to pull embedding models.
Watch it come up:
docker compose -f docker-compose.prod.yml logs -f api_serverCheck container health:
docker compose -f docker-compose.prod.yml ps7. TLS termination
The prod compose file ships its own nginx container listening on 80/443. The cleanest way to get a certificate without fighting two nginxes is to run certbot in standalone mode before/alongside it, or use the setup script Onyx provides:
cd onyx/deployment/data/nginx
./init-letsencrypt.shCheck the script for the domain/email variables it expects — set them at the top of the script or via env vars as documented in the repo before running it. If you'd rather front Onyx with your own host-level nginx and manage certs the way you already do elsewhere, bind Onyx's own nginx container to a local port only (e.g. 127.0.0.1:8080:80 in the compose file) and reverse-proxy from your host nginx into that instead — this fits better if you're centralizing TLS across multiple services on the same VPS.
8. Enable stack-on-boot
Docker Compose doesn't auto-restart on VPS reboot unless containers have a restart policy. Confirm (or add) restart: unless-stopped on each service in the compose file — Onyx's shipped prod compose file already sets this on most services, but it's worth checking after you pull a new version, since restart policies do occasionally change between releases.
Docker itself is already enabled via systemctl enable docker from step 3, so containers with restart: unless-stopped will come back up automatically after a host reboot.
9. Operational notes
- Backups: back up the Postgres volume (metadata, users, connector configs) and the Vespa data volume (search index — rebuildable but slow to reindex) and the MinIO volume (uploaded files).
docker compose exec relational_db pg_dump -U onyx onyx > backup.sqlis a reasonable starting point for Postgres; snapshot the Docker volumes for Vespa/MinIO or use RamNode's VPS-level snapshot/backup feature for the whole disk. - Updates:
git pull, review the changelog for breaking.env/compose changes, thendocker compose -f docker-compose.prod.yml pull && docker compose -f docker-compose.prod.yml up -d. - Resource pressure: if Vespa or the embedding model server gets OOM-killed, that's the signal to move up a plan tier rather than tune around it — these components are memory-hungry by design.
- Monitoring: add HTTP checks against the web server's root path and the API server's health endpoint to your monitoring stack; also watch
docker compose psfor restart loops, which usually means an env var was missed. - Connectors: once the stack is up, most configuration (data source connectors, LLM provider, user management) happens through the Onyx admin UI rather than further file edits.
