Odroid HC4 / NAS

Da sich mein Qnap NAS verabschiedet hat, war dies die Gelegenheit ein NAS selber zu bauen.

Anforderungen an Services

Ein NAS bietet heutzutage, nebst dem Speichern von Daten, diverse Services an. Folgendes möchte ich auch auf dem HC4 nutzen:

NAS-Strategie

Als erstes ist es eine gute Idee zu klären, was man mit dem NAS überhaupt erreichen möchte. Hier meine Kriterien:

  • Datenverlust: Die Daten sollen bestmöglich vor Verlust geschützt werden.
  • Verfügbarkeit: Die Daten können auch mal 1-2 Tage nicht verfügbar sein. Mehr als 2 Tage Ausfall sollten es aber nicht sein.

Massnahmen Datenverlust

  • Das NAS soll in einem RAID-1 Verbund laufen. Damit werden die Daten gespiegelt abgespeichert, so dass ein Festplatten-Ausfall einfach abgefedert werden kann.
  • Gleichzeitig werden die “Core-Daten” (alles ausser Musik, Filme etc.) regelmässig zusätzlich auf ein zweites Gerät gespeichert (rsync).

Massnahmen Verfügbarkeit

  • RAID-1 hilft hier ebenfalls, die Daten bleiben bei einem Ausfall einer der beiden Festplatten weiterhin verfügbar.
  • Es kann aber auch sein, dass die Hardware (SD-Karte oder HC4) ausfällt. Die SD-Karte klone ich zu diesem Zweck. So kann ich bei einem Ausfall die SD-Karte einfach austauschen. Beim HC4 wird es aber etwas schwieriger. Ich habe mir zwei HC4 Geräte besorgt. Bei einem Ausfall kann ich entsprechend auch den HC4 sofort ersetzen.

Hardware

Ich habe bereits mit dem Odroid HC2 sehr gute Erfahrungen gemacht. HC4 ist der Nachfolger und bietet neu mehr CPU Leistung, einen 64Bit Prozessor, 4Gb RAM, etc.

Das HC4 Gehäuse

Update 2024: Sie scheinen mittlerweile verstanden zu haben, dass das Originale Case nix bringt. Es gibt mittlerweile von odroid ein HC4 Case Kit, mit welchem man sich ein vernünftiges Case selber zusammenschrauben kann.

Das Gehäuse vom HC4 ist meines Erachtens nicht gelungen. Die Festplatten werden vertikal in den SATA-Anschluss des HC4 eingeschoben. Das ganze ist mir viel zu wackelig. “Serverschrank-Ready” ist dieses Ding so definitiv nicht. Auch frage ich mich, ob es sinnvoll ist, SATA Stecker so zu verwenden. Ich kann mir nicht vorstellen, dass die SATA Stecker des HC4 solide genug sind um häufiges wechseln von Festplatten zu überstehen:

Das SBC Case Builder Gehäuse

Ich drucke mir mit dem 3D Drucker, basierend auf dem Design von SBC Case Builder mein eigenes Gehäuse. Ziel soll es sein, ein Gehäuse zu produzieren, welches auch mit gutem Gewissen in einem Server- oder Netzwerkschrank platziert werden kann:

Der SBC-Build hat aber leider eine kleine Schwäche. Auf der einen Seite, wo sich das Board befindet, kann der Deckel nicht angeschraubt werden. Daraus resultiert, dass beim Stromanschluss ein Spalt von ca 2mm entsteht. Dem habe ich einfach mit einem Kabelbinder entgegengewirkt. Ist nicht schön, aber für den Serverschrankt tut es das allemal:

Alles in allem kann man den HC4 nun mit gutem Gewissen in den Serverschrank stellen:

  • Die Festplatten sind sehr gut fixiert und es wackelt rein gar nichts.
  • Der zweite Lüfter, den ich über den USB-Port betreibe, sorgt für zusätlich gute Belüftung.
  • Der Stock-Lüfter befindet sich übrigens unterhalb des HC4-Boards. Ein Lüfter wurde so montiert, dass er die Luft nach aussen bläst und einer zieht die Luft an.
  • Der Lüftungsregulierer erlaubt es die Touren des Lüfters einzustellen. Ich habe ihn auf ca. 50% eingestellt. Damit wird immer noch gut belüftet und der Lärmpegel hält sich in Grenzen. => Serverschrank-Ready.
  • Ist es schön? => NEIN 😀

Betriebssystem

Der HC4 bietet neu (im Gegensatz noch zum HC2) die Möglichkeit das Betriebssystem auf der SATA-Disk zu installieren. Hardkernel hat dafür den Petitboot Bootloader vorinstalliert. Dieser Bootloader ermöglicht den HC4 Start ohne eingelegte Disk oder SD-Karte. Anschliessend kann über netboot ein Betriebssystem direkt auf einer Disk installiert werden. Ich habe aber für die Installation das Image auf die SD Karte geschreiben und dabei folgende zwei Images getestet:

Die Ubuntu-Version stammt von Hardkernel und ist mit Petitboot kompatibel. Das bedeutet, dass das Betriebssystem (nach 10s wartezeit) von Petitboot erkannt und gebootet wird. Dieses Ubuntu könnte damit z.B. auf einer SATA SSD Disk installiert werden. Das Betriebssystem wird damit dann direkt von der SSD betrieben und nicht auf der SD-Karte.

Armbian hingegen wird von Petitboot nicht erkannt. bei Armbian muss Petitboot komplett entfernt werden. Mit gelöschtem Petitboot versucht der HC4 auf der SD-Karte ein Betriebssystem zu finden und startet dieses dann direkt. Dies hat den Vorteil, dass der Start sofort durchgeführt wird (ohne 10s) Wartezeit. Dafür aber auch den Nachteil, dass das Betriebssystem auf der SD-Karte liegt. SD-Karten sind bekanntlich nicht dafür geeignet ein Betriebssystem (mit vielen writes) zu betreiben.

Ich entscheide mich für eine Installation mit Armbian. Armbian ist leichtgewichtiger als die Hardkernel Ubuntu-Version und auf den HC4 abgestimmt. Armbian ist mir deswegen etwas sympatischer – ist aber eher ein Bauchentscheid als wirklich mit harten Fakten begründet…

Installation Armbian

# flash_eraseall /dev/mtd0
# flash_eraseall /dev/mtd1
# flash_eraseall /dev/mtd2
# flash_eraseall /dev/mtd3
    • => Dadurch wird der SPI-Flash-Speicher gelöscht und der HC4 startet ab sofort direkt von der SD Karte.
  • HC4 mit eingelegter Armbian SD-Karte starten
  • Installations-Anweisungen befolgen

Grund-Installation Armbian ist damit abgeschlossen

Lüfter-Support aktivieren:

vi /etc/fancontrol

Inhalt einfügen:

INTERVAL=10
DEVPATH=hwmon0=devices/virtual/thermal/thermal_zone0 hwmon2=devices/platform/pwm-fan
DEVNAME=hwmon0=cpu_thermal hwmon2=pwmfan
FCTEMPS=hwmon2/pwm1=hwmon0/temp1_input
FCFANS= hwmon2/pwm1=hwmon2/fan1_input
MINTEMP=hwmon2/pwm1=50
MAXTEMP=hwmon2/pwm1=60
MINSTART=hwmon2/pwm1=20
MINSTOP=hwmon2/pwm1=28
MINPWM=hwmon2/pwm1=0
MAXPWM=hwmon2/pwm1=255

