LensHub
Get startedlenshub.ai
Get started

Quickstart · Self-hosted

From nothing to a working search, in about fifteen minutes.

You need Docker with Compose, about 6 GB of free disk, and 3 GB of spare RAM.

Create a working directory

mkdir lenshub && cd lenshub

Write .env

Generate real values — do not copy the examples.

echo "POSTGRES_DB=lenshub"                          >  .env
echo "POSTGRES_USER=lenshub"                        >> .env
echo "POSTGRES_PASSWORD=$(openssl rand -hex 16)"    >> .env
echo "JWT_SECRET=$(openssl rand -hex 32)"           >> .env
echo "ENCRYPTION_KEY=$(openssl rand -base64 32)"    >> .env
echo "LENSHUB_REGISTRY=<the registry path you were given>" >> .env

LENSHUB_REGISTRY is the container registry your images are pulled from. It comes with your access, along with the credentials to authenticate against it — see Getting access if you do not have it yet.

Back up ENCRYPTION_KEY before you go further. It encrypts your connector credentials. If you lose it, every stored credential becomes unreadable and has to be re-entered. If you change it, the same thing happens.

Write docker-compose.yml

services:
  postgres:
    image: ${LENSHUB_REGISTRY}/postgres:latest
    restart: unless-stopped
    volumes: [pgdata:/var/lib/postgresql/data]
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
      interval: 5s
      retries: 5

  api:
    image: ${LENSHUB_REGISTRY}/api:latest
    restart: unless-stopped
    ports: ["127.0.0.1:8080:8080"]
    depends_on:
      postgres: { condition: service_healthy }
    volumes: [uploads:/data/uploads, attachments:/data/attachments]
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=disable
      JWT_SECRET: ${JWT_SECRET}
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}
      LLM_EMBED_BASE_URL: http://embedding:8001/v1
      BASE_URL: http://localhost:3000
      CORS_ORIGIN: http://localhost:3000

  web:
    image: ${LENSHUB_REGISTRY}/web:latest
    restart: unless-stopped
    ports: ["127.0.0.1:3000:3000"]
    depends_on: [api]
    environment:
      NEXT_PUBLIC_API_URL: http://localhost:8080
      API_INTERNAL_URL: http://api:8080

  worker:
    image: ${LENSHUB_REGISTRY}/worker:latest
    restart: unless-stopped
    depends_on:
      postgres: { condition: service_healthy }
    volumes: [git-clones:/tmp/lenshub-git-clones, attachments:/data/attachments]
    environment:
      DATABASE_URL: postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=disable
      ENCRYPTION_KEY: ${ENCRYPTION_KEY}
      LLM_EMBED_BASE_URL: http://embedding:8001/v1

  embedding:
    image: ${LENSHUB_REGISTRY}/embedding:latest
    restart: unless-stopped
    volumes: [embedding-models:/data]

volumes:
  pgdata:
  uploads:
  attachments:
  git-clones:
  embedding-models:

Start it

docker login <your registry host>   # with the credentials you were given
docker compose pull
docker compose up -d

The first pull is around 4 GB. Watch for everything to become healthy:

docker compose ps

Create your first user

The database starts empty. This creates an administrator and prints an API key.

docker compose run --rm \
  -e SEED_ADMIN_EMAIL=you@yourcompany.com \
  -e SEED_ADMIN_PASSWORD='pick-a-strong-one' \
  api /app/lenshub seed

Save the API key it prints. It is shown once. You can always create more later in Settings.

The command refuses to run a second time once an administrator exists, so it is safe to leave in your notes.

Sign in

Open http://localhost:3000 and log in with the email and password you just used.

Next

  1. Connect an AI provider — needed for chat and automatic tagging. Search works without it.
  2. Add your first connector — start with a git repository; it is the fastest to see working.
  3. Connect your first agent.

This setup binds everything to 127.0.0.1 and runs without HTTPS, which is right for trying it out on one machine. Before anyone else uses it, read Putting it on a network.

On this page