Troubleshooting Fail2Ban
Organised by what you see. Start with the container's log, which carries both the service's and the
fail2ban daemon's lines. From the folder that holds docker-compose.yml:
sudo docker compose logs fail2ban --tail 200
sudo docker compose logs fail2ban-ui --tail 200
The console's Logs page shows the daemon's recent lines, and Diagnostics on the Options page proves whether a firewall rule can be written on this host.
Bans that do not block
A ban on the list is not proof that anything is blocked. Two commands on the host tell you:
sudo iptables -S | grep f2b
sudo iptables -L f2b-<jail> -n -v
The first should show a chain named f2b-<jail> for every running jail. In the second, the packet
counters of a ban's rule should rise while that address keeps trying.
| Symptom | Cause | Fix |
|---|---|---|
The ban list grows, iptables -S shows no f2b- chains | The container was started without NET_ADMIN, NET_RAW or host networking. The log at start says WARNING neither iptables backend answers on this host | Start it as in the compose file, with network_mode: host and both capabilities |
The log says WOULD BAN instead of Ban, and the Dashboard shows a banner | The service is not licensed, so it detects and blocks nothing | Install a license on the License page; blocking starts within 30 seconds. See Licensing |
| Every ban vanished at once, and a mail said every ban was lifted | The license lapsed, was removed, or was withdrawn by the Odoo Host Manager | The License page says why, and the Audit log says who removed it. Bans lifted then are not restored |
The f2b- chains exist, but their counters stay at zero | The jail bans into the wrong chain: INPUT for a published container port, or DOCKER-USER for a service on the host itself | Change the chain on the Options page, or give that jail its own chain. See Which chain the bans go into |
| The counters stay at zero behind a reverse proxy | Every packet arrives from the proxy, so the rule for the client's address matches nothing | A ban here can only drop what reaches this host from the client. Run the service on the host that terminates the clients' connections, with jails over that host's logs. See A listed ban is not necessarily an enforced ban |
| The proxy's own address is banned | The protected program logs the proxy's address instead of the client's | Make it log the client's address, for Odoo with proxy_mode = True and X-Forwarded-For from the proxy. See Odoo |
| Every firewall call fails on a NAS or an appliance | Its kernel has no nftables support | Set Fail2Ban__IptablesBackend=legacy, or leave it on auto, which picks it. The Firewall card says which backend is in use. See The iptables backend |
| Banning by hand answers that the address is not blocked, in the daemon's words | The firewall rule could not be written | Run Diagnostics on the Options page. See Banning by hand |
| The chains grow with every container restart, or an old port still bans | Rules left behind by a replaced container, or a jail whose port or chain changed | Rebuild the rules on the Options page. See Repairing the rules |
Jails that catch nothing
| Symptom | Cause | Fix |
|---|---|---|
| A jail shows zero failures however many wrong passwords arrive | The log it names is not mounted into the container, or is written somewhere else | Mount the folder read-only at the same path, as the compose file mounts /var/log. See The log has to be mounted |
| Testing from your own PC never produces a ban | Never ban private addresses is on, so failures from your LAN are ignored | Test from outside, or switch it off after putting your own addresses on the whitelist. See The whitelist and the blacklist |
Saving a jail is refused with The log path ... is outside the log folders this service may read | The path is not in a folder mounted into the container, or not under Jails__LogRoots__<n> | Mount the folder at the same path, or list it. See Where a jail may read |
| Saving a jail is refused with the daemon's own error | fail2ban's configuration test refused the definition; the jail you had keeps running | Correct the filter or the jail and save again. See A bad definition never reaches the daemon |
| A jail file you added by hand disappeared | Jail files are written from the service's database at every start, and unknown files are removed | Add the jail on the Jails page or with PUT /jails/{name} |
| SSH on a Synology NAS counts nothing | DSM writes no Failed password lines | Use the SSH on Synology DSM template. See SSH on a Synology NAS |
Licensing
| Symptom | Cause | Fix |
|---|---|---|
| The License page says the license is bound to another machine | The license was activated on another host, or /etc/machine-id is not mounted and the recreated container looks like a new machine | Mount /etc/machine-id read-only as in the compose file. Moving a license to another host: see Moving a license |
| The hardware challenge on the License page changes after every recreate | /etc/machine-id is not mounted | Mount it, recreate the container, and activate again if the license was activated for the old challenge |
| The license worked for two weeks, then stopped | It was never activated, or no check-in has got through for 14 days | Activate online on the License page. Let the container reach the internet for its daily check-in |
The start-up log says running unlicensed | The reason follows in brackets: no license of its own, a sponsorship that no longer holds, or a refused offer | Install or activate a license, or, when another product sponsors this service, look at that product's license |
API keys and sign-in
| Symptom | Cause | Fix |
|---|---|---|
| Every call answers 401 | The X-Api-Key header is missing, or the key is wrong, revoked or expired | Send a configured key (Api__Keys__<name>) or a live issued one |
Every call from one address answers 429 Too many failed API key attempts, even with the right key | Twenty wrong keys came from that address within five minutes | Find the caller sending the wrong key, then wait out the window. See API keys and backup |
A POST, PUT or DELETE answers 403 | The key is read-only, or the signed-in account's role does not allow it | Use a key that is not read-only, or have an administrator change the role on the Users page. See Roles |
| A call with a session answers 401 | The person's session has ended | Sign in again |
| The console says the service is not reachable | The console cannot reach the API at Fail2BanApi__BaseUrl | Check that the API runs, that the address matches where it listens (ASPNETCORE_URLS), and that the host firewall admits the console's Docker network to port 5421 |
| Nobody can sign in to the console as admin | The password is forgotten, or the account is locked | Change FAIL2BAN_SEED_ADMIN_PASS and restart the API. On a first start with no value set, read the generated one with sudo docker compose exec fail2ban cat /config/first-admin-password |
| Signing in works over an SSH tunnel but not on the server's own name | The console keeps a sign-in only over HTTPS or on localhost | Put a reverse proxy with HTTPS in front of the console. Ui__AllowPlainHttp=true is the alternative for a trusted network only. See the reference |
Every sign-in says The sign-in could not be confirmed. Try again. | Cloudflare Turnstile is refusing: a wrong key, a hostname the widget does not list, or the console cannot reach challenges.cloudflare.com | Start the console with the bypass, fix the cause, and remove the bypass. See Locked out by the check |
| The API or the console does not start | An invalid value, such as an authenticator secret in FAIL2BAN_SEED_ADMIN_TOTP that is not base32 of at least 26 characters, or a trusted proxy entry that is not an address or network | The log's last line, The service did not start or stopped on an error, names the setting. Correct it and start again |
Mail, flags and proxies
| Symptom | Cause | Fix |
|---|---|---|
| No ban notification arrives | No mail server or no recipient on the SMTP page, On a ban is off, or the relay refused the message | Fill them in and send a test message from the page, which shows the relay's own words |
| Notifications arrive minutes after the ban | Bans are collected and sent as one message every Collect for (seconds), five minutes by default | Lower it if you need them sooner. At 0 a host under attack sends a message per ban |
| Settings in the compose file have no effect on mail | Settings saved on the SMTP page replace the environment's entirely | Change them on the SMTP page, or remove the saved set (DELETE /smtp) to hand control back to the environment |
| Banned addresses show no flag | No GeoIP service is set on the GeoIP page, or that service is unlicensed and serves no database | The GeoIP page shows each edition's state. Nothing else depends on the flags. See Flags on the ban list |
| The audit log and the session list show one address for everyone | A reverse proxy in front of the console or the API is not named as trusted | Set Ui__TrustedProxies__0 or Api__TrustedProxies__0 to its address and restart that container. The notice on every page names the address. See A proxy that is not trusted |
Recording what you did
A bug report describes a problem from memory. A session trace records it.
Start one on the Support page, reproduce the problem, and stop it with the recording button that appears beside your name. What you did is stored by the service and can be attached to a bug report.
A trace lists the pages you opened, the controls you used, and anything that went wrong. It can also save a copy of each page as it looked, which is the only thing that answers it rendered wrong.
A trace records which field you filled, never what you put in it, and the places that show a secret are blanked before anything is written down. A copy of a page still shows whatever that page showed - names, host names, addresses - so read a trace before you send it, as you would a log or a support bundle.
A trace belongs to the tab it was started in, and it names the user it belongs to, so a file can be read back to a person.
What an administrator decides
The Support page carries a Configuration card, and what is set there is what every user gets: whether the recording button sits beside your name at all, how much a trace writes down, and how many session traces the service keeps. Lowering a keep count deletes the files above it as soon as the card is saved.
Attaching it
Download the trace from the Support page and send it to whoever asked for it, privately. Never attach it to a public post: see Getting help.
Getting help
Without a license, ask on the community forum on antelao.io, like any free product: say what you did, what you saw, and quote the error. With a license, write to support@antelao.io.
Never post a backup, a log export or your configuration on the forum or in a public issue. They hold your accounts, your settings and visitors' addresses. When Antelao asks for one, send it privately to support@antelao.io.