Anubis on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of Anubis on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. Anubis is the open source Web AI Firewall: a single Go binary that runs 24/7 under systemd, sits in front of your application as a reverse proxy, and weighs the soul of every incoming request to keep AI scrapers and abusive crawlers off your site. Normal visitors flow straight through to your upstream; suspicious browsers are served a lightweight proof of work challenge; and known AI crawler user agents are blocked outright, so aggressive bots stop hammering your site and running up your bandwidth.
The image installs the latest stable Anubis release, resolved at build time from the official GitHub release package and baked reproducibly into the image (the exact version is recorded in /opt/anubis/VERSION). Anubis runs under systemd as the unit anubis@default.service, and reverse proxies to a target upstream that you point at your own application.
HTTPS out of the box. In this image nginx terminates TLS on port 443 and reverse proxies to Anubis on the loopback interface. On the very first boot the image generates a fresh per instance self signed certificate (its Subject Alternative Names cover the VM public IP, hostname and loopback), so no default certificate ships inside the image. You replace it with a CA signed certificate for your own domain in production.
No default secret ships in the image. Anubis signs the cookies it issues to challenged visitors with an ED25519 key. This image generates that key per instance on the first boot from the kernel random source, straight into /etc/anubis/default.env (owned by root, not world readable, injected into the service by systemd). The shipped image carries only a placeholder, so no two VMs ever share a signing key.
You bring your own upstream. Anubis protects whatever you set as its TARGET. The image ships a small local demo upstream so you can see the firewall working the moment it boots, and you repoint TARGET at your own application after launch.
What is included:
-
The latest stable Anubis release (single Go binary), run under systemd as
anubis@default.service -
nginx terminating TLS on :443 with a per instance self signed certificate regenerated on first boot, reverse proxying to Anubis on
127.0.0.1:8923 -
An unauthenticated
/healthzload balancer probe and a301redirect to HTTPS on :80, plus a local demo upstream on127.0.0.1:8000 -
The built in default bot policy: allow normal visitors, challenge suspicious browsers with proof of work, and deny known AI scrapers (Amazonbot, Bytespider, GPTBot family, anthropic-ai, PerplexityBot, Scrapy and many more)
-
Prometheus metrics on
127.0.0.1:9090showing exactly how many requests were allowed, challenged and denied, broken down by rule -
A per instance ED25519 signing key generated on first boot into
/etc/anubis/default.env, rendered from a placeholder template so the shipped image carries no key -
Ubuntu 24.04 LTS base with latest security patches applied at build time
-
Azure Linux Agent for seamless cloud integration and SSH key injection
-
24/7 cloudimg support with guaranteed 24 hour response SLA
Prerequisites
-
Active Azure subscription, SSH public key, VNet + subnet in target region
-
Subscription to the Anubis listing on Azure Marketplace
-
An application (upstream) you want to protect, and a DNS domain you can point at the VM for production
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for a firewall fronting a typical site. For heavier traffic use Standard_D2s_v5 or larger. Anubis is stateless (its challenge state is in memory), so it scales with CPU and memory.
Step 1: Deploy from the Azure Portal
Search Anubis in Marketplace, select the cloudimg publisher, click Create. NSG rules: TCP 22 (admin), TCP 443 (the proxy over HTTPS) and TCP 80 (HTTP to HTTPS redirect and health probe) from the networks your visitors connect from.
Step 2: Deploy from the Azure CLI
RG="anubis-prod"; LOCATION="eastus"; VM_NAME="anubis-01"
GALLERY_IMAGE_ID="/subscriptions/<sub-id>/resourceGroups/azure-cloudimg/providers/Microsoft.Compute/galleries/cloudimgGallery/images/anubis-ubuntu-24-04/versions/<version>"
SSH_KEY="$(cat ~/.ssh/id_rsa.pub)"
az group create --name "$RG" --location "$LOCATION"
az network vnet create -g "$RG" --name anubis-vnet --address-prefix 10.100.0.0/16 --subnet-name anubis-subnet --subnet-prefix 10.100.1.0/24
az network nsg create -g "$RG" --name anubis-nsg
az network nsg rule create -g "$RG" --nsg-name anubis-nsg --name allow-ssh --priority 100 \
--source-address-prefixes "<your-mgmt-cidr>" --destination-port-ranges 22 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name anubis-nsg --name allow-https --priority 110 \
--destination-port-ranges 443 --access Allow --protocol Tcp
az network nsg rule create -g "$RG" --nsg-name anubis-nsg --name allow-http --priority 120 \
--destination-port-ranges 80 --access Allow --protocol Tcp
az vm create -g "$RG" --name "$VM_NAME" --image "$GALLERY_IMAGE_ID" \
--size Standard_B2s --storage-sku StandardSSD_LRS \
--admin-username azureuser --ssh-key-values "$SSH_KEY" \
--vnet-name anubis-vnet --subnet anubis-subnet --nsg anubis-nsg --public-ip-sku Standard
Step 3: Verify the Anubis and nginx services
Connect over SSH, then confirm both services are active and see which ports are bound. nginx listens on :443 (TLS) and :80 (redirect and health probe), Anubis listens on 127.0.0.1:8923 (the proxy) and 127.0.0.1:9090 (metrics), and the demo upstream on 127.0.0.1:8000:
sudo systemctl status anubis@default nginx --no-pager | head -14
sudo ss -tlnp | grep -E ':443|:80 |:8923|:9090|:8000'
cat /opt/anubis/VERSION