Restart fancontrol

sudo systemctl restart fancontrol

Wichtig: Wenn man den Kernel 5.15.x einsetzt, muss die Zeile FCFANS=hwmon2/pwm1=hwmon2/fan1_input entfernt werden.

Reboot Issue

Ein soft reboot (sudo reboot) funktionierte in diesem Zustand nicht. Die Lösung ist hier zu finden:

armbian-config ---> System -> Install -> Install/Update the bootloader on SPI/Flash

Danach bootet armbian sauber nach einem “sudo reboot”.

Wiederherstellen/Update Petitboot

Es besteht die Möglichkeit Petitboot zu aktualisieren bzw. über das gleiche Vorgehen, nach einer Löschung, wieder zu installieren.

Dafür stellt Hardkernel ein Image zur Vefügung:

  • Download aktuelles spiupdate-image unter http://ppa.linuxfactory.or.kr/images/petitboot/odroidhc4/ => Die heute aktuelle Version ist “spiupdate_odroidhc4_20201112.img”
  • Optional:
    • Download letzte Firmware “spiboot-20220317.img
    • Auf der geflashten SD-Karte das File “spiboot.img” durch die neue heruntergeladene Variante ersetzen. Das File muss natürlich nach spiboot.img umbenannt werden.
  • Den HC4 mit dieser SD-Karte booten. Das Firmware-Update wird automatisch durchgeführt.
Hint: Boot ohne Petitboot

Gut zu Wissen ist, dass der HC4 auch ohne das entfernen von Petitboot die Möglichkeit bietet ohne Petitboot zu starten. Dafür muss man einfach den schwarzen Reset-Knopf drücken und gleichzeitig den Stromstecker einstecken. Dann warten, bis der HC4 blau zu blinken beginnt. Damit startet HC4 ohne Petitboot. => Das ist aber natürlich für den täglichen Gebrauch nicht wirklich zu empfehlen.

Installation Festplatten / RAID1

Partition erstellen

Als erstes schliesse ich eine der beiden 8TB Festplatten an und boote das System neu. Nun eine Partition erstellen:

sudo fdisk /dev/sda
g

Dies erstellt eine gpt-Partitionstabelle und wir erhalten das Disk-Label (GUID) => Dieses notieren

  • Nun mit n eine Partition erstellen und alle vorgeschlagenen Standardwerte übernehmen.
  • Am Schluss mit w die Änderungen auf die Platte schreiben.
sudo fdisk -l
  • Zeigt nun die partitionierte Festplatte an
  • Filesystem erstellen

  • Wir erstellen ein Btrfs Filesystem, über welches dann Raid1 umgesetzt wird.
mkfs.btrfs /dev/sda1

Dies erstellt das Filesystem und weist eine UUID zu (UUID notieren).

Die notierten GUID und UUID habe ich mir mit einem P-Touch auf ein Label ausgedruckt und auf die Disk geklebt. Das ermöglicht im späteren Betrieb die Disk einwandfrei zu identifizieren.

Der Disk Identifier kann folgendermassen ermittelt werden

fdisk -l /dev/sda

Subvolumes einrichten

Btrfs unterstützt Subvolumes. Btrfs hat ein unabhängiges einhängbares Root-Verzeichnis für das Volume (Subvolume der obersten Ebene) und für jedes Subvolume. Ein Btrfs-Volume kann also mehr als einen einzelnen Dateibaum enthalten. Einen ganze Tree  von Dateibäumen enthalten. Ein Btrfs-Subvolume kann man sich als POSIX-Dateinamensraum vorstellen.

Es ist zum empfehlen Subvolumes für voneinander unabhängige Datenablagen zu verwenden (z.B. Backup, Filme, Musik, etc.)

Als erstes hängen wir das Btrfs Root-Subvolume ein:

sudo mount /dev/sda1 /mnt

Ich erstelle für mich ein Subvolume, welches alle Multimedia-Daten beinhalten soll (Filme, Musik, Bücher, etc.):

btrfs subvolume create /mnt/@backup

Nun das Root-Subvolume wieder aushängen

sudo umount /dev/sda1

Jetzt kann man das erstellte Subvolume direkt in das Filesystem einhängen:

sudo mkdir /mnt/multimedia
sudo vi /etc/fstab
/dev/sda1 /mnt/multimedia btrfs defaults,nofail,noatime,compress=zstd,subvol=@multimedia 0 0

Dieser fstab Eintrag kann anschliessend über die CLI gemountet werden

sudo mount /mnt/multimedia

Komplette Rechte auf /mnt/multimedia setzen

chmod 0777 /mnt/multimedia

Auf diese Art und Weise kann man so viele Subvolumes erstellen wie man eben braucht.

Raid1

Bis jetzt haben wir nur eine HDD installiert. Nachdem das Filesystem angelegt ist funktioniert (an dieser Stelle habe ich auch bereits Samba eingerichtet und getestet), setzen wir die zweite Disk (nach einem shutdown und anschliessendem Neustart) ein und erstellen das Raid1.

Hinweis 1: An dieser Stelle habe ich festgestellt, dass ich die erste HDD in Slot2 des HC4 gesteckt habe. Der SATA-Slot, der sich näher am Stromanschluss/Netzwerkanschluss befindet ist offensichtlich Slot Nr. 2 – Nach dem Restart hat nämlich die zweite HDD /dev/sda zugewiesen bekommen und wodurch dann natürlich das vorhin erstellte Btrfs Filesystem nicht mehr verfügbar war. Nach einem erneuten Stopp, wechsel der Festplatten und Neustart war dieses Problem behoben.

Hinweis 2: Bei der Einrichtung von Raid1 habe ich mich gefragt, ob es denn möglich ist, den Raid-level je nach subvolume zu setzen. Das ist offenbar nicht möglich. Btrfs scheint dies als Feature offen zu haben, es ist aber offenbar seit fast 10 Jahren nichts mehr in diese Richtung gegangen. Also: Nein. 🙂

fdisk verrät mir, wie die neue Festplatte erkannt wurde:

sudo fdisk -l

In meinem Falle ist die neue HDD das Device /dev/sdb.

Nun wird für diese HDD (/dev/sdb) ebenfalls eine gpt-Partition und eine Partition über die gesamte Platte erstellt siehe hier.

Nun teilen wir btrfs mit, dass die neue Platte als Raid-1 Verbund zur ersten Platte verwendet werden soll. Dafür hängen wir alle gemounteten subvolumes erst aus.

sudo umount /mnt/<subvolumes>

Nun hängen wir die gesamte erste Festplatte ein

sudo mount /dev/sda1 /mnt

btrfs die neue Festplatte bekannt machen

sudo btrfs device add /dev/sdb1 /mnt

/dev/sdb in einen Raid1-Verbund aufnehmen. Erklärung:

  • -mconvert= Option, ein neues Profil “raid1” auf die Metadaten des Diskarrays anzuwenden
  • -dconvert = Neues Profil “raid1” auf die Nutzdaten des Diskarrays zu legen
# sudo btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt
# Done, had to relocate 5 out of 5 chunks

