UniFi Protect mit Docker auf dem Raspberry Pi 4 installieren

Es geht, UniFi Protect im Docker Container auf eigener ARM64 Hardware installieren!
Ich nutze das nicht produktiv, sondern erstmal nur in einer Testumgebung zum ausprobieren.

Diese Anleitung basiert auf https://github.com/markdegrootnl/unifi-protect-arm64.
Funktioniert, einige bugs, kommt aber leider nicht über die Version 3.1.16 heraus. (neue Images lassen sich nicht erstellen)

*** Neues Repository gefunden, siehe #2. ***

23.06.2024 - aktuellste Version: UniFi OS 3.1.16 mit UniFi Protect 2.8.35 (die 3.2.x lässt sich nicht erstellen)
24.09.2023 - Anleitung aktualisiert (neues Docker Image erstellen, 3.1.16)

mein Setup:

  • Raspberry Pi 4 (4GB)
  • Raspberry Pi OS Lite (64bit, Debian 11 Bullseye)
  • 120GB SSD mit USB-Adapter (für Pi OS)
  • 500GB SSD mit USB-Adapter (für storage)
  • 2 Kameras (G3 Flex, G3 Micro)

Geht auch mit nur einer grossen SSD. Der Ordner /storage muss aber => 100GB sein, da sonst unifi-protect nicht startet.

Docker installieren

pi@nvr:~ $ curl -fsSL https://get.docker.com -o get-docker.sh
pi@nvr:~ $ sudo sh get-docker.sh

pi@nvr:~ $ docker -v
Docker version 24.0.5, build ced0996

Den aktuellen Benutzer (nicht root) in die Docker Gruppe aufnehmen.

pi@nvr:~ $ sudo usermod -aG docker ${USER}

System vorbereiten

Problem mit systemd im Docker Container. (Failed to connect to bus: No such file or directory)
Am Ende der /boot/cmdline.txt diesen Kernel Parameter anhängen und neu starten.

systemd.unified_cgroup_hierarchy=0

SSD nach /storage einbinden. (Die Platte erscheint nach dem einstecken bei mir als /dev/sdb.)
Mit, z.B. cfdisk, die SSD löschen, eine Partition erstellen und diese dann mit ext4 formatieren.

pi@nvr:~ $ sudo mkdir /storage
pi@nvr:~ $ sudo cfdisk /dev/sdb
pi@nvr:~ $ sudo mkfs.ext4 /dev/sdb1

Die UUID der Festplatte ermitteln

pi@nvr:~ $ lsblk -f
NAME   FSTYPE FSVER LABEL  UUID                                 FSAVAIL FSUSE% MOUNTPOINT
sda
├─sda1 vfat   FAT32 bootfs 0B22-2966                             224.3M    12% /boot
└─sda2 ext4   1.0   rootfs 3ad7386b-e1ae-4032-ae33-0c40f5ecc4ac   24.9G     7% /
sdb
└─sdb1 ext4   1.0          81a19315-d7ff-4ef3-8367-e945dd06816a

und in die /etc/fstab eintragen, damit sie automatisch nach jedem reboot unter /storage eingebunden wird!

UUID=81a19315-d7ff-4ef3-8367-e945dd06816a   /storage   ext4   auto,nofail,sync,users,rw   0   0

Reboot und kontrollieren ob die Platte eingebunden ist. (erscheint jetzt als /dev/sda1)

pi@nvr:~ $ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        28G  3.3G   24G  13% /
devtmpfs        3.6G     0  3.6G   0% /dev
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           1.6G  1.3M  1.6G   1% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
/dev/sda1       458G   40K  435G   1% /storage
/dev/sdb1       255M   31M  225M  13% /boot
tmpfs           782M     0  782M   0% /run/user/1000

Docker

Container erstellen und starten. (das Image kommt mit UNVR 3.1.14 und Protect 2.8.35)

docker run -d \
    --name unifi-protect  \
    --privileged \
    --tmpfs /run \
    --tmpfs /run/lock \
    --tmpfs /tmp \
    --restart unless-stopped \
    -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
    -v /storage/srv:/srv \
    -v /storage/data:/data \
    -v /storage/persistent:/persistent \
    --network host \
    -e STORAGE_DISK=/dev/sda1 \
    markdegroot/unifi-protect-arm64

Container läuft.

pi@nvr:~ $ docker ps
CONTAINER ID   IMAGE                             COMMAND                  CREATED          STATUS          PORTS     NAMES
ba511ed9ce27   markdegroot/unifi-protect-arm64   "/lib/systemd/systemd"   44 minutes ago   Up 28 minutes             unifi-protect

UniFi Protect

Über https://ip-addresse kann das WebUI gestartet werden.

Fehlersuche

Sollte die WebUI mal nicht erreichbar sein, in den Container wechseln.

pi@nvr:~ $ docker exec -it unifi-protect bash

Prüfen ob die Dienste laufen (ggf. neu starten) und die Ports offen sind.

Sollte die WebUI nicht laden oder Dienste nicht starten, den Container stoppen und den Ordner /storage/data löschen. (unifi-core)
Die unifi-protect Konfiguration bleibt erhalten. (/storage/srv, Kamera Settings und Recordings.)

