← Back home

2026.10 / access recovery 074

Docker Mailserver Fail2Ban blocked my IP: unban it safely

IMAP, SMTP submission, or both suddenly time out from one network, even though Docker Mailserver is healthy and other clients still connect. If that network recently produced repeated bad logins, Fail2Ban may have blocked its public source address.

Do not begin by disabling Fail2Ban. First prove that a ban—not DNS, a closed port, TLS, or the mail service—is stopping this client. Then stop the device that is repeating the bad credential, remove only the confirmed source address, and verify that the relevant jail still catches deliberate failures.

An unban restores access; it does not fix the event that triggered the ban. Stop the failing client before removing the block or the address can be banned again immediately.

Fast recovery path

  1. Confirm the failure affects one public source network rather than every client.
  2. Identify that source address privately and match it to Docker Mailserver’s ban list.
  3. Use logs and jail status to identify the triggering service.
  4. Stop or correct every client behind that address.
  5. Unban only that exact address with the DMS setup command.
  6. Retest IMAP or SMTP once and confirm Fail2Ban remains enabled.

1. Distinguish a ban from a general outage

A Fail2Ban block is usually source-specific. Run the same narrow connection test from two genuinely different networks, such as the affected broadband connection and a mobile connection:

# IMAPS: implicit TLS
openssl s_client -connect mail.example.com:993 \
  -servername mail.example.com -brief

# SMTP submission: STARTTLS
openssl s_client -starttls smtp \
  -connect mail.example.com:587 \
  -servername mail.example.com -brief

Replace the example hostname with your public mail hostname. If both sources fail, inspect public DNS, host reachability, published ports, firewall policy, and service health instead. The SMTP timeout guide covers that wider path.

If a second network connects while the first times out, a source-specific firewall or ban becomes likely. It is still not proof: the first network may have broken IPv6, captive filtering, or a local firewall. Keep the comparison and check the server-side ban state next.

2. Confirm Fail2Ban is enabled and running

Docker Mailserver’s documented container integration requires both ENABLE_FAIL2BAN=1 and the NET_ADMIN capability. Check the effective environment and service status without printing the entire environment:

docker compose exec mailserver \
  sh -c 'test "$ENABLE_FAIL2BAN" = 1 && echo enabled || echo disabled'

docker compose exec mailserver supervisorctl status fail2ban

If it is disabled, Fail2Ban did not create this block. Check the host firewall, a separate security container, a provider firewall, and any upstream proxy. If it is enabled but not running, inspect current startup logs before restarting anything:

docker compose logs --since 20m mailserver

Keep logs private. They can contain real addresses, account names, message identifiers, internal hostnames, and authentication activity.

3. List bans through Docker Mailserver

DMS exposes a supported setup helper for viewing bans:

docker compose exec mailserver setup fail2ban

docker compose exec mailserver setup fail2ban status

The first command shows banned addresses; the status view provides more detail. Match the affected network’s current public source address exactly. Do not assume it is the address shown by a laptop’s Wi-Fi settings: home routers and mobile networks normally present a translated public address, and IPv4 and IPv6 can take different paths.

Treat the address as private operational data. Record it in the incident note, not a public issue or screenshot. If it is absent from every jail, stop following the unban path and investigate the actual network boundary.

4. Identify the jail and triggering failures

Inspect the detailed status for the named jail reported by Fail2Ban:

docker compose exec mailserver \
  fail2ban-client status '<jail-name-from-status>'

Then correlate a short log window with the affected account, protocol, and source. Typical causes include:

EvidenceLikely causeFix before unban
Repeated SASL failures on 587 or 465Stale SMTP password or wrong mailbox identityCorrect or stop the sending client
Repeated Dovecot auth failuresMail app polling with an old IMAP passwordUpdate every configured device
Failures immediately after a password rotationOne forgotten phone, desktop, scanner, or applicationFind all consumers of the old credential
Many account names from one unfamiliar sourceCredential attack rather than your clientLeave it banned and review account security
Many real users appear as one proxy addressSource-address visibility is lostRepair the network design before tuning bans