Damit wurde der Raid1 Verbund erstellt. Wenn die zweite HDD  (wie bei mir zu Testzwecken) kleiner als die erste HDD ist, dann wird der Gesamtspeicherplatz neu maimal die Grösse der kleineren Festplatte betragen. Was bei mir auch so korrekt funktioniert hat.

Nun die ganze Festplatte wieder aushängen und die zuvor angelegten subvolumes einhängen (z.B. durch reboot, so dass die fstab Einträge geladen werden).

sudo umount /mnt
sudo reboot

Test / weitere Befehle

Überblick über das Raid

# btrfs fi usage /mnt/<subvolume>

Overall:
Device size: 14.55TiB
Device allocated: 10.06GiB
Device unallocated: 14.54TiB
Device missing: 0.00B
Used: 4.51GiB
Free (estimated): 7.27TiB (min: 7.27TiB)
Free (statfs, df): 7.27TiB
Data ratio: 2.00
Metadata ratio: 2.00
Global reserve: 6.11MiB (used: 0.00B)
Multiple profiles: no

Data,RAID1: Size:3.00GiB, Used:2.25GiB (74.92%)
/dev/sda1 3.00GiB
/dev/sdb1 3.00GiB

Metadata,RAID1: Size:2.00GiB, Used:8.55MiB (0.42%)
/dev/sda1 2.00GiB
/dev/sdb1 2.00GiB

System,RAID1: Size:32.00MiB, Used:16.00KiB (0.05%)
/dev/sda1 32.00MiB
/dev/sdb1 32.00MiB

Unallocated:
/dev/sda1 7.27TiB
/dev/sdb1 7.27TiB

Prüfen der Devices

sudo btrfs fi show /mnt/<subvolume>

Label: none uuid: 0edb47d3-ea4a-4667-b609-223212ec41b1
Total devices 2 FS bytes used 2.26GiB
devid 1 size 7.28TiB used 5.03GiB path /dev/sda1
devid 2 size 7.28TiB used 5.03GiB path /dev/sdb1

Raid 1 – Festplattenwechel

Es ist eine Frage der Zeit, bis eine Festplatte den Geist aufgeben wird. Da wir ein Raid1 haben, sollte dies kein grossen Problem darstellen. Ob das aber funktioniert, muss getestet werden.

Das Vorgehen

  1. System herunterfahren
  2. Defekte HDD entfernen und stattdessen neue HDD in den Slot stecken.
    Als Simulation ersetzte ich die zweite (kleinere) HDD nun mit einer neuen gleichgrossen HDD (8TB)
  3. System hochfahren.
    Nach dem reboot wurden die subvolumes, wie erwartet, nicht mehr gemountet. Ich habe aber auch nirgends einen Hinweis erhalten, dass es ein Problem mit BTRFS gibt (auch nicht in dmesg). An dieser Stelle kann man über fdisk die Devices identifizieren.

    sudo fdisk -l

    Anhand der auf der HDD gekenntzeichneten GUID stelle ich fest, dass die noch funktionierende HDD als /dev/sda und die neue als /dev/sdb erkannt wurde.

  4. RAID im degraded mode mounten.
    Damit die noch funktionierende Festplatte eingehängt werden kann, muss das Raid mit der Option -o degraded eingehängt werden

    sudo mkdir /mnt/temp
    sudo mount -o degraded /dev/sda1 /mnt/temp

    Nun kann überprüft werden, welche Festplatte fehlt (in diesem Falle ID2):

    # sudo btrfs device usage /mnt/temp
    
    /dev/sda1, ID: 1
    Device size: 7.28TiB
    Device slack: 3.50KiB
    Data,RAID1: 3.00GiB
    Metadata,RAID1: 1.00GiB
    System,RAID1: 32.00MiB
    Unallocated: 7.27TiB
    
    missing, ID: 2
    Device size: 0.00B
    Device slack: 0.00B
    Data,RAID1: 3.00GiB
    Metadata,RAID1: 1.00GiB
    System,RAID1: 32.00MiB
    Unallocated: 1.81TiB
  5. Die neue Festplatte partitionieren
    Die neue Festplatte (hier /dev/sdb) muss nun wie her beschrieben partitioniert werden.
  6. RAID wiederherstellen (`btrfs replace`).
    Nun kann die neue Festtplatte in den Raid1 Verbund aufgenommen werden. Hier wird das vermisste Device mit der ID 2, welches sich an /dev/sdb1 in das Raid1, welches an /mnt/temp eingebunden wurde, aufgenommen (siehe auch btrfs Doku).

    sudo btrfs replace start 2 /dev/sdb1 /mnt/temp

    Der replace-Prozess wird im Hintergrund durchgeführt. Das kann einige Stunden dauern. Der Status des replace kann folgendermassen abgerufen werden

    sudo btrfs replace status /mnt/temp/

    Sobald der replace-Prozess beendet wurde (zu überprüfen mit status) kann die neue disk angezeigt werden:

    # sudo btrfs device usage /mnt/temp
    
    /dev/sda1, ID: 1
    Device size: 7.28TiB
    Device slack: 3.50KiB
    Data,single: 3.00GiB
    Data,RAID1: 3.00GiB
    Metadata,single: 2.00GiB
    Metadata,RAID1: 1.00GiB
    System,single: 64.00MiB
    System,RAID1: 32.00MiB
    Unallocated: 7.27TiB
    
    /dev/sdb1, ID: 2
    Device size: 7.28TiB
    Device slack: 5.46TiB
    Data,RAID1: 3.00GiB
    Metadata,RAID1: 1.00GiB
    System,RAID1: 32.00MiB
    Unallocated: 1.81TiB
  7. Jetzt die Redundaz wieder herstellen
    # sudo btrfs balance start -dconvert=raid1,soft -mconvert=raid1,soft /mnt/temp
    # Done, had to relocate 7 out of 12 chunks
  8. System rebooten

Nach dem reboot ist das Raid1 mit der neuen Festplatte wieder hergestellt und alle subvolumes sollten wieder korrekt gemountet sein.

Raid1 vergrössern

Die alte Festplatte hatte in meinem Falle eine Grössen von 2TB, die neue Festplatte hat eine Grösse von 8TB. Damit habe ich 2x 8TB verbaut. Das Raid1 hat aber zu diesem Zeitpunkt immer noch die Grösse der früheren kleineren Festplatte. Wir müssen also nun noch die Grösse des Raids auf den maximal verfügbaren Speicher anheben. Dies geschieht über den resize Befehl:

Dazu muss das Raid wieder als gesamtes unter /mnt/temp gemountet werden und alle subvolumes ausgehängt sein.

sudo umount /mnt/<subvolumes>
sudo mount /dev/sda1 /mnt/temp

Hier müssen wir nun Device ID 2 auf deren maximal verfügbare Grösse vergrössern

# sudo btrfs filesystem resize 2:max /mnt/temp
Resize device id 2 (/dev/sdb1) from 1.82TiB to max

Nun zeigt btrfs device usage auch für das Device 2 die korrekte Grössen an (unallocated):

#sudo btrfs device usage /mnt/temp

/dev/sda1, ID: 1
Device size: 7.28TiB
Device slack: 3.50KiB
Data,RAID1: 3.00GiB
Metadata,RAID1: 2.00GiB
System,RAID1: 32.00MiB
Unallocated: 7.27TiB

/dev/sdb1, ID: 2
Device size: 7.28TiB
Device slack: 3.50KiB
Data,RAID1: 3.00GiB
Metadata,RAID1: 2.00GiB
System,RAID1: 32.00MiB
Unallocated: 7.27TiB

