Deployment
The simplest live deployment is a single Linux host running Docker Compose. The production compose stack starts:
- traefik — reverse proxy, terminates TLS via Let’s Encrypt.
- db — Postgres 18 with pgvector.
- app — the Next.js app, pulled from GHCR.
The app container applies committed database migrations before starting Next.js.
Prerequisites
Section titled “Prerequisites”- A Linux host with Docker Engine and Docker Compose v2 installed.
- A DNS A record for your app host, for example
offers.example.com, pointing to the host’s public IP. - Inbound TCP 80 and 443 open in the host firewall.
- Access to the public GHCR image
ghcr.io/solivio-ai/solivio-app. - An OpenAI API key for AI-backed catalog import, offer generation, semantic search, and offer chat.
Image build
Section titled “Image build”The production image is built from apps/solivio/Dockerfile:
ghcr.io/solivio-ai/solivio-app— Next.js standalone runtime that ships with the committed migrations and applies them on container startup.
Both are declared in docker-compose.build.yml. CI (.github/workflows/build-image.yml) runs on every push to main:
IMAGE_TAG=$GITHUB_SHA docker compose -f docker-compose.build.yml build --pulldocker compose -f docker-compose.build.yml pushEach push tags the image with :latest and :<commit-sha>. Pin IMAGE_TAG=<sha> in /opt/solivio/.env for reproducible deploys; leave on latest to always run the newest build.
To build locally:
docker compose -f docker-compose.build.yml buildProduction settings
Section titled “Production settings”The production stack reads secrets and host-specific values from .env next to
docker-compose.prod.yml.
Important values:
| Variable | Purpose |
|---|---|
APP_HOST | Public hostname routed by Traefik. |
LETSENCRYPT_EMAIL | Email used for Let’s Encrypt certificate registration. |
IMAGE_TAG | latest for fast iteration, or a commit SHA for reproducible deploys. |
POSTGRES_PASSWORD | Database password used by the db service. |
DATABASE_URL | Internal app database URL, usually postgresql://solivio:<password>@db:5432/solivio. |
OPENAI_API_KEY | Enables AI-backed product import, matching, offer generation, and chat. |
OPENAI_MODEL_* | Optional per-role model overrides (see apps/solivio/src/server/agents/modelConfig.ts). |
EMBEDDING_MODEL | Optional override for product embedding model. Defaults to text-embedding-3-large. |
BETTER_AUTH_URL | Public app URL, for example https://offers.example.com. |
BETTER_AUTH_SECRET | Auth signing secret. Generate with openssl rand -base64 32. |
AUTH_SIGNUP_ENABLED | Keep true for first setup; set false after creating initial users in shared environments. |
First-time host setup
Section titled “First-time host setup”sudo mkdir -p /opt/soliviosudo chown $USER:$USER /opt/soliviocd /opt/solivio
git clone --depth 1 https://github.com/solivio-ai/Solivio.git .
cp .env.production.example .env# Fill in: APP_HOST, LETSENCRYPT_EMAIL, POSTGRES_PASSWORD,# DATABASE_URL, BETTER_AUTH_URL, BETTER_AUTH_SECRET, and OPENAI_API_KEY.Generate secrets on the host:
openssl rand -base64 32Paste the value into BETTER_AUTH_SECRET.
Deploy
Section titled “Deploy”cd /opt/soliviogit pulldocker compose -f docker-compose.prod.yml pulldocker compose -f docker-compose.prod.yml up -dup -d starts the database, waits for it to become healthy, then starts the app.
The app container runs pending migrations before Next.js starts. Traefik requests
the TLS certificate from Let’s Encrypt the first time your configured host is
reached.
Open https://<APP_HOST>, create the first account, then consider setting
AUTH_SIGNUP_ENABLED=false and running docker compose -f docker-compose.prod.yml up -d
again.
Verify
Section titled “Verify”docker compose -f docker-compose.prod.yml pscurl -fsS https://<APP_HOST>/api/healthAll services should be running.
Rolling back
Section titled “Rolling back”Pin IMAGE_TAG to the last known-good SHA in /opt/solivio/.env, then:
docker compose -f docker-compose.prod.yml pulldocker compose -f docker-compose.prod.yml up -dCommon operations
Section titled “Common operations”docker compose -f docker-compose.prod.yml logs -f appdocker compose -f docker-compose.prod.yml logs -f traefikdocker compose -f docker-compose.prod.yml exec db psql -U solivio -d soliviodocker compose -f docker-compose.prod.yml restart appFrom local to live
Section titled “From local to live”After the app is reachable:
- Create an admin or evaluation account.
- Import a small CSV catalog from Catalog Upload.
- Generate a draft from New Offer using a real customer request.
- Review unmatched items and pricing in the offer review screen.
- Accept the draft and download the generated PDF.
- Disable public signup if the environment is shared.
Schema changes
Section titled “Schema changes”Production uses committed Drizzle migrations. For schema changes:
yarn db:generateyarn db:migrateReview generated SQL before merging to main; the app container applies the same
migrations on startup after the updated image is pulled.
Secrets
Section titled “Secrets”/opt/solivio/.env holds every secret used by the stack and is not committed. To rotate, edit the file and run docker compose -f docker-compose.prod.yml up -d.