Jetzt sollte sich das WebUI mit der Ersteinrichtung wieder zeigen. Das Problem hatte ich mehrmals und konnte mir damit helfen.

Updates

Updates lassen sich nicht über das WebUI installieren. Es muss ein neues Docker Image erstellt werden!

Neues Image erstellen.

auf dem Pi alles als root

sudo su

build Verzeichnis anlegen

mkdir /opt/build-unvr && cd /opt/build-unvr

benötigte Pakete installieren

apt install git binwalk dpkg-repack

unifi-protect-arm64 Git Repository klonen

git clone https://github.com/markdegrootnl/unifi-protect-arm64.git

UNVR4 Firmware herunterladen und entpacken

mkdir /opt/build-unvr/firmware && cd /opt/build-unvr/firmware

wget -O fwupdate.bin https://fw-download.ubnt.com/data/unifi-nvr/5146-UNVR-3.1.16-923e980d-ab69-4884-b152-e68329b6a80a.bin
binwalk -e fwupdate.bin

Paketliste erstellen

dpkg-query --admindir=_fwupdate.bin.extracted/squashfs-root/var/lib/dpkg/ -W -f='${package} | ${Maintainer}\n' | grep -E "@ubnt.com|@ui.com" | cut -d "|" -f 1 > packages.txt

deb Pakete neu erstellen (die warnings können ignoriert werden)

while read pkg; do
  dpkg-repack --root=_fwupdate.bin.extracted/squashfs-root/ --arch=arm64 ${pkg}
done < packages.txt

die /usr/lib/version Datei aus der Firmware nach unifi-protect-arm64/put-version-file-here kopieren

cp -v _fwupdate.bin.extracted/squashfs-root/usr/lib/version ../unifi-protect-arm64/put-version-file-here/

einige deb Dateien aus der Firmware nach unifi-protect-arm64/put-deb-file-here kopieren (ubnt-archive-keyring, unifi-core, ubnt-tools, ulp-go, unifi-assets-unvr)

cp -v ubnt-archive-keyring* unifi-core* ubnt-tools* ulp-go* unifi-assets-unvr* ../unifi-protect-arm64/put-deb-files-here/

Änderungen im Dockerfile! (Fehlermeldungen beim docker build)

# fehlermeldung: debconf: delaying package configuration, since apt-utils is not installed
+ install apt-utils

# fehlermeldung: sed: can't read /usr/share/unifi-core/app/config/config.yaml: No such file or directory
- #&& sed -i 's/redirectHostname: unifi//' /usr/share/unifi-core/app/config/config.yaml \

# fehlermeldung: This script, located at https://deb.nodesource.com/setup_X, used to install Node.js is deprecated now and will eventually be made inactive.
+ neue Installationsroutine für Node.js (https://github.com/nodesource/distributions)

# pull request (https://github.com/markdegrootnl/unifi-protect-arm64/pull/16/commits/4b915be6e13286ba44f2956b9d6dfd499cc6af52)
+ && chmod 666 /etc/timezone /etc/localtime

Bitte mein Dockerfile benutzen und das unifi-protect-arm64/Dockerfile ersetzen!

cd /opt/build-unvr/unifi-protect-arm64
curl -sL https://bachmann-lan.de/projects/unifi-protect-arm64/Dockerfile -o Dockerfile

neues Docker Image erstellen

docker build -t markdegroot/unifi-protect-arm64:3.1.16 .

Container aus neuem Image erstellen.

Docker Images auflisten.

$ docker images
REPOSITORY                        TAG       IMAGE ID       CREATED         SIZE
markdegroot/unifi-protect-arm64   3.1.16    0f7d634890be   9 minutes ago   1.18GB
markdegroot/unifi-protect-arm64   latest    333237f5ae00   4 weeks ago     1.28GB

Docker Container auflisten. (CONTAINER-ID kopieren)

$ docker container list
CONTAINER ID   IMAGE                             COMMAND                  CREATED             STATUS             PORTS     NAMES
338743a93a57   markdegroot/unifi-protect-arm64   "/lib/systemd/systemd"   About an hour ago   Up About an hour             unifi-protect

Docker Container stoppen.

$ docker stop unifi-protect
unifi-protect

Docker Container löschen.

$ docker rm 338743a93a57
338743a93a57

Erst nachdem ich /storage/data gelöscht habe, startet der unifi-core Service im Container. (die Config des NVR geht verloren)

rm -r /storage/data

Docker Container aus neuem Image erstellen.

docker run -d \
    --name unifi-protect  \
    --privileged \
    --tmpfs /run \
    --tmpfs /run/lock \
    --tmpfs /tmp \
    --restart unless-stopped \
    -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
    -v /storage/srv:/srv \
    -v /storage/data:/data \
    -v /storage/persistent:/persistent \
    -v /etc/timezone:/etc/timezone:ro \
    -v /etc/localtime:/etc/localtime:ro \
    -e TZ=Europe/Berlin \
    --network host \
    -e STORAGE_DISK=/dev/sda2 \
    markdegroot/unifi-protect-arm64:3.1.16

neuer Docker Container läuft

$ docker ps
CONTAINER ID   IMAGE                                   COMMAND                  CREATED         STATUS         PORTS     NAMES
a32a8aa7f9c7   markdegroot/unifi-protect-arm64:3.1.16  "/lib/systemd/systemd"   8 seconds ago   Up 7 seconds             unifi-protect

Da die Config weg ist, wird das Setup neu  gestartet.

Update durchgeführt … ;)