Damit stehen nun die gesamten 8TB als Raid zur Verfügung.

Über diesen Prozess kann übrigens das Raid durch neuere grössere Festplatten ersetzt werden. Der HC4 unterstütz bis zu 12 TB grosse Festplatten. Es besteht also noch Luft nach oben 🙂

Btrfs Wartung

Damit das Btrfs-Filesystem gut “in Schuss” bleibt, ist es notwendig etwas in die Wartung dessen zu investieren.  Wartungsaufgaben können mit dieser Script-Sammlung automatisiert werden (Scrubben, Ausbalancieren, Trimmen oder Defragmentieren).

Installation btrfsmaintenance

sudo apt-get update
sudo apt-get install btrfsmaintenance

Dies installiert btrfsmaintenance

  • Skripte unter /usr/share/btrfsmaintenance
  • Konfig-File unter /etc/default/btrfsmaintenance

Anpassen Konfig-File

sudo vi /etc/default/btrfsmaintenance

=> Setze auto um alle btfrs subvolumes abzudecken.
BTRFS_BALANCE_MOUNTPOINTS="auto"
BTRFS_SCRUB_MOUNTPOINTS="auto"

Installieren der cron-job Skripte.

sudo /usr/share/btrfsmaintenance/btrfsmaintenance-refresh-cron.sh
Refresh script btrfs-scrub.sh for monthly
Refresh script btrfs-defrag.sh for none
Refresh script btrfs-balance.sh for weekly
Refresh script btrfs-trim.sh for none

Samba

Damit das NAS Files im Netzwerk bereitstellen kann, benötigt es natürlich den entsprechenden Dienst. Mit Armbian könnten wir hier natürlich aus den vollen schöpfen. Aber ich begnüge mich mit Samba:

sudo apt-get install samba

Die einzelnen subvolumes sollen mittles Samba im Netzwerk verfügbar gemacht werden. Pro Subvolume muss entsprechend ein Linux-User erstellt werden, der sich aber nicht am System selber anmelden kann:

sudo useradd -s /bin/false multimedia
sudo smbpasswd -a multimedia

Gruppe erstellen und user multimedia zuweisen

sudo groupadd multimedia
sudo usermod -a -G multimedia multimedia

Nun die Samba Konfiguration durchführen

sudo mv /etc/samba/smb.conf /etc/samba/smb.orig
sudo vi /etc/samba/smb.conf

Inhalt

[global]
workgroup = WORKGROUP
server string = %h server (Samba, HC4_NAS)
security = user
map to guest = never

[multimedia]
path = /mnt/multimedia
public = yes
writable = yes
comment = hc4 nas: multimedia share
printable = no
guest ok = no
force group = multimedia
valid users = multimedia
create mask = 0660
directory mask = 0770

Nun Samba Dienste neu starten. Anschliessend steht das Sama-Share ‘multimedia’ zur Verfügung:

sudo systemctl restart smbd.service
sudo systemctl restart nmbd.service

Das Share kann nun z.B. unter Ubuntu in Dateibrowser mit

smb://<ip>/multimedia/

unter Verwendung des Users ‘multimedia’ & Passwort verbunden werden.

FTP Server

HC4 soll auch einen FTP Server bereitstellen. Ich installier dafür PureFTPd. Die Installation habe ich hier bereits einmal beschrieben.

Video-Überwachung

Für die Video Überwachung setzte ich Shinoi ein. Die Installation wird hier beschrieben.

Bibliotheksverwaltung für eReader

Für die Bibliotheksverwaltung setze ich Calibre ein. Hier wird die Installation beschrieben.

Fazit

Wenig überraschend lassen sich alle Services eines Standard-NAS nachbauen.

Daten-Transfer Performance

Das Kopieren von sehr grossen Files (20 à ca. 10GB) oder auch gleichzeitig vielen kleineren Files ( 300 à 10MB) ergeben eine Durchschnittsgeschwindigkeit von 55-57MB/s. Damit befinden wir uns in dem, für die eingesetzten HDDs, erwarteten Rahmen. Hardkernel verspricht beim Einsatz von SSDs Werte von bis zu 100MB/s. Wer das notwendige Budget hat => go4it 😉

Festplattenwechsel

Ein Festplattenwechsel hat ohne Probleme und ohne Datenverlust funktioniert.

Performance allgemein

Die Performance des HC4 reicht für die von mir eingesetzten Services locker aus. Für die Video-Überwachung habe ich 4 Neztwerk-Kameras installiert, welche alle durchwegs im recording Modus laufen, also Daueraufnahmen machen und gleichzeitig den Stream auch noch an diverse Clients weiterleiten. Trotzdem läuft der HC4 ziemlich unbeeindruckt auf rund 5-10% CPU und ca 20% RAM-Auslastung. Die Temperaturen belaufen sich auf rund 55°C (CPU) und 45°C (Storage).

Systemd Startreihenfolge der Services

Nach einigen Monaten Laufzeit ist aufgefallen, dass das System öfters nach einem Reboot nicht mehr korrekt funktioniert hat. Zum einen musste ich die korrektur des “Reboot Issues” wieder durchführen. Diese Anpassung ging wohl nach einem apt-get upgrade verloren.

Das andere Problem war dass das Mounten der btrfs Verzeichnisse teilweise länger dauerte, als das starten der systemd Services. Das führte zur unschönen Situation, dass das System nach einem Reboot im Status “degraded” hängen blieb, weil benötigte Verzeichnisse noch nicht gemountet waren. Hier habe ich beschrieben, wie ich diese Problematik gelöst habe.

Links

PanelAPI

Hier habe ich beschrieben, wie man ein eigenes Panel für die Hausautomation erstellt, welches nun zufriedenstellend funktioniert. Um gewisse Funktionen auf dem Panel automatisiert ausführen zu können, habe ich ja auch bereits xdotool mit installiert. Dies möchte ich nun aktiv nutzen:

Use-Case

  • Wenn jemand an der Haustüre Klingelt, soll die Kamera das Klingelevent verwenden, um das Panel automatisch einzuschalten und die entsprechende Kamera-Sicht auf dem Panel zu aktivieren.
  • Da ich vom Sofa aus direkte Sicht zum Hausautomations-Panel habe, wird mir dies erlauben zukünftig zu entscheiden, ob es sich lohnt aufzustehen ;))

Umsetzung

Hier habe ich bereits beschrieben, wie man xdotool nutzen kann um bestimmte Mausklicks auf dem Panel automatisch ausführen zu können. Das Ziel ist es nun, dass die Kamera dieses Script bei einem Klingelevent aufrufen kann. Die Kamera kann sich nicht per SSH auf das Panel einloggen und ein Script aufrufen. Was sie aber kann, ist ein HTTP-GET Call ausführen. Deswegen habe ich ein sehr simples REST-API geschrieben, welches auf dem Panel HTTP-Calls entgegennehmen kann. Das REST-API nimmt damit HTTP Get Calls entgegen und führt dann das xdotool Script aus.

Sparkjava

Ich bin ein ehemaliger Java-Entwickler. Deswegen fällt die Wahl wieder auf Java. Um sowas umzusetzten, musste man früher einige Handstände vollziehen und insbesondere einen Application-Server/Container wie z.B. Tomcat betreiben.

