How To Secure Coolify Server with Fail2Ban
- Mustafa Ramadan
- 6 days ago
- 5 min read

Self-hosting Coolify on a VPS is awesome — it gives you full control and zero limits compared to Vercel or Netlify. But that control comes with responsibility. One of the biggest risks is leaving your server exposed to brute-force, port scans, and bots hammering /wp-login.php or similar paths and admin panels.
In this guide, I’ll show you exactly how I secured my Coolify server using Fail2Ban, even when Traefik is handling all the reverse proxy traffic.
Why Fail2Ban?
Fail2Ban monitors logs for suspicious patterns (e.g. 404s, failed SSH logins) and blocks offending IPs by injecting firewall rules — using iptables or nftables.
Step-by-Step Setup (Tested on Coolify + Ubuntu)
Install Fail2Ban
sudo apt update
sudo apt install fail2ban -y
to confirm your fail2ban is now ready and running on your coolify check it by this:
sudo systemctl status fail2ban
You should see: Active: active (running)
Lets Configure Fail2Ban
Create a local configuration file to customize settings:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
In the [DEFAULT] section, you can adjust parameters like:
• bantime = 1d
• findtime = 10m
• maxretry = 5
These settings control how long an IP is banned, the time window for counting failures, and the number of retries allowed
Enable SSH Protection
Still in jail.local, ensure the [sshd] section is enabled, by default is already enabled like this:
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
This configuration helps protect against brute-force SSH attacks.
Restart Fail2Ban
Apply your changes:
sudo systemctl restart fail2ban
Check if sshd jail is active:
sudo fail2ban-client status
You should see something.
Status
|- Number of jail: 1
`- Jail list: sshd
to get more details like "Currently banned IPs: 0 , Log path ,Max retry, find time, etc." run:
sudo fail2ban-client status sshd
Great! At this point, your Coolify server is already protected from brute-force SSH attacks. Fail2Ban is installed, active, and monitoring login attempts in real time. Now let’s take things a step further — it’s time to secure your web layer too. To do that, we need to enable HTTP access logging in Traefik so Fail2Ban can watch and act on suspicious traffic hitting your websites.
Lets Protect Our Websites, Enable Logging in Traefik
Edit your traefik config (command) to enable the access logs:
- '--accesslog=true'
- '--accesslog.filepath=/traefik/access.log'
- '--accesslog.format=json'
Restart Traefik to apply.

This will log access logs in structured JSON to /data/coolify/proxy/access.log (inside the container: /traefik/access.log).
To confirm is working:
tail -f /data/coolify/proxy/access.log
Create Fail2Ban Filter for Traefik
Create /etc/fail2ban/filter.d/traefik-http.conf:
[Definition]
failregex = .*"ClientHost":"<HOST>".*"(404|403|401|429|502|503|504)"
ignoreregex =
Create Jail Config
Edit or create /etc/fail2ban/jail.d/traefik-http.conf:
[traefik-http]
enabled = true
backend = auto
filter = traefik-http
logpath = /data/coolify/proxy/access.log
maxretry = 5
findtime = 60
bantime = 3600
banaction = nftables
Restart Fail2Ban and Check status:
sudo systemctl restart fail2ban
sudo fail2ban-client status traefik-http
to check fail2ban logs run:
sudo cat /var/log/fail2ban.log
Then Fail2Ban uses the default nftables action, which:
creates a set in inet f2b-table
injects rules into inet filter INPUT
drops IPs matching the set
To check the blocked rules in the firewall:
sudo nft list ruleset | grep reject
Or check the actual nftables sets:
sudo nft list set inet f2b-table addr-set-traefik-http
sudo nft list set inet f2b-table addr6-set-traefik-http
Now your Coolify server is protected with real-time IP banning for HTTP/s threats using Fail2Ban and nftables. This setup actively blocks bots and attackers trying to brute-force or probe your apps through Traefik. But why stop there? Let’s level up and extend those bans — so if someone hits your SSH, they also get blocked from all your websites.
Merge Fail2Ban SSH Bans into Traefik Middleware
Fail2Ban is great at blocking brute-force attacks on services like SSH. But what if you want to propagate those bans to your web layer too — for example, block the same IPs at the Traefik level?
Yes, it’s possible — and here’s how we did it in our Coolify setup.
Use the fail2ban Traefik Plugin (Built-in Middleware)
We will use the official Traefik plugin github.com/tomMoulard/fail2ban — this allows us to block IPs directly from within Traefik using a middleware. For more info about the Traefik Plugin:
To install the plugin here’s what we will add to the Coolify-managed docker-compose command for Traefik:
- '--experimental.plugins.fail2ban.modulename=github.com/tomMoulard/fail2ban'
- '--experimental.plugins.fail2ban.version=v0.8.3'
We also enable this middleware on both HTTP and HTTPS routes add them inside the Traefik configuration file:
labels:
- traefik.http.routers.traefik.middlewares=fail2ban@file
- traefik.https.routers.traefik.middlewares=fail2ban@file
So even if attackers try hitting /admin or /wp-login.php on HTTPS — they’ll still get blocked.

This enables the plugin. Then, we created a middleware using the plugin that reads denied IPs from a file or config name it : fail2ban.yml
http:
middlewares:
fail2ban:
plugin:
fail2ban:
logPath: /traefik/access.log
maxretry: 5
findtime: 60
bantime: 600
statuscodes:
- 401
- 403
- 404
- 429
- 500
- 502
- 503
- 504
denylist:
files:
- "/traefik/denylist.txt"

Sync Fail2Ban Bans to Traefik
We write a small cronjob or script to export current Fail2Ban bans (e.g. from the sshd jail):
fail2ban-client status sshd | grep 'Banned IP list' | cut -d ':' -f2 | tr ',' '\n' > /data/coolify/proxy/denylist.txt
Then Traefik plugin will automatically pick up new IPs from that file — and apply them instantly.
And we Done... One source of truth (Fail2Ban), multiple layers of protection (SSH + Traefik). Super flexible, and easy to maintain.
Using Cloudflare or Tunnels?
If you’re using Cloudflare or Cloudflared Tunnels, make sure your Traefik setup trusts forwarded headers like X-Forwarded-For — so you can log the real IP address behind the tunnel or proxy. Otherwise, Fail2Ban or Traefik plugins might end up banning 127.0.0.1 or your tunnel instead of the attacker 🚫
If yes then include, the following in Traefik configuration file:
- '--entrypoints.http.forwardedHeaders.trustedIPs=10.0.0.0/8'
- '--entrypoints.https.forwardedHeaders.trustedIPs=10.0.0.0/8'
- '--entrypoints.http.forwardedHeaders.insecure=true'
- '--entrypoints.https.forwardedHeaders.insecure=true'
This lets Traefik read the real client IP even when traffic comes from a reverse proxy.
If you don’t use Cloudflare or any proxy in front of your server — you can safely remove those flags for extra security.
Final Thoughts:
Fail2Ban Works on Coolify, But CrowdSec Works Smarter
While the old school Fail2Ban can secure both SSH and HTTP on your Coolify + Traefik setup, it needs extra scripting to fully protect Docker traffic. It works — but it’s not built for modern stacks like Coolify.
CrowdSec, on the other hand, is designed for today’s web:
Native Traefik Bouncer — no hacks, no custom scripts
Real-time ban propagation across services
Works even behind Cloudflare or Cloudflared tunnels
Maintains a global threat intelligence network
Fail2Ban is local, old-school, IP-based and needs work to be cloudflare compatible .
CrowdSec is cloud-native, collaborative, and modern.
So while this guide helps you harden your Coolify server with Fail2Ban, if you want a cleaner, more powerful security layer, go with CrowdSec — it just fits better. Check this guide: Secure Your Coolify Server & Websites with CrowdSec and Traefik
Need Help Securing Your Coolify Server?
I offer hands-on consulting & setup for a rock-solid production server:
CrowdSec Firewall + Traefik Bouncer on self-hosting
Traefik tuning & performance tweaks
SSH hardening & system lockdown
Monitoring, alerts & auto-bans
Full Coolify install & app deployment
👉 Reach out below — I’ll help you secure your stack the right way.
Comments