Setup a Unifi Controller on FreeBSD with Apache Reverse Proxy

There is an official FreeBSD port, but there is no official 'supported' configuration or documentation for using a Unifi Controller behind a reverse proxy. This guide will hopefully save you time from researching and digging around for a solution. If you are not familiar with what a Unifi Controller is then you may want to have a look at Ubiquiti's products.

I was able to compile this configuration by scraping through posts on the Ubuquiti community forums[2][3], blogs[4], as well as some trial and error.

Requirements

  • A supported version FreeBSD

Install Unifi Controller

Install the port using the pre-built package. This will pull in any dependencies such as a JDK and MongoDB. As of this writing the latest version of the Unifi Controller is 6. If you prefer a more stable release you can install the Unifi LTS version instead.[1]

pkg install -y unifi6

When the port and dependencies are done installing, enable the Unifi service. There is no need to enable MongoDB, it will be started automatically by the Unifi server.

sysrc unifi_enable="YES"

If all you want is a Unifi Controller then you could stop here, but it would not be available on port 80 or 443. The purpose of the reverse proxy is to access it through the browser without having to specify a port number at the end of the URL.

Install & Configure Apache

If you already have Apache installed and running, you can skip this section.

The stock version of the package has everything required to use Apache as a reverse HTTP proxy. Install and enable using pkg.

pkg install -y apache24
sysrc apache24_enable="YES"

Enable the required modules in /usr/local/etc/apache24/httpd.conf:

  • proxy_module
  • proxy_http_module
  • proxy_wstunnel_module
  • ssl_module
  • rewrite_module

These commands will enable the mentioned modules by un-commenting them from httpd.conf.

sed -i '' 's,#\(LoadModule proxy_module.*$\),\1,g' /usr/local/etc/apache24/httpd.conf
sed -i '' 's,#\(LoadModule proxy_http_module.*$\),\1,g' /usr/local/etc/apache24/httpd.conf
sed -i '' 's,#\(LoadModule proxy_wstunnel_module.*$\),\1,g' /usr/local/etc/apache24/httpd.conf
sed -i '' 's,#\(LoadModule ssl_module.*$\),\1,g' /usr/local/etc/apache24/httpd.conf
sed -i '' 's,#\(LoadModule rewrite_module.*$\),\1,g' /usr/local/etc/apache24/httpd.conf

Enable Apache to listen on port 443 to support TLS connections.

cat << EOF >/usr/local/etc/apache24/modules.d/443_mod_ssl.conf
Listen *:443
EOF

Setup Reverse Proxy

We'll use the V-Host feature to simplify things. If for whatever reason you can't use Apache V-Host's, you'll need to adjust the examples to fit your requirements.

Create a file named unifi.conf in /usr/local/etc/apache24/Includes with the following contents. Each section is commented to explain it's purpose.

# HTTP Virtual Host
<VirtualHost *:80>
    ServerName unifi
    ServerAlias unifi.domain.tld

    # Correctly pass encoded slashes in the URL to the backend
    AllowEncodedSlashes NoDecode

    # Reverse Proxy setting to allow authentication to work
    ProxyPreserveHost On
   
    # Proxy all requests to the backend HTTP and websocket server
    ProxyPass "/wss/" "wss://127.0.0.1:8080/wss/"
    ProxyPassReverse "/wss/" "wss://127.0.0.1:8080/wss/"
    ProxyPass "/" "http://127.0.0.1:8080/"
    ProxyPassReverse "/" "http://127.0.0.1:8080/"

    # URL Re-writing is required when proxying websockets
    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /wss/(.*) wss://127.0.0.1:8080/wss/$1 [P]

    # Limit access to internal network clients
    <Proxy *>
        <RequireAll>
            Require ip 192.168.0.0/16
        </RequireAll>
    </Proxy>
</VirtualHost>

# HTTPS Virtual Host
<VirtualHost *:443>
    ServerName unifi
    ServerAlias unifi.domain.tld

    # Correctly pass encoded slashes in the URL to the backend
    AllowEncodedSlashes NoDecode

    # Reverse Proxy setting to allow authentication to work
    ProxyPreserveHost On

    # Proxy all requests to the backend HTTPS and websocket server
    ProxyPass "/wss/" "wss://127.0.0.1:8443/wss/"
    ProxyPassReverse "/wss/" "wss://127.0.0.1:8443/wss/"
    ProxyPass "/" "https://127.0.0.1:8443/"
    ProxyPassReverse "/" "https://127.0.0.1:8443/"

    # URL Re-writing is required when proxying websockets
    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule /wss/(.*) wss://127.0.0.1:8443/wss/$1 [P]

    # Limit access to internal network clients
    <Proxy *>
        <RequireAll>
            Require ip 192.168.0.0/16
        </RequireAll>
    </Proxy>

    # Needed in order to Proxy TLS sessions
    SSLProxyEngine on
    SSLProxyVerify none

    # Allow self-signed, non-matching name,  and expired certificate
    SSLProxyCheckPeerCN off
    SSLProxyCheckPeerName off
    SSLProxyCheckPeerExpire off

    # Provide a proper TLS certificate.
    # Get a free signed certificate from Pacy World.  Mention this article. (TDMC/Pacy World, LLC. root CA required on clients)
    SSLCertificateFile /usr/local/etc/ssl/certs/unifi.cert.pem
    SSLCertificateKeyFile /usr/local/etc/ssl/private/unifi.key.pem
    SSLCACertificateFile /usr/local/etc/ssl/certs/morante-ca-bundle.pem
</VirtualHost>

Change the paths to your TLS certificate as needed. Unfortunately HTTPS is required for the Unifi Controller to work properly.

    SSLCertificateFile /usr/local/etc/ssl/certs/unifi.cert.pem
    SSLCertificateKeyFile /usr/local/etc/ssl/private/unifi.key.pem
    SSLCACertificateFile /usr/local/etc/ssl/certs/morante-ca-bundle.pem

Change your subnet if it's not 192.168.0.0/16 or if you want to limit access to a specific IP. The purpose of this is to prevent public access to your Unifi Controller. Remember to do it for both the HTTP and HTTPS virtual hosts.

    <Proxy *>
        <RequireAll>
            Require ip 192.168.0.0/16
        </RequireAll>
    </Proxy>

Set the server name and and optional alias for the virtual host. Remember to do it for both HTTP and HTTPS.

    ServerName unifi
    ServerAlias unifi.domain.tld

Create DNS records if needed and save your changes.

Start your Servers

Start the Apache and Unifi Controller servers.

service apache24 start
service unifi start

Open Unifi Controller

Open the URL used for ServerName (or ServerAlias) in your browser. You'll be presented with the Setup Wizard.

If/when you have completed the setup wizard for your controller, You should be automatically redirected to the TLS version of the Unifi Controller login page while keeping the correct URL

Enter in your credentials to sign in. You should see the dashboard and no errors should popup.


[1] These instructions where written for Unifi Controller version 6.0.x. Earlier or later versions may include changes that could break redirection.
[2] community.ui.com: https://community.ui.com/questions/UniFi-behind-apache-reverse-proxy
[3] community.ui.com: https://community.ui.com/questions/Controller-behind-Apache-Reverse-Proxy-greater-login-does-not-work
[4] Warren Argus: https://blog.warbel.net/index.php/2017/10/04/how-to-configure-a-unifi-controller-behind-an-apache-reverse-proxy-with-letsencrypt

PacyWorld Button
Powered by Pacy