# Configuring your server

> Environment variables of the Eggent open core, a reverse proxy with HTTPS for a VPS, the Telegram webhook, an egress proxy and security rules.

Source: https://eggent.ai/docs/self-host-config/

Almost everything is configured in the Eggent interface, and a `.env` file is optional. Environment variables are for what must be known before start-up: the address, the port, fallback keys.

## Environment variables {#env}

The full list is in `.env.example` in the repository. The main ones:

| Variable | Default | What for |
| --- | --- | --- |
| `APP_BIND_HOST` | `127.0.0.1` | Host address Docker listens on. `0.0.0.0` only on purpose |
| `APP_PORT` | `3000` | Host port |
| `APP_BASE_URL` | `http://localhost:3000` | Public address — for webhooks and links |
| `EGGENT_AUTH_SECRET` | generated in `data/settings/` | Session signing secret |
| `EXTERNAL_API_TOKEN` | unset | Fallback token for the [external API](https://eggent.ai/docs/external-api.md) |
| `TELEGRAM_BOT_TOKEN` | unset | Bot token, if you would rather not enter it in the interface |
| `TELEGRAM_WEBHOOK_SECRET` | unset | Telegram webhook secret |
| `TELEGRAM_DEFAULT_PROJECT_ID` | unset | Default project for Telegram |
| `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_API_KEY`, `OPENROUTER_API_KEY` | unset | Fallback provider keys |
| `EGGENT_STT_ENABLED`, `EGGENT_STT_MODEL`, `EGGENT_STT_LANGUAGE` | `1`, `base`, `auto` | [Speech recognition](https://eggent.ai/docs/voice.md#self-host) |
| `HTTPS_PROXY`, `HTTP_PROXY`, `NO_PROXY` | unset | Outbound traffic through a proxy |
| `EGGENT_LEARNING` | on | `off` stops the agent from keeping notes and skills from conversations (see [Memory](https://eggent.ai/docs/memory.md#learned)). What is already saved is no longer read either |
| `EGGENT_LEARNING_MODEL` | the chat's model | The model for the background look-back, as `provider/id` or just the id — a cheaper one is enough |
| `EGGENT_LEARNING_DAILY_CAP`, `EGGENT_LEARNING_MIN_GAP_SECONDS`, `EGGENT_LEARNING_EVERY_TURNS` | `40`, `60`, `6` | Look-backs per day, the pause between two, and how often a conversation with nothing flagged is looked at |
| `EGGENT_TURN_WATCHDOG` | on | `off` switches off the check that stops a turn which has gone quiet (see [Chats](https://eggent.ai/docs/chats.md#while-working)). Worth doing if you run a slow local model that can think for longer than the limits below |
| `EGGENT_TURN_SILENCE_SOFT_SECONDS`, `EGGENT_TURN_SILENCE_START_SECONDS`, `EGGENT_TURN_SILENCE_MODEL_SECONDS`, `EGGENT_TURN_SILENCE_TOOL_SECONDS` | `90`, `180`, `360`, `1200` | How long a turn may say nothing before the chat tells you it is still going, and before it is stopped: while it starts, while the model has not answered, while a command runs. A command that is running next to another one keeps its full allowance |
| `EGGENT_TURN_QUESTION_WAIT_SECONDS` | `86400` | How long a question to you may wait for an answer before the turn is stopped (see [Chats](https://eggent.ai/docs/chats.md#questions)). `0` or `off` lets a question wait for ever |
| `EGGENT_VISITS_MAX`, `EGGENT_VISIT_TIMEOUT_MINUTES`, `EGGENT_VISIT_STOP_GRACE_SECONDS` | `2`, `10`, `20` | [Asking a project with `@`](https://eggent.ai/docs/projects.md#ask): how many may run at once, how long one may take, and how long one that was told to stop is given before it is let go of |
| `EGGENT_BOARD` | on | `off` stops the [task board](https://eggent.ai/docs/board.md) from starting cards; the board and its cards stay |
| `EGGENT_BOARD_MAX_RUNNING`, `EGGENT_BOARD_MAX_PER_PROJECT` | `3`, `1` | How many cards work at once across the board, and in one project. Cards of one project share its folder |
| `EGGENT_BOARD_RETRY_SECONDS` | `60` | How long a failed card waits before its one automatic retry |
| `EGGENT_ZIP_MAX_MB`, `EGGENT_ZIP_MAX_FILES`, `EGGENT_ZIP_IDLE_SECONDS` | `1024`, `10000`, `120` | The size and file count of one [archive](https://eggent.ai/docs/files.md#zip), and how long one may stand still, with nobody taking it, before it is dropped |
| `EGGENT_VERSIONS` | on | `off` stops keeping [versions of files](https://eggent.ai/docs/files.md#history); what is already kept can still be looked at |
| `EGGENT_VERSIONS_KEEP_DAYS`, `EGGENT_VERSIONS_DAILY_DAYS`, `EGGENT_VERSIONS_MAX_PER_FILE`, `EGGENT_VERSIONS_MAX_FILE_MB` | `30`, `90`, `200`, `10` | How long every version is kept after it was replaced, until when one a day is kept, how many one file keeps, and the size above which a file gets no history |
| `EGGENT_VERSIONS_SCAN_SECONDS` | `120` | How often files that have a history are looked at for changes made elsewhere: the sync, the terminal, another program |
| `EGGENT_VERSIONS_MAX_TOTAL_MB`, `EGGENT_VERSIONS_DISK_SHARE` | `1024`, `0.25` | The most the whole history may take, and the share of the disk it may take when the deployment reports one; past it the versions replaced longest ago go first |
| `EGGENT_WEB_SEARCH_DEFAULTS` | on | `off` stops Eggent from writing the order of free search engines into `data/pi-agent/web-search.json` at start (see [Agent tools](https://eggent.ai/docs/agent-tools.md#web)) |
| `EGGENT_CLOUD_PROMO` | on | `0` takes away the short card about Eggent Cloud at the bottom of **Settings → Models** |
| `EGGENT_VERSION` | `latest` | Image tag for `docker-compose.ghcr.yml` |

After changing `.env`, recreate the container:

```bash
docker compose up -d --force-recreate
```

## Reverse proxy and HTTPS {#reverse-proxy}

On a VPS, keep Eggent on `127.0.0.1` and put a proxy with HTTPS in front of it. HTTPS is not only about security: without it the browser will not allow the microphone, and Telegram will not accept a webhook.

**Caddy** (gets the certificate by itself):

```text
eggent.example.com {
    request_body {
        max_size 100MB
    }
    reverse_proxy 127.0.0.1:3000
}
```

**Nginx**:

```nginx
server {
    server_name eggent.example.com;
    client_max_body_size 100m;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_buffering off;
        proxy_read_timeout 600s;
    }
}
```

> [!WARNING]
> The proxy caps the request size, and its cap is usually lower than Eggent's: Nginx defaults to 1 MB, so uploading a large file fails with `413`. Raise it to 100 MB as in the examples. `proxy_buffering off` and a long `proxy_read_timeout` let the agent's answers stream and keep long tasks from being cut off.

Once the proxy is set up, put the public address into `APP_BASE_URL`.

## Telegram on your own server {#telegram}

Connect the bot in **Settings → Messengers**, as described in [Telegram](https://eggent.ai/docs/telegram.md#own-bot). Modes:

- **Long Polling** — works without a public address. Good for a home machine. Messages are handled one after another, so something you send while the agent is busy — including `/reset` or "stop" — is read when that turn ends; a turn that has gone quiet is ended by the limits under `EGGENT_TURN_SILENCE_*` above.
- **Webhook** — needs a public HTTPS address (`APP_BASE_URL`). Faster and more reliable on a VPS.

**Auto** picks the webhook once a public HTTPS address is set.

## Egress proxy {#egress-proxy}

If the server reaches the internet only through a proxy, set `HTTPS_PROXY` (and `HTTP_PROXY`, `NO_PROXY` if needed). Needs Node.js 22.23 or newer; the Docker image already has it.

## Security {#security}

- Do not expose Eggent's port to the internet without HTTPS. By default it listens only on `127.0.0.1` — keep it that way behind a proxy.
- Change the default login and password straight away.
- Treat the external API token like a password and never use it in browser code.
- Protect and back up the `data/` folder: it holds chats, files, memory, settings and keys.
- The agent has a terminal inside the container. Do not mount folders into the container that the agent does not need.