Step 4: See the AI firewall in action
Anubis classifies every request. A normal client is proxied straight through to your upstream, a known AI scraper user agent is denied, and a suspicious browser is served a proof of work challenge it must solve before it is let through. You can see all three on the VM with curl:
# A normal visitor (curl) is ALLOWED and proxied to the upstream:
curl -sk https://127.0.0.1/ | grep -q "cloudimg Anubis demo upstream" && echo "normal visitor: proxied to the upstream (allowed)"
# A known AI scraper user agent is DENIED (served the Anubis block page, never reaches the upstream):
curl -sk -A 'Amazonbot/0.1' https://127.0.0.1/ | grep -q "Oh noes" && echo "Amazonbot: blocked by the AI firewall"
# A browser is served the proof of work challenge page (it solves it in the browser, then is let through):
curl -sk -A 'Mozilla/5.0 (X11; Linux x86_64)' https://127.0.0.1/ | grep -q "not a bot" && echo "browser: served the proof of work challenge"
The normal request reaches the demo upstream, the Amazonbot request is denied with the Anubis block page and never touches your application, and the browser request receives the "making sure you're not a bot" proof of work challenge. This is the core of Anubis: real visitors are unaffected while automated AI crawling is stopped at the door.

Step 5: Inspect the classification metrics
Anubis exposes Prometheus metrics on 127.0.0.1:9090. The anubis_policy_results counter shows exactly how many requests each policy rule allowed, challenged or denied, so you can see the firewall working and wire it into your monitoring:
curl -s http://127.0.0.1:9090/metrics | grep -E '^# HELP anubis_|^anubis_policy_results|^anubis_challenges_issued' | head -20
You will see anubis_policy_results broken down by action (ALLOW, CHALLENGE, DENY) and rule (for example bot/ai-catchall for the AI scraper denials and threshold/... for the browser challenges), alongside anubis_challenges_issued. These are standard Prometheus counters you can scrape from your existing stack.

Step 6: Understand the per instance key and configuration
Anubis is configured through the environment file /etc/anubis/default.env, which systemd injects into the service. This image generates the ED25519 signing key on first boot into that file (owned by root, not world readable); the shipped image carries only a placeholder. The endpoints for this VM are summarized in a root only file, and the per instance TLS certificate covers this VM:
sudo grep -E '^BIND|^TARGET|^METRICS_BIND|^DIFFICULTY|^SERVE_ROBOTS_TXT|^ED25519_PRIVATE_KEY_HEX' /etc/anubis/default.env
sudo cat /root/anubis-credentials.txt
sudo openssl x509 -in /etc/nginx/certs/cert.pem -noout -subject -ext subjectAltName
In the environment file you can see BIND (Anubis on loopback :8923), TARGET (the upstream Anubis protects), METRICS_BIND (:9090), DIFFICULTY (the proof of work difficulty), and the per instance ED25519_PRIVATE_KEY_HEX (masked in the screenshot below). The credentials file lists this VM's access URL, and the certificate Subject Alternative Names cover this VM.

