Recovering UniFi historical data from multiple backups
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.