Heute ist das zum Glück einiges einfacher. Ich nutze dafür Sparkjava. Spark ist ein leichtgewichtiges Framework, welches es erlaubt rasch WebApplikationen bzw. REST-APIs zu schreiben.

Für einen ersten Start siehe die Spark-Doku.

Ich beschreibe hier kurz, wie ich die Umsetzung gemacht habe. Achtung: Das ist nicht Best-Practice sondern ein straight-forward Ansatz, ohne spezielles exception-handling…

Maven POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>ch.paket</groupId>
    <artifactId>PanelAPI</artifactId>
    <version>1.0</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.sparkjava</groupId>
            <artifactId>spark-core</artifactId>
            <version>2.9.3</version>
        </dependency>
    </dependencies>

</project>

Die Main-Methode

Die Main Methode macht folgendes

  • Starten Web-Server auf Port 8011, er hört auf get URL “/selectMobotixCamera”
  • Wenn die URL aufgerufen wird, wird das Bash-Script ausgeführt. Die return-messages des Scripts werden anschliessend gelesen und zurückgegeben:
package ch.intelli;

import spark.Request;
import spark.Response;
import spark.Route;
import spark.Spark;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args){
        spark.Spark.port(8011);
        Spark.get("/selectMobotixCamera", new Route() {
            public Object handle(final Request request, final Response response){

                String message = "";
                BufferedReader in;
                String[] cmd = new String[]{"/bin/sh", "/home/xxx/xdotool_script.sh", "parameter1"};
                Process pr = null;
                try {
                    pr = Runtime.getRuntime().exec(cmd);

                    in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
                    String line = null;
                    line = in.readLine();

                    while(line != null)
                    {
                        message = message.concat(line);
                        System.out.println(line);
                        line = in.readLine();
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }

                return message;
            }
        });
    }
}

Jar als Service einbinden

Nachdem wir nun einen Spark-Webservice erstellt haben (jar), kann dieses als Service auf dem Raspberry Pi eingebunden werden:

Struktur und Service-File erstellen

cd ~
mkdir PanelAPI
cd PanelAPI
vi panelAPI.service

Inhalt panelAPI.service

[Unit]
Description=Java Service for PanelAPI
After=network.target

[Service]
ExecStart=java -jar /home/xxx/PanelAPI/PanelAPI.jar
Restart=always
User=ralwet

[Install]
WantedBy=multi-user.target

Service registrieren

sudo cp panelAPI.service /etc/systemd/system/panelAPI.service
sudo systemctl enable panelAPI.service

Nach einem Reboot ist das REST-API aktiv.

Links

https://codetober.com/how-to-start-jar-file-as-service-raspberry-pi-4/

 

 

OpnSense – Reboot wenn WAN nicht erreichbar

Ich betreibe meine OpnSense Firewall hinter einer UPC Giga Connect Box. Diese ist auf Bridge-Modus gestellt, so dass alle Requests direkt an die OpnSense Firewall gelangen.

Hin und wieder scheint UPC etwas zu maintainen. In der Folge verliert OpnSense die connectivity auf dem WAN-Port. Je nachdem wie häufig die UPC Unterhalt betreibt, fliegt die connectivity 1 – 2x pro Monat raus. Einzig ein Reboot löst dann das Problem.

Um dies zu automatisieren, habe ich ein Script hier abgekupfert.

Ich überprüfe die connectivity, indem ich die DNS-Server von Switch und DigitaleGesellschaft anpinge. Die Pings werden nach /root/pingtest.log geschrieben – und NICHT gelöscht – Wenn alles sauber funktioniert, kann das logfile auch jeweils gelöscht werden.
Als erstes ein Config-File ”actions_pingcheck.conf” mit folgenden Inhalt erstellen.

[start]
command:/usr/local/etc/rc.d/ping_check.sh
parameters:
type:script
message:starting ping_check
description:ping_check

Kopiere das File nach

/usr/local/opnsense/service/conf/actions.d

Jetzt das Bash-Script “ping_check.sh” erstellen:

#!/bin/sh

#=====================================================================
# USER SETTINGS
#
# Testing uptime to run script only xx seconds after boot 
#
# Log file
LOGFILE=/root/pingtest.log
#
#=====================================================================


# Current time
curtime=$(date +%s)

# Bootime in seconds
uptime=$(sysctl kern.boottime | awk -F'sec = ' '{print $2}' | awk -F',' '{print $1}')

# Uptime in seconds
uptime=$(($curtime - $uptime))

# If boot is longer than 120 seconds ago...
if [ $uptime -gt 120 ]; then

# A message to the console (I like feedback -if you don't then comment out the echo, wall and rm lines) 
    echo "Testing Connection at" `date +%Y-%m-%d.%H:%M:%S` "uptime:" $uptime "seconds" >> $LOGFILE
    wall $LOGFILE 
    #rm $LOGFILE 

    # Try 1 or 2 minutes worth of very short pings to googles DNS servers - In this case I am only using 10 seconds worth which is the -c 10 value. change this to suit.
    # eg a value of 60 would be pne minute.
    # Quit immediately if we get a single frame back.
    # If neither server responds at all then reboot the firewall.
    counting=$(ping -o -s 0 -c 10 185.95.218.42 | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }' )

    if [ $counting -eq 0 ]; then

        counting=$(ping -o -s 0 -c 10 130.59.31.248 | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }' )

        if [ $counting -eq 0 ]; then
            # trying to just restart NIC
            # echo "ping_check: ping fail - trying interface down/up" >> $LOGFILE 
            # wall $LOGFILE 
            # rm $LOGFILE 
            # ifconfig igb0 down
            # ifconfig igb0 up
            sleep 20
            # echo "ping_check: ping fail - Interface reset - trying pings again." >> $LOGFILE 
            #wall $LOGFILE  
            # rm $LOGFILE 
            counting=$(ping -o -s 0 -c 10 185.95.218.42 | grep 'received' | awk -F',' '{ print $2 }' | awk '{ print $1 }' )
            if [ $counting -eq 0 ]; then
                # network down
                echo "Network down - restart Firewall..." >> $LOGFILE
                wall $LOGFILE
                # Save RRD data && clean reboot
                /usr/local/etc/rc.reboot
            fi
        fi
    fi
fi

Kopiere das Bash-Script nach /usr/local/etc/rc.d und stelle sicher, dass es über das execute-flag verfügt

chmod 755 /usr/local/etc/rc.d/ping_check.sh

Nun noch das neu erstellte Script im System als Cron-Job einrichten. Ich führe den Ping alle zwei Minuten durch:

Links

Panel für Hausautomation – 2. Versuch

