> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sevalla.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These are the docs for Sevalla, a platform for deploying applications, databases, static sites, object storage and load balancers. The dashboard is at https://app.sevalla.com.
> Bold text in steps is an exact dashboard label.
> To act on a Sevalla account, prefer the Sevalla MCP server (https://mcp.sevalla.com/mcp, see https://docs.sevalla.com/ai-agents/overview.md), then the Sevalla CLI (https://docs.sevalla.com/developer-tools/cli.md), then the REST API (https://api-docs.sevalla.com, OpenAPI spec at https://api.sevalla.com/v3/openapi.json).
> Every page index is at https://docs.sevalla.com/llms.txt.

# Deploy AnythingLLM

> Run AnythingLLM from its official image with its storage on a disk and a password from the first start, chat with your documents through Claude, LiteLLM or Ollama, and use its API.

AnythingLLM runs on Sevalla as an application from its official Docker image, `mintplexlabs/anythingllm`: the web process serves the chat interface, the developer API and the document collector, and a disk keeps everything AnythingLLM stores, from its SQLite database and your uploaded documents to the vectors in LanceDB and the embedding model. AnythingLLM embeds documents on the CPU with its built-in embedder, so a document chat needs only a model provider: Anthropic in this guide, or [LiteLLM](https://docs.sevalla.com/guides/ai/litellm.md) or [Ollama](https://docs.sevalla.com/guides/ai/ollama.md) on Sevalla over an internal connection.

## At a glance

| | |
| - | - |
| Source | The `mintplexlabs/anythingllm:1.19.0` Docker image |
| Start command | The image's own, `/bin/bash /usr/local/bin/docker-entrypoint.sh`, which runs the database migrations and starts the server and the document collector |
| Port | `8080`, from `SERVER_PORT` (AnythingLLM's default is `3001`) |
| Processes | Web process |
| Services | None. Optionally [LiteLLM](https://docs.sevalla.com/guides/ai/litellm.md) or [Ollama](https://docs.sevalla.com/guides/ai/ollama.md) over an internal connection |
| Disk | 10 GB at `/app/server/storage`, on the web process |
| Health check | `GET /api/ping` returns `200` (readiness probe) |
| Size | **S1** (0.5 vCPU, 1 GB) |

### Environment variables

| Variable | Required | Available during | Secret | Value |
| - | - | - | - | - |
| `STORAGE_DIR` | Yes | Runtime | No | `/app/server/storage`, the disk's path |
| `SERVER_PORT` | Yes | Runtime | No | `8080`, the web process port |
| `AUTH_TOKEN` | Yes | Runtime | Yes | The instance password. Generate with `openssl rand -base64 18` |
| `JWT_SECRET` | Yes | Runtime | Yes | Generate with `openssl rand -hex 32` |
| `SIG_KEY` | Yes | Runtime | Yes | Generate with `openssl rand -hex 32` |
| `SIG_SALT` | Yes | Runtime | Yes | Generate with `openssl rand -hex 32` |
| `LLM_PROVIDER` | Yes | Runtime | No | `anthropic`, or `litellm` or `ollama` for a provider on Sevalla |
| `ANTHROPIC_API_KEY` | For Anthropic | Runtime | Yes | Your Anthropic API key |
| `ANTHROPIC_MODEL_PREF` | For Anthropic | Runtime | No | `claude-haiku-5-5` |
| `LITE_LLM_BASE_PATH` | For LiteLLM | Runtime | No | `http://` plus LiteLLM's internal hostname plus `:8080` |
| `LITE_LLM_API_KEY` | For LiteLLM | Runtime | Yes | A virtual key for AnythingLLM from LiteLLM |
| `LITE_LLM_MODEL_PREF` | For LiteLLM | Runtime | No | A `model_name` from LiteLLM's `config.yaml`, for example `claude-haiku-5-5` |
| `OLLAMA_BASE_PATH` | For Ollama | Runtime | No | `http://` plus Ollama's internal hostname plus `:8080` |
| `OLLAMA_MODEL_PREF` | For Ollama | Runtime | No | A model you pulled in Ollama, for example `lfm3:1.7b` |
| `DISABLE_TELEMETRY` | No | Runtime | No | `true` stops AnythingLLM from sending anonymous usage events |

An application from a Docker image has no build, so every variable is a runtime variable. [Set the environment variables](#set-the-environment-variables) explains each one.

## Before you begin

* A Sevalla company with a payment method.
* An API key from [Anthropic](https://console.anthropic.com/), or a [LiteLLM proxy](https://docs.sevalla.com/guides/ai/litellm.md) or an [Ollama application](https://docs.sevalla.com/guides/ai/ollama.md) in the location where AnythingLLM will run.
* OpenSSL on your computer, to generate the secrets (`openssl version` prints its version).

## How AnythingLLM runs on Sevalla

| Part | Setup |
| - | - |
| Image | `mintplexlabs/anythingllm:1.19.0`, pinned to a release. It runs as the unprivileged user `anythingllm` (UID `1000`) |
| Storage | A disk at `/app/server/storage`. AnythingLLM keeps its SQLite database, uploaded documents, the LanceDB vectors and the downloaded embedding model there |
| Settings | Environment variables. Settings you change in AnythingLLM's own settings pages are written to `/app/server/.env`, which isn't on the disk. See [Keep settings in environment variables](#keep-settings-in-environment-variables) |
| Embeddings | The built-in embedder, `Xenova/all-MiniLM-L6-v2`, runs on the CPU and needs no key |
| Sign-in | `AUTH_TOKEN` protects the instance with a password from the first start. [Multi-user mode](#let-your-team-sign-in) adds accounts |
| Instances | 1, because the process has a disk. Each deployment stops the running instance before it starts the new one: in the tests, AnythingLLM answered `503` for about 40 seconds |

## Create the application

**1. Choose the image**

In the sidebar, click **Applications**, then click **Create** > **Application**. Under **Source**, click **Docker image** and enter `mintplexlabs/anythingllm:1.19.0` in **Docker image**. Keep the **Registry credential** at **None (public image)**.

**2. Name, place and size it**

Enter the **Name** `anythingllm`, choose the **Data center**, and choose the **Size** **S1**. To use LiteLLM or Ollama, choose the location where they run.

**3. Create it without deploying**

Click **Create application**. The application opens with the status **Not deployed yet**.

**4. Add the disk**

Click the **Disks** tab, then click **Create disk**. In **Process**, pick the web process. Enter the **Path** `/app/server/storage`, pick the **Size** `10 GB`, and click **Create disk**.

The tag pins one AnythingLLM release: `1.19.0` is the current one. AnythingLLM migrates its database when a new version starts, so pin a version and [update on purpose](#update-anythingllm).

## Set the environment variables

Generate the password and the three secrets on your computer, and store them in your password manager:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
openssl rand -base64 18
openssl rand -hex 32
openssl rand -hex 32
openssl rand -hex 32
```

On the application's **Environment variables** tab, click **Add environment variables**, paste these lines into the first key field, replace the password, the secrets and the Anthropic key with yours, and click **Add environment variables**:

```bash .env theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
STORAGE_DIR=/app/server/storage
SERVER_PORT=8080
AUTH_TOKEN=Q2hvb3NlIHlvdXIgb3du
JWT_SECRET=7c1e0f8a2b9d4e6f8a1c3e5b7d9f0a2c4e6b8d0f1a3c5e7b9d1f3a5c7e9b0d2f
SIG_KEY=3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a
SIG_SALT=9e1c3a5f7b9d1e3c5a7f9b1d3e5c7a9f1b3d5e7c9a1f3b5d7e9c1a3f5b7d9e1c
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=sk-ant-your-key
ANTHROPIC_MODEL_PREF=claude-haiku-5-5
DISABLE_TELEMETRY=true
```

| Variable | Why AnythingLLM needs it on Sevalla |
| - | - |
| `STORAGE_DIR` | Points AnythingLLM at the disk. The server falls back to the same path from a file in the image, but the start script checks the variable and logs `WARNING: STORAGE_DIR environment variable is not set!` without it |
| `SERVER_PORT` | AnythingLLM listens on `3001` unless told otherwise, and doesn't read `PORT`. `8080` matches the web process port, so you don't change the port on the **Networking** tab |
| `AUTH_TOKEN` | The password the sign-in page asks for. Without it, anyone who opens the domain can use the instance, read its documents and spend from your model account: every API answers without a password, including the one that turns on [multi-user mode](#let-your-team-sign-in) and creates the admin account |
| `JWT_SECRET` | Signs sign-in sessions. With `AUTH_TOKEN`, it's what turns password protection on |
| `SIG_KEY`, `SIG_SALT` | Encrypt the data AnythingLLM stores, including the password inside each session. Without them, AnythingLLM generates both into `/app/server/.env`, which the next deployment deletes |
| `LLM_PROVIDER`, `ANTHROPIC_API_KEY`, `ANTHROPIC_MODEL_PREF` | The chat model. `claude-haiku-5-5` is Anthropic's fastest and cheapest current model. With `LLM_PROVIDER` set, AnythingLLM skips its setup screens |
| `DISABLE_TELEMETRY` | Optional. AnythingLLM logs `[TELEMETRY DISABLED]` at start and sends no usage events |

## Add a readiness probe

A readiness probe tells Sevalla when the new version is ready to receive requests.

**1. Open the web process**

Click the **Processes** tab, click **⋯** on the web process, then click **Update process**.

**2. Turn on the probe**

Under **Health checks**, turn on **Readiness probe**, enter the **Path** `/api/ping`, the **Initial delay** `10` and the **Timeout** `5`. Keep the **Port** at `8080`.

**3. Save**

Click **Update process**.

## Deploy AnythingLLM

Click the **Overview** tab, click **Deploy now**, then click **Deploy**. The deployment pulls the image (about 1.1 GB) and starts the web process; there's no build. The first start creates the database on the disk.

## Verify the deployment

1. On the **Deployments** tab, the deployment's status is **Deployed**. With the API, [Get deployment](https://api-docs.sevalla.com/v3/applications/get-deployment) (`getDeploymentV3`) returns `"status": "success"`.

2. The application's [runtime logs](https://docs.sevalla.com/applications/logs.md) show `Primary server in HTTP mode listening on port 8080`.

3. The health endpoint answers:

   ```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
   curl -s https://anythingllm-x7k2m.sevalla.app/api/ping
   ```

   ```json theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
   {"online":true}
   ```

4. Without the password, AnythingLLM's APIs refuse requests:

   ```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
   curl -s https://anythingllm-x7k2m.sevalla.app/api/v1/workspaces
   ```

   ```json theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
   {"error":"No valid api key found."}
   ```

5. Open the domain. AnythingLLM shows **Welcome** and a password field. Enter `AUTH_TOKEN` and click **Login**.

## Chat with a document

A workspace is a set of documents and a chat. AnythingLLM splits each document into chunks, embeds them, and sends the chunks that match a question to the model with it.

**1. Create a workspace**

In AnythingLLM's sidebar, click **New Workspace**, enter the **Workspace Name** `Support`, and click **Save**.

**2. Upload a document**

Click the upload icon next to the workspace's name (**Upload documents to this workspace for RAG indexing**). Click **Click to upload or drag and drop** and pick a file, for example a shipping policy.

**3. Embed it**

Select the file under **My Documents**, click **Move to Workspace**, then click **Save and Embed**.

**4. Ask about it**

Close the window, type a question about the document in **Send a message**, and press Enter. The answer streams in and lists the document under its sources.

The upload, the chunks, the vectors and the chat history are on the disk, so they survive deployments. In the tests, a workspace, its documents and an API key were all still there after a deployment, and the same session stayed signed in.

## Use the API

AnythingLLM's developer API manages workspaces and documents and runs chats. Every request needs an API key in the `Authorization` header.

**1. Create an API key**

Click **Open settings** (the wrench icon at the bottom of the sidebar), then **Tools** > **Developer API**. Click **Generate New API Key**, optionally enter a **Name**, click **Create API Key**, and copy the key.

**2. Create a workspace**

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -X POST https://anythingllm-x7k2m.sevalla.app/api/v1/workspace/new \
  -H "Authorization: Bearer $ANYTHINGLLM_API_KEY" -H "Content-Type: application/json" \
  -d '{"name":"Support"}' | jq -r .workspace.slug
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
support
```

**3. Upload and embed a document**

Write a small document, upload it, and add it to the workspace in the same request with `addToWorkspaces`:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
cat > shipping-policy.md <<'EOF'
# Shipping policy

Acme Coffee Supply ships orders from Monday to Friday.

- Orders placed before 14:00 CET leave the warehouse the same day.
- Shipping within Germany costs 4.90 EUR and is free from 50 EUR.
- Shipping to Canada costs 19.90 EUR, takes 6 to 9 business days, and isn't available for grinders.
- Returns are accepted within 30 days, unopened.
EOF
curl -s -X POST https://anythingllm-x7k2m.sevalla.app/api/v1/document/upload \
  -H "Authorization: Bearer $ANYTHINGLLM_API_KEY" \
  -F "file=@shipping-policy.md" -F "addToWorkspaces=support" | jq -c '{success, title: .documents[0].title}'
```

```json theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
{"success":true,"title":"shipping-policy.md"}
```

**4. Ask about it**

`"mode":"query"` answers only from the workspace's documents:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -X POST https://anythingllm-x7k2m.sevalla.app/api/v1/workspace/support/chat \
  -H "Authorization: Bearer $ANYTHINGLLM_API_KEY" -H "Content-Type: application/json" \
  -d '{"message":"How much does shipping to Canada cost, and how long does it take?","mode":"query"}' \
  | jq -c '{textResponse, sources: [.sources[].title]}'
```

```json theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
{"textResponse":"Shipping to Canada costs 19.90 EUR and takes 6 to 9 business days.","sources":["shipping-policy.md"]}
```

The model writes the answer in its own words, so yours can differ. In the test, the answer took 2.6 seconds. Without a key, or with a wrong one, the API answers `403` with `{"error":"No valid api key found."}`. Store the key in the calling application's [environment variables](https://docs.sevalla.com/applications/environment-variables.md), never in front-end code: anyone with it can read every workspace and spend from your model account.

`/api/v1/workspace/support/stream-chat` takes the same body and returns the answer as Server-Sent Events (`Content-Type: text/event-stream`, `Cache-Control: no-cache`): one `textResponseChunk` event per piece of text, then `finalizeResponseStream`. Through Cloudflare and Sevalla's proxy, the first chunk arrived after 1.19 s and the last after 1.68 s, without buffering. The full API reference is at `/api/docs` on your domain.

## Embed large documents

The built-in embedder runs on the web process's CPU, and the upload request waits until the document is embedded. On **S1**, a 618 KB text file became 666 chunks and took 3 minutes 20 seconds to embed.

Through Cloudflare, a request that sends nothing for about 125 seconds ends with `524`: in the test, the upload request returned `524` with the page title `524: A timeout occurred` after 125.7 seconds. AnythingLLM kept embedding, and the document was in the workspace about a minute later. For large documents, upload them in the interface, which shows the progress, or check the workspace after the `524`. A larger size embeds faster.

## Use LiteLLM or Ollama on Sevalla

AnythingLLM can send chats to a model provider that runs on Sevalla instead of Anthropic. Both stay private: their HTTP traffic is off, and AnythingLLM reaches them over an internal connection.

| Provider | Use it for |
| - | - |
| [LiteLLM](https://docs.sevalla.com/guides/ai/litellm.md) | One virtual key and budget for AnythingLLM, with the models from LiteLLM's `config.yaml`, hosted or on Ollama |
| [Ollama](https://docs.sevalla.com/guides/ai/ollama.md) | Models that run on Sevalla's CPUs, with no provider account |

**1. Connect the provider**

On the `anythingllm` application's **Networking** tab, under **Connected services**, click **Add internal connection** and choose `litellm` or `ollama`. It needs no variables. Copy the provider's hostname from **Internal hostnames** on its own **Networking** tab, for example `litellm-q9w3e-web.litellm-q9w3e.svc.cluster.local`.

**2. Change the variables**

On the **Environment variables** tab, change `LLM_PROVIDER` and add the provider's variables:

**LiteLLM**

```bash .env theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
LLM_PROVIDER=litellm
LITE_LLM_BASE_PATH=http://litellm-q9w3e-web.litellm-q9w3e.svc.cluster.local:8080
LITE_LLM_API_KEY=sk-your-virtual-key
LITE_LLM_MODEL_PREF=claude-haiku-5-5
```

**Ollama**

```bash .env theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
LLM_PROVIDER=ollama
OLLAMA_BASE_PATH=http://ollama-k3j4h-web.ollama-k3j4h.svc.cluster.local:8080
OLLAMA_MODEL_PREF=lfm3:1.7b
```

**3. Deploy**

Click the **Overview** tab, click **Deploy now**, then click **Deploy**.

`LITE_LLM_MODEL_PREF` is a `model_name` from LiteLLM's `config.yaml`, and `LITE_LLM_API_KEY` is a [virtual key for AnythingLLM](https://docs.sevalla.com/guides/ai/litellm.md#create-a-key-for-each-application), so LiteLLM tracks its spend. In the test, with LiteLLM's HTTP traffic off and `claude-haiku-5-5` behind it, the [document question](#use-the-api) got the same answer through LiteLLM in 6.1 seconds. AnythingLLM sends no `temperature` unless you set one on the workspace, which matters for `claude-haiku-5-5`: LiteLLM rejects any value other than `1` for it with `claude-haiku-5-5 does not support temperature=0.7. Only temperature=1 is supported.`

Without `LITE_LLM_MODEL_TOKEN_LIMIT` or `OLLAMA_MODEL_TOKEN_LIMIT`, AnythingLLM assumes the model reads 4,096 tokens and sends fewer document chunks with each question. Set it to the model's context window to send more. The embedder stays the built-in one; to embed with Ollama too, set `EMBEDDING_ENGINE=ollama`, `EMBEDDING_BASE_PATH` and `EMBEDDING_MODEL_PREF` , and embed your documents again.

## Keep settings in environment variables

AnythingLLM's settings pages, such as **AI Providers** > **LLM**, save their values into the running process and into `/app/server/.env`, a file in the image, not on the disk. Each deployment starts from the image again, and the environment variables on Sevalla win. In the tests, changing the model to `claude-sonnet-5-5` in AnythingLLM worked until the next deployment, which set it back to `ANTHROPIC_MODEL_PREF`.

Change the model, the provider and the keys on the application's **Environment variables** tab, then deploy. Settings that AnythingLLM keeps in its database, such as workspaces, users, a workspace's own model and the system prompt, live on the disk and stay.

## Let your team sign in

With `AUTH_TOKEN` alone, everyone shares one password and one set of chats. Multi-user mode gives each person an account with a role.

**1. Turn on multi-user mode**

Click **Open settings**, then **Security**. Under **Multi-User Mode**, turn on **Enable Multi-User Mode**, enter the **Admin account username** and **Admin account password**, and click **Save changes**.

**2. Add people**

Click **Admin** > **Users**, then **Add user** for each person. Give each one a role, and add them to workspaces on the workspace's settings.

Only someone with `AUTH_TOKEN` can turn multi-user mode on. After that, AnythingLLM asks for a username and a password: `AUTH_TOKEN` alone returns `[001] Invalid login credentials.`, and existing sessions end with `{"error":"Invalid auth token."}`. Developer API keys keep working. The accounts are in the database on the disk, so they survive deployments; keep `JWT_SECRET`, `SIG_KEY` and `SIG_SALT` unchanged: in the tests, a new `JWT_SECRET` signed everyone out, and old sessions got `{"error":"Token expired or failed validation."}`.

## Update AnythingLLM

**1. Read the release notes**

Read the notes of every version between yours and the new one on [AnythingLLM's GitHub releases](https://github.com/Mintplex-Labs/anything-llm/releases).

**2. Change the image**

On the application's **Settings** tab, in the **Source** section, click **Update source**, change the tag in **Docker image**, and click **Update source**.

**3. Deploy**

Deploy. AnythingLLM migrates its database on the disk when the new version starts.

Sevalla [backs up the disk](https://docs.sevalla.com/applications/disks.md#backups) every day and keeps each backup for 7 days. To go back after a failed update, set the previous tag and [contact support](https://docs.sevalla.com/support/get-help.md) to restore the disk from the backup before the update.

## Add a custom domain

To serve AnythingLLM from your own domain, such as `docs-chat.example.com`, add the domain on the application's **Domains** tab and create the DNS records Sevalla shows. **S1** is larger than **H1**, so custom domains work. See [Custom domains](https://docs.sevalla.com/domains/overview.md).

## Troubleshoot

| Symptom | Cause | Fix |
| - | - | - |
| Anyone who opens the domain can chat without a password | `AUTH_TOKEN` or `JWT_SECRET` isn't set | Set both and deploy. See [Set the environment variables](#set-the-environment-variables) |
| Workspaces, documents and the password session are gone after a deployment | The web process has no disk at `/app/server/storage` | Add the disk, then deploy. See [Create the application](#create-the-application) |
| A model or provider changed in AnythingLLM's settings is back to the old one after a deployment | The settings page writes to `/app/server/.env`, outside the disk | Change the environment variable on Sevalla. See [Keep settings in environment variables](#keep-settings-in-environment-variables) |
| An upload through the API returns `524` after about 125 seconds | Embedding a large document takes longer than Cloudflare waits | Wait and check the workspace: AnythingLLM keeps embedding. See [Embed large documents](#embed-large-documents) |
| Everyone has to sign in again after a deployment, and an old session token returns `401` with `{"error":"Token expired or failed validation."}` | `JWT_SECRET` changed, or `SIG_KEY` or `SIG_SALT` | Keep the three secrets unchanged. Sign in again with `AUTH_TOKEN` |
| The API answers `403` with `{"error":"No valid api key found."}` | The request has no developer API key, or a deleted one | Send a key from **Tools** > **Developer API** in `Authorization: Bearer` |
| Sign-in with the password returns `[001] Invalid login credentials.` | Multi-user mode is on | Sign in with a username and password. See [Let your team sign in](#let-your-team-sign-in) |
| A chat through LiteLLM fails with `claude-haiku-5-5 does not support temperature=0.7. Only temperature=1 is supported.` | The workspace has a temperature set | Clear the workspace's temperature, or set `drop_params: true` in LiteLLM's `litellm_settings` |

## Deploy with the API

These calls create the same deployment without the dashboard: the application, the disk, the probe, the variables and the first deployment, then a document chat through AnythingLLM's own API. They need:

* An [API key](https://docs.sevalla.com/developer-tools/api-keys.md) that can create applications, in `SEVALLA_API_KEY`, and your Anthropic key in `ANTHROPIC_API_KEY`.
* `curl`, `jq` and `openssl`.

The application comes from a public Docker image, so no Git provider needs to be connected.

**1. Choose the location and sizes**

[List clusters](https://api-docs.sevalla.com/v3/resources/list-clusters) (`listClustersV3`), [List process resource types](https://api-docs.sevalla.com/v3/resources/list-process-resource-types) (`listProcessResourceTypesV3`) and [List disk resource types](https://api-docs.sevalla.com/v3/resources/list-disk-resource-types) (`listDiskResourceTypesV3`). Pick the location by its region ID, here Frankfurt:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
API=https://api.sevalla.com/v3
AUTH="Authorization: Bearer $SEVALLA_API_KEY"
CLUSTER_ID=$(curl -s "$API/resources/clusters" -H "$AUTH" | jq -r '.[] | select(.location == "eu-frankfurt-1") | .id')
S1=$(curl -s "$API/resources/process-resource-types" -H "$AUTH" | jq -r '.[] | select(.name == "s1") | .id')
DISK_10GB=$(curl -s "$API/resources/disk-resource-types" -H "$AUTH" | jq -r '.[] | select(.size_gib == 10) | .id')
```

CLI: `sevalla resources clusters`, `sevalla resources process-types` and `sevalla resources disk-types`. MCP: `get_platform_options`, and `sevalla_api_read` with `listDiskResourceTypesV3`.

**2. Create the application**

[Create application](https://api-docs.sevalla.com/v3/applications/create-application) (`createApplicationV3`) with the Docker image source. It doesn't start a deployment:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
APP_ID=$(curl -s -X POST "$API/applications" -H "$AUTH" -H "Content-Type: application/json" \
  -d "$(jq -n --arg c "$CLUSTER_ID" '{display_name:"anythingllm", cluster_id:$c, source:"dockerImage", docker_image:"mintplexlabs/anythingllm:1.19.0"}')" \
  | jq -r .id)
for i in $(seq 1 30); do APP_HOST=$(curl -s "$API/applications/$APP_ID/domains" -H "$AUTH" | jq -r '.data[] | select(.is_primary) | .name'); [ -n "$APP_HOST" ] && break; sleep 2; done
WEB_ID=$(curl -s "$API/applications/$APP_ID/processes" -H "$AUTH" | jq -r '.data[] | select(.type == "web") | .id')
```

The last two calls are [List application domains](https://api-docs.sevalla.com/v3/applications/list-application-domains) (`listApplicationDomainsV3`) and [List processes](https://api-docs.sevalla.com/v3/applications/list-processes) (`listProcessesV3`). CLI: `sevalla apps create --name anythingllm --cluster $CLUSTER_ID --source dockerImage --docker-image mintplexlabs/anythingllm:1.19.0`. MCP: `create_application` with `deploy: false`, then `get_application`.

**3. Add the disk**

[Attach or update process disk](https://api-docs.sevalla.com/v3/applications/attach-or-update-process-disk) (`updateProcessDiskV3`):

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -X PUT "$API/applications/$APP_ID/processes/$WEB_ID/disk" -H "$AUTH" -H "Content-Type: application/json" \
  -d "$(jq -n --arg r "$DISK_10GB" '{resource_type_id:$r, mount_path:"/app/server/storage"}')" | jq -r .mount_path
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
/app/server/storage
```

CLI: `sevalla apps processes disk update $WEB_ID --app-id $APP_ID --resource-type $DISK_10GB --mount-path /app/server/storage`. MCP: `sevalla_api_update` with `updateProcessDiskV3`.

**4. Size the web process and add the readiness probe**

[Update process](https://api-docs.sevalla.com/v3/applications/update-process) (`updateProcessV3`). The API creates the web process at **S1** already; send the size anyway if you change it. Always send `timeoutSeconds`: without it, the probe gets 120 seconds instead of the dashboard's 1:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -X PATCH "$API/applications/$APP_ID/processes/$WEB_ID" -H "$AUTH" -H "Content-Type: application/json" \
  -d "$(jq -n --arg r "$S1" '{resource_type_id:$r, readiness_probe:{httpGet:{path:"/api/ping", port:8080}, initialDelaySeconds:10, periodSeconds:5, timeoutSeconds:5, successThreshold:1, failureThreshold:3}}')" \
  | jq -r .resource_type_name
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
s1
```

CLI: `sevalla apps processes update $WEB_ID --app-id $APP_ID --resource-type $S1` (the CLI can't set a probe). MCP: `sevalla_api_update` with `updateProcessV3` and the same body.

**5. Add the environment variables**

[Create environment variable](https://api-docs.sevalla.com/v3/applications/create-environment-variable) (`createEnvironmentVariableV3`), once per variable. Store `AUTH_TOKEN` and the three secrets somewhere safe before you send them:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
AUTH_TOKEN=$(openssl rand -base64 18)
add_var() {
  curl -s -X POST "$API/applications/$APP_ID/env-vars" -H "$AUTH" -H "Content-Type: application/json" \
    -d "$(jq -n --arg k "$1" --arg v "$2" '{key:$k, value:$v, is_runtime:true, is_buildtime:false}')" | jq -r .key
}
add_var STORAGE_DIR /app/server/storage
add_var SERVER_PORT 8080
add_var AUTH_TOKEN "$AUTH_TOKEN"
add_var JWT_SECRET "$(openssl rand -hex 32)"
add_var SIG_KEY "$(openssl rand -hex 32)"
add_var SIG_SALT "$(openssl rand -hex 32)"
add_var LLM_PROVIDER anthropic
add_var ANTHROPIC_API_KEY "$ANTHROPIC_API_KEY"
add_var ANTHROPIC_MODEL_PREF claude-haiku-5-5
add_var DISABLE_TELEMETRY true
```

Each call prints the key it added. CLI: `sevalla apps env-vars create $APP_ID --key SERVER_PORT --value 8080`, once per variable; the CLI makes each variable available during runtime and build, which makes no difference for an image. MCP: `set_environment_variables` with all of them in `variables`.

**6. Deploy**

[Trigger deployment](https://api-docs.sevalla.com/v3/applications/trigger-deployment) (`triggerDeploymentV3`):

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
DEPLOYMENT_ID=$(curl -s -X POST "$API/applications/$APP_ID/deployments" -H "$AUTH" -H "Content-Type: application/json" -d '{}' | jq -r .id)
```

CLI: `sevalla apps deployments trigger $APP_ID`. MCP: `trigger_deployment`.

**7. Wait for the deployment**

[Get deployment](https://api-docs.sevalla.com/v3/applications/get-deployment) (`getDeploymentV3`) until `status` is final (`success`, `failed`, `cancelled` or `skipped`), for up to 30 minutes; [Get application deployment logs](https://api-docs.sevalla.com/v3/applications/get-application-deployment-logs) (`getApplicationDeploymentLogsV3`, with `?limit=5000`) shows why one failed:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
for i in $(seq 1 120); do
  STATUS=$(curl -s "https://api.sevalla.com/v3/applications/$APP_ID/deployments/$DEPLOYMENT_ID" \
    -H "Authorization: Bearer $SEVALLA_API_KEY" | jq -r '.status // empty')
  case $STATUS in success|failed|cancelled|skipped) break ;; esac
  sleep 15
done
echo "$STATUS"
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
success
```

CLI: `sevalla apps deployments get $DEPLOYMENT_ID --app-id $APP_ID` and `sevalla apps deployments logs $DEPLOYMENT_ID --app-id $APP_ID`. MCP: `get_deployment` and `get_deployment_logs`.

**8. Check AnythingLLM**

The health endpoint answers, and [Get application runtime logs](https://api-docs.sevalla.com/v3/applications/get-application-runtime-logs) (`getApplicationRuntimeLogsV3`) shows the port:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -w "\n" "https://$APP_HOST/api/ping"
curl -s "$API/applications/$APP_ID/runtime-logs?search=listening%20on%20port&order=desc&limit=1" -H "$AUTH" | jq -r '.[0].message' | grep -o 'listening on port [0-9]*'
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
{"online":true}
listening on port 8080
```

CLI: `sevalla apps logs runtime $APP_ID --search "listening on port"`. MCP: `search_runtime_logs`.

**9. Create an AnythingLLM API key**

AnythingLLM's own API: [sign in](#verify-the-deployment) with `AUTH_TOKEN` for a session token, then create a developer API key with it:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
SESSION=$(curl -s -X POST "https://$APP_HOST/api/request-token" -H "Content-Type: application/json" \
  -d "$(jq -n --arg p "$AUTH_TOKEN" '{password:$p}')" | jq -r .token)
ANYTHINGLLM_API_KEY=$(curl -s -X POST "https://$APP_HOST/api/system/generate-api-key" -H "Authorization: Bearer $SESSION" | jq -r .apiKey.secret)
curl -s -w "\n" "https://$APP_HOST/api/v1/auth" -H "Authorization: Bearer $ANYTHINGLLM_API_KEY"
```

```json theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
{"authenticated":true}
```

**10. Chat with a document**

Create the workspace, upload the document into it, and ask about it:

```bash theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
curl -s -X POST "https://$APP_HOST/api/v1/workspace/new" -H "Authorization: Bearer $ANYTHINGLLM_API_KEY" \
  -H "Content-Type: application/json" -d '{"name":"Support"}' | jq -r .workspace.slug
printf '%s\n' '# Shipping policy' '' 'Acme Coffee Supply ships orders from Monday to Friday.' \
  '- Shipping to Canada costs 19.90 EUR, takes 6 to 9 business days, and isn'"'"'t available for grinders.' > shipping-policy.md
curl -s -X POST "https://$APP_HOST/api/v1/document/upload" -H "Authorization: Bearer $ANYTHINGLLM_API_KEY" \
  -F "file=@shipping-policy.md" -F "addToWorkspaces=support" | jq -r '.documents[0].title'
curl -s -X POST "https://$APP_HOST/api/v1/workspace/support/chat" -H "Authorization: Bearer $ANYTHINGLLM_API_KEY" \
  -H "Content-Type: application/json" -d '{"message":"How much does shipping to Canada cost?","mode":"query"}' \
  | jq -r '.sources[0].title'
```

```text theme={"theme":{"light":"github-dark-default","dark":"github-dark-default"}}
support
shipping-policy.md
shipping-policy.md
```

The last line is the source the answer used; `.textResponse` holds the answer itself.

Then open `https://$APP_HOST` in a browser and sign in with `AUTH_TOKEN`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.