---
title: "Deploy Anubis"
description: "Reverse proxy that blocks AI scrapers with a browser puzzle"
category: "Other"
url: https://railway.com/deploy/anubis-proxy
---

# Deploy Anubis

Reverse proxy that blocks AI scrapers with a browser puzzle

**[Deploy Anubis on Railway](https://railway.com/template/anubis-proxy)**

Machine-readable deploy manifest (JSON, validated by TemplateCI): https://railway.com/deploy/anubis-proxy/manifest.json

- **Creator:** A3A
- **Category:** Other

## Template content

### Origin https://cdn.simpleicons.org/nginx/009639.svg

- **Source:** https://github.com/gridalpha/anubis-railway
- **Health check:** /healthz

### Redis https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/redis.svg

- **Image:** redis:8.2
- **Start command:** `/bin/sh -c "rm -rf $RAILWAY_VOLUME_MOUNT_PATH/lost+found/ && exec docker-entrypoint.sh redis-server --requirepass $REDIS_PASSWORD --save 60 1 --dir $RAILWAY_VOLUME_MOUNT_PATH"`

### Anubis https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/png/anubis.png

- **Source:** https://github.com/gridalpha/anubis-railway
- **Health check:** /healthz
- **Public domain:** Yes

## Documentation

# Deploy and Host Anubis on Railway

Anubis is a Web AI Firewall Utility that sits in front of a website and makes every visiting browser solve a small proof-of-work puzzle before the request reaches the application behind it. AI training crawlers now generate a large share of traffic to small sites, and a wiki or Git forge that was comfortable on one server can be knocked over by one walking every page revision. A scraper that does not execute JavaScript cannot solve the puzzle, so it never reaches the origin.

This template lets you deploy Anubis and self-host Anubis on Railway with the three pieces it needs already wired together. **Anubis** is the only service with a public domain: it weighs each request against a bot policy and proxies whatever passes to **Origin**, a small nginx service reachable only through it. **Redis** stores issued challenges so they survive a redeploy and stay valid across replicas. Origin is a stand-in for whatever you actually want protected — change one variable and Anubis fronts your own service instead.

![Public Anubis service above the private Origin and Redis](https://res.cloudinary.com/rroe4rtk/image/upload/v1788789391/anubis-architecture.png)

## Getting Started with Anubis on Railway

Anubis has no accounts and no admin panel, so the deployment works the moment the URL answers. Open the public URL of the **Anubis** service in a normal browser and you should see the challenge page with its jackal mascot for a second or two, then the page served by **Origin**. A challenge was issued, your browser solved it, and the signed token went into a cookie valid for a week.

Two checks confirm the policy is live. Visit `/robots.txt` — Anubis serves its own, naming every known AI crawler. Then request the site with a crawler user agent and confirm you get an Access Denied page rather than the content:

```
curl -A "Amazonbot/0.1" https://your-app.up.railway.app/
```

To protect your own application, set `TARGET` on the **Anubis** service to another service in the project using its private hostname, then move your custom domain onto Anubis. Anything behind Anubis should read the client address from `X-Real-IP`. Delete **Origin** once you no longer need it.

![Anubis proof-of-work challenge page with its jackal mascot](https://res.cloudinary.com/rroe4rtk/image/upload/v1788789393/anubis-challenge.png)
![Protected origin page served after the challenge passed](https://res.cloudinary.com/rroe4rtk/image/upload/v1788789394/anubis-origin-passed.png)
![Access denied page returned to the Amazonbot crawler](https://res.cloudinary.com/rroe4rtk/image/upload/v1788789396/anubis-crawler-denied.png)

## About Hosting Anubis

Anubis is a reverse proxy written in Go by Xe Iaso at Techaro, under the MIT licence. A policy file decides whether each request is allowed, denied with a page a scraper reads as success, challenged with proof of work, or reweighted so borderline traffic is judged on the balance of signals.

- A default policy denying the known AI crawler fleet by name and challenging anything else claiming to be a browser
- Rules matched on user agent, path, headers, address range and CEL expressions
- Configurable difficulty, so you decide how expensive scraping becomes
- An allow-list for real search engines, scoped to their published IP ranges, so indexing survives
- Open Graph passthrough, so chat-app link previews survive the challenge
- A Prometheus endpoint reporting how often each named rule fired

Self-host it when you cannot or will not put a commercial CDN in front of an origin and the traffic has stopped being sustainable. It is deliberately blunt: some smaller crawlers and text-mode browsers get blocked too.

## Why Deploy Anubis on Railway

Railway handles the tedious parts of running an edge service:

- TLS, certificates and the public domain are handled for you
- The protected service stays private, with no public domain at all
- Redis is provisioned with a volume, so challenges survive restarts
- Both services build from one GitHub repository and redeploy on push
- Scale the proxy independently of whatever sits behind it

## Common Use Cases

- Putting a self-hosted Gitea, Forgejo or GitLab instance back inside its resource budget after crawlers began walking every blame view and diff
- Protecting a documentation site, wiki or forum whose page count makes exhaustive crawling expensive
- Keeping an archive open to people and search engines while refusing bulk training-data collection

## Dependencies for Anubis

- **Anubis** — built from `github.com/gridalpha/anubis-railway`, which lifts the binary out of `ghcr.io/techarohq/anubis:latest` onto Alpine. The published image is distroless with no shell, and the challenge store can only be set in the policy file, so that file has to be rendered before the proxy starts.
- **Origin** — `nginxinc/nginx-unprivileged:1-alpine`, from the same repository. It serves a static page plus a `/whoami` route echoing the headers your application would receive.
- **Redis** — `redis:8.2` on a volume. Each issued challenge is recorded here so it can be verified exactly once, preventing token replay, and so state is shared rather than held in one container.

### Environment Variables Reference

| Variable | Service | Purpose |
|---|---|---|
| `TARGET` | Anubis | Service requests are proxied to once they pass |
| `DIFFICULTY` | Anubis | Leading zeroes the proof of work must produce; default 4 |
| `ED25519_PRIVATE_KEY_HEX` | Anubis | Signs challenge tokens; must stay stable across deploys |
| `REDIS_URL` | Anubis | Challenge store connection string |
| `SERVE_ROBOTS_TXT` | Anubis | Serve a `robots.txt` disallowing known AI crawlers |
| `OG_PASSTHROUGH` | Anubis | Fetch the origin's Open Graph tags for link previews |

### Deployment Dependencies

- Source repository: [github.com/gridalpha/anubis-railway](https://github.com/gridalpha/anubis-railway)
- Upstream project: [github.com/TecharoHQ/anubis](https://github.com/TecharoHQ/anubis)
- Container image: `ghcr.io/techarohq/anubis`
- Documentation: [anubis.techaro.lol](https://anubis.techaro.lol)

## Hardware Requirements for Self-Hosting Anubis

The proof of work runs in the visitor's browser, not on your server, so the proxy is cheap.

| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 0.5 vCPU | 1 vCPU |
| RAM | 128 MB | 512 MB |
| Storage | none for the proxy | 1 GB volume for Redis |
| Runtime | Go 1.24+ to build from source | Docker |

Budget separately for whatever sits behind it.

## Self-Hosting Anubis

Anubis sits between your TLS terminator and your application, one instance per protected service. A minimal Docker Compose arrangement:

```
services:
  anubis:
    image: ghcr.io/techarohq/anubis:latest
    environment:
      BIND: ":8923"
      TARGET: "http://my-app:3000"
      DIFFICULTY: "4"
      SERVE_ROBOTS_TXT: "true"
    ports:
      - "8080:8923"
```

Behaviour comes from the policy file — import the maintained default set, add your own rules, then point `POLICY_FNAME` at it:

```
bots:
  - import: (data)/meta/default-config.yaml
  - name: uptime-monitor
    user_agent_regex: MyUptimeBot
    action: ALLOW
store:
  backend: valkey
  parameters:
    url: "redis://redis:6379/0"
```

Native packages exist for Debian, Ubuntu, Alpine and RPM, with guides for nginx, Caddy, Apache, HAProxy, Traefik and Kubernetes.

## Is Anubis Free to Self-Host?

Anubis is free and open source under the MIT licence, with no paid tier, seat count or request limit. On Railway you pay only for the compute the proxy, the protected service and Redis use. Techaro sells BotStopper, a build for organisations whose policies do not allow the project's mascot branding, from $50 per month via GitHub Sponsors; it changes images, CSS, fonts and titles rather than blocking capability.

## FAQ

**What is Anubis?**
An open-source reverse proxy that asks each browser to solve a SHA-256 proof-of-work puzzle before serving the page, so scrapers that do not run JavaScript are turned away.

**What does this Railway template deploy?**
Three services: Anubis with a public domain, an nginx Origin reachable only through it, and Redis for issued challenges. Replace Origin by pointing `TARGET` at your own service.

**Why does the template include Redis?**
Anubis defaults to an in-memory store that upstream describes as validation-only. With Redis, challenges survive a redeploy and are shared across replicas, so visitors are not re-challenged whenever the proxy restarts.

**Will Anubis block Google and stop my site being indexed?**
No. The default policy allow-lists Google, Bing, DuckDuckGo, Kagi, Marginalia, Mojeek, Qwant and the Internet Archive against their published IP ranges, so the user agent alone cannot be forged. Smaller crawlers not on that list are blocked.

**How do I get the real client IP in the application behind Anubis?**
Read `X-Real-IP`. Anubis flattens the forwarded chain to the last public address it sees, which behind a platform load balancer is the balancer rather than the visitor, so `X-Forwarded-For` is not the header to trust.

**Does the proof of work slow visitors down or drain their battery?**
At difficulty 4 a modern browser finishes in a second or two and the token lasts a week, so it is a once-a-week cost, not a per-page one. Raising `DIFFICULTY` makes scraping more expensive and legitimate visits slower in equal measure.

**Can I customise which bots are challenged?**
Yes. The policy file matches on user agent, path, headers, IP range and CEL expressions, and each rule carries its own difficulty and algorithm. Edit it in the source repository and push; the service rebuilds on the commit.


## Similar templates

- [Rocky Linux](https://railway.com/deploy/rocky-linux) — Hosted Rocky Linux 9 workspace with SSH and persistent storage. 🚀
- [Foundry Virtual Tabletop](https://railway.com/deploy/X5tR6G) — A Self-Hosted & Modern Roleplaying Platform
- [Letta Code Remote](https://railway.com/deploy/letta-code-remote) — Run a Letta Code agent 24/7. No inbound ports, just deploy.

Open this page in a browser: https://railway.com/deploy/anubis-proxy
