Upgrade Unifi Network Application (controller) 7.5.x to 8.1.113 using docker and MongoDB

At home I’m using the Unifi switches, wireless access points and a self-hosted network controller.
This controller runs on my Intel NUC as a docker container which I deploy and manage using Portainer.io. Everything works like a charm!

Generally, upgrades of the network controller are pretty straight forward. I just have to change the version number in the yaml file and redeploy. However, starting from version 8.1, it uses an external MongoDB database so that requires some changes. I didn’t have any previous experience with that, but it turned out to be fairly easy.

In my homelab I’m using the docker image from linuxserver.io. This container then sits behind Traefik (reverse proxy) and provides me with Let’s Encrypt certificates, SSL offloading and more. That way everything looks neat in the browser and no need to add or remember any of the port numbers.
It basically looks like this:

If you want to know what’s new in this version, check out the official release notes or watch this great video by Lawrence Systems on YouTube which explains the top new features.

Step 1 – Download the current/latest configuration backup

Go to the Unifi Web UI and download the latest configuration backup. In general, you should always have a backup, but in this case, it’s mandatory. Upgrading to 8.1.x requires us to migrate from a mongodb-less installation to an installation with a separate MongoDB container.
More over, we will have to deploy a fresh installation and then use our backup to restore the previous configuration.

Go to Settings -> System -> Backups -> Download

I just selected No Limit in the dropdown box to get the full config and statistics and selected the last created backup in the list below. Hit Download to store it on my computer:

This creates a file called network_backup_29.03.2024_00-00_v7.5.187.unf or similar.

Step 2 – Prepare the docker environment

Next we need to create new folders on the docker host to store the configuration of the new Unifi and MongoDB containers. Of course you can also use default folders and skip this step. However I prefer to keep all my stuff in a particular folder to make it easy for when I need to restore from backup, I know what is what and where it is instead of having folders with auto-generated names with strings in them.

I created a few folders:

# folder to store the Unifi controller configuration files
mkdir /your/path/docker/unifi-network-controller/config

# folder to store the Unifi controller database files
mkdir /your/path/docker/unifi-db/data 

For the initial setup you also need to create a file called init-mongo.js and place it into the folder with the database files e.g. /your/path/docker/unifi-db/init-mongo.js and add the following lines into it to create users and permissions. Then mount it into the MongoDB container.

# create the file
nano /your/path/docker/unifi-db/init-mongo.js

# add the following lines into the file and change the user and pwd if desired
db.getSiblingDB("unifi").createUser({user: "unifi", pwd: "unifipwd", roles: [{role: "readWrite", db: "unifi"}]});
db.getSiblingDB("unifi_stat").createUser({user: "unifi", pwd: "unifipwd", roles: [{role: "readWrite", db: "unifi_stat"}]});

Step 3 – Stop the old stack / container

Time to say goodbye to our old network controller with version 7.5.x!
This is how my old config looked like: (GitHub)

version: "2.1"
networks: 
  proxy:
    external: true
    
services:
  unifi-controller: 
    container_name: unifi-controller
    hostname: unifi
    image: ghcr.io/linuxserver/unifi-controller:version-7.5.187
    networks:
      proxy:
    dns:
      - 192.168.0.1 # change to your DNS
      - 192.168.0.2 # change to your DNS
    environment: 
      PUID: 1000 # change to your user id
      PGID: 1000 # change to your group id
      #MEM_LIMIT: 1024M
      #MEM_STARTUP: 1024M
      TZ: Europe/Amsterdam # change to your time zone
    ports: 
      - "3478:3478/udp" # Unifi STUN port
      - "10001:10001/udp" # Unifi AP discovery
      - "8080:8080" # Required for device communication
      #- "8443:8443"
      #- "1900:1900/udp"
      #- "8843:8843"
      #- "8880:8880"
      - "6789:6789" # For mobile throughput test
      #- "5514:5514/udp"
    volumes: 
      - /your/path/docker/unifi:/config
    restart: unless-stopped
    labels: # remove if you do not use traefik
      - traefik.enable=true
      - traefik.http.routers.unifi.rule=Host(`unifi.yourdomain.com`)
      - traefik.http.routers.unifi.entrypoints=websecure
      - traefik.http.routers.unifi.tls=true
      - traefik.http.routers.unifi.tls.certresolver=cert-resolver
      - traefik.http.services.unifi.loadbalancer.server.scheme=https
      - traefik.http.services.unifi.loadbalancer.server.port=8443

