I wanted to find out some information about the WiFi usage on my network over the last year for reasons I won’t mention for the sake of brevity. Unfortunately, I learned I had my data retention settings set far lower than I needed: the last 30 days for daily statistics. However, I have monthly snapshots of the whole file system so, in theory, I should be able to at least load and view these statics by spinning up a container pointed to the backup data instead of the live data.

Upon closer inspection, I found UniFi uses MongoDB internally and upon inspection of the database, it appears the statistics data is stored in its own database (ace_stat) with a very simple structure such that a simple mongodump of the backup database and a mongorestore to the live database would result in a clean merger of data.

Now as for actually doing this, things get a bit tricky. To actually read the data, a MongoDB server needs to be running for mongodump to be able to connect to it. Same goes for the mongorestore operation. My first idea was to expose the port of the live database to the host to keep the live instance running during the operation, and also prevent having to start up yet another instance of MongoDB. This was thwarted by the server within the container actually being bound to the loopback interface, which makes it unreachable even if exposed (which is perhaps a good thing as the internal MongoDB server doesn’t require any authentication and would be exposed to the public if bound to a public interface without a firewall).

This answer gave me a very good tip (see workaround #3). I could simply start up another docker instance in the same network namespace as the UniFi controller and be able to connect to the existing MongoDB server without having to expose any ports at all.

Now to spin up another MongoDB container for the backup database.

$ docker-compose exec unifi-controller bash
root@9046c1c1cbe3:/usr/lib/unifi# bin/mongod --version
db version v3.4.23
git version: 324017ede1dbb1c9554dd2dceb15f8da3c59d0e8

As you can see, the version of MongoDB used by the current version of the controller is v3.4.23, which I will use to prevent any possible incompatibilities. After copying the read-only ZFS snapshot database to a new directory under /tmp, it can be mounted with a volume. Note: overlay volumes were just recently merged into Podman which should make it possible to mount in place.

$ docker run --name mongo --rm --net container:$(docker-compose ps -q) -v "/tmp/backup/data/db:/data/db" mongo:3.4.23

Now we can enter a shell inside the container to move the data:

$ docker exec -it mongo bash
# mongodump -d ace_stat
# mongorestore --port 27117 -d ace_stat dump/ace_stat

It may complain about some conflicting IDs, but that is normal if the data overlaps. Now if you look at your UniFi stats, you should see data appear for the range of the backup! These is nothing particularly novel here, though I felt compelled to share as this took far longer to figure out in the first place than I care to admit, and I learned a handful of tricks in the process.