Fail2ban, unable to forward host_addr from nginx

Tags: #<Tag:0x00007f3281e302c8>

I’m trying to setup fail2ban on my server. I’m running the HomeAssistant docker image behind nginx which listens for requests from my public website. All failed auth attempts log as coming from ip address ::1 which I’m not sure what that means but I believe it’s because the host_addr is not being forwarded from nginx. So I followed the docs (https://www.home-assistant.io/integrations/fail2ban/) and added the following to my nginx server config:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Now the problem I’m having: I’m trying to add the required line to my configuration.yml be the home-assistant docs.

http:
  use_x_forwarded_for: true

But I get a config error in HA:

Invalid config for [http]: some but not all values in the same group of inclusion 'proxy' @ data['http'][<proxy>]. Got None. (See /config/configuration.yaml, line 36). 

Reading the docs at https://www.home-assistant.io/integrations/http, it says:

You must also whitelist trusted proxies using the trusted_proxies setting for this to work.

Changing my config file to:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 127.0.0.1

Allows the config file to checkout but the server returns other errors.

2020-11-09 12:33:08 WARNING (MainThread) [homeassistant.components.http.forwarded] Received X-Forwarded-For header from untrusted proxy ::1, headers not processed
2020-11-09 12:33:08 ERROR (MainThread) [homeassistant.components.http.forwarded] Too many headers for X-Forwarded-For: ['<my_external_ip>', '<my_external_ip>']
2020-11-09 12:33:09 WARNING (MainThread) [homeassistant.components.http.forwarded] Received X-Forwarded-For header from untrusted proxy ::1, headers not processed
2020-11-09 12:33:09 ERROR (MainThread) [homeassistant.components.http.forwarded] Too many headers for X-Forwarded-For: ['<my_external_ip>', '<my_external_ip>']
2020-11-09 12:33:10 WARNING (MainThread) [homeassistant.components.http.forwarded] Received X-Forwarded-For header from untrusted proxy ::1, headers not processed
2020-11-09 12:33:10 ERROR (MainThread) [homeassistant.components.http.forwarded] Too many headers for X-Forwarded-For: ['<my_external_ip>', '<my_external_ip>']
2020-11-09 12:33:20 WARNING (MainThread) [homeassistant.components.http.forwarded] Received X-Forwarded-For header from untrusted proxy ::1, headers not processed
2020-11-09 12:33:20 ERROR (MainThread) [homeassistant.components.http.forwarded] Too many headers for X-Forwarded-For: ['<my_external_ip>', '<my_external_ip>']
2020-11-09 12:33:20 WARNING (MainThread) [homeassistant.components.http.forwarded] Received X-Forwarded-For header from untrusted proxy ::1, headers not processed
2020-11-09 12:33:20 ERROR (MainThread) [homeassistant.components.http.forwarded] Too many headers for X-Forwarded-For: ['<my_external_ip>', '<my_external_ip>']

How do I set up fail2ban to work with Home Assistant?

This should probably be docker IP of nginx container or the host running nginx

@tmjpugh, thanks. I added the IP of the Docker interface (the IP address shown when I run ip address. The interface name is docker0). But then all addresses were 127.0.0.1. So I also added that to the trusted_proxies list but then all requests were coming from the public IP of my server. I added my public IP to the trusted_proxies list but that didn’t change anything. All requests are still showing as coming from my public IP. It seems like the hass documentation should be cleared up here.

Is nginx running in docker?
Is fail to Ban in docker?

Have you read nginx docs for the the stuff you have set in nginx. Understanding this better may help you setup appropriately.

Honestly the examples are generic but you may need to make minor change for your system. Look at nginx config at link. This is general setup for nginx proxy to ha. I don’t use fail to Ban to I not have clear idea how traffic will route through it.

Ultimately, I believe trusted_ proxy should be IP of last address sending traffic (likely nginx).

I ask 2 question above because this determine how traffic should route and IP address to use, using docker or local networking

Also, take into account that

If nginx in docker and you send to [email protected] traffic is like
WAN>>LAN>>dockerlan>>nginx>>dockerlan>>LAN>>dockerlan>>ha

If nginx in docker and you send to [email protected] traffic is like
WAN>>LAN>>dockerlan>>nginx>>dockerlan>>ha

If nginx on host and you send to [email protected] traffic is like
WAN>>LAN>>nginx>>LAN>>dockerlan>>ha

I say this as how you setup trusted proxy and x_forward_for must take the routing into account as in first example you can imagine that from HA perspective nginxIP is not @localhost but docker IP but all traffic forwarded through localhost.

The ::1 in the log line

2020-11-09 12:33:08 WARNING (MainThread) [homeassistant.components.http.forwarded] Received X-Forwarded-For header from untrusted proxy ::1, headers not processed

Is the IPV6 loopback adapter. So add that to your trusted_proxies. Ex:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 127.0.0.1
    - ::1
  ip_ban_enabled: true
  login_attempts_threshold: 3

That did the trick for me. I have nginx proxying to HA running on a Mac without Docker.

I just wanted to follow up on this and post how I finally got this working. @tmjpugh was correct. I needed to add the IP range for the Docker container and add that to the trusted hosts list. In my case it was 172.17.0.0/16. My config yaml looks like this now:

 http:
    use_x_forwarded_for: true
    trusted_proxies:
        - 127.0.0.1
        - ::1
        - 172.17.0.0/16

I was able to find the Docker IP range using the following process:

Get the list of currently available networks

$ docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
d06e70b21455        bridge              bridge              local
9de201e51e9c        host                host                local
eaf2f3e49b17        none                null                local

Inspect each network for the subnet. In my case, it was the first network, bridge.

$ docker network inspect bridge | grep Subnet
                    "Subnet": "172.17.0.0/16",

Home Assistant now correctly reports failed auth attempts and fail2ban correctly recognizes them.

I hope this helps anyone else who stumbles upon this in the future.