MySQL Verbindungen mit SSL verschlüsseln – Ubuntu 14.04 / 18.04 / Mysql 5.6.28

Hier wird erklärt, wie ein MySQL Client eine verschlüsselte Verbindung zu einem MySQL Server, der mit Ubuntu 14.04 und Mysql-Server 5.6.28 betrieben wird, aufgebaut werden kann.

SSL Zertifikate erstellen

Es werden Zertifikate mit 2048 Bits und einer Gültigkeit von 3650 Tagen erstellt. Nach diesem Zeitraum müssen die Zertifikate verlängert oder neu erstellt werden.

Bitte nicht vergessen, dass der Common Name (CN) vom Client und Server Zertifikat unterschiedlich ist. z.B. servername.intelli.ch und client.intelli.ch

cd /etc/mysql/
# Generate a CA key and certificate with SHA1 digest 
openssl genrsa 2048 > ca-key.pem 
openssl req -sha1 -new -x509 -nodes -days 3650 -key ca-key.pem > ca-cert.pem 

# Create server key and certficate with SHA1 digest, sign it and convert 
# the RSA key from PKCS #8 (OpenSSL 1.0 and newer) to the old PKCS #1 format 
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout server-key.pem > server-req.pem 
openssl x509 -sha1 -req -in server-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > server-cert.pem 
openssl rsa -in server-key.pem -out server-key.pem 

