crazy-max/docker-fail2ban

Fail2ban Docker image

Dockerfile

763

347 commits

updated Sep 18, 2026

See the code

README

Latest Version Build Status Docker Stars Docker Pulls
Become a sponsor Donate Paypal

About

Fail2ban Docker image to ban hosts that cause multiple authentication errors.

[!TIP] Want to be notified of new releases? Check out 🔔 Diun (Docker Image Update Notifier) project!


Build locally

git clone https://github.com/crazy-max/docker-fail2ban.git
cd docker-fail2ban

# Build Alpine image and output to docker (default)
docker buildx bake

# Build Alpine multi-platform image
docker buildx bake image-all

# Build Debian image and output to docker
docker buildx bake image-debian-local

# Build Debian multi-platform image
docker buildx bake image-debian-all

Image

RegistryImage
Docker Hubcrazymax/fail2ban
GitHub Container Registryghcr.io/crazy-max/fail2ban

Supported tags

  • latest, <version>, edge
  • debian, <version>-debian, edge-debian

<version> has to be replaced with one of the Fail2ban releases available (e.g. 1.1.1). Tags without a debian suffix are Alpine-based.

Environment variables

  • TZ: The timezone assigned to the container (default UTC)
  • F2B_LOG_TARGET: Set the log target. This could be a file, SYSLOG, STDERR or STDOUT (default STDOUT)
  • F2B_LOG_LEVEL: Log level output (default INFO)
  • F2B_DB_PURGE_AGE: Age at which bans should be purged from the database (default 1d)
  • IPTABLES_MODE: Set iptables mode to auto, nft or legacy (default auto)

Volumes

  • /data: Contains customs jails, actions and filters and Fail2ban persistent database

Usage

Docker Compose

Docker compose is the recommended way to run this image. Copy the content of folder examples/compose in /var/fail2ban/ on your host for example. Edit the Compose and env files with your preferences and run the following commands:

$ docker compose up -d
$ docker compose logs -f

Command line

You can also use the following minimal command :

$ docker run -d --name fail2ban --restart always \
  --network host \
  --cap-add NET_ADMIN \
  --cap-add NET_RAW \
  -v $(pwd)/data:/data \
  -v /var/log:/var/log:ro \
  crazymax/fail2ban:latest

Upgrade

Recreate the container whenever I push an update:

$ docker compose pull
$ docker compose up -d

Notes

DOCKER-USER chain

In Docker 17.06 and higher through docker/libnetwork#1675, you can add rules to a new table called DOCKER-USER, and these rules will be loaded before any rules Docker creates automatically. This is useful to make iptables rules created by Fail2Ban persistent.

If you have an older version of Docker, you may just change the chain definition for your jail to chain = FORWARD. This way, all Fail2Ban rules come before any Docker rules but these rules will now apply to ALL forwarded traffic.

More info : https://docs.docker.com/network/iptables/

DOCKER-USER and INPUT chains

If your Fail2Ban container is attached to DOCKER-USER chain instead of INPUT, the rules will be applied only to containers. This means that any packets coming into the INPUT chain will bypass these rules that now reside under the FORWARD chain.

This is why the sshd jail contains a chain = INPUT in its definition and traefik jail contains chain = DOCKER-USER.

Jails examples

Here are some examples using the DOCKER-USER chain:

And others using the INPUT chain:

Use fail2ban-client

Fail2ban commands can be used through the container. Here is an example if you want to ban an IP manually:

$ docker exec -t <CONTAINER> fail2ban-client set <JAIL> banip <IP>

Global jail configuration

