---
title: Setting up Anubis
---

import EnterpriseOnly from "@site/src/components/EnterpriseOnly";
import RandomKey from "@site/src/components/RandomKey";

export const EO = () => (
  <>
    <EnterpriseOnly link="./botstopper/" />
    <div style={{ marginBottom: "0.5rem" }} />
  </>
);

Anubis is meant to sit between your reverse proxy (such as Nginx or Caddy) and your target service. One instance of Anubis must be used per service you are protecting.

<center>

```mermaid
---
title: With Anubis installed
---

flowchart LR
    LB(Load balancer /
TLS terminator)
    Anubis(Anubis)
    App(App)

    LB --> Anubis --> App
```

</center>

## Docker image conventions

Anubis is shipped in the Docker repo [`ghcr.io/techarohq/anubis`](https://github.com/TecharoHQ/anubis/pkgs/container/anubis). The following tags exist for your convenience:

| Tag                 | Meaning                                                                                                                            |
| :------------------ | :--------------------------------------------------------------------------------------------------------------------------------- |
| `latest`            | The latest [tagged release](https://github.com/TecharoHQ/anubis/releases), if you are in doubt, start here.                        |
| `v<version number>` | The Anubis image for [any given tagged release](https://github.com/TecharoHQ/anubis/tags)                                          |
| `main`              | The current build on the `main` branch. Only use this if you need the latest and greatest features as they are merged into `main`. |

The Docker image runs Anubis as user ID 1000 and group ID 1000. If you are mounting external volumes into Anubis' container, please be sure they are owned by or writable to this user/group.

Anubis has very minimal system requirements. I suspect that 128Mi of ram may be sufficient for a large number of concurrent clients. Anubis may be a poor fit for apps that use WebSockets and maintain open connections, but I don't have enough real-world experience to know one way or another.

## Native packages

For more detailed information on installing Anubis with native packages, please read [the native install directions](./native-install.mdx).

## Configuration

Anubis is configurable via environment variables and [the policy file](./policies.mdx). Most settings are currently exposed with environment variables but they are being slowly moved over to the policy file.

### Configuration via the policy file

Currently the following settings are configurable via the policy file:

- [Bot policies](./policies.mdx)
- [Open Graph passthrough](./configuration/open-graph.mdx)
- [Weight thresholds](./configuration/thresholds.mdx)

### Environment variables

Anubis uses these environment variables for configuration:

| Environment Variable           | Default value           | Explanation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| :----------------------------- | :---------------------- | :  |
| `ASSET_LOOKUP_HEADER`          | unset                   | <EO /> If set, use the contents of this header in requests when looking up custom assets in `OVERLAY_FOLDER`. See [Header-based overlay dispatch](./botstopper.mdx#header-based-overlay-dispatch) for more details.                                                                                                                                                                                                                                                                                                                            |
| `BASE_PREFIX`                  | unset                   | If set, adds a global prefix to all Anubis endpoints (everything starting with `/.within.website/x/anubis/`). For example, setting this to `/myapp` would make Anubis accessible at `/myapp/` instead of `/`. This is useful when running Anubis behind a reverse proxy that routes based on path prefixes.                                                                                                                                                                                                                                    |
| `BIND`                         | `:8923`                 | The network address that Anubis listens on. For `unix`, set this to a path: `/run/anubis/instance.sock`                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `BIND_NETWORK`                 | `tcp`                   | The address family that Anubis listens on. Accepts `tcp`, `unix` and anything Go's [`net.Listen`](https://pkg.go.dev/net#Listen) supports.                                                                                                                                                                                                                                                                                                                                                                                                     |
| `CHALLENGE_TITLE`              | unset                   | <EO /> If set, override the translation stack to show a custom title for challenge pages such as "Making sure your connection is secure!". See [Customizing messages](./botstopper.mdx#customizing-messages) for more details.                                                                                                                                                                                                                                                                                                                 |
| `COOKIE_DOMAIN`                | unset                   | The domain the Anubis challenge pass cookie should be set to. This should be set to the domain you bought from your registrar (EG: `techaro.lol` if your webapp is running on `anubis.techaro.lol`). See this [stackoverflow explanation of cookies](https://stackoverflow.com/a/1063760) for more information.<br/><br/>Note that unlike `REDIRECT_DOMAINS`, you should never include a port number in this variable.                                                                                                                         |
| `COOKIE_DYNAMIC_DOMAIN`        | false                   | If set to true, automatically set cookie domain fields based on the hostname of the request. EG: if you are making a request to `anubis.techaro.lol`, the Anubis cookie will be valid for any subdomain of `techaro.lol`.                                                                                                                                                                                                                                                                                                                      |
| `COOKIE_EXPIRATION_TIME`       | `168h`                  | The amount of time the authorization cookie is valid for.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `CUSTOM_REAL_IP_HEADER`        | unset                   | If set, Anubis will read the client's real IP address from this header, and set it in `X-Real-IP` header.                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `COOKIE_PARTITIONED`           | `false`                 | If set to `true`, enables the [partitioned (CHIPS) flag](https://developers.google.com/privacy-sandbox/cookies/chips), meaning that Anubis inside an iframe has a different set of cookies than the domain hosting the iframe.                                                                                                                                                                                                                                                                                                                 |
| `COOKIE_PREFIX`                | `anubis-cookie`         | The prefix used for browser cookies created by Anubis. Useful for customization or avoiding conflicts with other applications.                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `COOKIE_SECURE`                | `true`                  | If set to `true`, enables the [Secure flag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies#block_access_to_your_cookies), meaning that the cookies will only be transmitted over HTTPS. If Anubis is used in an unsecure context (plain HTTP), this will be need to be set to false                                                                                                                                                                                                                                          |
| `COOKIE_SAME_SITE`             | `None`                  | Controls the cookie’s [`SameSite` attribute](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value). Allowed: `None`, `Lax`, `Strict`, `Default`. `None` permits cross-site use but modern browsers require it to be **Secure**—so if `COOKIE_SECURE=false` or you serve over plain HTTP, use `Lax` (recommended) or `Strict` or the cookie will be rejected. `Default` uses the Go runtime’s `SameSiteDefaultMode`. `None` will be downgraded to `Lax` automatically if cookie is set NOT to be secure. |
| `DIFFICULTY`                   | `4`                     | The difficulty of the challenge, or the number of leading zeroes that must be in successful responses.                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `DIFFICULTY_IN_JWT`            | `false`                 | If set to `true`, adds the `difficulty` field into JWT claims, which indicates the difficulty the token has been generated. This may be useful for statistics and debugging.                                                                                                                                                                                                                                                                                                                                                                   |
| `ED25519_PRIVATE_KEY_HEX`      | unset                   | The hex-encoded ed25519 private key used to sign Anubis responses. If this is not set, Anubis will generate one for you. This should be exactly 64 characters long. **Required when using persistent storage backends** (like bbolt) to ensure challenges survive service restarts. When running multiple instances on the same base domain, the key must be the same across all instances. See below for details.                                                                                                                             |
| `ED25519_PRIVATE_KEY_HEX_FILE` | unset                   | Path to a file containing the hex-encoded ed25519 private key. Only one of this or its sister option may be set. **Required when using persistent storage backends** (like bbolt) to ensure challenges survive service restarts. When running multiple instances on the same base domain, the key must be the same across all instances.                                                                                                                                                                                                       |
| `ERROR_TITLE`                  | unset                   | <EO /> If set, override the translation stack to show a custom title for error pages such as "Something went wrong!". See [Customizing messages](./botstopper.mdx#customizing-messages) for more details.                                                                                                                                                                                                                                                                                                                                      |
| `JWT_RESTRICTION_HEADER`       | `X-Real-IP`             | If set, the JWT is only valid if the current value of this header matches the value when the JWT was created. You can use it e.g. to restrict a JWT to the source IP of the user using `X-Real-IP`.                                                                                                                                                                                                                                                                                                                                            |
| `METRICS_BIND`                 | `:9090`                 | The network address that Anubis serves Prometheus metrics on. See `BIND` for more information.                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `METRICS_BIND_NETWORK`         | `tcp`                   | The address family that the Anubis metrics server listens on. See `BIND_NETWORK` for more information.                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `OG_EXPIRY_TIME`               | `24h`                   | The expiration time for the Open Graph tag cache. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem.                                                                                                                                                                                                                                                                                                                                                                                        |
| `OG_PASSTHROUGH`               | `false`                 | If set to `true`, Anubis will enable Open Graph tag passthrough. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem.                                                                                                                                                                                                                                                                                                                                                                         |
| `OG_CACHE_CONSIDER_HOST`       | `false`                 | If set to `true`, Anubis will consider the host in the Open Graph tag cache key. Prefer using [the policy file](./configuration/open-graph.mdx) to configure the Open Graph subsystem.                                                                                                                                                                                                                                                                                                                                                         |
| `OVERLAY_FOLDER`               | unset                   | <EO /> If set, treat the given path as an [overlay folder](./botstopper.mdx#custom-images-and-css), allowing you to customize CSS, fonts, images, and add other assets to BotStopper deployments.                                                                                                                                                                                                                                                                                                                                              |
| `POLICY_FNAME`                 | unset                   | The file containing [bot policy configuration](./policies.mdx). See the bot policy documentation for more details. If unset, the default bot policy configuration is used.                                                                                                                                                                                                                                                                                                                                                                     |
| `PUBLIC_URL`                   | unset                   | The externally accessible URL for this Anubis instance, used for constructing redirect URLs (e.g., for Traefik forwardAuth).                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `REDIRECT_DOMAINS`             | unset                   | Comma-separated list of domain names that Anubis should allow redirects to when passing a challenge. See [Redirect Domain Configuration](./configuration/redirect-domains) for more details.                                                                                                                                                                                                                                                                                          |
| `SERVE_ROBOTS_TXT`             | `false`                 | If set `true`, Anubis will serve a default `robots.txt` file that disallows all known AI scrapers by name and then additionally disallows every scraper. This is useful if facts and circumstances make it difficult to change the underlying service to serve such a `robots.txt` file.                                                                                                                                                                                                                                                       |
| `SLOG_LEVEL`                   | `INFO`                  | The log level for structured logging. Valid values are `DEBUG`, `INFO`, `WARN`, and `ERROR`. Set to `DEBUG` to see all requests, evaluations, and detailed diagnostic information.                                                                                                                                                                                                                                                                                                                                                             |
| `SOCKET_MODE`                  | `0770`                  | _Only used when at least one of the `*_BIND_NETWORK` variables are set to `unix`._ The socket mode (permissions) for Unix domain sockets.                                                                                                                                                                                                                                                                                                                                                                                                      |
| `STRIP_BASE_PREFIX`            | `false`                 | If set to `true`, strips the base prefix from request paths when forwarding to the target server. This is useful when your target service expects to receive requests without the base prefix. For example, with `BASE_PREFIX=/foo` and `STRIP_BASE_PREFIX=true`, a request to `/foo/bar` would be forwarded to the target as `/bar`.                                                                                                                                                                                                          |
| `TARGET`                       | `http://localhost:3923` | The URL of the service that Anubis should forward valid requests to. Supports Unix domain sockets, set this to a URI like so: `unix:///path/to/socket.sock`.                                                                                                                                                                                                                                                                                                                                                                                   |
| `USE_REMOTE_ADDRESS`           | unset                   | If set to `true`, Anubis will take the client's IP from the network socket. For production deployments, it is expected that a reverse proxy is used in front of Anubis, which pass the IP using headers, instead.                                                                                                                                                                                                                                                                                                                              |
| `USE_SIMPLIFIED_EXPLANATION`   | false                   | If set to `true`, replaces the text when clicking "Why am I seeing this?" with a more simplified text for a non-tech-savvy audience.                                                                                                                                                                                                                                                                                                                                                                                                           |
| `USE_TEMPLATES`                | false                   | <EO /> If set to `true`, enable [custom HTML template support](./botstopper.mdx#custom-html-templates), allowing you to completely rewrite how BotStopper renders its HTML pages.                                                                                                                                                                                                                                                                                                                                                              |
| `WEBMASTER_EMAIL`              | unset                   | If set, shows a contact email address when rendering error pages. This email address will be how users can get in contact with administrators.                                                                                                                                                                                                                                                                                                                                                                                                 |
| `XFF_STRIP_PRIVATE`            | `true`                  | If set, strip private addresses from `X-Forwarded-For` headers. To unset this, you must set `XFF_STRIP_PRIVATE=false` or `--xff-strip-private=false`.                                                                                                                                                                                                                                                                                                                                                                                          |

<details>
<summary>Advanced configuration settings</summary>

:::note

If you don't know or understand what these settings mean, ignore them. These are intended to work around very specific issues.

:::

| Environment Variable          | Default value | Explanation                                                                                                                                                                                                                                                                                                                                                                                     |
| :---------------------------- | :------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FORCED_LANGUAGE`             | unset         | If set, forces Anubis to display challenge pages in the specified language instead of using the browser's Accept-Language header. Use ISO 639-1 language codes (e.g., `de` for German, `fr` for French).                                                                                                                                                                                        |
| `HS512_SECRET`                | unset         | Secret string for JWT HS512 algorithm. If this is not set, Anubis will use ED25519 as defined via the variables above. The longer the better; 128 chars should suffice. **Required when using persistent storage backends** (like bbolt) to ensure challenges survive service restarts. When running multiple instances on the same base domain, the key must be the same across all instances. |
| `TARGET_DISABLE_KEEPALIVE`    | `false`       | If `true`, disables HTTP keep-alive for connections to the target backend. Useful for backends that don't handle keep-alive properly.                                                                                                                                                                                                                                                           |
| `TARGET_HOST`                 | unset         | If set, overrides the Host header in requests forwarded to `TARGET`.                                                                                                                                                                                                                                                                                                                            |
| `TARGET_INSECURE_SKIP_VERIFY` | `false`       | If `true`, skip TLS certificate validation for targets that listen over `https`. If your backend does not listen over `https`, ignore this setting.                                                                                                                                                                                                                                             |
| `TARGET_SNI`                  | unset         | If set, TLS handshake hostname when forwarding requests to the `TARGET`. If set to auto, use Host header.                                                                                                                                                                                                                                                                                                                 |

</details>

For more detailed information on configuring Open Graph tags, please refer to the [Open Graph Configuration](./configuration/open-graph.mdx) page.

### Using Base Prefix

The `BASE_PREFIX` environment variable allows you to run Anubis behind a path prefix. This is useful when:

- You want to host multiple services on the same domain
- You're using a reverse proxy that routes based on path prefixes
- You need to integrate Anubis with an existing application structure

For example, if you set `BASE_PREFIX=/myapp`, Anubis will:

- Serve its challenge page at `/myapp/` instead of `/`
- Serve its API endpoints at `/myapp/.within.website/x/cmd/anubis/api/` instead of `/.within.website/x/cmd/anubis/api/`
- Serve its static assets at `/myapp/.within.website/x/cmd/anubis/` instead of `/.within.website/x/cmd/anubis/`

When using this feature with a reverse proxy:

1. Configure your reverse proxy to route requests for the specified path prefix to Anubis
2. Set the `BASE_PREFIX` environment variable to match the path prefix in your reverse proxy configuration
3. Ensure that your reverse proxy preserves the path when forwarding requests to Anubis

Example with Nginx:

```nginx
location /myapp/ {
    proxy_pass http://anubis:8923/myapp;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}
```

With corresponding Anubis configuration:

```
BASE_PREFIX=/myapp
```

#### Stripping Base Prefix

If your target service doesn't expect to receive the base prefix in request paths, you can use the `STRIP_BASE_PREFIX` option:

```
BASE_PREFIX=/myapp
STRIP_BASE_PREFIX=true
```

With this configuration:

- A request to `/myapp/api/users` would be forwarded to your target service as `/api/users`
- A request to `/myapp/` would be forwarded as `/`

This is particularly useful when working with applications that weren't designed to handle path prefixes. However, note that if your target application generates absolute redirects or links (like `/login` instead of `./login`), these may break the subpath routing since they won't include the base prefix.

### Key generation

To generate an ed25519 private key, you can use this command:

```text
openssl rand -hex 32
```

Alternatively here is a key generated by your browser:

<RandomKey />

## Next steps

To get Anubis filtering your traffic, you need to make sure it's added to your HTTP load balancer or platform configuration. See the [environments category](/docs/category/environments) for detailed information on individual environments.

- [Apache](./environments/apache.mdx)
- [Caddy](./environments/caddy.mdx)
- [Docker compose](./environments/docker-compose.mdx)
- [Kubernetes](./environments/kubernetes.mdx)
- [Nginx](./environments/nginx.mdx)
- [Traefik](./environments/traefik.mdx)

:::note

Anubis loads its assets from `/.within.website/x/xess/` and `/.within.website/x/cmd/anubis`. If you do not reverse proxy these in your server config, Anubis won't work.

:::
