Using Fail2ban behind a proxy requires additional configuration to block the IP address of offenders. Depending on how proxy is configured, Internet traffic may appear to the web server as originating from the proxy’s IP address, instead of the visitor’s IP address. This results in Fail2ban blocking traffic from the proxy IP address, preventing visitors from accessing the site.
To properly block offenders, configure the proxy and Nginx to pass and receive the visitor’s IP address. Then configure Fail2ban to add (and remove) the offending IP addresses to a deny-list which is read by Nginx.
Architecture
Proxy: HAProxy 1.6.3 Web Server: Nginx (Fail2ban)
Requests coming from the Internet will hit the proxy server (HAProxy), which analyzes the request and forwards it on to the appropriate server (Nginx). Errata: both systems are running Ubuntu Server 16.04. HAProxy is performing TLS termination and then communicating with the web server with HTTP.
Configuring the Proxy (HAProxy)
By default, HAProxy receives connections from visitors to a frontend and then redirects traffic to the appropriate backend. Connections to the frontend show the visitor’s IP address, while connections made by HAProxy to the backends use HAProxy’s IP address. On the web server, all connections made to it from the proxy will appear to come from the proxy’s IP address.
To change this behavior, use the option forwardfor
directive. You can add this to the defaults
, frontend
, listen
and backend
sections of the HAProxy config. If you wish to apply this to all sections, add it to your default
code block.
defaults
log global
mode http
...
option forwardfor
Once this option is set, HAProxy will take the visitor’s IP address and add it as a HTTP header to the request it makes to the backend. The header name is set to X-Forwarded-For
by default, but you can set custom values as required. The value of the header will be set to the visitor’s IP address. (Note: if you change this header name value, you’ll want to make sure that you’re properly capturing it within Nginx to grab the visitor’s IP address).
Configuring Nginx (Part 1)
Requests from HAProxy to the web server will contain a HTTP header named X-Forwarded-For
that contains the visitor’s IP address. To make this information appear in the logs of Nginx, modify nginx.conf
to include the following directives in your http
block.
http {
...
set_real_ip_from <proxy ip>; # enter your proxy's IP here.
real_ip_header X-Forwarded-For;
...
}
This tells Nginx to grab the IP address from the X-Forwarded-For
header when it comes from the IP address specified in the set_real_ip_from
value. This change will make the visitor’s IP address appear in the access
and error
logs.
Configuring Fail2ban
With the visitor IP addresses now being logged in Nginx’s access
and error
logs, Fail2ban can be configured. First, create a new jail:
[nginx-proxy]
enabled = true
port = http
logpath = %(nginx_error_log)s #path to Nginx's error log
ignoreip = <IPs excluded from jail scope>
action = nginx-proxy #name of the custom action that will be created
This jail will monitor Nginx’s error
log and perform the actions defined below:
actionstart = /etc/init.d/nginx reload
actionstop = /etc/init.d/nginx reload
actionban = echo "deny <ip>;" > /etc/nginx/deny/deny.conf && /etc/init.d/nginx reload
actionunban = grep -i "deny <ip>;" /etc/nginx/deny/deny.conf | sed -i '1d' /etc/nginx/deny/deny.conf && /etc/init.d/nginx reload
The ban action will take the IP address that matches the jail rules (based on max retry and findtime), prefix it with deny
, and add it to the deny.conf
file. Finally, it will force a reload of the Nginx configuration. The unban action greps the deny.conf file for the IP address and removes it from the file. Note: there’s probably a more elegant way to accomplish this.
All of the actions force a hot-reload of the Nginx configuration. This is important - reloading ensures that changes made to the deny.conf file are recognized.
Configuring Nginx (Part 2)
Finally, configure the sites-enabled
file with a location block that includes the deny.conf
file Fail2ban is writing to. This will allow Nginx to block IPs that Fail2ban identifies from the Nginx error
log file.
location / {
include /etc/nginx/deny/deny.conf;
}