The official DMS defaults currently document six failed attempts over the previous week and a one-week ban. Check the documentation for your pinned image and any persistent fail2ban-jail.cf override rather than assuming those values never change.

5. Stop the retry loop first

Disable automatic mail checking on the affected devices or stop the application that uses the mailbox. A single public address may represent many clients behind NAT, so fixing the laptop you are holding may not be enough. Check phones, desktop mail apps, monitoring systems, contact forms, scanners, and scheduled jobs that use the same account.

If the credential was intentionally rotated, update it through each client’s protected credential store. Do not put a mailbox password in a Compose command, shell history, process argument, chat, screenshot, or log. If failures are unfamiliar or continue while your devices are stopped, treat the event as hostile: leave the ban in place, preserve evidence, and rotate any credential that may be exposed.

6. Unban only the confirmed address

Once the bad retries have stopped and the address is proven to belong to the affected client network, use Docker Mailserver’s documented helper:

docker compose exec mailserver \
  setup fail2ban unban '<exact-client-ip>'

Replace the placeholder locally; never paste a real client address into a public guide. Repeat the ban listing and confirm only the intended entry disappeared:

docker compose exec mailserver setup fail2ban status

Do not flush every jail, disable ENABLE_FAIL2BAN, remove NET_ADMIN from a running protection design, or restart the whole mail stack merely to clear one known ban. Broad changes can release hostile sources and obscure whether your targeted recovery worked.

7. Verify access without creating another ban

  1. Connect once from the formerly blocked network to the intended port.
  2. Confirm the TLS certificate matches the mail hostname.
  3. Attempt one login with the corrected full mailbox identity and credential.
  4. For SMTP, send one harmless message to a mailbox you control and follow its queue ID to status=sent.
  5. For IMAP, confirm the mailbox opens and a known folder can be listed.
  6. Review the matching server log and make sure authentication failures are not continuing in the background.
  7. Recheck Fail2Ban status and confirm the jail is active and the source remains unbanned.

If SMTP still rejects the credential but the connection no longer times out, the ban is fixed and authentication is now the separate fault. Follow the SASL authentication guide. For mailbox access failures, use the IMAP and Dovecot guide.

8. Make tuning persistent only when evidence supports it

DMS loads persistent Fail2Ban overrides from the mail configuration volume. Its documentation maps docker-data/dms/config/fail2ban-jail.cf to /etc/fail2ban/jail.d/user-jail.local. Use that source if measured normal behaviour proves a jail needs adjustment.

Before changing maxretry, findtime, bantime, or ignoreip, answer three questions:

Never allowlist a whole consumer ISP range, mobile carrier range, or arbitrary public subnet to hide a credential problem. Dynamic addresses also make a one-address allowlist brittle. If a proxy masks origins, repair trusted source-address handling or place rate controls at the boundary that can see the real client; do not exempt the proxy casually.

After a persistent configuration change, validate it and apply it through the maintained service path. The DMS FAQ documents restarting the Fail2Ban sub-service after its configuration changes:

docker compose exec mailserver fail2ban-client -t

docker compose exec mailserver supervisorctl restart fail2ban

docker compose exec mailserver setup fail2ban status

For a clean DMS configuration recreation, preserve mail and state volumes and use the project’s pinned image. Never use docker compose down -v as a troubleshooting shortcut.

Common mistakes

Compact diagnosis order

  1. Compare the same protocol from two independent source networks.
  2. Confirm Fail2Ban is enabled and its supervised process is running.
  3. List current bans through setup fail2ban.
  4. Match the exact private source address and jail.
  5. Correlate the ban with a short server log window.
  6. Stop every client that is repeating the failed credential.
  7. Unban one confirmed address through the DMS helper.
  8. Run one corrected login and one protocol-level success test.
  9. Confirm the jail remains active and no failures continue.
  10. Tune persistent policy only from evidence, with a negative security check.

Authoritative references: Docker Mailserver’s Fail2Ban guide documents required capabilities, defaults, persistent override files, status, and ban management; its FAQ documents the supported unban helper and sub-service restart pattern; and its debugging guide explains log-led diagnosis and clean container recreation. Match commands and configuration paths to the image version you actually run.