Quickstart
Deploy CodeVector in under 10 minutes on any cloud or on-prem. Pre-built container images, Let's Encrypt TLS, and a single-command upgrade path.
Your gateway URL
Pin your own gateway hostname and we'll rewrite the routes and curl examples on every docs page so you can click straight through to the live console. Stored locally in your browser.
This guide gets CodeVector running in under 10 minutes. The product is a small stack of three container services (the API, a database, and a TLS reverse proxy) that runs anywhere you run containers: AWS, GCP, Azure, on-prem, or any single host.
The walkthrough below uses Docker on a single Linux host because it’s the fastest path from zero to a working install. The same prebuilt images run on Kubernetes, ECS, Nomad, or any other container orchestrator; adapt the manifest to whatever you already use.
Prerequisites
- A host or cluster with a container runtime (Docker, containerd, Kubernetes, etc.).
- A DNS A/AAAA record pointing your domain at the host.
- Inbound TCP 80 and 443 reachable from the public internet for the Let’s Encrypt HTTP-01 challenge.
1. Create the deployment files
On the target host, create a working directory and two files: compose.yml and .env.
mkdir codevector && cd codevector
Save the following as compose.yml:
# Reference production stack for codevector.
#
# Services:
# traefik - TLS termination + ACME (Let's Encrypt) on :80/:443
# app - codevector container (nginx + node via supervisord) on :8080
# db - PostgreSQL 18 (bookworm, non-alpine for performance)
# migrate - one-shot migration runner; run via `docker compose run --rm migrate`
#
# All secrets are injected via a gitignored `.env` sibling file.
#
# First deploy:
# 1. Fill in .env values
# 2. docker login registry.codevector.ai -u license -p "$LICENSE_TOKEN"
# 3. docker compose run --rm migrate
# 4. docker compose up -d
#
# Upgrades:
# docker compose pull && docker compose run --rm migrate && docker compose up -d
x-logging: &default-logging
driver: json-file
options:
max-size: "10m"
max-file: "5"
services:
traefik:
image: traefik:v3.6
container_name: codevector-traefik
restart: unless-stopped
command:
- --providers.docker=true
- --providers.docker.exposedbydefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
- --entrypoints.web.http.redirections.entrypoint.permanent=true
- --certificatesresolvers.letsencrypt.acme.email=${ACME_EMAIL:?ACME_EMAIL is required (email for Let's Encrypt notifications)}
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge=true
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
- --log.level=INFO
- --log.format=json
- --accesslog=true
- --accesslog.format=json
ports:
- "80:80"
- "443:443"
volumes:
- traefik_letsencrypt:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
logging: *default-logging
app:
image: registry.codevector.ai/flotorch/codevector:latest
container_name: codevector-app
restart: unless-stopped
expose:
- "8080"
depends_on:
db:
condition: service_healthy
environment:
# --- Server ---
PORT: "9000"
NODE_ENV: production
LOG_LEVEL: ${LOG_LEVEL:-info}
LOG_FORMAT: ${LOG_FORMAT:-json}
# --- Database ---
# Auto-built from POSTGRES_* + the compose service name (`db`).
# To point at an external/managed Postgres, replace the whole line with
# DATABASE_URL: ${DATABASE_URL} and drop the `db` service.
DATABASE_URL: "postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-codevector}"
DATABASE_LOGGER: "false"
# --- Session + envelope encryption ---
SESSION_SECRET: ${SESSION_SECRET:?SESSION_SECRET is required (exactly 32 chars)}
KEK_PRIMARY: ${KEK_PRIMARY:?KEK_PRIMARY is required (min 32 chars)}
KEK_SECONDARY: ${KEK_SECONDARY:-}
# --- Gateway + license ---
# Auto-built from DOMAIN. Override by setting GATEWAY_PUBLIC_URL in .env if you
# terminate TLS somewhere other than this stack's traefik.
GATEWAY_PUBLIC_URL: "https://${DOMAIN}"
LICENSE_TOKEN: ${LICENSE_TOKEN:?LICENSE_TOKEN is required}
# --- SMTP (optional) ---
SMTP_HOST: ${SMTP_HOST:-}
SMTP_PORT: ${SMTP_PORT:-587}
SMTP_USER: ${SMTP_USER:-}
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
SMTP_FROM: ${SMTP_FROM:-}
# --- Retention + catalog ---
RETENTION_MONTHS: ${RETENTION_MONTHS:-13}
ENABLE_REMOTE_CATALOG: ${ENABLE_REMOTE_CATALOG:-false}
CATALOG_SYNC_URL: ${CATALOG_SYNC_URL:-}
CATALOG_SYNC_PUBKEY: ${CATALOG_SYNC_PUBKEY:-}
# --- Degraded-mode on-disk usage buffer (mounted) ---
USAGE_BUFFER_DIR: /var/lib/codevector/usage-buffer
volumes:
- usage_buffer:/var/lib/codevector/usage-buffer
healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8080/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
labels:
- "traefik.enable=true"
- "traefik.http.routers.codevector.rule=Host(`${DOMAIN:?DOMAIN is required (e.g. gateway.acme.com)}`)"
- "traefik.http.routers.codevector.entrypoints=websecure"
- "traefik.http.routers.codevector.tls=true"
- "traefik.http.routers.codevector.tls.certresolver=letsencrypt"
- "traefik.http.services.codevector.loadbalancer.server.port=8080"
logging: *default-logging
db:
image: postgres:18-bookworm
container_name: codevector-db
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
POSTGRES_DB: ${POSTGRES_DB:-codevector}
# Pin the data directory path so it's stable across Postgres major upgrades.
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres} -d ${POSTGRES_DB:-codevector}"]
interval: 5s
timeout: 5s
retries: 10
logging: *default-logging
# One-shot migration runner. Uses the same image as `app`; overrides the command.
# Invoke: `docker compose run --rm migrate`
migrate:
image: registry.codevector.ai/flotorch/codevector:latest
container_name: codevector-migrate
profiles: ["migrate"]
command: ["/usr/local/bin/migrate.sh"]
depends_on:
db:
condition: service_healthy
restart: "no"
environment:
DATABASE_URL: "postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-codevector}"
logging: *default-logging
volumes:
postgres_data:
traefik_letsencrypt:
usage_buffer:
Save the following as .env (you will fill in real values in step 2):
# CodeVector environment variables.
# All values marked REQUIRED must be set; the stack refuses to start otherwise.
# --- Reverse proxy / TLS (traefik) ---
# REQUIRED. Public hostname served by this deployment.
DOMAIN=gateway.example.com
# REQUIRED. Email registered with Let's Encrypt for certificate notifications.
ACME_EMAIL=ops@example.com
# --- Database ---
# REQUIRED. Password for the postgres superuser used by the app.
POSTGRES_PASSWORD=change-me-to-a-strong-random-string
# Optional. Defaults: postgres / codevector.
POSTGRES_USER=postgres
POSTGRES_DB=codevector
# --- Session + envelope encryption ---
# REQUIRED. Exactly 32 characters. Used to sign session cookies.
# openssl rand -hex 16
SESSION_SECRET=your-32-character-session-secret
# REQUIRED. Minimum 32 characters. Key-encryption key for envelope-encrypted
# provider credentials.
# openssl rand -hex 32
KEK_PRIMARY=your-32-byte-primary-kek-in-hex
# Optional. Previous KEK during rotation.
KEK_SECONDARY=
# --- Gateway + license ---
# GATEWAY_PUBLIC_URL is auto-built in compose.yml as https://${DOMAIN}. Override
# only if you terminate TLS outside this stack.
# GATEWAY_PUBLIC_URL=https://gateway.example.com
# REQUIRED. License token issued by CodeVector.
LICENSE_TOKEN=your-license-token-from-codevector
# --- SMTP (optional, for invite and password-reset emails) ---
# Leave SMTP_HOST unset to disable email.
SMTP_HOST=
SMTP_PORT=587
SMTP_USER=
SMTP_PASSWORD=
SMTP_FROM=
# --- Catalog ---
ENABLE_REMOTE_CATALOG=false
CATALOG_SYNC_URL=
CATALOG_SYNC_PUBKEY=
# --- Logging + retention ---
LOG_LEVEL=info
LOG_FORMAT=json
RETENTION_MONTHS=13
Lock down the secrets file:
chmod 600 .env
The manifest is a Compose-format file that runs as-is on Docker or any Compose-compatible runtime. For Kubernetes, ECS, Nomad, or another orchestrator, see the Configuration reference for the full environment-variable list and translate the manifest into your platform’s format.
2. Configure secrets
Generate strong random values:
# SESSION_SECRET - must be exactly 32 chars
openssl rand -hex 16
# KEK_PRIMARY - min 32 chars
openssl rand -hex 32
# POSTGRES_PASSWORD - anything strong
openssl rand -base64 32
Open .env and replace the placeholder values for SESSION_SECRET, KEK_PRIMARY, and POSTGRES_PASSWORD with the generated values, then set:
DOMAIN- the hostname you will serve onACME_EMAIL- Let’s Encrypt registration emailLICENSE_TOKEN- contact the CodeVector team to obtain one
DATABASE_URL and GATEWAY_PUBLIC_URL are auto-constructed from POSTGRES_* and DOMAIN unless you override them.
3. Authenticate to the image registry
The image is served by CodeVector’s license-aware registry proxy. Authenticate with your license token as the password:
echo "$LICENSE_TOKEN" | docker login registry.codevector.ai -u license --password-stdin
Username can be anything (license is just a convention). The same token is
your LICENSE_TOKEN; the proxy verifies its signature server-side before any
pull. The login is host-wide; you do not need to repeat it for upgrades.
4. Pull and migrate
Pull the image and run migrations:
docker compose pull
docker compose run --rm migrate
The migrate service is under profiles: ["migrate"] so it does not start automatically with up. Always run it explicitly before up on any deploy that may include new migrations.
5. Start the stack
docker compose up -d
Traefik will obtain a certificate from Let’s Encrypt on the first request to ${DOMAIN}. Allow about 30 seconds, then check:
docker compose logs -f traefik
6. Verify
Visit https://${DOMAIN} in a browser. You should see the sign-in page. Create your first admin account through the setup wizard.
Upgrades
docker compose pull
docker compose run --rm migrate
docker compose up -d
If a release calls for changes to compose.yml or new environment variables, the release notes include the diff to apply.
Pin a specific tag in production by setting image: registry.codevector.ai/flotorch/codevector:v1.2.0 in compose.yml. latest is convenient but not reproducible.
Frequently asked questions
Do I need to build the image myself?
No. Production deployments use pre-built container images from the registry. You only need the deployment manifest, your environment configuration, and a configured secrets source.
Where can I deploy CodeVector?
Any cloud or on-prem environment that runs containers. The single-host walkthrough above uses Docker on a Linux host because it is the fastest path from zero to running. The same prebuilt images run on Kubernetes, ECS, Nomad, or any other container orchestrator.
What are the minimum host requirements?
A Linux host with a container runtime (or a cluster equivalent), and inbound TCP 80 + 443 reachable from the internet for Let’s Encrypt.
How do I get a license token?
. A license token is required before the server will start.
Can I use an external Postgres instead of the container?
Yes. Set DATABASE_URL and GATEWAY_PUBLIC_URL in .env to override the auto-constructed defaults.
Related docs
- Configuration. Full environment variable reference and secrets modes.
- License. License states and seat usage.