Documentation Index
Fetch the complete documentation index at: https://mintlify.com/TecharoHq/Anubis/llms.txt
Use this file to discover all available pages before exploring further.
Caddy is a modern HTTP server with automatic HTTPS. This guide shows how to deploy Anubis behind Caddy.
Basic Configuration
Caddy makes it simple to set up a reverse proxy with automatic TLS. Here’s a minimal Caddyfile:
example.com {
reverse_proxy anubis:3000 {
header_up X-Real-IP {remote_host}
}
}
Caddy automatically:
- Obtains and renews TLS certificates via Let’s Encrypt
- Redirects HTTP to HTTPS
- Sets HTTP/2 and HTTP/3
Complete Example
Here’s a production-ready setup with all recommended headers:
Caddyfile:
:80 {
reverse_proxy http://anubis:3000 {
header_up X-Real-IP {remote_host}
header_up X-Http-Version {http.request.proto}
}
}
:443 {
tls /etc/certs/cert.pem /etc/certs/key.pem
reverse_proxy http://anubis:3000 {
header_up X-Real-IP {remote_host}
header_up X-Http-Version {http.request.proto}
header_up X-Tls-Version {http.request.tls.version}
}
}
docker-compose.yml:
services:
caddy:
image: caddy:latest
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./certs:/etc/certs:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
- anubis
anubis:
image: ghcr.io/techarohq/anubis:main
environment:
BIND: ":3000"
TARGET: "http://backend:8080"
POLICY_FNAME: "/etc/techaro/anubis/policy.yaml"
volumes:
- ./anubis-config:/etc/techaro/anubis
backend:
image: your-app:latest
expose:
- "8080"
volumes:
caddy_data:
caddy_config:
Automatic HTTPS
For automatic HTTPS with Let’s Encrypt:
example.com {
reverse_proxy anubis:3000 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
}
}
Caddy automatically:
- Obtains a TLS certificate from Let’s Encrypt
- Renews certificates before expiration
- Redirects HTTP to HTTPS
No additional configuration needed!
Custom TLS Certificates
To use your own certificates:
example.com {
tls /path/to/cert.pem /path/to/key.pem
reverse_proxy anubis:3000 {
header_up X-Real-IP {remote_host}
}
}
Multiple Backends
Protect multiple applications with one Anubis instance:
# Protected site 1
site1.example.com {
reverse_proxy anubis:3000
}
# Protected site 2
site2.example.com {
reverse_proxy anubis:3000
}
# Unprotected site
unprotected.example.com {
reverse_proxy backend:8080
}
Configure Anubis to accept multiple domains:
anubis --cookie-domain example.com \
--redirect-domains site1.example.com,site2.example.com \
--bind :3000
Path-Based Routing
Protect only specific paths:
example.com {
# Protected admin area
reverse_proxy /admin/* anubis:3000
# Public content goes directly to backend
reverse_proxy backend:8080
}
Note: This requires configuring Anubis with --base-prefix /admin.
Caddy automatically sets several headers, but you can customize them:
example.com {
reverse_proxy anubis:3000 {
# Client IP
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
# Protocol information
header_up X-Forwarded-Proto {scheme}
header_up X-Forwarded-Host {host}
# TLS information
header_up X-Tls-Version {http.request.tls.version}
header_up X-Tls-Cipher {http.request.tls.cipher_suite}
}
}
Placeholders
Caddy provides many useful placeholders:
{remote_host} - Client IP address
{scheme} - http or https
{host} - Host header value
{method} - HTTP method
{uri} - Request URI
{http.request.proto} - HTTP version
{http.request.tls.version} - TLS version
{http.request.tls.cipher_suite} - TLS cipher suite
See Caddy placeholders for the complete list.
Health Checks
Caddy can perform active health checks on Anubis:
example.com {
reverse_proxy anubis:3000 {
header_up X-Real-IP {remote_host}
health_uri /healthz
health_port 9090
health_interval 10s
health_timeout 5s
}
}
This checks Anubis metrics endpoint every 10 seconds.
Load Balancing
Run multiple Anubis instances behind Caddy:
example.com {
reverse_proxy anubis1:3000 anubis2:3000 anubis3:3000 {
header_up X-Real-IP {remote_host}
lb_policy round_robin
lb_try_duration 5s
health_uri /healthz
health_port 9090
}
}
Important: All Anubis instances must share the same signing key:
# Generate key once
openssl rand -hex 32 > anubis-key.txt
# Use on all instances
anubis --ed25519-private-key-hex-file /secrets/anubis-key.txt
Logging
Customize access logs:
example.com {
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 10
}
format json
}
reverse_proxy anubis:3000 {
header_up X-Real-IP {remote_host}
}
}
Advanced Configuration
Custom Error Pages
example.com {
handle_errors {
@502 `{http.error.status_code} == 502`
handle @502 {
respond "Service temporarily unavailable" 502
}
}
reverse_proxy anubis:3000 {
header_up X-Real-IP {remote_host}
}
}
Rate Limiting
Caddy can rate limit before reaching Anubis:
example.com {
rate_limit {
zone example_zone 1m 100r/s
}
reverse_proxy anubis:3000 {
header_up X-Real-IP {remote_host}
}
}
Note: This requires the caddy-ratelimit plugin.
Request Buffering
example.com {
reverse_proxy anubis:3000 {
header_up X-Real-IP {remote_host}
# Buffer requests up to 10MB
flush_interval -1
request_buffers 10MB
}
}
Testing
Test your Caddy configuration:
# Validate Caddyfile syntax
caddy validate --config Caddyfile
# Test with curl
curl -v https://example.com
# Check headers received by Anubis
curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:3000/
Troubleshooting
Certificate Issues
If Let’s Encrypt certificates fail:
# Check Caddy logs
docker logs caddy
# Ensure port 80 is accessible for ACME challenge
curl http://example.com/.well-known/acme-challenge/test
IP Address Not Detected
Verify Anubis receives the correct IP:
- Don’t use
--use-remote-address when behind Caddy
- Ensure
header_up X-Real-IP {remote_host} is set
- Check Anubis logs for received IP
Connection Refused
Check that:
- Anubis is running:
docker ps
- Anubis is listening on correct port
- Network connectivity:
docker exec caddy wget -O- http://anubis:3000/
Resources