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

# Deploy Your Server

> Launch locally, deploy to a cloud provider, or export a portable server.

Larkup can run the retrieval and chat API locally or deploy it to a cloud provider. Open **Settings → Larkup Server** to manage both paths.

## Launch and test locally

<Steps>
  <Step title="Open Larkup Server">
    Go to **Settings → Larkup Server**. When the server is stopped, select **Launch server**.

    <Frame caption="Larkup Server before the local API is launched">
      <img src="https://mintcdn.com/larkup/13l_fOT1PJRw-f4o/documentation/images/deploy/server-off.png?fit=max&auto=format&n=13l_fOT1PJRw-f4o&q=85&s=875cfdf5719cf17a75f117420fcde386" alt="Larkup Server settings with the local server stopped" width="3012" height="1434" data-path="documentation/images/deploy/server-off.png" />
    </Frame>
  </Step>

  <Step title="Copy the connection details">
    After launch, the page shows the local endpoint, server API key, SDK connection action, test action, and interactive API reference.

    <Frame caption="A running local server with connection actions">
      <img src="https://mintcdn.com/larkup/13l_fOT1PJRw-f4o/documentation/images/deploy/server-on.png?fit=max&auto=format&n=13l_fOT1PJRw-f4o&q=85&s=bc7e37149d4b25e569f9202296d92404" alt="Running Larkup server with endpoint and API key controls" width="3012" height="1434" data-path="documentation/images/deploy/server-on.png" />
    </Frame>

    The app assigns an available workspace port starting at `8080`. A generated standalone server uses `8080` by default.
  </Step>

  <Step title="Verify the API">
    Use **Try it**, open **API reference**, or run:

    ```bash theme={null}
    larkup test --endpoint http://localhost:8080
    ```
  </Step>
</Steps>

## Deploy from the Web UI

Select **Deploy** to choose Vercel, Hetzner, Azure, AWS, GCP, DigitalOcean, or another available target.

<Frame caption="Choose a cloud target from Larkup Server settings">
  <img src="https://mintcdn.com/larkup/13l_fOT1PJRw-f4o/documentation/images/deploy/server-click-deploy.png?fit=max&auto=format&n=13l_fOT1PJRw-f4o&q=85&s=b3dea85b866cccd4d5b1ca5a3512a09a" alt="Deployment provider menu in Larkup Server settings" width="3012" height="1434" data-path="documentation/images/deploy/server-click-deploy.png" />
</Frame>

### Vercel

<Steps>
  <Step title="Choose Vercel">
    Select **Deploy → Vercel** from the server page.
  </Step>

  <Step title="Provider settings">
    Paste your Vercel token and a project name, then verify the connection.

    <Frame caption="Vercel provider settings">
      <img src="https://mintcdn.com/larkup/13l_fOT1PJRw-f4o/documentation/images/deploy/deploy1.png?fit=max&auto=format&n=13l_fOT1PJRw-f4o&q=85&s=5b6fc28f88e1347d1fdf2b9c88560825" alt="Vercel token and project name form" width="2982" height="1384" data-path="documentation/images/deploy/deploy1.png" />
    </Frame>
  </Step>

  <Step title="Server configuration">
    Confirm the embedding model, then choose the **AI chat runtime** for this deployment. It uses the Project provider by default and can be overridden with OpenAI, DeepSeek, Google, Mistral, Cohere, or Vercel AI Gateway. Review the environment values, including the server API key.

    <Frame caption="Server configuration for a Vercel deployment">
      <img src="https://mintcdn.com/larkup/13l_fOT1PJRw-f4o/documentation/images/deploy/deploy2.png?fit=max&auto=format&n=13l_fOT1PJRw-f4o&q=85&s=320cb5acf7be162f2d0533c8e18861e3" alt="Embedding model, AI chat runtime, and environment variables" width="2982" height="1384" data-path="documentation/images/deploy/deploy2.png" />
    </Frame>

    <Warning>
      Local LanceDB files are not durable on a serverless deployment. Use Pinecone, LanceDB with S3 compatible storage, or another persistent provider when the deployed server includes the knowledge base.
    </Warning>
  </Step>

  <Step title="Deploy">
    Select **Deploy Server**. Larkup opens the **Cloud deployments** tab when the request is accepted, where you can follow the provider status and open the API endpoint.
  </Step>
</Steps>

### VPS and other cloud targets

