Setting up a remote Unifi Controller with Traefik — manage your APs over the internet
In this post, I will explain how to configure a Unifi Network Application on a docker container to control a Unifi AP based on a remote location.
Requirements
- Docker and Traefik installed on your server
- Public Domain name
- Port 80 & 443 forwarded from your router to your server
Setup Unifi Controller with Docker
Unifi controller runs on a docker container, supported by a Mongo database to store the data. Let’s create a new directory to save our docker-compose file and its configurations.
mkdir unifi
vim docker-compose.yaml
docker-compose.yaml
services:
unifi-network-application:
image: lscr.io/linuxserver/unifi-network-application:latest
container_name: unifi-network-application
privileged: false
security_opt:
- no-new-privileges:true
depends_on:
unifi-db:
condition: service_started
required: true
networks:
- traefik-public
- default
env_file: .env
environment:
- MONGO_HOST=unifi-db
- MONGO_PORT=27017
- MONGO_DBNAME=unifi-db
- MEM_LIMIT=1024 #optional
- MEM_STARTUP=1024 #optional
volumes:
- ./<controller_data_dir>:/config
ports:
- 8443:8443
- 3478:3478/udp
- 10001:10001/udp
- 8080:8080
restart: unless-stopped
unifi-db:
image: docker.io/mongo:7.0
container_name: unifi-db
env_file: .env
volumes:
- ./<mongo_data_dir>:/data/db
- ./<mongo_data_dir>/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
restart: unless-stopped
networks:
traefik-public:
external: true
Then, we need to create our .env file and define some variables:
PUID=1000
PGID=1000
TZ=<your_timezone_here>
MONGO_USER=<put_random_user_here>
MONGO_PASS=<put_random_password_here>
Our Unifi controller and database are ready, let’s start and set them up:
docker-compose up -d
Access to the controller by typing https://server_ip:8443 in your browser and create your Unifi controller user. Once everything is set up, you will see the login page:
Enabling dashboard
This example includes traefik dashboard configuration, a UI that shows the status of our traefik resources as routers, services, middlewares, and so on. There are several ways to configure the dashboard, I chose to redirect port 8080 and create a traefik router (via labels) that provides its dashboard when accessing http://HOST_LOCAL_IP:8080/dashboard/
Now your Unifi controller is up & running on your local network. Let’s configure Traefik to manage requests from the remote Access Point.
Unifi Access Point configuration
The Unifi controller handles device management and adoption via the 8080 port. We will configure the AP to send requests to unifi.mydomain.com by connecting to the AP via SSH and running the following command:
set-inform http://unifi.mydomain.com/inform
The AP now knows how to talk with our remote Unifi controller. Now, let’s configure our custom host on the controller and establish the appropriate routing via traefik.
Override inform host on the controller
Sign in to the unifi network application as previously and go to Settings > System > Advanced > Inform Host and override with unifi.mydomain.com
Configure Traefik routing
The Traefik container retrieves its configuration from the static and dynamic config files (as shown in the documentation). This final step consists of routing the requests from unifi.mydomain.com to the unifi controller container and 8080 port. To achieve this, three new resources need to be defined: an entrypoint, a router and a service.
Entrypoint — static config
The entrypoint is going to be defined on the Traefik static configuration file.
entryPoints:
web:
address: :80
The entrypoint listens to the incoming trafic from port 80. It is important to listen on http (not https) due to unifi AP inform request does not support TLS encryption. This means that routing the requests over 443 port would not work.
HTTP router & service — dynamic config
The http router handles POST requests to the configured url on the AP (unifi.mydomain.com/inform) and redirects them to the unifi controller container and the 8080 port. This is defined on the dynamic configuration file:
traefik.yml
http:
routers:
Unifi:
rule: Host(`unifi.mydomain.com`) && Path(`/inform`) && Method(`POST`)
entrypoints:
- web
service: unifi
services:
unifi:
loadBalancer:
servers:
- url: "http://unifi-network-application:8080"
Controller info & debugging
At this point and with the AP adopted, the controller recognizes that the AP is up and shows some statistics:
If network issues are encountered, the access log on the unifi controller shows the incoming requests to the controller container. See these logs entering into the container:
_> docker exec -ti unifi-network-application /bin/bash
root@67cfb7f7b31c:/usr/lib/unifi# cd logs
root@67cfb7f7b31c:/usr/lib/unifi/logs# cat access.log
...
...
[2024-06-15 15:38:02,870] HTTP/1.1[172.18.0.3] 1ms 200 POST /inform
[2024-06-15 15:38:13,099] HTTP/1.1[172.18.0.3] 1ms 200 POST /inform
[2024-06-15 15:38:23,438] HTTP/1.1[172.18.0.3] 1ms 200 POST /inform
[2024-06-15 15:38:33,677] HTTP/1.1[172.18.0.3] 1ms 200 POST /inform
[2024-06-15 15:38:43,919] HTTP/1.1[172.18.0.3] 1ms 200 POST /inform
root@67cfb7f7b31c:/usr/lib/unifi/logs#
When everything is working as expected, the log contains inform POST requests that returns code 200 :)