> For the complete documentation index, see [llms.txt](https://docs.meganova.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.meganova.ai/libra-os/install.md).

# Install

> **Note:** Pull the public Libra OS Docker image and have a working gateway in under five minutes. This page is for operators standing up a self-hosted instance. If you already have one running and want to point your Anthropic SDK at it, jump to the [Anthropic SDK Quickstart](/libra-os/anthropic-sdk-quickstart.md) instead.

This is the operator path — for teams provisioning Libra OS for the first time, whether for evaluation or production.

> ⚠️ **License Notice**
>
> The **Libra OS server** is provided for **evaluation and development use** under the Business Source License. Production deployments require a commercial license — contact <contact@meganova.ai> for pricing.
>
> The **SDK** (Python, CLI, OpenAPI) at [`libraos/sdk`](https://github.com/libraos/sdk) is **MIT-licensed** and free to use commercially.

## What you'll do

1. Pull the Docker image from the public registry.
2. Provide three environment variables (database, JWT secret, LLM API key).
3. Run a smoke test against `/api/health`.

That's the minimum. Optional steps cover docker-compose, Kubernetes, and reverse-proxy setup.

***

## Step 1 — Prerequisites

| Requirement                      | Notes                                                                                                                                                                                        |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Docker 20.10+ or any OCI runtime | `linux/amd64` and `linux/arm64` images are published; pick the one that matches your host                                                                                                    |
| PostgreSQL 14+                   | Used for users, agents, settings, audit log. SQLite is **not** supported.                                                                                                                    |
| An LLM API key                   | One of `OPENAI_API_KEY` (any OpenAI-compatible endpoint), `ANTHROPIC_API_KEY`, or `GOOGLE_API_KEY`. A MegaNova-issued key works for all three via `OPENAI_API_BASE=https://api.meganova.ai`. |
| ≥ 2 GB RAM, ≥ 1 vCPU             | Conservative floor for a single-tenant evaluation. Production sizing depends on the tier model split (premium answer model is the dominant cost)                                             |

GPU is optional. Embeddings can run via the configured LLM gateway (recommended) or against a local Ollama you already have running. No CUDA or NVIDIA driver setup is required for the gateway path.

***

## Step 2 — Pull the image

The image lives at `ghcr.io/libraos/libraos` and is public — no GitHub login required.

```bash
docker pull ghcr.io/libraos/libraos:v0.1.19
```

**Choosing a tag:**

| Tag                                                       | When to use it                                                                                                                 |
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `:v0.1.5` (or any specific version)                       | Production. Pins to an exact release. Recommended.                                                                             |
| `:latest`                                                 | Tracks the most recent **stable** release. Pre-release tags (`-rc`, `-beta`, `-alpha`) do NOT update `:latest`.                |
| `:v0.1.5-week-2026-05-09` (weekly partner-validation tag) | Bake against new functionality before the production cutover. Weekly and RC tags are pre-1.0 and may include breaking changes. |

The full list of available tags lives at [GitHub Container Registry → libraos/libraos](https://github.com/orgs/libraos/packages/container/package/libraos) and on the [Releases page](https://github.com/libraos/sdk/releases).

> **No GHCR auth needed.** The image is public regardless of the source repo's visibility. If a `docker pull` fails with `denied: requested access to the resource is denied`, your Docker client is sending stale credentials — try `docker logout ghcr.io` first.

***

## Step 3 — First run

Provide three environment variables and start the container:

```bash
docker run -d --name libraos \
  -p 8900:8900 \
  -e LIBRA_OS_DATABASE_URL="postgres://nova:secret@host.docker.internal:5432/nova_os" \
  -e LIBRA_OS_JWT_SECRET="$(openssl rand -hex 32)" \
  -e OPENAI_API_KEY="<your-llm-key>" \
  -e OPENAI_API_BASE="https://api.meganova.ai" \
  ghcr.io/libraos/libraos:v0.1.19
```

The container exposes the API on port `8900`. First boot runs database migrations automatically — expect \~5 seconds before `/api/health` returns `200`.

### Required environment variables

| Variable                  | Required                                      | Notes                                                                                                                                                                                                                                                                                                                 |
| ------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `LIBRA_OS_DATABASE_URL`   | yes                                           | PostgreSQL connection string. The container does **not** ship Postgres — point at your own.                                                                                                                                                                                                                           |
| `LIBRA_OS_JWT_SECRET`     | yes                                           | ≥ 32 hex chars. Used to sign user JWTs. Lose this and all existing tokens become invalid.                                                                                                                                                                                                                             |
| `OPENAI_API_KEY`          | yes (or `ANTHROPIC_API_KEY`/`GOOGLE_API_KEY`) | LLM provider key. The MegaNova gateway issues a single key that covers all three providers.                                                                                                                                                                                                                           |
| `OPENAI_API_BASE`         | recommended                                   | Default `https://api.openai.com`. Set to `https://api.meganova.ai` to use MegaNova's multi-provider gateway. On a MegaNova **Token Plan**, use `https://enterprise.api.meganova.ai` instead so usage draws the plan allowance — see the [Libra OS integration guide](https://docs.meganova.ai/enterprise/token-plan). |
| `LIBRA_OS_ADMIN_EMAIL`    | first boot only                               | Auto-creates an admin user on a fresh database. Subsequent boots ignore this.                                                                                                                                                                                                                                         |
| `LIBRA_OS_ADMIN_PASSWORD` | first boot only                               | Pair with `LIBRA_OS_ADMIN_EMAIL`.                                                                                                                                                                                                                                                                                     |

A complete env-var reference lives in the [Admin Guide](/libra-os/admin-guide.md).

***

## Step 4 — Smoke test

```bash
# 1. Health probe (no auth required)
curl http://localhost:8900/api/health
# {"status":"ok","version":"v0.1.5","build_sha":"..."}

# 2. Log in to get a JWT
JWT=$(curl -s -X POST http://localhost:8900/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@example.com","password":"<your-admin-password>"}' \
  | python3 -c "import json,sys; print(json.load(sys.stdin)['access_token'])")

# 3. List registered agents (proves the registry loaded cleanly)
curl http://localhost:8900/v1/agents \
  -H "Authorization: Bearer $JWT" \
  -H "anthropic-beta: managed-agents-2026-04-01"
```

If all three commands return without error, you have a working Libra OS gateway. The next step is pointing your client at it — see the [Anthropic SDK Quickstart](/libra-os/anthropic-sdk-quickstart.md).

***

## Optional — Docker Compose

> **For production deploys**, use the pre-built manifests at [`libraos/stack`](https://github.com/libraos/stack) instead of the inline example below. That repo gives you the core (Libra OS + Postgres + SurrealDB) plus optional companion apps (LibreChat chat UI, SearXNG, crawl4ai, Firecrawl, Docling, FlashRank, Phoenix, Hermes) as independent overlay compose files. Required secrets use the fail-fast `${VAR:?required - hint}` pattern instead of insecure inline defaults.

For a single-host evaluation that also stands up Postgres in the same compose file:

```yaml
# docker-compose.yml
services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: nova_os
      POSTGRES_USER: nova
      POSTGRES_PASSWORD: change-me-in-prod
    volumes:
      - pg-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U nova"]
      interval: 5s

  libraos:
    image: ghcr.io/libraos/libraos:v0.1.19
    depends_on:
      postgres:
        condition: service_healthy
    ports:
      - "8900:8900"
    environment:
      LIBRA_OS_DATABASE_URL: postgres://nova:change-me-in-prod@postgres:5432/nova_os
      LIBRA_OS_JWT_SECRET: change-me-32-hex-chars-or-more
      OPENAI_API_KEY: ${OPENAI_API_KEY}
      OPENAI_API_BASE: https://api.meganova.ai
      LIBRA_OS_ADMIN_EMAIL: admin@example.com
      LIBRA_OS_ADMIN_PASSWORD: ${ADMIN_PASSWORD}

volumes:
  pg-data:
```

Bring it up:

```bash
ADMIN_PASSWORD="<pick-a-password>" OPENAI_API_KEY="<your-key>" docker compose up -d
```

> **Production caveat.** This compose file is fine for evaluation. For production: don't put `JWT_SECRET` and `ADMIN_PASSWORD` in inline literals; use a secrets manager (Docker Secrets, Vault, or Kubernetes Secrets). And put a TLS-terminating reverse proxy (Caddy, nginx, Traefik) in front — Libra OS speaks plain HTTP on `:8900`.

***

## Optional — Behind a reverse proxy

The container speaks plain HTTP. Terminate TLS at your edge.

**Caddy** (the simplest path — automatic Let's Encrypt):

```caddy
libra-os.your-company.example {
    reverse_proxy localhost:8900
}
```

**nginx** (when you already have nginx infra):

```nginx
server {
    server_name libra-os.your-company.example;
    listen 443 ssl http2;
    ssl_certificate     /etc/letsencrypt/live/libra-os.../fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/libra-os.../privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8900;
        proxy_http_version 1.1;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # SSE streaming endpoints — these flags are load-bearing
        proxy_buffering            off;
        proxy_cache                off;
        chunked_transfer_encoding  off;
        proxy_read_timeout         600s;
    }
}
```

The streaming-related flags are required for `/v1/messages` and `/v1/chat/completions` to work over HTTP/2 + Cloudflare. Without them, Cloudflare returns `ERR_HTTP2_PROTOCOL_ERROR` mid-stream.

***

## Worked example — minimum viable instance

The smallest working setup, end to end:

```bash
# 1. Postgres (any port-reachable instance — this just spins one up locally)
docker run -d --name nova-pg \
  -e POSTGRES_DB=nova_os -e POSTGRES_USER=nova -e POSTGRES_PASSWORD=secret \
  -p 5432:5432 postgres:16-alpine

# 2. Libra OS
docker run -d --name libraos -p 8900:8900 \
  -e LIBRA_OS_DATABASE_URL="postgres://nova:secret@host.docker.internal:5432/nova_os" \
  -e LIBRA_OS_JWT_SECRET="$(openssl rand -hex 32)" \
  -e OPENAI_API_KEY="<your-key>" \
  -e OPENAI_API_BASE="https://api.meganova.ai" \
  -e LIBRA_OS_ADMIN_EMAIL="admin@example.com" \
  -e LIBRA_OS_ADMIN_PASSWORD="changeme-please-12chars" \
  ghcr.io/libraos/libraos:v0.1.19

# 3. Verify
sleep 5 && curl http://localhost:8900/api/health
```

Open `http://localhost:8900/` in a browser to see the dashboard, log in with the admin credentials, and start binding collections to agents per the [Admin Guide](/libra-os/admin-guide.md).

***

## Troubleshooting

### `docker pull` fails with `manifest unknown` or `not found`

The tag you requested doesn't exist. Check the [GHCR package page](https://github.com/orgs/libraos/packages/container/package/libraos) for available tags. Pre-release tags use `-rcN` / `-betaN` suffixes; stable releases are bare semver (`v0.1.19`).

### `docker pull` fails with `denied: requested access to the resource is denied`

Your Docker client is sending stale GHCR credentials for a different package. Run `docker logout ghcr.io` and retry.

### `libraos` container exits immediately with `failed to connect to database`

The `LIBRA_OS_DATABASE_URL` value isn't reachable from inside the container. Common causes:

* `localhost` inside a container points to the container itself, not the host. Use `host.docker.internal` (Docker Desktop) or the host's LAN IP.
* The Postgres container isn't accepting external connections — pass `-p 5432:5432` when running it.
* Wrong username/password — Postgres logs the rejection at startup.

### Container starts, `/api/health` returns 200, but `/v1/messages` returns 500 with `no LLM API keys configured`

Either no provider key is set, or the key isn't reaching the container. Confirm with `docker exec libraos env | grep -E 'OPENAI|ANTHROPIC|GOOGLE'`.

### `HTTP 401 — invalid token: token expired` after a few hours

JWT lifetime defaults to short. The Anthropic SDK and dashboard both auto-refresh; bare `curl` doesn't. Re-issue via `POST /api/auth/login` or generate a long-lived service token from the admin dashboard.

### `HTTP 426 Upgrade Required` on `/v1/agents` or `/v1/sessions`

Managed Agents endpoints require the beta header. Add `-H "anthropic-beta: managed-agents-2026-04-01"` to your request. The Messages API at `/v1/messages` does **not** require it — it's GA.

***

## Known limitations

* **No SQLite.** Postgres is required. The schema uses Postgres-specific features (JSONB, partial indexes, advisory locks). SQLite is not on the roadmap.
* **No bundled Ollama.** The image doesn't ship local LLM weights. Set `OPENAI_API_BASE` to a gateway you trust (MegaNova or your own); for fully on-prem inference, run Ollama separately and point `OPENAI_API_BASE` at it.
* **Stateful upgrades.** Schema migrations run on container start. For multi-replica deployments, run one replica at a time across an upgrade boundary; concurrent migrations on the same database race.
* **No multi-tenant isolation across instances.** Per-user filesystem and per-tenant agent overrides exist within an instance; running tenants on truly-isolated instances is the path for hard tenancy boundaries.

These are intentional v0 scope cuts.

***

## Next steps

* [**Anthropic SDK Quickstart**](/libra-os/anthropic-sdk-quickstart.md) — point your existing Anthropic-SDK code at the gateway you just installed
* [**Documents & Knowledge**](/libra-os/documents-and-knowledge.md) — upload files so agents can retrieve from them
* [**Admin Guide**](/libra-os/admin-guide.md) — agent-to-collection bindings, system status, troubleshooting
* [**Releases**](/libra-os/releases.md) — what's new in each version, migration notes
* [**`libraos/stack`**](https://github.com/libraos/stack) — production-grade compose manifests, plus 8 optional companion apps (LibreChat chat UI, SearXNG, crawl4ai, Firecrawl, Docling, FlashRank, Phoenix, Hermes)