Choose the provider from the same **Deploy** menu. For an SSH target, provide the host, user, authentication method, and required environment values. Larkup builds the server, launches it through Docker, and returns the deployed endpoint.

<Note>
  Put a reverse proxy such as Caddy or Nginx in front of a public VPS endpoint to provide HTTPS and a custom domain.
</Note>

## Deploy from the CLI

Generate a portable artifact:

```bash theme={null}
larkup deploy docker --out ./deployment
larkup deploy vercel --out ./deployment
```

Start locally or create the agent server target:

```bash theme={null}
larkup deploy local
larkup deploy agent
larkup deploy agent --start
```

After deployment, verify the endpoint:

```bash theme={null}
larkup test --endpoint https://your-server.example.com \
  --api-key "$LARKUP_API_KEY"
```

## Before going live

* Set a strong server API key.
* Use persistent storage for the deployed knowledge base.
* Add the model, embedding, and storage credentials required by your configuration.
* Keep secrets in the deployment provider rather than source control.
* Test the health, query, chat, and API reference endpoints.

The generated output is a standard Node.js server and includes a `Dockerfile` and `vercel.json`.

## Create a chat assistant for your website in minutes

Once your server is running, open **Settings → Larkup Server → Connections → Chat Widget → Customize**.

### Customize the appearance

Set the title, welcome message, placeholder, accent colour, position, and dark mode. Save, then restart the local runtime or redeploy to publish the update.

<Frame caption="Chat widget appearance settings with a live preview">
  <img src="https://mintcdn.com/larkup/13l_fOT1PJRw-f4o/documentation/images/chat-widget.png?fit=max&auto=format&n=13l_fOT1PJRw-f4o&q=85&s=82ca96bee39c85e57c3f2947a65b1985" alt="Chat widget appearance form with a live preview" width="2982" height="1384" data-path="documentation/images/chat-widget.png" />
</Frame>

This is what it looks like running on a page:

<Frame caption="The widget open on a live site">
  <img src="https://mintcdn.com/larkup/13l_fOT1PJRw-f4o/documentation/images/demo-widget-preview.png?fit=max&auto=format&n=13l_fOT1PJRw-f4o&q=85&s=51adf0b1cebf90a2476feb63f6ebc9e1" alt="Chat widget open and answering a question on a demo site" width="3012" height="1418" data-path="documentation/images/demo-widget-preview.png" />
</Frame>

### Embed it

The same page gives you a ready to copy script using your server's URL:

```html theme={null}
<script
  async
  src="https://your-agent.example.com/widget.js"
  data-api-key="YOUR_SERVER_API_KEY"
  data-position="bottom-right"
  data-theme="light"
></script>
```

The generated server owns `/widget.js` and `/chat`, so the widget works the same locally, in Docker, and after deployment. It renders inside a Shadow DOM to keep its styles separate from the host site.

Individual embeds can override the generated defaults:

```html theme={null}
<script
  async
  src="https://your-agent.example.com/widget.js"
  data-api-key="YOUR_SERVER_API_KEY"
  data-title="Sales questions"
  data-primary-color="#0ea5e9"
  data-position="bottom-left"
  data-theme="dark"
  data-class="fixed z-50"
></script>
```

`data-class` is applied to the widget's outer mount. The chat interface itself is intentionally isolated, so host Tailwind classes cannot accidentally break the embedded UI.

### Security

`data-api-key` is readable by every visitor to the page. Use a scoped, low-privilege retrieval key for a browser widget, or put a small authenticated proxy in front of the Agent server for production sites. Never embed an admin, ingest, model-provider, sandbox, or Marketplace credential in client code.

The same key is available behind a reveal/copy control in the Larkup Server screen only for the current browser session. Use it server side for production calls, where the key stays private.

### React

Load the same script once in a client component:

```tsx theme={null}
'use client';

import { useEffect } from 'react';

export function SupportWidget() {
  useEffect(() => {
    const script = document.createElement('script');
    script.async = true;
    script.src = 'https://your-agent.example.com/widget.js';
    script.dataset.apiKey = process.env.NEXT_PUBLIC_LARKUP_WIDGET_KEY!;
    document.body.appendChild(script);
    return () => window.LarkupWidget?.destroy();
  }, []);

  return null;
}
```

Prefer a proxy or a purpose-made retrieval key rather than exposing a general server key through a `NEXT_PUBLIC_*` variable.
