1. The problem I’m having:
I am in the process of switching my Gitea installation from Nginx to Caddy. As a security measure, I have set up fail2ban to block repeat login attempts. The source of IPs is the application log, the blocking/banning happens inside Nginx at the moment. Normally, this would be at the iptables level and wouldn’t concern the reverse proxy.
However, this particular deployment is actually fronted by two proxies:
Internet -> HAProxy -> Caddy -> Gitea
This creates a situation where banning an IP address will have no effect: Since the TCP connection is between HAProxy & Caddy, banning the public IP on the host where Caddy runs does nothing.
Instead, what I currently do within Nginx is to use the map
command to dynamically read a ban file and reject requests at the HTTP level based on banned IPs.
Is this possible with Caddy? The map directive does not seem to support dynamic loading of content like this. I couldn’t find anything else that came close.
2. Error messages and/or full log output:
There are no errors or relevant logs.
3. Caddy version:
v2.7.6 h1:w0NymbG2m9PcvKWsrXO6EEkY9Ru4FJK8uQbYcev1p3A=
4. How I installed and ran Caddy:
a. System environment:
Arch Linx, x64. Running inside a docker container.
b. Command:
docker compose up -d
c. Service/unit/compose file:
services:
caddy:
build:
context: .
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./sites:/etc/caddy/sites
- ./hosts:/etc/caddy/hosts
- data:/data
- config:/config
- /usr/share/webapps:/srv
env_file:
- env
networks:
- reverse-proxy
volumes:
data:
config:
networks:
reverse-proxy:
name: reverse-proxy
d. My complete Caddy config:
{
email myemail@example.com
acme_dns cloudflare {env.CF_API_TOKEN}
}
git.home.xevaj.eu {
log
reverse_proxy gitea:3000
}
5. Links to relevant resources:
Relevant Nginx config:
map $remote_addr $blck_lst_ses { include blacklisted-sessions.map; }
server {
listen 443 ssl http2;
server_name git.home.xevaj.eu;
# With SSL via Let's Encrypt
ssl_certificate /etc/letsencrypt/live/git.home.xevaj.eu/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/git.home.xevaj.eu/privkey.pem; # managed by Certbot
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
if ($blck_lst_ses != "") {
rewrite ^.*$ /banned last;
}
location /banned {
default_type text/html;
return 403 '<h1>Banned</h1>';
}
}
/etc/fail2ban/jail.d/gitea.conf
[gitea]
enabled = true
filter = gitea
logpath = /var/lib/gitea/gitea/log/gitea.log
maxretry = 10
findtime = 3600
bantime = 900
action = nginx-block-map
ignoreip = 192.168.1.0/24