Sonstiges

  • der UNVR läuft bisher ohne Probleme mit den zwei Kameras
  • alles OHNE einen Ubiquiti Account nutzbar (auch die Android Protect App)
  • Fehler: die Storage Seite lädt nicht, keine Übersicht der Speichernutzung (bekanntes Problem)
  • Fehler: System Config Backup funktioniert nicht
  • Update: großer Aufwand und die Config des NVR geht verloren
  • alles ziemlich frickelig …

Links

9 Gedanken zu „UniFi Protect mit Docker auf dem Raspberry Pi 4 installieren“

  1. Hi, I’m trying this on my pi5, but i cannott get the WEBUI to open,
    dmesg no longer throw read only error after systemd.unified_cgroup_hierarchy=0 fix,
    the only red error i see on dmesg is this but not sure if it related.

    systemd-journald.service: Attaching egress BPF program to cgroup /sys/fs/cgroup/unified/system.slice/systemd-journald.service failed: Operation not permitted

    The portainer doesnt show any logs either

    secondly you mention checking the services, problem is, after pulling the first docker image none of the services existed for my case.
    The github doesnt mention anything about services either. What am i missing?

    Antworten
  2. Hi,

    danke für die Doku, die ist super!
    Ein Frage, bei mir auf dem rpi4 startet protect mit der Option “-v /sys/fs/cgroup:/sys/fs/cgroup:ro” nicht. Lasse ich diese weg, startet protect. Ich nutze Raspberry Pi OS 11 (64-bit), welche kommt bei dir zum Einsatz?

    VG,
    Michael

    Antworten
  3. Hi,

    danke für deine Antwort (wer lesen kann… steht auch ganz oben; ich bl*). Habe 3.1.16 nun am rennen. Geht nun auch mit ohne cgroup Option.
    Schicke dir die Tage noch ein Patch für Dockerfile, evtl. kann es der eine oder andere Gebrauchen :-)

    Version 3.2.X habe ich bisher nicht am laufen, die Abhängigkeiten zu nginx in Debian 11 funktionieren noch nicht.
    Hast du irgendeine 3.2er Version am laufen und wie hast du das mit den Abhängigkeiten hinbekommen?

    VG

    Antworten
  4. Also,
    die 3.16 läuft auch super schon länger, aber das mit den 3.2 er geht einfach nicht. Image naja aber dann container geht einfach nicht. Hab schon viel probiert.

    mfg

    Antworten
  5. Auf dem Odroid M1S mit Ubuntu-Image startet die Protect-App mit der Fehlermeldung “Cannot read properties of null (reading ‘writeThroughput’)” ständig neu. Grund war, dass im Ubuntu-Kernel IO Accounting nicht konfiguriert ist. Es half, den Kernel mit den Optionen CONFIG_TASKSTATS, CONFIG_TASK_DELAY_ACCT und CONFIG_TASK_IO_ACCOUNTING neu zu bauen. Vermutlich geht alternativ auch das Debian-Image von Odroid. Vielleicht hilft das ja jemandem. :-)

    Das 3.1.16-Image konnte ich dank deiner ausführlichen Anleitung nachbauen. Wenn ich es starte, leitet der Browser aber immer sofort auf http://unifi weiter, ich erreiche die Weboberfläche deshalb gar nicht. Mit dem alten markdegroot/unifi-protect-arm64:latest-Image funktioniert es. Hast du eine Idee, was ich falsch gemacht haben könnte? (Ich habe den Container mit leeren /storage-Verzeichnissen komplett neu aufgesetzt, kann also keine alte Konfiguration sein.)

    Danke!

    Antworten
  6. Vielen Dank für das tolle Image und die hervorragende Anleitung!

    Mit “root@piprotect:/# unifi-protect ” gabs jeweils eine Fehlermeldung wie “Error: EACCES: permission denied, mkdir ‘/data/unifi-protect'”. Seltsam.
    Docker hat von cgroups v1 zu cgroups v2 aktualisiert.

    Das sollte wohl dann so starten:

    docker run -d \
    –name unifi-protect \
    –privileged -v /sys/fs/cgroup:/sys/fs/cgroup:rw \
    –tmpfs /run \
    –tmpfs /run/lock \
    –tmpfs /tmp \
    –restart unless-stopped \
    -v /sys/fs/cgroup:/sys/fs/cgroup:ro \
    -v /storage/srv:/srv \
    -v /storage/data:/data \
    -v /storage/persistent:/persistent \
    –network host \
    -e STORAGE_DISK=/dev/sda1 \
    markdegroot/unifi-protect-arm64

    So. Jetzt muss ich nur noch rausfinden, warum der Webaccess nichts zeigt…

    Antworten

Schreibe einen Kommentar