fail2ban
ECTLogger includes Fail2Ban-compatible security logging to protect against brute-force authentication attacks.
Note: The
install.shscript can automatically set up Fail2Ban for you. Run./install.shand answer “yes” when prompted for Fail2Ban setup. The manual instructions below are for custom installations.
Quick Setup
1. Configure ECTLogger Logging
Add the LOG_FILE environment variable to your backend/.env:
# Enable file logging for Fail2Ban
LOG_FILE=/var/log/ectlogger/app.log
Create the log directory with proper permissions:
sudo mkdir -p /var/log/ectlogger
sudo chown $USER:$USER /var/log/ectlogger
2. Install Fail2Ban Filter
Copy the filter configuration:
sudo cp fail2ban/filter.d/ectlogger.conf /etc/fail2ban/filter.d/
3. Configure Fail2Ban Jail
Copy the jail configuration:
sudo cp fail2ban/jail.d/ectlogger.conf /etc/fail2ban/jail.d/
Or add to /etc/fail2ban/jail.local:
[ectlogger]
enabled = true
port = http,https,8000
filter = ectlogger
logpath = /var/log/ectlogger/app.log
maxretry = 5
findtime = 600
bantime = 3600
4. Restart Services
# Restart ECTLogger to enable file logging
sudo systemctl restart ectlogger
# Restart Fail2Ban to load new configuration
sudo systemctl restart fail2ban
Configuration Options
ECTLogger Environment Variables
| Variable | Description | Default |
|---|---|---|
LOG_FILE |
Path to log file for Fail2Ban | None (stdout only) |
LOG_LEVEL |
Minimum log level | INFO |
Fail2Ban Jail Settings
| Setting | Description | Default |
|---|---|---|
maxretry |
Failed attempts before ban | 5 |
findtime |
Time window for counting failures (seconds) | 600 (10 min) |
bantime |
Ban duration (seconds) | 3600 (1 hour) |
Log Format
ECTLogger produces Fail2Ban-compatible log entries:
2025-11-29 12:34:56 [WARNING] [AUTH] Authentication failed: Invalid or expired magic link token - IP: 192.168.1.100
2025-11-29 12:35:00 [WARNING] [SECURITY] Banned user access attempt: user@example.com - IP: 192.168.1.100
2025-11-29 12:35:05 [WARNING] [SECURITY] Rate limit exceeded on /auth/magic-link/request - IP: 192.168.1.100
2025-11-29 12:36:00 [INFO] [AUTH] Authentication successful for user@example.com - IP: 192.168.1.101
Testing
Test the Filter
# Test with sample log entries
fail2ban-regex /var/log/ectlogger/app.log /etc/fail2ban/filter.d/ectlogger.conf
# View matched IPs
fail2ban-regex /var/log/ectlogger/app.log /etc/fail2ban/filter.d/ectlogger.conf --print-all-matched
Check Fail2Ban Status
# View jail status
sudo fail2ban-client status ectlogger
# View banned IPs
sudo fail2ban-client status ectlogger | grep "Banned IP"
# Unban an IP
sudo fail2ban-client set ectlogger unbanip 192.168.1.100
Reverse Proxy Configuration
If ECTLogger runs behind nginx or another reverse proxy, ensure the proxy forwards the real client IP:
Nginx Example
location / {
proxy_pass http://localhost:8000;
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;
}
ECTLogger automatically reads these headers, but only when the connection reaching the
backend comes directly from 127.0.0.1 or ::1 (app/security.py::get_client_ip) — the
reverse proxy must run on the same host as the backend. If your proxy is a separate
machine (a remote load balancer, for example), these headers are ignored entirely and
every request logs as coming from the proxy’s own address, which breaks Fail2Ban’s
ability to ban the real client:
X-Forwarded-For(standard proxy header) — the last hop is trusted, since Caddy’sreverse_proxy(and nginx’s$proxy_add_x_forwarded_for) append their own view of the client to whatever a client sent, rather than replacing itX-Real-IP(nginx-specific)
Security Events Logged
| Event | Log Level | Category |
|---|---|---|
| Invalid magic link token | WARNING | AUTH |
| Expired magic link token | WARNING | AUTH |
| Banned user login attempt | WARNING | SECURITY |
| Rate limit exceeded | WARNING | SECURITY |
| Successful authentication | INFO | AUTH |
Troubleshooting
Logs not appearing in file
- Check
LOG_FILEis set in.env - Verify the directory exists and is writable
- Restart ECTLogger
Fail2Ban not banning IPs
- Check log file path matches jail configuration
- Test filter with
fail2ban-regex - Check Fail2Ban logs:
sudo tail -f /var/log/fail2ban.log
IPs behind proxy not detected
- Ensure proxy sends
X-Forwarded-FororX-Real-IP - Confirm the proxy connects to the backend from
127.0.0.1/::1— see the note above. A proxy on a different host is not trusted, and its headers are ignored - Check ECTLogger logs show correct client IPs
Fail2Ban fails to start on Debian 12+
Modern Debian/Ubuntu systems use systemd journal instead of /var/log/auth.log. If you see errors like Have not found any log file for sshd jail, configure the sshd jail to use the systemd backend:
# Edit /etc/fail2ban/jail.d/defaults-debian.conf
[sshd]
enabled = true
backend = systemd
Then restart: sudo systemctl restart fail2ban
Caddy Reverse Proxy Protection
If you’re using Caddy as a reverse proxy, ECTLogger includes additional Fail2Ban filters to block web scanners and exploit attempts.
What It Blocks
- CMS Scanners: WordPress, Joomla, Drupal probes (
wp-admin,wp-login, etc.) - Database Admin Probes: PHPMyAdmin, Adminer, MySQL admin paths
- Sensitive File Access:
.env,.git,.htaccess, config files - Exploit Attempts: Shell uploads, path traversal, SQL injection
- Vulnerability Scanners: CGI-bin, ASP/JSP/PL paths
Quick Setup
# Copy Caddy filter and jail
sudo cp fail2ban/filter.d/caddy-ectlogger.conf /etc/fail2ban/filter.d/
sudo cp fail2ban/jail.d/caddy-ectlogger.conf /etc/fail2ban/jail.d/
# Create log directory
sudo mkdir -p /var/log/caddy
sudo chown caddy:caddy /var/log/caddy
# Restart Fail2Ban
sudo systemctl restart fail2ban
Configure Caddy Logging
Add logging to your Caddyfile (inside your site block):
ectlogger.example.com {
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 5
}
format json
}
# ... rest of your configuration
}
Reload Caddy:
sudo systemctl reload caddy
Jail Settings
The Caddy jails are more aggressive than the application jail:
| Jail | Max Retry | Find Time | Ban Time |
|---|---|---|---|
caddy-ectlogger |
3 | 10 min | 24 hours |
caddy-ectlogger-aggressive |
10 | 24 hours | 1 week |
Check Status
# View Caddy jail status
sudo fail2ban-client status caddy-ectlogger
# Test filter against access log
fail2ban-regex /var/log/caddy/access.log /etc/fail2ban/filter.d/caddy-ectlogger.conf
# View currently banned IPs
sudo fail2ban-client status caddy-ectlogger | grep "Banned IP"