Nachdem mein erster Versuch ein Panel für die Hausautomation zu erstellen, gescheitert ist (siehe https://www.dev-metal.ch/?p=1586) ist dies nun der zweite Versuch. Das Grundsetting ist das gleiche  geblieben:

Hardware:

Installation

Neu verwende ich nicht fullpageos sondern das raspberry pi OS. Die Full-Version in der 64bit Variante.

Raspberry Pi Installation wie gewohnt durch schreiben eines SD-Images. Ich aktiviere dabei den SSH-Server gleich mit. Ich konfiguriere das OS auch so, dass ein autologin stattfindet. Am Ende eines Bootvorgangs gelangt man damit direkt auf den eingeloggten Desktop.

Welectron gibt an, dass man für die Installation auf einem Raspberry Pi folgende Anpassungen an der /boot/config.txt vornehmen muss:

# uncomment to force a specific HDMI mode (this will force VGA)
hdmi_group=2
hdmi_mode=82
hdmi_cvt 1920 1080 60 6 0 0 0

Diese Anpassungen waren aber in meinem Falle gar nicht nötig. Das Panel wurde sofort korrekt erkannt.

X11VNC Server

Da es sich hierbei um ein Panel handelt, sind Tastatur und Maus nicht fix montiert. Entsprechend macht es Sinn, das Gerät per Remote steuern zu können. Das wird mit X11VNC-Server umgesetzt. X11VNC ermöglicht es existierende X11-Sessions per VNC weiterzuleiten:

x11vnc installieren

sudo apt-get update
sudo apt-get install x11vnc

Server testeshalber starten

x11vnc -usepw -forever -display :0

Beim ersten Start wird das Setzen eines Passwortes verlangt. Hier entsprechend eines setzen.

Nun noch sicherstellen, dass der X11VNC-Server beim booten bzw. beim Login des Users

nano /home/pi/.config/autostart/x11vnc.desktop

Folgende Zeilen eingeben

[Desktop Entry]
Type=Application
Name=X11VNC
Exec=x11vnc -usepw -forever -display :0
StartupNotify=false

Raspberry Pi neu starten.

sudo reboot

Ab sofort ist der VNC-Server verfügbar. Ein Client kann nun mit

 vncviewer <ip>:0

auf den Raspberry Pi zugreifen.

Chromium installieren

Chromium bietet einen Kiosk-Mode. Dieser wurde bei fullpageos auch verwendet. Ich verwende der Einfachheit halber den gleichen Browser, mit den gleichen Start-Parametern:

Installieren:

 sudo apt-get install raspberrypi-ui-mods chromium-browser

Damit die Mouse-Curser entfernt werden können, muss noch unclutter installiert werden

 sudo apt-get install unclutter

Ein Config-Verzeichnis im eigenen ~/ erstellen:

 mkdir -p /home/pi/.config/lxsession/LXDE-pi/

Script aufsetzen

 nano /home/pi/.config/lxsession/LXDE-pi/autostart

und folgendermassen befüllen

# @xset s off ^[#(Screensaver ausschalten) Geht alternativ auch über die Oberfläche.
@xset -dpms #(Energiesparmodus deaktivieren) Geht alternativ auch über die Systemeinstellungen
# @xset s noblank #(Screensaver ausschalten)
@chromium-browser --v=0 --kiosk --touch-events=enabled --disable-pinch --noerrdialogs --simulate-outdated-no-au='Tue, 31 Dec 2099 23:59:59 GMT' --disable-session-crashed-bubble --disable-component-update --overscroll-history-navigation=0 --disable-features=Translate --app=http://primary-spacelynk.home.arpa/scada-vis
@unclutter -idle 0 # besagt, dass der Mouse-Curser 0s nach der letzten Aktivierung ausgeblendet werden soll

Ich lasse hier bewusst den Screensaver an (auskommentieren von @xset s off und #@xset s noblank). Das Panel soll schwarz werden, sobald es eine weile nicht gebraucht wird.

xscreensaver

Xscreensaver soll nach einigen Minuten inaktivität das Panel auf “Blank” setzen, also einen schwarzen Bildschirm an das Panel senden.

Installation

sudo apt-get install xscreensaver

Komplettes entfernen des Maus-Cursors

Unclutter entfernt den Maus-Cursor nicht komplett. Es blendet den Cursor lediglich nach x.xx sekunden inaktivität wieder aus. Wenn man aber auf das Touchpanel streicht, bleibt der Cursor auch dann sichtbar, wenn man -idle 0 konfiguriert hat.

Man kann die Maus auch komplett ausblenden. Damit ist dann aber die Maus auch  nicht verfügbar, wenn man auf dem Raspi eine Maus anschliesst:

vi /etc/lightdm/lightdm.conf
#xserver-command=X 
neu:  xserver-command=X -nocursor

xdotool

xdotool bietet die Möglichkeit per command-line (ssh) Maus und Tastatur-events an die x-session zu senden:

sudo apt-get install xdotool

Folgendes Script (geklaut bei fullpageos) setzt das Chromium-Fenster aktiv und senden ein refresh (ctrl+f5)

#!/bin/bash
export DISPLAY=:0
sleep 1
WID=$(xdotool search --onlyvisible --class chromium|head -1)
xdotool windowactivate ${WID}
xdotool key ctrl+F5

xdotool key F11

Mausklicks für Kamera-Auswahl

Wenn es an der Türe klingelt, soll das Panel automatisch auf der Visualisierung das Kamerabild einblenden. Dies kann man nun mit xdotool wunderbar umsetzen. Folgendes Script simuliert zwei Toches auf dem Panel und wählt damit das gewünschte Kamerabild automatisch aus. Dieses Script wird von der Kamera getriggert, sobald jemand die Klingel getätigt hat:

#!/bin/bash
export DISPLAY=:0
sleep 1
WID=$(xdotool search --onlyvisible --class chromium|head -1)
xdotool windowactivate ${WID}

### Select Kamera-Menu
xdotool mousemove 1720 900 click 1
sleep .5

### Select Mobotix Camera
xdotool mousemove 250 200 click 1

 

Reboot to Chromium/Desktop

Falls ich mal den Desktop per VNC benötige, habe ich mir zwei bash-scripte geschrieben, welche das autostart-File entfernt und duchbootet (bootToDesktop.sh) oder das autostart-File nach /home/pi/.config/lxsession/LXDE-pi/ schreibt und bootet (bootToChromium.sh).

Problembehebungen

Wayland Display Server / ydotool

Wenn man xdotool unter Wayland (z.B. Ubuntu 22.04) verwendet kann das Problem auftauchen, dass xdotool den “Black-Screen” nicht wieder deaktiviert. Will hiessen, dass die Mausbewegungen und Clicks zwar ausgeführt werden, der Bildschirm selber aber Schwarz bleibt, wenn er mal in den “Tiefschlaf” gefallen ist. Abhilfe bringt dann ydotool:

ydotool kann nicht aus den Quellen installiert werden (veraltet). Stattdessen hier eine Anleitung, wie man ydotool aus Github selber bildet:

Nach der Installation konnte ydotool immer noch nicht als normaler User ausgeführt werden, weil das Socket-File nicht gefunden wird. Hier die Lösung dafür:

Schlussendlich habe ich einfach in meinen xdotool-Files erst einen ydotool command ausgeführt. Dieser aktiviert den Screen. Anschliessend führe ich mit xdotool fort:

#!/bin/bash
export DISPLAY=:0
YDOTOOL_SOCKET="/tmp/.ydotool_socket" ydotool mousemove --absolute -- 1720 800

sleep .5

WID=$(xdotool search --onlyvisible --class chromium|head -1)
xdotool windowactivate ${WID}

### Select Kamera-Menu
xdotool mousemove 1720 800 click 1

sleep .1

### Select Axis Kinderzimmer Camera
xdotool mousemove 900 600 click 1

 

SWAP Speicher erhöhen

Es zeigt sich, dass Chromium sehr Speicherhungrig ist und das Anzeigen von sehr grossen Grafana-Panels das System zum erliegen bringen kann. Deswegen habe ich den SWAP Speicher auf 2048 erhöht: https://pimylifeup.com/raspberry-pi-swap-file/

WLAN Verbindung (Stabilität) verbessern

Der Standard WLAN Adapter des Raspberry PIs 4 ist zwar schnell aber seine Reichweite ist nicht wirklich gut. Deswegen verwende ich einen WLAN USB-Stick, der auch vom System bereits automatisch erkannt und eingebunden wurde (als Wlan1). Um sicherzustellen, dass der Raspi nur über diesen Wlan1 Adapter kommuniziert habe ich zu einem kleinen Trick gegriffen. Unter

/etc/wpa_supplicant/wpa_supplicant.conf

kann bekanntlich das WLAN konfiguriert werden. Alle Wlan Adapter verwenden diese Konfig-File.

Man kann aber auch mehrere solcher Konfig-Files anlegen und diese den Adaptern zuweisen. Dies nach dem Muster wpa_supplicant-“$interface”.conf

Um Wlan0 nicht mehr reden zu lassen, habe ich ein File wpa_supplicant-wlan0.conf ohne entsprechende Netzwerk-Konfig erstellt.

cp wpa_supplicant.conf wpa_supplicant-wlan0.conf

Das wlan0 File sieht dann so aus:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=CH

network={
}

Damit wird für den Adapter Wlan0 dieses Konfig-File verwendet, welches sich entsprechend gar nicht verbindet. Alle anderen Wlan Adapter verwendet weiterhin wpa_supplicant.conf. Damit verbindet sich Wlan1 und Wlan0 bleibt stumm.

Optionale Info: HDMI Power off

Mein Panel besitzt eine Hintergrundbeleuchtung. Dieses blieb bei fullpageos  an, wenn xscreensaver einen Blank-Screen sendete. Dies konnte ich folgendermassen ausschalten:

sudo vcgencmd display_power 0  # HDMI Power off
sudo vcgencmd display_power 1  # HDMI Power on

Kios-Mode verlassen

  • Über VNC verbinden und  Alt+F4 drücken oder
  • über SSH mit ps -ef | grep chromium die Prozess-ID herausfinden und den Prozess killen.

 

Links

 

Panel mit fullpageos

Achtung – Fehlversuch

Nach einiger Testzeit hat sich folgendes gezeigt:

Fullpageos hat folgendes Problem mit HML-Streams: https://github.com/guysoft/FullPageOS/issues/291

Meine Visualisierung beinhaltet auch Video-Streams. Sobald diese aktiviert werden, crashed chromium. Das ist so natürlich nicht zu gebrauchen 🙁


 

Für die Steuerung meiner Hausautomation habe ich mir eine HTML5 Web-Site erstellt. Nun benötige ich ein Touch-Screen Panel, welches ausschliesslich diese Seite anzeigen soll.

Panel: https://www.welectron.com/Waveshare-156inch-HDMI-LCD_1

Beim OS bin ich bei  fullpageos fündig geworden. Es ermöglicht eine Kiosk-View basierend auf einem Raspberry Pi.

fullpageos: https://github.com/guysoft/FullPageOS

Die Installation erfolgt wie bei jedem anderen Raspi-OS. Ich beschreibe hier nur die Spezialitäten, welche ich zusätzlich ausgeführt habe.

Entfernen des Maus-Cursors

Standardmässig wird der Maus-Cursor eigeblendet, wenn man den Touchscreen bedient. Ich möchte aber ein “Tablet-Feeling”. Der Maus-Cursor stört. Dieser kann komplett entfernt werden:

https://github.com/guysoft/FullPageOS/issues/15

simply edited lightdm config in
/etc/lightdm/lightdm.conf changing line #xserver-command=X to xserver-command=X -nocursor

Fonts

Meine HTML5 Seite verwendet diverse Fonts, welche fullpageos nicht standardmässig mit installiert. Diese nachinstallieren:

sudo apt-get install ttf-mscorefonts-installer

Screensaver

fullpageos deaktiviert standardmässig den screensaver. Das macht bei einem öffentlichen Panel auch Sinn. Ich verwende das Panel aber im Haus und möchte, dass der Blank-Screensaver (schwarzer Bildschirm) nach unbenutzer Zeit einschaltet. Dafür folgende Zeile in /home/pi/scripts/start_gui auskommentieren:

# xset s off # don't activate screensaver

Hintergrundbeleuchtung des Panels

xscreensaver sendet nach 10min einen “Blank-Screen” (also schwarzer Screen) an das Panel. Das Panel selber bleibt aber anschliessend an bzw. die Hintergrundbeleuchtung schaltet nicht ab. Zugunsten einer langen Lebendsauer möchte ich, dass das Panel die Hintergrundbeleuchtung ausschaltet und dann, wenn das Panel wieder bedient wird, wieder einschaltet.

Vi

Vi ist etwas komisch konfiguriert. Sobald man etwas kopieren will, fällt vi in den “visual” mode. Das kann man verhindern, indem man ein File ~/.vimrc erstellt. Es kann leer sein:

touch ~/.vimrcsudo touch /root/.vimrc

Shinobi auf HC4

Mein neues HC4 NAS möchte ich gerne auch als Überwachungs-Station verwenden. Ich entscheide mich Shinobi eine Chance zu geben.

Da Shinobi eine MariaDB einsetzt, wird es hier etwas “unseriös”. Dies, weil ich das Betriebssystem auf dem HC4 auf einer SD Karte betreibe. Eine Datenbank auf einer SD-Karte zu betreiben ist bekanntlich eine sehr schlechte Idee. Deswegen werde ich das Daten-Verzeichnis von mariaDB nach der Installation auf die HDD Disk verlegen (siehe Installation). Das wird zwar die Geschwindigkeit der DB reduzieren, aber dafür  auch die “Anzahl writes” auf die SD-Karte.

Im weiteren ist Armbian nicht unter dem offiziell unterstützen OS. Es wird Ubuntu empfohlen. Armbian bassiert aber wie Ubuntu auf Debian. Es besteht also eine Chance… 😉

Installation

Hier habe ich Installations-Instruktionen für Shinobi auf Armbian gefunden:

https://i12bretro.github.io/tutorials/0548.html

sudo apt update
sudo apt upgrade -y
sudo apt install git -y
cd ~git clone https://gitlab.com/Shinobi-Systems/Shinobi.git Shinobi
cd Shinobi
sudo chmod +x INSTALL/ubuntu.sh
  • mariadb installieren (y) und passwort setzen
  • shinobi Datenbank installieren (y)
  • State Shinobi on boot (y)

===> Installation beendet.

NodeJs

Während der Installation wurde ich darauf hingewiesen, dass die aktuell installierte Version von nodejs veraltet ist. Auf armbian “jammy” ist aktuell Verison 12 installiert. Ich installiere nun Version 16 (LTS-Version), welche von shinobi empfohlen wird:

Achtung, bevor die Installation der neuen VErsion durchgeführt werden kann, sollte die alte nodejs Version deinstalliert werden:

sudo apt-get purge nodejs
sudo apt-get autoremove

Anschliessend den Instruktionen von Shinobi folgen:

https://hub.shinobi.video/articles/view/JX1o76s8R8Lm56D

MariaDb Datenverzeichnis wechseln (armbian)

Da ich die mariadb auf einer SD-Karte betreibe, verschiebe die die Datenverzeichnisse auf die HDD:

Als erstes überprüfen wir, wo sich das Datenverzeichnis von MariaDb befindet

sudo mysql -u root -p
MariaDB [(none)]> select @@datadir;
+-----------------+
| @@datadir |
+-----------------+
| /var/lib/mysql/ |
+-----------------+
1 row in set (0.000 sec)
MariaDB [(none)]> exit

Offenkundig liegt es unter /var/lib/mysql. Dieses Verzeichnis müssen wir nun auf unser gewünschtes Ziel hin syncronisieren.

Dazu erstmal die DB stoppen

sudo service mariadb stop

Ich habe mir für das Zielverzeichnis ein subvolume auf btrfs erstellt. Die Daten sollen neu auf “/mnt/program_data/mariadb/data” geschrieben werden:

sudo rsync -av /var/lib/mysql /mnt/program_data/mariadb/data

Zur Sicherheit das alte Datenverzeichnis umbenennen

sudo mv /var/lib/mysql /var/lib/mysql.bak

Jetzt “biegen” wir das data Verzeichnis der MariaDB Konfiguration auf das neue Ziel um.

sudo vi /etc/mysql/mariadb.conf.d/50-server.cnf
[mysqld]
. . .
datadir=/mnt/program_data/mariadb/data/mysql
socket=/mnt/program_data/mariadb/data/mysql/mysql.sock
sudo vi /etc/mysql/mariadb.conf.d/50-client.cnf
[client]
socket=/mnt/program_data/mariadb/data/mysql/mysql.sock

[client-mariadb]

Jetzt mariadb neu starten

sudo service mariadb start

und status überprüfen

sudo service mariadb status

Und nun noch überprüfen ob mariadb die änderung übernommen hat:

sudo mysql -u root -p
MariaDB [(none)]> select @@datadir;
+---------------------------------------+
| @@datadir |
+---------------------------------------+
| /mnt/program_data/mariadb/data/mysql/ |
+---------------------------------------+
1 row in set (0.000 sec)
MariaDB [(none)]> exit

MariaDB Runlevel

Da ich die DB auf einem btrfs mount verschoben habe, muss sichergestellt sein, dass MariaDB erst dann gestartet wird, wenn die mounts im System verfügbar sind. Es ist daher nötig, die Reihenfolge der Services zu beeinflussen. Hier habe ich beschrieben wie ich das konkret umgesetzt habe.

Konfiguration shinobi

Über die Admin-Oberfläche einloggen:

http://192.168.x.x:8080/super
  • Passwort von admin@shinobi.video ändern unter “Preferences” ändern.
  • Neuer Account unter “Accounts” erstellen.

Die Videos sollen auf meinem HC4 auf den HDD gespeichert werden, nicht auf dem default “video”, welches shinobi vorgibt. Dazu in der Config “Streamdir” und “VideoDir” anpassenAnschliessend reboot oder Shinobi Restart.

Jetzt über der Benutzer-Oberfläche mit dem eben erstellen User einloggen.

http://192.168.x.x:8080

Anschliessend diesen punkten folgen:

Was ist zu tun nach einer Shinobi-Installation?

Restart Shinobi

Wenn sich Shinobi aus irgendeinem Grunde aufgehängt hat, kann man den Service neu starten:

cd ~/Shinobi
sudo pm2 restart all

Logs

Die Shinobi-Logs sind über PM2 einsehbar

sudo pm2 logs

Steams

Einder der Gründe wieso ich mich für Shinobi entschieden habe, ist die Möglichkeit alle Streams für externe Anwendungen (z.B. zum Einbinden als iFrame) zu verwenden. Hier ein Link auf die Dokumentation, wie die Streams eingebunden werden können.

Temporär vs. Permanenter API-Key

Ich hatte zu Beginn das Problem, dass nach jedem Shinobi Restart die Stream-Adresse geändert hat. Konkret ändert der API-Key unter welchem auf den Stream zugegriffen werden kann. Hier findet man die Lösung. Offenbar gibt es ein temporärer API-Key, der bei verwendet wird, wenn man auf der Kamera-Übersichtsseite einen Stream anwählt. Und dann gibt es noch einen permanenten API-Key. Diesen muss man einmalig erstellen. Dabei kann man auch den Zugriff auf eine bestimmte IP eingrenzen. Für die Einbindung des Streams in eine andere Applikation muss der permanente API-Key verwendet werden.

Links

Shinobi Closed Circuit TV (CCTV): Creating a Video Monitoring System Using the ODROID-HC2

https://i12bretro.github.io/tutorials/0548.html

How To Configure a Linux Service to Start Automatically After a Crash or Reboot – Part 2: Reference

https://docs.shinobi.video/

Raspberry Pi – Reboot wenn kein Netz / Linux Watchdog

Ich verwende diverse Raspberry PIs als IOT Gerät. In seltenen Fällen kommt es vor, dass der Raspberry PI die Netzwerk-Verbindung verliert. Dies nicht nur bem wlan0- sondern auch beim eth0-interface. Ich konnte bis jetzt nicht herausfinden, wieso das passiert. Es kommt aber alle 4-6 Monate mal vor. Da die Ursachenforschung zu aufwändig ist, löse ich dieses Problem mit dem Linux-Watchdog.

Watchdog ist ein Linux-Demon, der das OS geordnet neu startet, wenn ein Test fehlschlägt.

Installation Watchdog

sudo apt-get install watchdog

Backup watchdog Config

sudo cp /etc/watchdog.conf /etc/watchdog.conf.backup

Konfiguration Watchdog:

sudo vi /etc/watchdog.conf 

ping = 192.168.1.1  # Ziel-IP-Adresse des Ping-Tests (z.B. Router) 
interface = wlan0   # Schnittstelle wlan0 verwenden
retry-timeout = 180  # Startet neu, wenn ein Test länger als 180 Sekunden fehlschlägt
interval = 5        # Teste alle 5s

Nach einem restart wird watchdog die IP über das entsprechende interface regelmässig testen. Wenn die Ziel-IP nicht antwortet, wird der Raspberry Pi neu gestartet.

Reminder bei Login

Um nicht zu vergessen, dass diese Logik implementiert ist, gebe ich bei jeder Anmeldung an das System (mit dem User pi) eine Info-Meldung aus:

sudo vi /home/pi/.profile
echo " "
echo "************************************************"
echo "Warnung: Wenn das Netzwerk ausgefallen ist, wird dieses System neu gestartet."
echo "Kommentieren Sie die Zeile ping = 192.168.1.1 aus /etc/watchdog.conf aus, um Neustarts zu vermeiden."
echo "************************************************"
echo " "

Status von Watchdog

sudo service watchdog status

 

 

 

OPNsense Blacklist mit Spamhaus Droplists

Mittels OPNsense ist es auf einfache Art und Weise möglich, “bösartige” IPs (z.B. basierend auf Spamhaus) zu blockieren.

Blacklists mit OPNsense

  1. Alias mit den Blacklisten erstellen
  2. Firewall Regel erstellen
    Alle Rule-Tabs mit Ausnahme von “Floating” sind nur für den eingehenden Datenverkehr vorgesehen. Wir wollen aber sowohl eine ausgehende als auch eingehende Filterung erreichen. Dies kann über eine “Floating-Regel” erreicht werden:

 

Links