Step 7: Protect your own application
To put Anubis in front of your own application, point TARGET at your upstream and restart the service. Set TARGET to wherever your application listens (for example http://127.0.0.1:3000 for a local app, or http://10.0.0.5:8080 for another host):
sudo nano /etc/anubis/default.env
Change the TARGET= line, save, then apply:
sudo systemctl restart anubis@default
Anubis now proxies allowed traffic to your application and blocks AI scrapers in front of it. Because nginx terminates TLS and forwards the real client IP to Anubis in the X-Forwarded-For header, your policy decisions and logs see the true visitor address.
Step 8: Tune the bot policy
The built in default policy already allows normal visitors, challenges suspicious browsers and denies a large list of known AI scrapers. To customise it, provide your own policy file and reference it from the environment:
# Anubis ships its data files (including example policies) under /usr/share/docs/anubis or the package docs.
sudo cp /etc/anubis/default.env /etc/anubis/default.env.bak
Add a POLICY_FNAME=/etc/anubis/default.botPolicies.yaml line to /etc/anubis/default.env pointing at a policy file you author (start from the upstream default policy documented at the Anubis project site), then sudo systemctl restart anubis@default. Policies can allow, weigh (challenge based on accumulated suspicion) or deny by user agent, path, header, IP range and more. Leaving POLICY_FNAME unset keeps the sensible built in default.
Step 9: Use your own domain and a trusted certificate (production)
The self signed certificate is a convenience for getting started. For production, point a DNS name you control at the VM public IP and replace the certificate:
-
Drop a CA signed certificate and key into
/etc/nginx/certs/cert.pemand/etc/nginx/certs/key.pem(or point the nginxssl_certificatedirectives at your own paths), thensudo systemctl reload nginx. -
Alternatively front the VM with a managed certificate from Azure Application Gateway or a CDN and forward to nginx on :443.
-
Visitors then reach your site at your own domain with no certificate trust step, and Anubis keeps the scrapers out.
Step 10: Server components
| Component | Version / Detail |
|---|---|
| Firewall / proxy | Anubis (latest stable release, baked reproducibly, see /opt/anubis/VERSION) |
| TLS | terminated by nginx on :443 (self signed per VM), certificate at /etc/nginx/certs/ |
| Anubis listener | 127.0.0.1:8923 (proxy), 127.0.0.1:9090 (Prometheus metrics) |
| Front helper | nginx (:80 -> 301 https, unauthenticated /healthz, loopback 127.0.0.1:8000 demo upstream) |
| Signing key | per instance ED25519_PRIVATE_KEY_HEX generated first boot into /etc/anubis/default.env |
| Bot policy | built in default (allow visitors, challenge browsers, deny known AI scrapers) |
| Upstream | your application via TARGET (demo upstream shipped) |
| Operating system | Ubuntu 24.04 LTS (patched at build) |
| License | MIT (Anubis) |
Step 11: Managing the Anubis service
sudo systemctl status anubis@default --no-pager | head -12
sudo systemctl is-active anubis@default nginx
Apply a configuration change with sudo systemctl restart anubis@default, reload the nginx helper with sudo systemctl reload nginx, and follow the logs live with sudo journalctl -u anubis@default -f. The configuration lives at /etc/anubis/default.env. After any change, restart Anubis.
Step 12: Security recommendations
-
Restrict the NSG. Allow TCP 443 (and 22 for admin) only from the networks your visitors connect from.
-
Use a trusted certificate and your own domain (Step 9) so visitors validate the site without a manual trust step.
-
Point TARGET at your real application and remove the demo upstream from production use.
-
Tune the policy for your traffic (Step 8). Start from the built in default and add allow rules for any legitimate automation you rely on, and stricter rules for abusive ranges.
-
Protect the key.
/etc/anubis/default.envholds the ED25519 signing key and is not world readable; keep it that way and regenerate it if a VM is ever exposed. -
Keep the OS patched. Unattended security upgrades remain enabled on the running VM.
Step 13: Support and Licensing
Anubis is distributed under the MIT License. This cloudimg image bundles the unmodified official open source release; cloudimg provides the packaging, hardening, per instance key and TLS automation, the working demo upstream, and 24/7 support with a guaranteed 24 hour response SLA. Anubis is an independent open source project by Techaro and this image is not affiliated with or endorsed by Techaro or the Anubis project.
Deploy on Azure
Find Anubis on Ubuntu 24.04 on the Azure Marketplace, published by cloudimg. Deploy from the Portal or the Azure CLI as shown above.
Need Help?
Email support@cloudimg.co.uk for deployment help, configuration questions, or licensing enquiries.