# Create client key and certificate with SHA digest, sign it and convert 
# the RSA key from PKCS #8 (OpenSSL 1.0 and newer) to the old PKCS #1 format 
openssl req -sha1 -newkey rsa:2048 -days 3650 -nodes -keyout client-key.pem > client-req.pem 
openssl x509 -sha1 -req -in client-req.pem -days 3650 -CA ca-cert.pem -CAkey ca-key.pem -set_serial 01 > client-cert.pem 
openssl rsa -in client-key.pem -out client-key.pem
chmod 400 /etc/mysql/*.pem
chown mysql /etc/mysql/*.pem

SSL Konfiguration aktivieren

In der MySQL Konfiguration (/etc/mysql/my.cnf) muss SSL mit den zugehörigen Zertifikaten aktiviert werden.

ssl-ca=/etc/mysql/ca-cert.pem
ssl-cert=/etc/mysql/server-cert.pem
ssl-key=/etc/mysql/server-key.pem

Nun MySql-Server neu starten

sudo service mysql restart

Es kann auf der DB überprüft werden, ob die Konfiguration richtig übernommen wurde:

mysql > show variables like '%ssl%';

+---------------+----------------------------------+
| Variable_name | Value                            |
+---------------+----------------------------------+
| have_openssl  | YES                              |
| have_ssl      | YES                              |
| ssl_ca        | /etc/mysql/ca-cert.pem           |
| ssl_capath    |                                  |
| ssl_cert      | /etc/mysql/server-cert.pem       |
| ssl_cipher    |                                  |
| ssl_key       | /etc/mysql/server-key.pem        |
+---------------+----------------------------------+

SSL Verschlüsselung für MySQL User aktivieren

Es gibt folgende Möglichkeiten bei der Rechtevergabe für Benutzer in Bezug auf SSL:

  • REQUIRE X509: ein beliebiges gültiges SSL Client Zertifikat kann verwendet werden
  • REQUIRE ISSUER / REQUIRE SUBJECT: ein beliebiges gültiges SSL Client Zertifikat reicht nicht aus, es muss von einer mit ISSUER spezifizierten CA kommen und/oder ein bestimmtes SUBJECT enthalten.
  • REQUIRE SSL: die Verbindung muss über SSL verschlüsselt aufgebaut werden, die Authenfizierung kann sowohl via Passwort als auch über ein SSL Client Zertifikat erfolgen.

Im Folgenden Beispiel wird der User „ssluser“ erstellt der alle Rechte (ALL PRIVILEGES) auf alle Datenbanken (*.*) am „localhost“ hat und ein gültiges SSL Client Zertifikat vorweisen muss.

GRANT ALL PRIVILEGES ON *.* TO 'ssluser'@'localhost' IDENTIFIED BY 'topsecret' REQUIRE X509;

Client SSL erzwingen

grant all privileges on database.* to 'username'@'hostaddress' identified by 'password' require SSL;

oder 

GRANT USAGE ON *.* TO 'ralph'@'%' REQUIRE SSL;

Verschlüsselte MySQL Verbindung testen

cd /etc/mysql/
mysql -ussluser -p -h127.0.0.1 --ssl-ca=ca-cert.pem --ssl-cert=client-cert.pem --ssl-key=client-key.pem

Hint: Auf Ubuntu 18.04 schlug dieser Befehl mit dem Feher „SSL connection error: SSL_CTX_set_default_verify_paths failed“ fehl. Das liegt daran, weil der lokale User mit dem dieser mysql-Befehl ausgeführt wird, keine Berechtigung auf die Zertifikate hat. Um den Test trotzdem machen zu können, kann der Befehl mit sudo ausgeführt werden.

Die SSL Keys müssen wenn der Zugriff von einem entfernten Host aus erfolgen soll natürlich vorher dorthin kopiert werden.

Mittels dem Befehl SHOW STATUS LIKE 'Ssl_cipher'; kann sich der Verschlüsselungsstatus des verbundenen MySQL Clients angezeigt werden lassen.

mysql > SHOW STATUS LIKE 'Ssl_cipher';

+---------------+--------------------+
| Variable_name | Value              |
+---------------+--------------------+
| Ssl_cipher    | DHE-RSA-AES256-SHA | 
+---------------+--------------------+
1 row in set (0.00 sec)
mysql> SHOW STATUS LIKE 'Ssl_version';

+---------------+---------+
| Variable_name | Value   |
+---------------+---------+
| Ssl_version   | TLSv1.1 |
+---------------+---------+
1 row in set (0.01 sec)

Überprüfe alle Server-Connections

Es kann auch überprüft werden ob ALLE Verbindungen zum Mysql-Server auch wirklich mit SSL Connecten.

Mit folgendem Befehl kann überprüft werden ob und welche User mit SSL mit dem Mysql-Server kommunizieren:

SELECT sbt.variable_value AS tls_version,  t2.variable_value AS cipher, processlist_user AS user, processlist_host AS host FROM performance_schema.status_by_thread AS sbt JOIN performance_schema.threads AS t ON t.thread_id = sbt.thread_id JOIN performance_schema.status_by_thread AS t2 ON t2.thread_id = t.thread_id WHERE sbt.variable_name = 'Ssl_version' and t2.variable_name = 'Ssl_cipher' ORDER BY tls_version;

Links

Influxdb v2 auf Proxmox (LXC)

Hier beschreibe ich eine Möglichkeit eine Influxdb auf Proxmox containerbasiert zu installieren.

  1. Login Proxmox
  2. Proxmox-Host Shell anwählen => Commando Prompt wird angezeigt
  3. Folgenden Befehl eingeben (aus https://tteck.github.io/Proxmox/)
    bash -c "$(wget -qLO - https://github.com/tteck/Proxmox/raw/main/ct/influxdb.sh)"
    • Settings: „Advanced“
    • OS: Wähle Debian>Ubuntu 22.04 (LTS)
    • Container Type: Unprivileged
    • Password: Setze Root Passwort
    • Container ID: default belassen
    • Hostname: influxdbV2
    • Disk Size in GB: 8
    • CPU Cores: 2
    • RAM in MiB: 2048
    • Bridge: vmbr0
    • IP Adress: dhcp
    • IPv6: enable
    • MTU Size: blank
    • DNS Search Domain: blank
    • DNS Server IP: 192.168.3.1
    • MAC Address: blank
    • Vlan: blank
    • Enable Root SSH Access: yes
    • Enable Verbose Mode: no
    • Create InfluxDB LXC: yes

  • Als nächstes kann ausgewählt werden, welche Influxdb Version installiert werden soll. Hier wähle ich Version 2.
  • Telegraf installiere ich auch gleich mit.
  • Damit ist die Installation auch schon abgeschlossen.
  • Als nächstes überprüfen ob der Container korrekt erstellt wurde.

InfluxDB Configuration

  • Öffne einen Browser mit Link „http://<ip Adresse des Containers>:8086
  • Es öffnet sich die Browser-Oberfläche von Influxdb V2
  • Get Startet
  • Username: admin
  • Passwort: => passwort
  • Organisation Name: Home
  • Initial Bucket Name: iobroker
  • Kopiere den Operater API Token an einen sicheren Ort
  • Let’s get startet!

Damit ist die InfluxDB als LXC Container installiert und grundsätzlich konfiguriert.

Migriere Influxdb V1 Bucket nach Influxdb V2

Nun möchte ich bestehendes Bucket einer Influxdb V1.8 in die neue Influxdb V2 migrieren.

  • SSH Login auf Influxdb V1
  • Folgender Befehl schreibt das Bucket in ein Line Protokoll File (auszuführen als root user):
    influx_inspect export -database iobroker -datadir /mnt/files/influxdb/data -waldir /mnt/files/influxdb/wal -compress -out iobroker.line.gz
  • Das erstelle File „iobroker.line.gz“ auf die Zielmaschine kopieren
    scp iobroker.line.gz <user>@<ipadresse des LXC Containers>:
  • Jetzt mit ssh auf der Zielmaschine einloggen
  • das iobroker.line.gz entpacken
    gzip -d iobroker.line.gz
  • Bevor das entpackte File jetzt importiert werden kann, musste ich dieses noch manipulieren.
    vi iobroker.line
    Den gesamten Header löschen:
    #INFLUXDB EXPORT: 2023-01-01T01:59:59+01:00 - 2262-04-12T00:47:16+01:00
    #DDL
    CREATE DATABASE iobroker WITH NAME autogen
    #DML
    #CONTEXT-DATABASE:iobroker
    #CONTEXT-RETENTION-POLICY:autogen
    #writing tsm data
  • Jetzt das file iobroker.line importieren
    influx write -b iobroker --org Home --token <token> -f iobroker.line

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

 

Armbian SD Karte klonen

Ich verwende für mein HC4 NAS ein Armbian, welches auf einer SD Karte installiert ist. Zwecks Backup wird diese SD Karte geklont.

Hier habe ich bereits beschreiben, wie man ein Klon für ein Raspberry Pi OS durchführen kann.

Für das Klonen der Armbian SD Karte wollte ich eigentlich ein Image wie hier beschreiben erstellen und dieses dann auf eine neue SD-Karte schreiben. Leider schlug dies fehl. Egal ob das Image mit dd, usbimager oder mit Win32DiskImager erstellt wurde. Die Ziel SD-Karte konnte anschliessend den HC4 nicht booten (Kernel Panic). Es schien als ob die zu klonende SD-Karte bereits so fehlerhaft ist, dass ein 1:1 Klon auf Bit-Ebene nicht mehr geht (reine Spekulation. Ich weiss auch nicht ob das überhaupt möglich wäre).

Nichts desto trotz habe ich deswegen die Strategie gewechselt und das Image aus dem laufenden Betrieb gezogen. Hier habe ich das für den Raspberry Pi bereits beschrieben. Für Armbian braucht es aber ein anderes Script. Hier bin ich fündig geworden

Hotclone Script (siehe auch hier )

#!/bin/bash
#----------------------------------------------------
# armbian_hotclone.sh
#
# Copies the sdcard your Armbian system is running from 
# to a new sdcard in an USB-attached card reader. 
#
# The new sdcard can be of any size as long as it can hold 
# the data content of the original card.
#
# The cloned card should be tested after creation to ensure
# it can be used for desaster recovery.
#
# c) Rodolfo 2016-06-19 enjoy !
#-----------------------------------------------------
#

ARMBIAN_ORIG=/dev/mmcblk0
ARMBIAN_CLONE=/dev/sdd

# Clone partial image of original SDcard ( bootstuff + partition table + start of first partition )
# we just copy 4M to account for strange partition alignment

dd if=$ARMBIAN_ORIG of=$ARMBIAN_CLONE bs=1M count=4

# Delete invalid partition of target SDCARD and create/format new ext4-partition

umount $ARMBIAN_CLONE"1"
echo -e "p\nd\nn\n\n\n\n\np\nw\nq\n" | fdisk $ARMBIAN_CLONE 
echo -e "y\n" | mkfs.ext4 $ARMBIAN_CLONE"1"

# Target mount

mkdir /mnt/armbian_clone
mount $ARMBIAN_CLONE"1" /mnt/armbian_clone
rm -r /mnt/armbian_clone/* # cleanup lost+found

# System copy to SDcard

time rsync -avSz --exclude=/dev/* --exclude=/proc/* --exclude=/sys/* --exclude=/media/* \
--exclude=/mnt/* --exclude=/run/* --exclude=/tmp/* / /mnt/armbian_clone

sync

umount $ARMBIAN_CLONE"1"

Ablauf

  1. Starte Armbian und schliesse einen SD-Card Adapter an
  2. Lege eine leere SD-Karte in den SD-Card Adapter
  3. Füre „sudo fdisk -l“ aus und ermittle das Device => bei mir war es /dev/sdd
  4. Ändere den Script-Parameter ARMBIAN_CLONE entsprechend auf
    ARMBIAN_CLONE=/dev/sdd
    Auf diese SD-Karte soll das Skript den Klone ausführen
  5. Rufe das Script auf
    sudo ./armbian_hotclone.sh
    Das Script formatiert die SD-Karte und kopiert Bootloader, Partition-Table sowie die Daten auf die neue Karte.
  6. Am Schluss muss noch die UUID auf der geklonten Karte angepasst werden. Dafür
    blkid
    aufrufen und die UUID der neuen Karte notieren.
  7. Diese UUID muss in folgenden Files auf der geklonten Karte angepasst werden
    1. /boot/armbianEnv.txt
    2. /etc/fstab
  8. Damit sollte die geklonte Karte einsatzbereit sein

Auf diese Weise ist ein Klon der Armbian SD-Karte doch noch gelungen.

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/

Systemd Service – Startreihenfolge und warten auf Godot

Für meine  NAS Lösung habe ich ein Raid1, basierend auf btrfs eingesetzt. Services wie Video-Recording und die Bibliotheks-Software speichern dabei ihre Daten auf Mount-Verzeichnisse aus btrfs ab. Leider kam es vor, dass das Mounten der btrfs Verzeichnisse 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. Folgende Services waren bei mir betroffen:

  • /lib/systemd/system/mariadb.service (für shinobi)
  • /etc/systemd/system/calibre-server.service (für calibre)
  • /etc/systemd/system/cps.service (für calibre)
  • /etc/systemd/system/pm2-root.service (für shinobi)

Ich habe das gelöst, indem ich einen eigenes systemd Target definiert habe und besagte Services auf dieses Target, welches nach „multi-user.target“ ausgeführt wird, gesetzt habe.

Und so geht das:

Erstelle ein eigenes Target

vi /etc/systemd/system/custom.target
[Unit]
Description=My Custom Target - um sicherzustellen, dass caliberdb cps und mariadb ganz am schluss starten
Requires=multi-user.target
After=multi-user.target
AllowIsolate=yes

Betroffene Systemd Services auf custom.target legen

Die betroffenen Services werden nun nach custom.target gelegt. Gleichzeitig habe ich eine „sleep“ Phase eingebaut um dem btrfs mount sicher genügend zeit zu geben. Damit triggere ich den Start der Services schön nacheinander.

mariadb.service

vi /lib/systemd/system/mariadb.service
[Unit]
...
After=multi-user.target
...

[Install]
...
WantedBy=custom.target
...

[Service]
...
# Warte 120s
TimeoutStartSec=300
ExecStartPre=/bin/sleep 120
...

Services neu installieren

sudo systemctl disable mariadb.service 
sudo systemctl enable mariadb.service

calibre-server.service

vi /etc/systemd/system/calibre-server.service

## startup service
[Unit]
Description=calibre content server
After=multi-user.target

[Service]
...
TimeoutStartSec=300
ExecStartPre=/bin/sleep 140
...

[Install]
WantedBy=custom.target

Services neu installieren

sudo systemctl disable mariadb.service 
sudo systemctl enable mariadb.service

cps.service

vi /etc/systemd/system/cps.service
[Unit]
Description=Calibre-Web
After=multi-user.target

[Service]
...
TimeoutStartSec=300 
ExecStartPre=/bin/sleep 160
...

[Install]
WantedBy=custom.target

Services neu installieren

sudo systemctl disable mariadb.service 
sudo systemctl enable mariadb.service

pm2-root.service

vi /etc/systemd/system/pm2-root.service
[Unit]
...
After=multi-user.target
...

[Install]
WantedBy=custom.target

[Service]
..
TimeoutStartSec=300 
ExecStartPre=/bin/sleep 180
...

Services neu installieren

sudo systemctl disable mariadb.service 
sudo systemctl enable mariadb.service

Links

Calibre und Calibre-web auf HC4 mit armbian

Auf meinem HC4 NAS soll Calibre die Bibliotheksverwaltung meiner eBooks übernehmen. Hier wird die Installation beschrieben.

Seit Mitte 2022 ist die Version 6.0 von Calibre verfügbar, welche die ARM CPU Architektur unter Linux unterstützt. Es waren bisher zwar auch Debian-Pakete für Calibre verfügbar, diese waren aber meist veraltet. Calibre empfielt explizit, keine Distro-Pakete einzusetzen und statdessen ihren Installer zu verwenden.

Installation

Notwendige Pakages installieren

  • python ≥ 3.3 => armbian liefert bereits 3.10 mit.
  • xdg-utils
  • wget => wget bereits auf armbian installiert.
  • xz-utils
  • libegl1
  • libopengl0
sudo apt-get install xdg-utils
sudo apt-get install xz-utils
sudo apt-get install libegl1
sudo apt-get install libopengl0

Nun kann Calibre über das installer-Skript installiert werden. Ich führe eine isolierte Installation durch und installiere Calibre auf einem eigens dafür eingerichteten Platz auf der HDD:

wget -nv -O- https://download.calibre-ebook.com/linux-installer.sh | sh /dev/stdin install_dir=/mnt/program_data/calibre-bin isolated=y

Damit ist Calibre unter /mnt/program_data/calibre-bin installiert. Calibre ist eine Desktop Anwendung, welche über eine Server-Komponente verfügt. Logischerweise kann Calibre selber nicht gestartet werden, da wir ja einen headless Server einsetzen. Folgender Aufruf führt entsprechend zu einem Fehler:

/mnt/program_data/calibre-bin/calibre/calibre

Um die Server-Komponente starten zu können, müssen noch einige Schritte getan werden:

cd /mnt/program_data/calibre-bin
mkdir mkdir calibre-library
cd calibre-library

irgend ein eBook herunterladen

wget http://www.gutenberg.org/ebooks/46.kindle.noimages -O christmascarol.mobi

Das Buch der Calibre-db hinzufügen:

cd /mnt/program_data/calibre-bin/calibre
./calibredb add /mnt/program_data/calibre-bin/calibre-library/*.mobi --with-library /mnt/program_data/calibre-bin/calibre-library/Calibre

Damit wurde eine Calibre Library unter /mnt/program_data/calibre-bin/calibre-library/Calibre erstellt und gleichzeitig das Buch hinzugefügt.

Nun kann der Calibre-Server gestartet werden. Da ich den Standart-Port 8080 breits verwende, weise ich über den Parameter –port den Port 8081 zu:

cd /mnt/program_data/calibre-bin/calibre
./calibre-server --port 8081  /mnt/program_data/calibre-bin/calibre-library/Calibre

Nun, da der Server läuft, kann man das Web-Interface aufrufen:

http://192.168.x.xxx:8081

Service erstellen

Achtung: Dieser Service soll nach dem mounten der btrfs Shares durchgeführt werden. Es ist daher nötig, die Reihenfolge der Services zu beeinflussen. Hier habe ich beschrieben wie ich das konkret umgesetzt habe.

sudo vi /etc/systemd/system/calibre-server.service
## startup service
[Unit]
Description=calibre content server
After=runlevel4.target => eigenes Target siehe https://www.dev-metal.ch/?p=1913

[Service]
Type=simple
User=xxx
Group=<Gruppe, welche Schreibzugriff auf /mnt/multimedia/books hat>
ExecStart=/mnt/program_data/calibre-bin/calibre/calibre-server --port 8081 /mnt/program_data/calibre-bin/calibre-library/Calibre --enable-local-write

[Install]
WantedBy=multi-user.target  => eigenes Target siehe https://www.dev-metal.ch/?p=1913
sudo systemctl enable calibre-server
sudo service calibre-server start

Ab sofort wird Calibre-Server als Service beim System-Boot mit gestartet.

Die Bücherbilbiothek Calibre hinzufügen

Ich verfüge bereits über sehr viele eBooks, welches sich unter /mnt/multimeda/books befinden. Dies können nun der Calibre-DB hinzugefügt werden:

./calibredb add /mnt/multimedia/books/ -r --with-library http://localhost:8081#Calibre

Zu beachten ist hier, dass für den library-pfad die lokale http URL verwendet wird. Dies ist nötig, weil calibredb ansonsten den Aufruf bei laufendem Server nicht erlaubt. Da wir den Service mit –enable-local-write gestartet haben, kann calibredb über die lokale URL (localhost) dennoch direkte Bücher hinzufügen.

Im weiteren werden hier die Bücher von /mnt/multimedia/books nach Calibre kopiert.

Automatisch Bücher der Bibliothek hinzufügen

Es gäbe die Möglichkeit einen „Listener-Ordner“ zu definieren, über welchem calibredb dann jeweils Bücher direkt importiert. Dann müssten die bücher nur in diesen Ordner kopiert werden und diese würden dann automatisch nach Calibre eingelesen: https://www.digitalocean.com/community/tutorials/how-to-create-a-calibre-ebook-server-on-ubuntu-20-04#step-6-mdash-optional-automatically-adding-books-to-your-calibre-library

Dies verwende ich aber (mal bis auf weiteres) nicht, da Bücher auch elegant über die Weboberfläche von Calibre oder Calibre-Web hochgeladen werden können.

Calibre-web

Das Standard- Web-Interface von Calibre ist zwar zu gebrauchen, aber sicher nicht „state of the art“. Es gibt ein Projekt „Calibre-Web„, welches ein schöneres Interface für die Verwaltung einer Calibre Datenbank bietet (https://github.com/janeczku/calibre-web/wiki/Manual-installation):

sudo apt install python3-pip python3-venv python3-dev

Installations-Verzeichnis erstellen:

mkdir /mnt/program_data/calibre-bin/calibre-web
cd /mnt/program_data/calibre-bin/calibre-web

Virtuelle Umgebung für calibre-web in ordner venv erstellen

python3 -m venv venv

Calibreweb in virutelle Umgebung installieren:

cd /mnt/program_data/calibre-bin/calibre-web
./venv/bin/python3 -m pip install calibreweb

Calibre-Web starten

./venv/bin/python3 -m calibreweb

URL öffnen

http://192.168.x.x:8083

Login

Default admin login:
Username: admin
Password: admin123

Calibre Datenbank konfigurieren

Calibre-Web Konfig Files

Alle Konfig-Files (settings database, logfiles) befinden sich unter

cd /homes/[username]/.calibre-web

zusätzlichen Konfig-Files (für gdrive,  gmail, etc.) sind dort zu konfigurieren.

Calibre-Web als Service installieren

Siehe https://github.com/janeczku/calibre-web/wiki/Setup-Service-on-Linux#start-calibre-web-as-service-under-linux-with-systemd

Achtung: Dieser Service soll nach dem mounten der btrfs Shares durchgeführt werden. Es ist daher nötig, die Reihenfolge der Services zu beeinflussen. Hier habe ich beschrieben wie ich das konkret umgesetzt habe.

Service File erstellen

sudo vi /etc/systemd/system/cps.service
[Unit]
Description=Calibre-Web
After=runlevel4.target => eigenes Target. Siehe https://www.dev-metal.ch/?p=1913

[Service]
Type=simple
User=ralwet
ExecStart=/mnt/program_data/calibre-bin/calibre-web/venv/bin/python3 -m calibreweb

[Install]
WantedBy=multi-user.target => eigenes Target. Siehe https://www.dev-metal.ch/?p=1913

Service aktivieren

sudo systemctl enable cps.service

Service starten

sudo service cps status

Gut zu wissen:

Installations-Pfad

Hier wird die Installation über den pip paket-manager durchgeführt. Wenn man wissen will, wo calibre-web effektiv installiert ist:

/mnt/program_data/calibre-bin/calibre-web/venv/bin/pip show calibreweb

Name: calibreweb
Version: 0.6.19
Summary: Web app for browsing, reading and downloading eBooks stored in a Calibre database.
Home-page: https://github.com/janeczku/calibre-web
Author: @OzzieIsaacs
Author-email: Ozzie.Fernandez.Isaacs@googlemail.com
License: GPLv3+
Location: /mnt/program_data/calibre-bin/calibre-web/venv/lib/python3.10/site-packages
Requires: advocate, APScheduler, Babel, backports-abc, chardet, Flask, Flask-Babel, Flask-Login, Flask-Principal, flask-wtf, iso-639, lxml, PyPDF3, pytz, requests, SQLAlchemy, tornado, unidecode, Wand, werkzeug
Required-by:
Security-Header

Der Security-Header kann hier angepasst werden. => Man muss aber wissen was man tut… 😉

vi /mnt/program_data/calibre-bin/calibre-web/venv/lib/python3.10/site-packages/calibreweb/cps/web.py

@app.after_request
def add_security_headers(resp):
# csp = "default-src 'self'"
# csp += ''.join([' ' + host for host in config.config_trustedhosts.strip().split(',')])
# csp += " 'unsafe-inline' 'unsafe-eval'; font-src 'self' data:; img-src 'self' "
# if request.path.startswith("/author/") and config.config_use_goodreads:
# csp += "images.gr-assets.com i.gr-assets.com s.gr-assets.com"
# csp += " data:"
# resp.headers['Content-Security-Policy'] = csp
# if request.endpoint == "edit-book.show_edit_book" or config.config_use_google_drive:
# resp.headers['Content-Security-Policy'] += " *"
# elif request.endpoint == "web.read_book":
# resp.headers['Content-Security-Policy'] += " blob:;style-src-elem 'self' blob: 'unsafe-inline';"
# resp.headers['X-Content-Type-Options'] = 'nosniff'
# resp.headers['X-Frame-Options'] = 'SAMEORIGIN'
# resp.headers['X-XSS-Protection'] = '1; mode=block'
# resp.headers['Strict-Transport-Security'] = 'max-age=31536000;'
return resp

 

Links

 

OpnSense Multicast: Miele XGW3000 / WLAN Tockner in unterschiedlichem Subnet

Ich verwende einen Miele XGW3000 als Zigbee Gateway, welches im LAN (192.168.20.x) angeschlossen ist (fixe IP über DHCP). Gleichzeitig betreibe ich ein WLAN Netz (192.168.30.x). Die beiden Netze sind über zwei Ports an der OpnSense Firewall angeschlossen (LAN/WLAN Interface). Am WLAN ist der Trockner verbunden (fixe IP über DHCP). Das XGW3000 erkennt über Multicast die WLAN Geräte. Da Mulitcast aber auf das Netz-Segment beschränkt ist, findet der XGW3000 aus dem LAN den Trockner im WLAN natürlich nicht.

Hier beschreibe ich, wie ich die Verbindung doch noch hinbekommen habe:

  1. Installation Plugin „UDP Broadcast Relay“
  2. Konfiguration Plugin (Services>UDP Broadcast Relay). Die Multicast-Adresse sowie den Port habe ich mittels Wireshark ausgelesen.
  3. Firewall
    1. LAN
    2. WLAN
  4. NAT > Outbound

Wichtige Anmerkung

Diese „sehr offen“ Firewall Rules habe ich nur temporär gesetzt bzw. nach dem erfolgreichen XGW3000 Scan wieder deaktiviert. Denn wenn der XGW3000 das Gerät bzw. die IP Adresse aus dem anderen Subnet mal gefunden hat, bleibt die Verbindung bestehen (weil die IP bekannt ist). Deswegen macht es auch Sinn, dem Gerät eine fixe IP Adresse (über DHCP) zu vergeben.

Schlussendlich habe ich dann nur noch eine Firewall-Rule aktiv, welche die direkte 1:1 Kommunikation zwischen den beiden Geräten erlaubt.

 

 

Bash Scripting: Existieren aktuelle Files in einem Ordner?

Ich verwende seit einiger Zeit Shinobi als Video-Recorder für meine Kameras. Die Installation habe ich hier beschreiben.

Problem

Nun kam es einmal vor, dass Shinobi die Aufnahmen ungeplant gestoppt hat. Damit ich dies schneller bemerke habe ich mir ein Bash-Script gezimmert.

Anforderungen:

  • Skript soll regelmässig überprüfen ob sich in den Video-Verzeichnissen aktuelle Aufnahmen befinden.
  • Falls sich keine aktuellen Aufnahmen darin befinden, soll eine Pushover Nachricht ausgelöst werden.

Umsetzung

Folgendes Script überprüft vordefinierte Verzeichnisse und sendet eine Pushover-Nachricht, falls sich in den Verzeichnissen keine aktuellen Files befinden.

Für das versenden der pushover Nachricht wird das Script von https://github.com/akusei/pushover-bash verwendet.

#!/bin/bash

#***********************************************************************************************
#**
#** Dieses Script überprüft ob sich aktuelle Video-Files in den dafür vorgesehenen Verzeichnissen
#** befindet.
#**
#***********************************************************************************************

#***********************
# Variablen
#***********************
notOlderThan="10" # die Files dürfen nicht älter als diese Variable (in minuten) sein
sourcepath="/home/xxx/checkVideosAvailable/"
paths=( "${sourcepath}videos" "${sourcepath}videos2" "${sourcepath}videos3") # Die zu überprüfenden Verzeichnisse (Array)
pushover_App_Key="xxxxx" #Pushover API Key
pushover_User_Key="xxxxx" #Pushover User Key
out=$(mktemp /tmp/message.XXXXXXXX) #Temp-File zum Aufbereiten der Pushover-Nachricht
timestampLocation="./timestamp" #Pfad und Name zum timestamp File, welches für die Überprüfung des alters gebraucht wird.


#***********************
# Logik
#***********************
filesExists=true

# Erstelle ein File "timestamp" mit einem Timestamp "jetzt - $notOlderThan min". 
# Dieses File wird anschliessend verwendet um über den "find" Befehl das Alter der Files vergleichen zu können. 
date --date="-$notOlderThan minutes" +"%Y%m%d%H%M" | xargs touch $timestampLocation -mt

#iteriere über die paths und überprüfe ob sich darin Files befinden, welche jünger als $notOlderThan bzw. das File $timestampLocation sind 
for i in "${paths[@]}"
do
#echo "Testing $i" >> "$out"
# Suche Files, welche neuer als das erstellte timestamp-file sind.
if test "`find $i/. -newer $timestampLocation -type f`"
then
echo "Aktuelle Video-Files existieren in $i"
else
filesExists=false
echo "Es existieren keine aktuellen Video-Files in \n $i"
fi
done

if [ "$filesExists" = false ] ; 
then
echo "Sende Pushover Nachricht"
cat "$out" | xargs -0 -I XX ./pushover.sh -t $pushover_App_Key -u $pushover_User_Key -m XX
fi

# Entferne die temp Files
rm "$out"
rm $timestampLocation

Installation auf HC4

Das obige bash-Script inkl. Pushover Bashscript in ein Verzeichnis schreiben (z.B. nach /home/xxxx/checkVideosAvailable/ )

cronjob

Das Script soll als cron-job jede Stunde laufen.

sudo -s
crontab -e
-------------
45 * * * * /bin/bash /home/xxx/checkVideosAvailable/checkVideosAvailable.sh > /dev/null 2>&1