# fail2ban vs DenyHosts

> fail2ban vs DenyHosts: hosts.deny and TCP wrappers vs firewall bans, maintenance status in 2026, OpenSSH libwrap removal, and a step-by-step migration to fail2ban.
>
> Source: https://fail2ban.dev/alternatives/denyhosts/ · Updated 2026-10-25 · Checked against fail2ban 1.1.1
> fail2ban.dev is an independent guide, not the official fail2ban project.

**Use fail2ban, not DenyHosts.** DenyHosts only protects SSH, its last tagged release dates from 2015, Debian stopped shipping it after Debian 7, and its classic blocking method — writing attackers into `/etc/hosts.deny` — only works if `sshd` was built with TCP wrappers support, which upstream OpenSSH removed in 2014 and RHEL 8+ and Fedora don't have at all. fail2ban covers SSH and 96 other filters, bans in the firewall and is actively maintained.

If you still run DenyHosts on an old server, it probably works in the narrow sense — but it is worth replacing, and the migration takes about ten minutes.

## fail2ban vs DenyHosts at a glance

| Feature | fail2ban | DenyHosts |
|---|---|---|
| What it protects | SSH plus mail, web, FTP, VPN, databases… (96 filters) | SSH only |
| Detection source | Log files, systemd journal | SSH auth log file only (`/var/log/auth.log` or `/var/log/secure`) |
| Response | Firewall (nftables, iptables, firewalld, ufw, pf), Cloudflare, mail, and optionally `hosts.deny` | Writes `/etc/hosts.deny`; 3.x can also add iptables rules |
| Thresholds | `maxretry` within `findtime`, per jail | Separate limits for invalid users, valid users and root |
| Ban expiry | `bantime` (10 min by default), incremental bans | `PURGE_DENY` (empty by default = never purged) |
| Shared intel | Can report to AbuseIPDB / blocklist.de | Optional sync server (disabled by default) |
| IPv6 | Yes | Not documented |
| systemd journal | Yes (`backend = systemd`) | No |
| License | GPL-2.0-or-later | GPL-2.0 |
| Maintenance | Active, 1.1.1 (Aug 2026) | Last tagged release v3.1 (Sep 2015); occasional commits since |

## How DenyHosts works

DenyHosts is a Python script, usually run as a daemon, that reads the SSH log named in `SECURE_LOG` and counts failed logins per source address. Its stock `denyhosts.conf` uses three thresholds: 5 failures for users that don't exist (`DENY_THRESHOLD_INVALID`), 10 for real users (`DENY_THRESHOLD_VALID`) and **1 for root** (`DENY_THRESHOLD_ROOT`). When an address crosses a threshold, DenyHosts appends a line to `/etc/hosts.deny`:

```text
```

The GitHub-maintained 3.x line added an `IPTABLES` option that also inserts a firewall rule, and a `BLOCKPORT` option to limit it to port 22. It also kept an optional synchronization feature for sharing attackers between DenyHosts users, disabled by default.

## Why DenyHosts is obsolete

- **TCP wrappers are going away.** OpenSSH removed libwrap support upstream in version 6.7 (2014). Debian and Ubuntu still patch it back into their `openssh-server`, so `hosts.deny` still works there, but Red Hat removed TCP wrappers entirely in RHEL 8 and Fedora dropped them too. On those systems, a DenyHosts install that only writes `hosts.deny` blocks nothing.
- **No journal support.** Many current systems log SSH only to the systemd journal (Debian 12 doesn't install rsyslog by default), so there is no `auth.log` for DenyHosts to read.
- **SSH only.** Attackers who move on to your mail server or web login are invisible to it.
- **Slow release cadence.** The last tagged release is v3.1 from September 2015. The repository received a few maintenance commits in 2025, but there has been no stable release in a decade, and Debian removed the package after Debian 7 "wheezy".
- **Late blocking.** `hosts.deny` is checked after the TCP connection is accepted, so attackers still reach `sshd`. A firewall ban drops packets before they get there.

## How fail2ban does the same job

The fail2ban equivalent of a DenyHosts setup is a single jail:

```ini
[sshd]
enabled  = true
backend  = systemd
maxretry = 5
findtime = 10m
bantime  = 1d
bantime.increment = true
```

DenyHosts' "one strike for root" has no direct equivalent, but the better fix is in SSH itself: set `PermitRootLogin no` (or `prohibit-password`) in `sshd_config` so root password guesses can never succeed.

> **Want the hosts.deny behaviour anyway?**
fail2ban ships a [`hostsdeny` action](/actions/#action-hostsdeny) that writes the same `daemon: IP` lines. It only works where `sshd` still honours TCP wrappers (Debian, Ubuntu), so a firewall action is the better default.

## Migrate from DenyHosts to fail2ban


1. **Stop DenyHosts** so it no longer edits `hosts.deny`:
   `sudo systemctl disable --now denyhosts` (or remove its init script/cron entry on older systems).
2. **Save its block list** if you want to keep the worst offenders: `grep '^sshd:' /etc/hosts.deny > ~/denyhosts-blocked.txt`.
3. **Clean `/etc/hosts.deny`**: remove the lines DenyHosts added (they look like `sshd: 203.0.113.42`), keeping any entries you wrote by hand. Then remove the package and its work directory (commonly `/var/lib/denyhosts`).
4. **Install fail2ban** with your package manager — see the [install guides](/install/).
5. **Create `/etc/fail2ban/jail.local`** with the `[sshd]` jail above. Put your own addresses in `ignoreip` (DenyHosts used `allowed-hosts` in its work directory for the same purpose). Why `jail.local` and not `jail.conf` is explained in [jail.local explained](/config/jail-local/).
6. **Start and check**:
   `sudo systemctl enable --now fail2ban` then `sudo fail2ban-client status sshd`.
7. **Optionally re-ban the old list** with a long ban:
   `sudo fail2ban-client set sshd banip $(awk '{print $2}' ~/denyhosts-blocked.txt)`

Re-importing old DenyHosts entries is usually not worth it — most of those addresses were transient bots years ago — but it doesn't hurt if the list is small.

## Can you run DenyHosts and fail2ban together?

Technically yes, since one writes `hosts.deny` and the other the firewall. In practice it only makes unbanning confusing: an address can be blocked by either tool and you have to check both. Pick fail2ban and remove DenyHosts.

## FAQ

### Is DenyHosts still maintained?

Barely. The GitHub project's last tagged release is v3.1 from September 2015, though a few maintenance commits landed in 2025. Debian dropped the package after Debian 7, and it protects only SSH. For a new server, use fail2ban or another maintained tool instead.

### What is the difference between fail2ban and DenyHosts?

DenyHosts watches only the SSH log and blocks attackers by writing them to `/etc/hosts.deny`, which relies on TCP wrappers. fail2ban watches logs or the systemd journal for many services and bans in the firewall, with expiring and incremental bans. fail2ban is more flexible and actively maintained.

### Does /etc/hosts.deny still work for SSH?

Only if your `sshd` is built with TCP wrappers. Upstream OpenSSH removed that support in 6.7; Debian and Ubuntu patch it back in, so it still works there. RHEL 8 and later, Rocky, AlmaLinux and Fedora don't support TCP wrappers, so `hosts.deny` has no effect on SSH on those systems.

### How do I replace DenyHosts with fail2ban?

Stop and remove DenyHosts, delete the `sshd: IP` lines it added to `/etc/hosts.deny`, install fail2ban, and enable an `[sshd]` jail in `/etc/fail2ban/jail.local` with `backend = systemd` on journal-only systems. Add your own IPs to `ignoreip` and check the jail with `fail2ban-client status sshd`.