You can provide customizations in /data/jail.d/*.local files.

Both image variants default to iptables-multiport / iptables-allports ban actions and backend = auto for SSH and Postfix. You can override these in your jail configuration. Journal monitoring requires the Debian variant and mounted host journals, as shown in the systemd example.

For example, to change the default bantime for all jails:

[DEFAULT]
bantime = 1h

[!NOTE] Loading order for jail configuration:

jail.conf
jail.d/*.conf (in alphabetical order)
jail.local
jail.d/*.local (in alphabetical order)

A sample configuration file is available on the official repository.

Custom jails, actions and filters

Custom jails, actions and filters can be added respectively in /data/jail.d, /data/action.d and /data/filter.d. If you add an action/filter that already exists, it will be overriden.

[!WARNING] Container has to be restarted to propagate changes

GeoIP2

If you want to use MaxMind GeoIP2 databases with Fail2Ban, see the example in examples/geoip. It runs the geoip-updater image as a sidecar, mounts the downloaded GeoLite2-Country.mmdb database in /data/geoip, and uses a custom ignorecommand.

In this example, GEOIP_ALLOWED_COUNTRIES=FR,BE,CH means IPs from these countries are ignored by Fail2Ban and will not be banned. IPs from other countries follow the regular jail behavior. This is not proactive country blocking, Fail2Ban still only reacts to matching log entries.

You need to set LICENSE_KEY in geoip-updater.env.

Sending email using a sidecar container

If you want to send emails using a sidecar container, see the example in examples/smtp. It uses the smtp.py action and msmtpd SMTP relay image.

systemd journal backend

If you want to use Fail2ban's backend = systemd, see the example in examples/systemd. It uses the Debian image variant with Python systemd bindings and mounts the host journal read-only.

Contributing

Want to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. You can also support this project by becoming a sponsor on GitHub or by making a PayPal donation to ensure this journey continues indefinitely!

Thanks again for your support, it is much appreciated! 🙏

License

MIT. See LICENSE for more details.

alpine-linux
docker
docker-compose
fail2ban
firewall
iptables

crazy-max/docker-fail2ban

Fail2ban Docker image

Dockerfile

763

347 commits

updated Sep 18, 2026

See the code

README

Latest Version Build Status Docker Stars Docker Pulls
Become a sponsor Donate Paypal

About

Fail2ban Docker image to ban hosts that cause multiple authentication errors.

[!TIP] Want to be notified of new releases? Check out 🔔 Diun (Docker Image Update Notifier) project!


Build locally

git clone https://github.com/crazy-max/docker-fail2ban.git
cd docker-fail2ban

# Build Alpine image and output to docker (default)
docker buildx bake

# Build Alpine multi-platform image
docker buildx bake image-all

# Build Debian image and output to docker
docker buildx bake image-debian-local

# Build Debian multi-platform image
docker buildx bake image-debian-all

Image

RegistryImage
Docker Hubcrazymax/fail2ban
GitHub Container Registryghcr.io/crazy-max/fail2ban

Supported tags

  • latest, <version>, edge
  • debian, <version>-debian, edge-debian

<version> has to be replaced with one of the Fail2ban releases available (e.g. 1.1.1). Tags without a debian suffix are Alpine-based.

Environment variables

  • TZ: The timezone assigned to the container (default UTC)
  • F2B_LOG_TARGET: Set the log target. This could be a file, SYSLOG, STDERR or STDOUT (default STDOUT)
  • F2B_LOG_LEVEL: Log level output (default INFO)
  • F2B_DB_PURGE_AGE: Age at which bans should be purged from the database (default 1d)
  • IPTABLES_MODE: Set iptables mode to auto, nft or legacy (default auto)

Volumes

  • /data: Contains customs jails, actions and filters and Fail2ban persistent database

Usage

Docker Compose

Docker compose is the recommended way to run this image. Copy the content of folder examples/compose in /var/fail2ban/ on your host for example. Edit the Compose and env files with your preferences and run the following commands:

$ docker compose up -d
$ docker compose logs -f

Command line

You can also use the following minimal command :

$ docker run -d --name fail2ban --restart always \
  --network host \
  --cap-add NET_ADMIN \
  --cap-add NET_RAW \
  -v $(pwd)/data:/data \
  -v /var/log:/var/log:ro \
  crazymax/fail2ban:latest

Upgrade

Recreate the container whenever I push an update:

$ docker compose pull
$ docker compose up -d

Notes

DOCKER-USER chain

In Docker 17.06 and higher through docker/libnetwork#1675, you can add rules to a new table called DOCKER-USER, and these rules will be loaded before any rules Docker creates automatically. This is useful to make iptables rules created by Fail2Ban persistent.

If you have an older version of Docker, you may just change the chain definition for your jail to chain = FORWARD. This way, all Fail2Ban rules come before any Docker rules but these rules will now apply to ALL forwarded traffic.

More info : https://docs.docker.com/network/iptables/

DOCKER-USER and INPUT chains

If your Fail2Ban container is attached to DOCKER-USER chain instead of INPUT, the rules will be applied only to containers. This means that any packets coming into the INPUT chain will bypass these rules that now reside under the FORWARD chain.

This is why the sshd jail contains a chain = INPUT in its definition and traefik jail contains chain = DOCKER-USER.

Jails examples

Here are some examples using the DOCKER-USER chain:

And others using the INPUT chain:

Use fail2ban-client

Fail2ban commands can be used through the container. Here is an example if you want to ban an IP manually:

$ docker exec -t <CONTAINER> fail2ban-client set <JAIL> banip <IP>

Global jail configuration

You can provide customizations in /data/jail.d/*.local files.

Both image variants default to iptables-multiport / iptables-allports ban actions and backend = auto for SSH and Postfix. You can override these in your jail configuration. Journal monitoring requires the Debian variant and mounted host journals, as shown in the systemd example.

For example, to change the default bantime for all jails:

[DEFAULT]
bantime = 1h

[!NOTE] Loading order for jail configuration:

jail.conf
jail.d/*.conf (in alphabetical order)
jail.local
jail.d/*.local (in alphabetical order)

A sample configuration file is available on the official repository.

Custom jails, actions and filters

Custom jails, actions and filters can be added respectively in /data/jail.d, /data/action.d and /data/filter.d. If you add an action/filter that already exists, it will be overriden.

[!WARNING] Container has to be restarted to propagate changes

GeoIP2

If you want to use MaxMind GeoIP2 databases with Fail2Ban, see the example in examples/geoip. It runs the geoip-updater image as a sidecar, mounts the downloaded GeoLite2-Country.mmdb database in /data/geoip, and uses a custom ignorecommand.

In this example, GEOIP_ALLOWED_COUNTRIES=FR,BE,CH means IPs from these countries are ignored by Fail2Ban and will not be banned. IPs from other countries follow the regular jail behavior. This is not proactive country blocking, Fail2Ban still only reacts to matching log entries.

You need to set LICENSE_KEY in geoip-updater.env.

Sending email using a sidecar container

If you want to send emails using a sidecar container, see the example in examples/smtp. It uses the smtp.py action and msmtpd SMTP relay image.

systemd journal backend

If you want to use Fail2ban's backend = systemd, see the example in examples/systemd. It uses the Debian image variant with Python systemd bindings and mounts the host journal read-only.

Contributing

Want to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. You can also support this project by becoming a sponsor on GitHub or by making a PayPal donation to ensure this journey continues indefinitely!

Thanks again for your support, it is much appreciated! 🙏

License

MIT. See LICENSE for more details.

alpine-linux
docker
docker-compose
fail2ban
firewall
iptables

Significant stargazers

Filippo Tessarotto

177 followers · starred Mar 2025

Dimitris Mostrous

56 followers · starred Oct 2024

waltherjj

0 followers · starred Jun 2020