Unifi Controller behind HAproxy reverse proxy (including mobile apps)

Getting the Unifi controller working behind a reverse-proxy isn’t that hard (if you manage to reverse-proxy 8443 on http and 8080 on tcp to your controller). At least not if you only want your APs to be able to register and access the webinterface from a Browser.

However, getting it to work with the iOS App caused me some headache. The iOS App just kept reconnecting forever and no changes went through. Turns out the Unifi App doesn’t like HTTP/2. We need to disable h2 capabilities on the frontend serving the controller.

Now that was fixed the app no longer reconnected, but still did not work at all. Turns out the iOS App sets Host header to “Host: unifi.example.org:443” if you specify a port in the connection settings that is not the Unifi default of 8443. Current Browsers don’t do that if you use default ports like 80 + 443. Luckily that is also an easy fix, either by using an addtional hdr(Host) match including “Host: unifi.example.org:443” or by using the controller as default_backend for the frontend (if the frontend is dedicated for serving the controller).

Working config:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
frontend tcp-frontend-unifi-inform
    mode            tcp
    bind            [203.0.113.1]:8080
    bind            [2001:DB8::1]:8080
    default_backend b-unifi.example.org-8080
frontend http-frontend-shared
    mode            http
    bind            [203.0.113.1]:80 alpn http/1.1
    bind            [2001:DB8::1]:80 alpn http/1.1
    bind            [203.0.113.1]:443 ssl crt /etc/haproxy/ssl/ alpn http/1.1
    bind            [2001:DB8::1]:443 ssl crt /etc/haproxy/ssl/ alpn http/1.1
    use_backend     b-unifi.example.org if { hdr(host) -i unifi.example.org }
    use_backend     b-unifi.example.org if { hdr(host) -i unifi.example.org:443 }
    default_backend b-sorry.example.org
backend b-unifi.example.org
    balance         source
    http-request    set-header X-Forwarded-Proto https if { ssl_fc }
    http-request    set-header X-Forwarded-Port %[dst_port]
    http-request    set-header X-Real-IP %[src]
    http-request    set-header X-Forward-For %[src]
    http-request    add-header Connection "upgrade"
    http-response   set-header Strict-Transport-Security max-age=15768000
    redirect        scheme https code 301 if !{ ssl_fc }
    server          unifi-controller.example.org [fd4d:446e:67a5:100::30]:8443 ssl verify none check inter 2000 rise 2 fall 5 maxconn 1000
backend b-unifi.example.org-8080
    balance         source
    server          unifi-controller.example.org [fd4d:446e:67a5:100::30]:8080 check inter 2000 rise 2 fall 5 maxconn 1000