Now let’s stop the container, this can be easily done from Portainer or via the command line.

In Portainer just click Stop this stack and the container will be stopped.

Via CLI we can simply type:

docker container unifi stop

Step 4 – Create a stack / yaml file for the new version

First let’s have a look at our new configuration file. This time it contains 2 containers as we’ve added a MongoDB: (GitHub)

version: "2.1"
networks: 
  proxy:
    external: true
    
services:
  unifi-network-application:
    image: lscr.io/linuxserver/unifi-network-application:version-8.1.113
    container_name: unifi-network-application
    depends_on:
      - unifi-db
    networks:
      proxy:
    dns:
      - 192.168.0.1 # change to your DNS
      - 192.168.0.2 # change to your DNS
    environment: 
      PUID: 1000 # change to your user id
      PGID: 1000 # change to your group id
      TZ: Europe/Amsterdam # change to your time zone
      MONGO_USER: unifi
      MONGO_PASS: unifipwd
      MONGO_HOST: unifi-db 
      MONGO_PORT: 27017
      MONGO_DBNAME: unifi
      #- MEM_LIMIT=1024 # optional
      #- MEM_STARTUP=1024 # optional
      #- MONGO_TLS: # optional
      #- MONGO_AUTHSOURCE: # optional
    ports: 
      #- 8443:8443 # Web Admin UI
      - 3478:3478/udp # STUN port
      - 10001:10001/udp # Required for AP discovery
      - 8080:8080 # Required for device communication
      - 1900:1900/udp # Required for Make controller discoverable on L2 network option
      - 8843:8843 # guest portal HTTPS redirect port
      - 8880:8880 # guest portal HTTP redirect port
      - 6789:6789 # For mobile throughput test
      - 5514:5514/udp # Remote syslog port
    volumes: 
      - /your/path/docker/unifi-network-controller/config:/config
    restart: unless-stopped
    labels: # remove if you do not use traefik
      - traefik.enable=true
      - traefik.http.routers.unifi.rule=Host(`unifi.yourdomain.com`)
      - traefik.http.routers.unifi.entrypoints=websecure
      - traefik.http.routers.unifi.tls=true
      - traefik.http.routers.unifi.tls.certresolver=cert-resolver
      - traefik.http.services.unifi.loadbalancer.server.scheme=https
      - traefik.http.services.unifi.loadbalancer.server.port=8443
  unifi-db:
    image: docker.io/mongo:7.0.7
    container_name: unifi-db
    networks:
      proxy:
    ports:
      - 27017:27017
    volumes:
      - /your/path/docker/unifi-db/data:/data/db
      - /your/path/docker/unifi-db/init-mongo.js:/docker-entrypoint-initdb.d/init-mongo.js:ro
    command: 
      mongod --port 27017
    restart: unless-stopped

In Portainer, go to Stacks -> Add Stack
Give the stack a name, copy paste your configuration and click Deploy the stack to create the containers.

For docker compose, just create a new yml file, copy paste the configuration in it. Then run the following command to fetch and deploy the stack.

docker-compose -f /your/path/unifi-new.yml up

Issue

At this time, I had an issue in my lab. The stack would deploy, but the Web UI wouldn’t show up. The Unifi container logs would show that it could not connect to the MongoDB, hmm!
Then I remembered that my Unifi controller sits behind Traefik and that the MongoDB container did not have any network specified. I added the correct proxy network to the MongoDB container and poof, it worked! YES!

Step 5 – Restore the previous configuration

Time to hit the Unifi Web UI and check what’s going on there!
Right! It’s a new installation so there’s nothing yet.
Once we hit the Web UI, we’re prompted with the option to deploy it as a new controller or restore from backup.

Here we click Restore and upload the previously downloaded backup from Step 1.
The restore starts and we see it’s migrating the old data to the new format:

After a few minutes, we refresh again and now we get the login screen.
It also shows the latest version so that is looking all great!

Once we login, we see again the version number, Self-Hosted, uptime etc.

That’s it! Time to check out the official release notes again and see what we can play with.

Hope this was useful, thanks again for reading!