tag:blogger.com,1999:blog-56118869374516928372024-03-27T19:40:16.626+01:00Otto's Technik BlogHier geht es um Computer, Fhem, Homematic, RaspberryPi und mehrOttohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.comBlogger188125tag:blogger.com,1999:blog-5611886937451692837.post-45504322240935168702024-03-25T11:41:00.002+01:002024-03-25T11:46:02.997+01:00Webhosting - DNS Einstellungen<p>Ein typisches Webhosting besteht aus diesen Servicekomponenten :<br /></p>
<p></p>
<ol style="text-align: left;">
<li>Domainregistrierung, DNS</li>
<li>Webserver, SSL Zertifikate</li>
<li>Mailserver</li>
</ol>
<p></p>
<p>
Normalerweise befindet sich alles bei einem Provider, die Verwaltung und die
Funktionen können sich individuell unterscheiden. Es ist aber auch möglich
Services bei einem anderen Provider zu nutzen. Warum sollte man das tun?
</p>
<p></p>
<ul style="text-align: left;">
<li>Umzug vorbereiten, </li>
<li>Funktionalitäten des Providers testen,</li>
<li>einzelne Services auslagern.</li>
</ul>
<p></p>
<p>Möglich wird dies durch Manipulation der DNS Einträge. <span></span></p>
<a name='more'></a>
<p></p>
<h2 style="text-align: left;">Allgemeine Annahmen</h2>
<p>
Der Domainservice liegt bei Provider A, damit man DNS Einträge beim Provider B
anlegen kann muss diese Domain dort eigerichtet werden: "ist schon registriert
und soll später umgezogen werden"
</p>
<h3 style="text-align: left;">
Scenario 1 - Webserver und Mailserver Provider B
</h3>
<p></p>
<ul style="text-align: left;">
<li>DNS 2 NS Record Einträge zu dem Nameserver bei Provider B</li>
</ul>
<p></p>
<p>
Damit werden alle DNS Einträge bei Provider B administriert, nur die NS
Einträge bei Provider A spielen noch eine Rolle. Die Namensauflösung ist quasi
komplett auf den anderen Nameserver delegiert.
</p>
<p>Geeignet für:</p>
<p></p>
<ul style="text-align: left;">
<li>Delegation einer kompletten Subdomain auf einen anderen Host,</li>
<li>Umzug einer kompletten Website,</li>
<li>Vorbereitung Domaintransfer.</li>
</ul>
<p></p>
<p>
Der Umzug der Homepage geht hiermit beinahe unterbrechungsfrei und hat
Möglichkeiten zu testen. Der Umzug von Postfächern erfordert immer die
Mitarbeit des Users! Achtung: Je nach Aufgabe gelten nur einzelne Schritte:
</p>
<p></p>
<ol style="text-align: left;">
<li>Domain bei Provider B einrichten,</li>
<li>
Inhalt des Web zu Provider B kopieren und Anpassungen (Datenbank, SSL)
vornehmen,
</li>
<li>Postfächer einrichten,</li>
<li>
NS Einträge bei Provider A ändern und
<a href="https://www.whatsmydns.net/" target="_blank">testen</a> (Wartezeit)
</li>
<li>
Wartezeit nutzen um Postfachinhalte zu übertragen (Tools vom Provider oder
Mailstore Home),
</li>
<li>Homepage testen und eventuell DNS Eintrag auf alten Host ändern,</li>
<li>Postfächer testen,</li>
<li>Bei Umzug den final Domaintransfer vollziehen.</li>
</ol>
<p></p>
<h3 style="text-align: left;">Scenario 2a - Webserver Provider B</h3>
<p></p>
<ul style="text-align: left;">
<li>DNS Host Record zur Adresse Provider B,</li>
<li>oder CNAME auf DDNS Hostadresse.</li>
</ul>
<p></p>
<p>
Alle DNS Einträge werden beim Provider A administriert, etwaige Einträge beim
Provider B spielen keine Rolle. Damit kann man einzelne verteilte Hosts unter
einer Stammdomain erreichbar machen. Gut geeignet um die Funktionalität eines
Webservice bei Provider B zu testen. Da sich der Nameserver nicht ändert, ist
in der Regel keine Wartezeit zwischen der Einrichtung und dem Test nötig, nur
lokale Caches müssen berücksichtigt werden.
</p>
<p>Provider B kann dabei auch der Host zu Hause sein. </p>
<h3 style="text-align: left;">
Scenario 2b - Webserver bei Provider B mit Let's Encrypt SSL Zertifikaten
</h3>
<p></p>
<ul style="text-align: left;">
<li>2 NS Record bei Provider A auf die NS bei Provider B setzen, </li>
<li>
alle Mail relevanten Records müssen 1:1 von Provider A nach Provider B
übertragen werden, siehe auch Scenario 3.
</li>
</ul>
<p></p>
<p>
Hierbei werden vom Let's Encrypt Agenten dynamisch DNS Einträge zur
Autorisierung erzeugt. Die DNS Verwaltung für den Webservice wird quasi
umgekehrt.
</p>
<h3 style="text-align: left;">Scenario 3 - Mailserver Provider B</h3>
<p></p>
<ul style="text-align: left;">
<li>MX Record bei Provider A zur Adresse Provider B, </li>
<li>
Mail relevante TXT, SRV Records bei Provider A entsprechend Provider B
setzen.
</li>
</ul>
<p></p>
<p>
Die komplette Einrichtung für eine Mailumgebung ist aufwendiger als für einen
Webhost, da zahlreiche Einträge eine Rolle spielen:
</p>
<p></p>
<ol style="text-align: left;">
<li>MX Records für die Erreichbarkeit des Mailservers.</li>
<li>TXT Records für die Sicherheit (SPF und DKIM)</li>
<li>SRV Records für automatische Konfiguration des Mailclients.</li>
</ol>
<p></p>
<p>
Der Umzug eines Mailhosts geht nicht ohne Einfluss beim Benutzer, da sich in
der Regel mindestens die Hostnamen für IMAP und SMTP ändern. SRV Records
können die Sache für den Benutzer vereinfachen.
</p>
<h2 style="text-align: left;">Noch ein paar Links</h2>
<p>Tools zur DNS Abfrage</p>
<p>
<a href="https://www.dnswatch.info/" target="_blank"
>https://www.dnswatch.info/</a
>
</p>
<p>
<a href="https://www.heise.de/netze/tools/dns/" target="_blank"
>https://www.heise.de/netze/tools/dns/</a
>
</p>
<p>
<a href="https://www.whatsmydns.net/" target="_blank"
>https://www.whatsmydns.net/</a
>
</p>
<p>Beschreibungen </p>
<p>
<a
href="https://www.hardill.me.uk/wordpress/2021/01/24/email-autoconfiguration/" target="_blank"
>https://www.hardill.me.uk/wordpress/2021/01/24/email-autoconfiguration/</a
>
</p>
<p>
<a
href="https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat" target="_blank"
>https://wiki.mozilla.org/Thunderbird:Autoconfiguration:ConfigFileFormat</a
>
</p>
<p>
<a
href="https://kb.mailbox.org/en/private/custom-domains/how-to-configure-e-mail-clients-automatically-through-dns/" target="_blank"
>https://kb.mailbox.org/en/private/custom-domains/how-to-configure-e-mail-clients-automatically-through-dns/</a
>
</p>
<p>
<a href="https://kinsta.com/de/wissensdatenbank/was-ist-dns/" target="_blank"
>https://kinsta.com/de/wissensdatenbank/was-ist-dns/</a
>
</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-60436529468794670042024-01-19T12:00:00.000+01:002024-01-26T19:27:47.611+01:00Website umziehen - Zusammenfassung<p>
Alle PHP basierten Websites (Applikationen) sind nach dem gleichen Schema
aufgebaut: Datenbank plus viele Dateien in einem Pfad. Das bedeutet
prinzipiell:
</p>
<p></p><ul style="text-align: left;"><li>ein Pfad pro "Applikation" im Webserver, den kopiert man von A nach B</li><li>eine Datenbank, die exportiert man in A und importiert sie in B.</li></ul><span><a name='more'></a></span><h3 style="text-align: left;">Kleine Anpassungen im Ziel</h3>
<p>In der Konfigurationsdatei ändert man die Datenbank Konfiguration (DB-Server,
-Name, -User, -Passwort ). Hier gibt es ein <a href="https://heinz-otto.blogspot.com/2023/12/wordpress-datenbank-neu-machen.html" target="_blank">Beispiel</a>.</p>
<p>Jetzt könnte die Applikation wieder erreichbar sein, vor allem wenn sich die Domain URL nicht geändert hat. Wenn sich die URL durch den Umzug/Kopie geändert muss man ev. nacharbeiten. </p><p>Die PHP Applikationen arbeiten unterschiedlich bei der Auslieferung der HTML Seiten: Absolute Links (Wordpress), relative Links zur aktuellen URL (Nextcloud, joomla), relative Links zur absoluten URL. Je nach Fall muss man nacharbeiten, die "ini" bearbeiten, im Backend die siteurl anpassen, eine extra "configuration.php" aufrufen, ein Tool in der Konsole nutzen.</p><h3 style="text-align: left;">Wordpress </h3><p>In Wordpress kann man mit einer Kommandozeile die urls anpassen (Details siehe <a href="https://heinz-otto.blogspot.com/2023/12/wordpress-website-umziehen-oder.html" target="_blank">hier </a>).</p><pre class="language-bash"><code contenteditable="" spellcheck="false">wp search-replace 'https://www.old-domain.test' 'https://www.new-domain.de'</code></pre><p>Jetzt sollte die Wordpress Site wieder in allen Bildern und Links funktionieren.</p><h3 style="text-align: left;">Nextcloud - Vertrauen herstellen</h3><p>In der config/config.php muss man das Array trusted_domains bearbeiten, falls sich die URL geändert hat. Hiermit bietet sich auch die Möglichkeit eine Installation über mehrere Domains zu erreichen.</p><h3 style="text-align: left;">Nacharbeit</h3><p>Auch wenn scheinbar alles läuft gibt es ev. noch etwas zu tun. </p><p>PHP Einstellungen anpassen. global im Management Interface, in der .htaccess oder in der .user.ini.</p>
<p>Hoster und Server spezifische Besonderheiten:</p>
<p></p><ul style="text-align: left;"><li>Webserver spezifische Plugins</li><li>absolute Pfade in Konfigurationsdateien z.B. für Log Pfade ...</li><li>Verwendung von diversen Cache Möglichkeiten</li><li>Verwendung von besonderen PHP Modulen</li><li>Verwendung von besonderen PHP Versionen</li></ul><p></p>
<p><br /></p><h3 style="text-align: left;">ToDo</h3><p>Noch Details einarbeiten, wenns schlimm kommt:</p>
<p>Datenbank (Server) Einstellungen: Zeichensatz, collate</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
Text
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-40562768016852781702024-01-04T16:51:00.002+01:002024-01-04T16:51:35.685+01:00joomla - Webauftritt auf einen neuen Server ziehen<p>Wie alle PHP Web Applikationen besteht auch joomla im wesentlich aus einem Sack Dateien (ca. 10.000 gegenüber Wordpress ca. 3000 bei etwa gleicher Größe knapp 30 MB) und einer SQL Datenbank. In der Datei configuration.php steht die Datenbankanbindung drin. Als Sicherung vom alten Server benötigt man ein Backup der Dateien vom gesamten Pfad sowie ein Backup/Export/SQL Dump der Datenbank.</p><span><a name='more'></a></span><h3 style="text-align: left;">Restore</h3><p>Auf dem neuen Server erstellt man eine neue Datenbank, notiert die Namen vom Server, der Datenbank, vom User und natürlich das User Passwort. Anschließend folgt der Restore/Import der Datenbanksicherung, meist steht dazu phpMyAdmin zur Verfügung.</p><p>Beim Restore des Verzeichnispfades ist der Upload eines Archives und auspacken direkt auf dem Server einem Upload des Verzeichnisses mit FTP vorzuziehen! Manche Web Upload Tools vom Hoster bieten diese Möglichkeit.</p><h3 style="text-align: left;">Konfiguration anpassen</h3><p>Zunächst muss man nur die Datei configuration.php editieren und die Datenbankkonfiguration einzutragen. </p><h3 style="text-align: left;">Test</h3><p>Erster Test: Aufruf der URL und/oder URL/administrator/ </p><p>Sollte beides nicht funktionieren, kann man als erste Maßnahme im Server Log schauen ob irgendetwas nicht passt und eventuell die .htaccess Datei teilweise oder ganz "tot legen". </p><p>Funktioniert die URL der Seite nicht, aber man erreicht die Administrationsseite (URL/administrator/) sollte man nach Plugins schauen die eine Lizenz erfordern. Bei mir hat "JRealtime Analytics" den Start der PHP Applikation komplett verhindert: http: Error 500.</p><h3 style="text-align: left;">User Account verschaffen</h3><p>Hat man keinen funktionierenden User Account zur Administration (passwort vergessen, Administrator abhanden gekommen), kann man das Passwort des Super Users in der Datenbank neu setzen. Um den alten Super User Account zu erhalten:</p><p></p><ul style="text-align: left;"><li>kopiert man den Hash bevor man ihn neu setzt, </li><li>meldet sich an und schafft sich einen neuen Super User Account, </li><li>prüft die Anmeldung und schreibt den alten Hash zurück in die Datenbank. </li></ul><p></p><p>Siehe auch: https://www.domaintechnik.at/joomla-passwort-reset.html</p><h3 style="text-align: left;">Feintuning und Tipps</h3><p>Die beiden Werte für $tmp_path und $log_path müssen angepasst werden. Beide Pfade sind absolut und nicht relativ zum gesamten Pfad.</p><p>Die Mailanbindung ist zu Überprüfen und eventuell zu korrigieren.</p><p>Unter Erweiterung / Verwalten / Warnung schauen ob es Einträge gibt. Das tmp Verzeichnis muss 770 haben.</p><p>Bei fc-hosting.de habe ich ein paar nützliche Informationen und Tools (PHP Scripte) gefunden, die bei der Neukonfiguration helfen. </p><p><br /></p>Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-59825179446752903812023-12-23T15:33:00.000+01:002023-12-23T15:33:12.683+01:00libvirt - Hardware direkt zum Gast verbinden<p>
Ein großer Vorteil der Linux QEMU/KVM gegenüber Windows Hyper-V ist meiner
Meinung nach die Möglichkeit physische Hardware mit dem Gast System zu
verbinden. Ich will kurz die Möglichkeiten aufzeigen einen USB Speicherstick
einzubinden.
</p>
<p>
<span></span>
</p>
<a name='more'></a>
<p>
Über den virt-manager geht das ganze recht intuitiv per GUI:
Maschinenkonfiguration öffnen, Gerät hinzufügen, links USB Host-Gerät
auswählen und rechts das konkrete USB Device auswählen, fertig.
</p>
<p>
In der Kommandozeile schaut man sich zunächst mit dem Befehl lsusb die
Situation an und hat die Zeile mit dem betreffenden Gerät im Blick.
</p>
<p>
Beispiel:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">lsusb
Bus 002 Device 010: ID 0781:5588 SanDisk Corp. Extreme Prob</code></pre>
<p>Die Anbindung mit virsh erfolgt in dem Fall mit einer XML Datei, mit diesem Inhalt. </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false"><hostdev mode="subsystem" type="usb" managed="yes">
<source>
<vendor id="0x0781"/>
<product id="0x5588"/>
</source>
</hostdev></code></pre>
<p>Wie man sieht, muss man die Zahlen hinter ID entsprechend übernehmen. Man könnte auch mit Bus und Device arbeiten, dies hat den Nachteil, dass der Stick dann immer am gleichen Anschluss stecken müsste.</p>
<p>
Per Befehl kann man jetzt den Stick mit dem Gast verbinden. Der Schalter --current schreibt entweder in die Konfiguration oder und man kann anschließend die VM starten oder im laufenden System wird das Gerät direkt verbunden (und nicht gespeichert). Siehe: virsh attach-device --help</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">virsh attach-device vmID usbstick.xml --current</code></pre>
<p>bzw. später auch wieder "abziehen". </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">virsh detach-device vmID usbstick.xml --current</code></pre>
<p>Mit dieser Methode lässt sich offenbar jedes USB Gerät so wie es ist zum Gast verbinden, das ist nicht auf Speichersticks beschränkt.</p><p>Handelt es sich um eine USB HDD kann man diese auch per Laufwerkspfad (/dev/sdx) anbinden:</p><p>Zunächst wird der Devicename ermittelt</p><pre class="language-bash"><code contenteditable="" spellcheck="false">lsblk</code></pre><p>Und dann ohne Umwege eingebunden.</p><pre class="language-bash"><code contenteditable="" spellcheck="false">virsh attach-disk win11 /dev/sdf vdf --config</code></pre><p>Ich finde diese Methode für eine USB HDD nicht sinnvoll, zumindest ist es mir auch nicht gelungen davon zu starten. </p><p>Sehr umfangreich kann man auch mit Storage pools arbeiten, siehe im libvirt Handbuch:</p><p>Libvirt Storage Pool https://libvirt.org/storage.html</p><p>ToDo? </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code</code></pre>
<p> </p>Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-1282493023052721442023-12-23T00:10:00.007+01:002024-02-12T20:04:47.409+01:00Wordpress - Website umziehen oder reparieren<p>
Der individuelle Inhalt einer Wordpress Website steckt in der Datenbank,
alleine mit ihr sind wesentliche Inhalte wieder herstellbar. Der andere
individuelle Teil steckt im steckt im Ordner wp-content/uploads. Im
allgemeinen sind die Inhalte wp-content/themes und wp-content/plugins durch
Installation wieder beschaffbar.
</p>
<p><span></span></p>
<a name='more'></a>Den ersten Schritt habe ich in
<a href="https://heinz-otto.blogspot.com/2023/12/wordpress-datenbank-neu-machen.html" target="_blank">diesem Artikel </a>beschrieben.
<p></p>
<ol style="text-align: left;">
<li>
Es muss die Datenbank wieder hergestellt werden. Falls sich die url geändert
hat, muss man diese entweder direkt in der Datenbank (siteurl und home in
_options) oder mit wp_cli (siehe unten) anpassen, sonst kann man wp-admin
für die weitere Arbeit nicht aufrufen.
</li>
<li>Bei einer Reparatur muss man </li>
<ul>
<li>
das verwendete Theme wiederherstellen, entweder neu installieren oder vom
alten Server kopieren und aktivieren.
</li>
<li>die Mediathek - das Verzeichnis uploads wieder herstellen. </li>
</ul>
</ol>
<p></p>
<p>
Sehr schnell geht letzteres direkt auf dem Server, wenn man ssh Zugang hat.
Beispiel:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">cd ~/clickandbuilds/NeueWebsite/wp-content/uploads/
cp -R ~/clickandbuilds/AlteWebsite/wp-content/uploads/2017/ .</code></pre>
<p>
Zum Schluss sollte man prüfen ob noch wesentliche Plugins fehlen, auch diese
kann man am besten neu installieren oder vom alten Server kopieren.
</p>
<p>
Es gibt 4 Komponenten die eine Wordpress Website ausmachen und die man
regelmäßig sichern muss:
</p>
<p></p>
<ol style="text-align: left;">
<li>Datenbank</li>
<li>Uploads</li><li>Plugins</li>
<li>Themes</li>
</ol>
<p></p>
<h3>Wordpress wp-cli zur Nacharbeit </h3>
<p>
Achtung: Für die Bearbeitung mit wp-cli im Startpfad für die jeweiligen
Wordpress Site stehen!
</p>
<p>
Es gibt Hoster, da ist das Tool vorinstalliert. Kann man in der Konsole
einfach prüfen:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">wp --info</code></pre>
<p>
Normal kann man auf einem Webspace keine Software "nachinstallieren", man kann
dieses Tool aber trotzdem verwenden:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
echo alias wp=\"/usr/bin/php -d allow_url_fopen=On /usr/home/$USER/wp-cli.phar\" >> ~/.bashrc
source ~/.bashrc</code></pre>
<p>
Weitere Informationen gibt es <a href="https://wp-cli.org/" target="_blank">hier</a>.
</p>
<p>
Mit den folgender Codezeilen wird die siteurl und home angepasst. Das könnte
man auch in der Datenbank direkt mit phpMyAdmin machen.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">wp option update home 'http://yoursiteurl.com'
wp option update siteurl 'http://yoursiteurl.com'</code></pre>
<p>Mit folgender Codezeile werden alle restlichen urls angepasst.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">wp search-replace 'https://www.old-domain.test' 'https://www.new-domain.de'</code></pre>
<p>
Jetzt sollte die Wordpress Site wieder in allen Bildern und Links
funktionieren.
</p>
<h3 style="text-align: left;">ToDo </h3>
<p>Notizen noch ausarbeiten!</p>
<p>Serverwechsel, Cache ausschalten, </p>
<p>
https://www.ionos.de/digitalguide/hosting/blogs/wordpress-migration-tipps-fuer-den-serverumzug/
</p>
<p><br /></p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-76694710903982570872023-12-22T23:18:00.001+01:002024-01-26T19:05:17.975+01:00Wordpress - Datenbank neu machen<p>Falls der Webauftritt etwas in die Jahre gekommen ist und neben der Applikation auch die Datenbank auf eine neue Version gehoben werden soll: Für Datenbank Server gibt es immer mal wieder Versionssprünge ohne direktes Update (z.B. MySQL 5 auf 8). Es bleibt dann nur der Weg den Inhalt der Datenbank zu exportieren und in eine neue Datenbank (auf neuem (DB) Server) zu importieren.</p><span><a name='more'></a></span><p>Datenbank auf Server mit neuer Version verlagern.</p><p></p><ol style="text-align: left;"><li>Neue Datenbank anlegen</li><li>Alte Datenbank exportieren (SQL Dump) </li><li>Die Sicherung (SQL Dump) in die neue Datenbank importieren, meist einfach mit phpMyAdmin.</li></ol><p></p>
<p>Die alte wp-config.php im Bereich der Datenbank Daten anpassen </p>
<pre class="language-php"><code contenteditable="" spellcheck="false">// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'database_name_here' );
/** Database username */
define( 'DB_USER', 'username_here' );
/** Database password */
define( 'DB_PASSWORD', 'password_here' );
/** Database hostname */
define( 'DB_HOST', 'localhost' );</code></pre>
<p>Alles andere bleibt in der Datei so wie es ist. </p><p><br /></p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-59188334793476767402023-11-20T12:00:00.018+01:002023-11-23T17:04:43.295+01:00vlan tag - oder Stämme, Etiketten, Brücken ...<p>
Meine Fritzbox ist nur DSL Anschluss und Telefonanlage, meine Netzwerkzentrale
ist ein OpenWrt Router und dazwischen gibt es ein paar Kabel - immer zu
wenige. Mein Haupt Switch hat 24 Ports, auf dem wollte ich gern auch ein paar
wenige Anschlüsse von dem Netz zwischen Fritzbox und OpenWrt Router, räumlich
in Nähe der Fritzbox braucht es auch noch ein paar Ports vom internen
Netzwerk.
</p>
<h2 style="text-align: left;">Aufgabenstellung</h2>
<p></p>
<ul style="text-align: left;">
<li>2 VLANs, ein Trunk zwischen zwei Switches einrichten und </li>
<li>
kann man eigentlich auf einem Linux Host für VMs mit einer Netzwerkkarte
beide Netzwerke haben - also einen Trunk direkt zuführen?
</li>
</ul>
<p></p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz4Rq9RHHXt3nzv8YJbJLa-01ddii6XBV5eujrLWw3qV5Qbn5GrS6R5oskenZtA0gEV-EaiSCp9w2eU9RLSOJKMt142V9n7Vv-iu8Ll0rUefGuQnbaVN_Urnw6boeHnf5Bz89v67BDnwJgvC-lvPZizWJfLUZQ0UbmLVH9kJkadvjQF0O-LN7U_4reLU2C/s390/Aufgabe.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="390" data-original-width="389" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz4Rq9RHHXt3nzv8YJbJLa-01ddii6XBV5eujrLWw3qV5Qbn5GrS6R5oskenZtA0gEV-EaiSCp9w2eU9RLSOJKMt142V9n7Vv-iu8Ll0rUefGuQnbaVN_Urnw6boeHnf5Bz89v67BDnwJgvC-lvPZizWJfLUZQ0UbmLVH9kJkadvjQF0O-LN7U_4reLU2C/s320/Aufgabe.png" width="319" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;"><a href="https://www.yworks.com/yed-live/" target="_blank">Mit yEd Live erstellt.</a></td></tr></tbody></table><div class="separator" style="clear: both; text-align: center;">
</div>
<span><a name='more'></a></span>
<p><br /></p>
<h2 style="text-align: left;">Begriffe und Vorbereitung im Netzwerk</h2>
<p>
Ich will jetzt nicht die gesamte Theorie zum Netzwerk erklären (besser als
<a href="https://uwe-kernchen.de/phpmyfaq/index.php?action=faq&cat=4&id=340&artlang=de" target="_blank">hier </a>könnte ich das nicht), nur das aller wichtigste:
</p>
<p></p>
<ul style="text-align: left;">
<li>
Trunk Port - alle Frames sind mit ihrem VLAN gekennzeichnet. Mehrere VLANs
auf einem Kabel möglich. Ein normales Endgerät kann hier nicht betrieben
werden.
</li>
<li>Device Port - kein Frame ist mit einem VLAN gekennzeichnet</li>
</ul>
<p></p>
<p>
Bei meinem netgear Switch heißt der Menüpunkt "Erweiterte
802.1Q-VLAN-Konfiguration"
</p>
<p></p>
<ol style="text-align: left;">
<li>
VLAN-ID hinzufügen (erzeugen), z.B. 1090 und 1056 (VLAN 1 ist reserviert)
</li>
<li>
VLAN-Mitgliedschaft den Ports zuweisen. U- untagged - normales Device Port,
T - tagged - für einen Trunk Port, leer - kein Port für diese VLAN
</li>
<li>
Den Ports eine PVID zuweisen - jedes Port bekommt die bzw. eine der
zugewiesenen VLAN-ID als PVID.
</li>
</ol>
<p></p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-Re6X0D5HgDr01ILUx78W_9i1hWWQe5p_10MxSMVhE7rPQ58MKIH2SRh6Uk4VdpqenRxB-Ei_oku6YDLyVXAS_bOmdNi3XPHMT3HlAcQs5jgd4CPxz2htnsmUdgeXEhr69RL4ONCQkkgPgbqqQogWryASw33i0t5TyOd-_mIIdSjZYTltnHsmdK4P3t-j/s1193/VLAN_8port.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="490" data-original-width="1193" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-Re6X0D5HgDr01ILUx78W_9i1hWWQe5p_10MxSMVhE7rPQ58MKIH2SRh6Uk4VdpqenRxB-Ei_oku6YDLyVXAS_bOmdNi3XPHMT3HlAcQs5jgd4CPxz2htnsmUdgeXEhr69RL4ONCQkkgPgbqqQogWryASw33i0t5TyOd-_mIIdSjZYTltnHsmdK4P3t-j/s320/VLAN_8port.png" width="320" /></a>
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhySahBN8N6vnYx-FhQD-8xn64U_DPr6LKIeCWAp_tbhziLPpwMYKNP_1sir_WTO1xyzwq0D0D4aYcsEY6g7UcKkGtN9pekpmfEkuoHphpRa85eh7Nqj8e2k9qNduSmAERXnvZPiFBfm5lNbWgqEwYRajRCVLvLxF8Fq9ZOElU2Rf3Ez6vfWNwnZGxCMU_1/s1003/VLAN_24port.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="454" data-original-width="1003" height="145" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhySahBN8N6vnYx-FhQD-8xn64U_DPr6LKIeCWAp_tbhziLPpwMYKNP_1sir_WTO1xyzwq0D0D4aYcsEY6g7UcKkGtN9pekpmfEkuoHphpRa85eh7Nqj8e2k9qNduSmAERXnvZPiFBfm5lNbWgqEwYRajRCVLvLxF8Fq9ZOElU2Rf3Ez6vfWNwnZGxCMU_1/s320/VLAN_24port.png" width="320" /></a>
</div>
<br />
<p><br /></p>
<p>
Jetzt hat mein zwei Switche mit je zwei getrennten Netzwerk Bereichen, die
über eine Trunk Verbindung am Port 1 kommunizieren. Soweit so einfach ...
</p>
<h2 style="text-align: left;">Trunk mit dem Linux Host verbinden</h2>
<p>
Dazu muss man etwas in die Konfiguration der Netzwerkschnittstelle einsteigen.
Zuerst die Konfiguration im laufenden Betrieb. Ich habe zur Übung einen
zusätzlichen USB Ethernet Adapter angeschlossen. Den nimmt Linux zwar in
Betrieb (Treiber muss vorhanden sein) aber aktiviert die Netzwerkschnittstelle
nicht. Man kann die Konfiguration des Netzwerkes und den Syntax der Befehle
auch gut in einer virtuellen Maschine testen.
</p>
<p>
Zur live Konfiguration kann man ziemlich unabhängig von der konkreten Linux
Distribution den
<a href="https://manpages.ubuntu.com/manpages/jammy/man8/ip.8.html" target="_blank">Befehl ip</a>
verwenden.
</p>
<p>
Zunächst mal einen Überblick verschaffen, entweder nur mit
<span style="font-family: courier;">ip a</span> oder gezielt:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">ip link show|grep DOWN</code></pre>
<p>
Mit beiden Befehlen (auch in Abwandlung) kann man sich nach jedem der
folgenden Schritte vom Ergebnis überzeugen. Nach der laufenden Nummer steht
der Interface Name, ein USB Adapter beginnt häufig mit enx gefolgt von einer
12 stelligen Ziffer (MAC Adresse?).
</p>
<p>
Für die weitere Arbeit notiert man den Namen des Adapters den man in Betrieb
nehmen möchte in einer Variablen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">if_name=enx010203040506</code></pre>
<p>Jetzt nimmt man das Interface in Betrieb</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo ip link set dev $if_name up</code></pre>
<p>
Pro VLAN erzeugt man ein virtuelles Interface (Beispiel: vlan1056 vlan1090),
aktiviert das Interface und versorgt es mit einer IPv4 Adresse. Die Netzkarte
selbst erhält keine IP Adresse!
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">vlan_id=1090
sudo ip link add link $if_name name vlan${vlan_id} type vlan id ${vlan_id}<br />sudo ip link set dev vlan${vlan_id} up
sudo dhclient -4 vlan${vlan_id}</code></pre>
<p>
Die Funktion kann man mit traceroute gut prüfen. Von einem anderen Gerät kann
man die neuen Interfaces mit ping ansprechen.
</p>
<h3 style="text-align: left;">Bridge</h3>
<p>
Für die Arbeit mit einer virtuellen Maschine braucht man eine Bridge. Eine
Bridge ist so etwas wie ein virtueller Netzwerk Switch, sie verbindet mehrere
Netzkarten (physische und virtuelle) zu einem Netzwerk.
</p>
<p>
Wichtig: Bei der Einrichtung der Bridge muss die IP Adresse vom zugehörigen
(VLAN-)Interface entfernt werden. Final darf es nur eine IP Adresse in der
Kette Ethernet Adapter - VLAN - Bridge geben!
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false"># vlan_id=1090
sudo ip link add name br${vlan_id} type bridge
sudo ip link set dev br${vlan_id} up
sudo ip link set vlan${vlan_id} up
sudo ip link set vlan${vlan_id} master br${vlan_id}
sudo dhclient -r vlan${vlan_id}
sudo dhclient -4 br${vlan_id}</code></pre>
<p>
Die entstandene Bridge br1090 kann man jetzt als Interface für virtuelle
Maschinen verwenden.
</p>
<p>
Die bisherige Konfiguration überlebt einen Neustart nicht, sie ist nur
transient. Die vor eingestellte permanente Netzwerkkonfiguration ist von der
Linux Distribution abhängig. (<a href="https://wiki.debian.org/NetworkConfiguration#A3_ways_to_configure_the_network" target="_blank">debian: interfaces</a>)
</p>
<p>
Will man mit dem nächsten Abschnitt ohne reboot weitermachen, muss man die
bisherige Konfiguration löschen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo ip link delete vlan${vlan_id}
sudo ip link delete br${vlan_id}
sudo ip link set dev $if_name down</code></pre>
<p><br /></p>
<h3 style="text-align: left;">Netplan</h3>
<p>
Ubuntu verwendet netplan und networkd, netplan wird mit yaml Dateien
konfiguriert. Man kann diese Datei mit einem Editor oder per cli (mit
Syntaxprüfung!) erzeugen. Netplan (<a href="https://netplan.io/design" target="_blank">Design</a> und <a href="https://netplan.io/faq" target="_blank">FAQ</a>) wendet alle Dateien in /etc/netplan in
lexikalischer Reihenfolge an, gleiche Einträge werden dabei überschrieben oder
ergänzt (<a href="https://linuxconfig.org/netplan-network-configuration-tutorial-for-beginners" target="_blank">siehe</a>). Netplan hat eine gute
<a href="https://netplan.readthedocs.io/en/stable/" target="_blank">Dokumentation</a>,
mit Tutorials die man auch in virtuellen Umgebungen (im Tutorial mit Linux
Container LXC) ausprobieren kann!
</p>
<p>Die wichtigsten Befehle netplan </p>
<p></p>
<ul style="text-align: left;">
<li>
set: schreibt eine netplan Konfiguration (yaml Datei) in /etc/netplan/
</li>
<li>get: liest alle Dateien und zeigt das resultierende Ergebnis an</li>
<li>
generate: erzeugt die Dateien für networkd in /run/systemd/network/
</li>
<li>
apply: macht vorab neplan generate und aktiviert die Konfiguration mit
networkd
</li>
<li>
status: zeigt gut strukturierte Informationen an, erst nach Ubuntu update
verfügbar!
</li>
<li>
try: probiert die Konfiguration, das revert am Ende hat bei mir nie
funktioniert!
</li>
</ul>
<p></p>
<p>
Will man hin und wieder einen USB Ethernet Adapter "hot plug" verwendet,
braucht man eine entsprechende yaml Datei. Für mich war der USB Adapter zunächst zum Test und später als Rückversicherung gedacht, falls mit dem Trunk etwas schiefgeht.</p>
<p>
Dieses Beispiel bringt Adapter mit DHCP online, deren Name mit enx beginnt.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false"># Inhalt yaml
network:
version: 2
ethernets:
usb0:
match:
name: enx*
dhcp4: true</code></pre>
<p>
Mit zwei Zeilen könnte man die yaml Datei erzeugen, würde <span style="font-family: courier;">netplan set</span> richtig
arbeiten:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo netplan set --origin-hint 10-USB-interface "ethernets.usb0={dhcp4: true}"
sudo netplan set --origin-hint 10-USB-interface "ethernets.usb0.match={name: enx*}"
sudo sed -i 's/"enx\*"/enx\*/' /etc/netplan/10-USB-interface.yaml</code></pre>
<p>
Hinweis: netplan macht hier einen Fehler, es setzt quotes: name: "enx*" - der
match funktioniert aber nur ohne! Deshalb braucht man noch eine (unschöne)
Korrekturzeile.
</p>
<p>
Tipp: Man könnte das entstehende Interface auch einheitlich umbenennen:
<span style="font-family: courier;">{dhcp4: true, set-name: usb0}
</span></p>
<p>
Bisher sind nur Dateien erzeugt und die Konfiguration ist noch nicht aktiv,
ein
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">netplan apply</code></pre>
<p>
aktiviert die Konfiguration sofort, wenn man unsicher ist kann man vorher mit
einem netplan get die resultierende Konfiguration aus allen Dateien anschauen.
</p>
<p>
Eine yaml Konfiguration, die dem obigen vlan und der Bridge entspricht, sieht
so aus.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">network:
version: 2
ethernets:
enx010203040506:
dhcp4: false
bridges:
br1090:
dhcp4: true
interfaces:
- vlan1090
vlans:
vlan1090:
dhcp4: false
id: 1090
link: "enx010203040506"</code></pre>
<p>
Hinweis: Mit der Option --origin-hint behandelt der Befehl exakt diese Datei.
Lässt man diese Option weg, erkennt netplan zwar die richtige Datei, räumt
aber die Konfiguration auf: nicht verwendete Konfigurationsdateien werden
gelöscht, ergänzende Dateien in der "letzten" konsolidiert.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">if_name=enx010203040506
vlan_id=1090
YAML=40-vlan-interface
sudo rm /etc/netplan/$YAML.yaml
sudo netplan set --origin-hint $YAML "ethernets.${if_name}={dhcp4: false}"
sudo netplan set --origin-hint $YAML "vlans.vlan${vlan_id}={id: ${vlan_id}, link: ${if_name}, dhcp4: false}"
sudo netplan set --origin-hint $YAML "bridges.br${vlan_id}={interfaces: [vlan${vlan_id}], dhcp4: true}"</code></pre>
<p>ToDo?</p>
<p>Grafik einfügen</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Text</p>
<h3 style="text-align: left;">Finale Umstellung</h3>
<p>
Die folgende netplan Konfiguration schaltet DHCP am Adapter enp2s0 ab,
verbindet darauf das vlan1056 und vlan1090, erzeugt ein Bridge br0 und eine
Bridge br1090 mit DHCP Konfiguration. Eine existierende Bridge br0 (wie in
meinem Fall) bleibt dabei erhalten und wird lediglich modifiziert. Alle meine
virtuellen Maschinen bekommen davon nichts mit.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">if_name=enp2s0
vlan_id=1056
YAML=40-vlan-interface
sudo rm /etc/netplan/$YAML.yaml
sudo netplan set --origin-hint $YAML "ethernets.${if_name}={dhcp4: false}"
sudo netplan set --origin-hint $YAML "vlans.vlan${vlan_id}={id: ${vlan_id}, link: ${if_name}, dhcp4: false}"
sudo netplan set --origin-hint $YAML "bridges.br0={interfaces: [vlan${vlan_id}], dhcp4: true}"
vlan_id=1090
sudo netplan set --origin-hint $YAML "vlans.vlan${vlan_id}={id: ${vlan_id}, link: ${if_name}, dhcp4: false}"
sudo netplan set --origin-hint $YAML "bridges.br${vlan_id}={interfaces: [vlan${vlan_id}], dhcp4: true}"</code></pre>
<p>Hinweis: Ich hatte bisher den Empfehlungen folgend für virsh ein virtuelles Netzwerk "host-bridge" mit br0 erzeugt. Ich habe aber mittlerweile festgestellt: Man kann die br1090 auch direkt bei Netzwerkquelle als Bridge Device eintragen. Temporär in der Kommandozeile zum testen</p><pre class="language-bash"><code contenteditable="" spellcheck="false">virsh attach-interface --type bridge --source $YOUR_HOST_BRIDGE --model virtio $YOUR_VM</code></pre><div><code contenteditable="" spellcheck="false"><span style="font-family: "Times New Roman";">oder dauerhaft mit dem Zusatz --config . Ob das Vor- oder Nachteile hat muss ich mal noch untersuchen.</span></code></div><p>ToDo?</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Text</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code BlockM</code></pre>
<p>Text</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Text</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-85262519766837234702023-10-30T23:43:00.010+01:002023-11-01T08:59:19.328+01:00Windows Server 2022 auf Consumer Hardware installieren<p>
Das Problem: Die Hardware Hersteller liefern Treiber und Setup Dateien nur für
Desktop Windows Versionen und nicht für Server. Je nach Hersteller gibt es
Treiber Setups zum Download die auf dem Server nicht laufen (man möchte die da
auch nicht haben) oder es gibt Rundumsorglos Tools ("Armoury Crate" von Asus
oder "msi driver utility installer") die alles mögliche installieren wenn man
nicht aufpasst, nur die Treiber sind eine Nebensache.
</p>
<p>
Jetzt hat man die Möglichkeit bei den üblichen Herstellern Intel, Amd, Realtek
usw. nach Treibern zu suchen, meist eine Odyssee. Ich wollte einen kleinen
Windows Server möglichst schlank aufbauen und installieren. Beim ITX Board
geht es schon los: alles irgendwie "Gamer" Hardware mit jeder Menge
Komponenten die ein Server nicht braucht.<span></span>
</p>
<a name='more'></a>
<p></p>
<h3 style="text-align: left;">Vorbereitung</h3>
<p>
Im aktualisierten Bios deaktiviert man erstmal alles, was der Server nicht
braucht:
</p>
<p></p>
<ul style="text-align: left;">
<li>Wifi und Bluetooth, </li>
<li>HD Audio. </li>
</ul>
<p></p>
<p>Kein Gerät vorhanden - kein Treiber notwendig!</p>
<p>
Ich empfehle temporär Windows 10 zu installieren, oder ein mobiles System vom
Stick zu starten.
</p>
<p>
Damit wir wirklich bei null beginnen, werden alle OEM Treiber gelöscht,
optional könnte man die Geräte noch im Device-Manager deinstallieren. Meine
Befehlszeilen kommen alle in eine Powershell (Administrator) Konsole. Pnputil
löscht und deinstalliert mit dem Befehl wirklich alle OEM Treiber.
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Get-WindowsDriver -Online -All |where {$_.driver -like "oem*"}| foreach {pnputil.exe /delete-driver $_.driver /uninstall /force}</code></pre>
<h3 style="text-align: left;">Treiber installieren</h3>
<p>
Mit der Treiberinstallation des Board Herstellers können jetzt alle Treiber
installiert werden. Als Ergebnis sollte der Geräte-Manager keine Geräte mehr
ohne Treiber anzeigen. Ich musste allerdings zusätzlich noch die aktuelle
<a href="https://www.intel.de/content/www/de/de/support/products/1145/software/chipset-software/intel-chipset-software-installation-utility.html" target="_blank">Chipset Software von Intel</a>
holen und starten.
</p>
<p>
Hat man als Grundlage ein vorinstalliertes Windows, muss man besonders
bereinigen. Hier gibt es meist jede Menge "Leichen" von der Image Erzeugung.
</p>
<p>
Zunächst holen und starten wir ein
<a href="https://github.com/istvans/scripts/tree/master" target="_blank">Powershell Script</a>, welches hidden Devices löscht - also Hardware die aktuell gar nicht
vorhanden ist. Danach löschen wir alle OEM Treiber die nicht verwendet werden,
pnputil erzeugt hier nur eine Fehlermeldung und löscht die Treiber nicht, die
verwendet werden.
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">wget -O removeGhosts.ps1 https://raw.githubusercontent.com/istvans/scripts/master/removeGhosts.ps1
.\removeGhosts.ps1 -force
Get-WindowsDriver -Online -All |where {$_.driver -like "oem*"}| foreach {pnputil.exe /delete-driver $_.driver }</code></pre>
<h3 style="text-align: left;">Export der Treiber</h3>
<p>
Aus dem komplett installiertem Windows, kann man jetzt die OEM Treiber
exportieren:
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">mkdir c:\treiber
dism /online /export-driver /destination:c:\treiber</code></pre>
<h3 style="text-align: left;">Zwischentest</h3>
<p>
Man kann alles noch kurz testen, einfach wie ganz oben alle Treiber löschen
und mit folgendem Befehl wieder importieren.
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">pnputil.exe /add-driver c:\treiber\*.inf /subdirs /install</code></pre>
<p>
Funktioniert alles, kopiert man die Treiber von der Testinstallation an einen
erreichbaren Ort. Beispiel Netzlaufwerk.
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">New-SmbMapping -RemotePath '\\nas' -UserName 'user' -Password 'Kennwort'
copy c:\treiber \\nas\sicherung\board\ -Recurse</code></pre>
<h2 style="text-align: left;">Windows Server installieren</h2>
<div>
Mit wenigen Schritten hat man eine vollständige Installation. Nach dem Setup
von DVD oder USB Stick öffnet man wieder nur die Powershell Konsole.
</div>
<p></p>
<ol style="text-align: left;">
<li>
Zeitzone setzen, egal was man in der Setup Maske einstellt, die Zeitzone
wird falsch/nicht gesetzt und steht auf "Microsoftland".
</li>
<li>
Windows Server kann sich nicht auf meine Linux basierte NAS verbinden, der
Registrykey hilft sofort.
</li>
<li>Die Verbindung zum Netzwerk vorbereiten.</li>
<li>Alle Treiber in dem Pfad installieren.</li>
</ol>
<div>
Wenn man bequem per RDP arbeiten will, kann man dies als erstes aktivieren.
</div>
<p></p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Set-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\Terminal Server' -name "fDenyTSConnections" -value 0
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"</code></pre>
<p><br /></p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Set-TimeZone -Name 'W. Europe Standard Time' -PassThru
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters" AllowInsecureGuestAuth -Type DWORD -Value 1 -Force
New-SmbMapping -RemotePath '\\nas' -UserName 'user' -Password 'Kennwort'
pnputil.exe /add-driver \\nas\sicherung\board\*.inf /subdirs /install</code></pre>
<p>
Es kann sein, dass der Treiber zwar ordentlich installiert, das zugehörige
Gerät aber nicht erkannt wird. Irgendein Mechanismus blockiert den PNP Vorgang
auf dem Server für meinen Intel(R) Ethernet Controller I226-V.
</p>
<p>
In dem Fall kann man per Hand einen alternativen Adapter I226-LM aktivieren.
Die Informationen in der Inf Datei für beide Adapter sind völlig identisch,
ich hoffe damit auf einwandfrei Funktion.
</p>
<p>
Update Driver / Browse my Computer ... / Let me pick ... / Intel / Intel(R)
Ethernet Controller I226-LM
</p>
<p>
Damit Windows diese Installation nicht einfach ändert, kann man verhindern das
die Geräteistellungen geändert werden (interaktiv: Change Device Installation
Settings).
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Device Metadata' -Name 'PreventDeviceMetadataFromNetwork' -Value 1 -ea SilentlyContinue</code></pre>
<p>Und man kann die Treiber vom Windows Update ausschließen:</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Set-ItemProperty -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate' -Name 'ExcludeWUDriversInQualityUpdate' -Value 1 -ea SilentlyContinue</code></pre>
<p>ToDo?</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Text</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-29596586307259687032023-08-06T20:25:00.013+02:002023-08-08T14:07:27.226+02:00nextcloud zu Hause - sicher mit nextcloudpi<p>
Wie der Name sagt, wurde <a href="https://nextcloudpi.com/" target="_blank">nextcloudpi</a> ursprünglich für den Raspberry Pi entwickelt und ist eine Art
Komplettlösung. Primär gibt es dafür ein Systemimage, ich habe das auf einem
Pi3 ausprobiert und kann sagen: das wird schnell langsam. Vielleicht geht es
auf einem Pi4, aber darunter (läuft ab Pi2) kann ich es nicht empfehlen.
</p>
<p>
Ich habe es auf einem Intel Celeron N5105 System mit 8 GB RAM installiert, da
finde ich es ganz brauchbar. Man kann später sehr viel bei nextcloud dazu
installieren - ich denke, da kann man jede beliebige Hardware ausreizen.
</p>
<p>
Mein Ziel ist eine eigene Cloud zu Hause, alle Bewohner können die Daten ihrer
Smartphones, vorhandene Bildarchive usw. darauf speichern und von unterwegs
will man natürlich mal ein paar Bilder zeigen oder auf Dokumente
zugreifen.<span></span>
</p>
<p>
Ich möchte die Setup Schritte hier notieren, da es viele Möglichkeiten zum
"abbiegen" gibt.<span></span>
</p>
<a name='more'></a>
<p></p>
<p>
Mit nextcloudpi (ncp) entstehen zwei Administrationsseiten: die nextcloudpi
(System) Administration und die nextcloud Administration.
</p>
<h3 style="text-align: left;">Linux System installieren</h3>
<p>
Für debian gibt es einen
<a href="https://help.nextcloud.com/t/curl-installer-debian" target="_blank">curl installer</a>. Da einige Produkte zusammen spielen müssen, wird nicht jede neue debian
Version gleich unterstützt. Aktuell (Juli 2023) wird Bookworm noch nicht
unterstützt.
</p>
<p>
Ich starte das Systemsetup von einer debian-11.6.0-amd64-netinst.iso, geladen
von
<a href="https://cdimage.debian.org/mirror/cdimage/archive/" target="_blank">hier</a>. Welchen Computernamen man vergibt ist zweitrangig, der curlinstaller
benennt ihn später in nextcloudpi um. Ansonsten muss man beim debian Setup
nichts besonderes beachten, am Ende deaktiviere ich die beiden Desktop Punkte
und aktiviere den SSH Server für das weitere headless Setup.
</p>
<p>Der curl installer benötigt curl, das muss nachinstalliert werden.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt install curl</code></pre>
<p>
Danach startet man das Installationsskript und holt sich ein Getränk zur
Entspannung.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">curl -sSL https://raw.githubusercontent.com/nextcloud/nextcloudpi/master/install.sh | sudo bash</code></pre>
<p>
Am Ende des Setups werden Informationen und die weiteren Schritte ausgegeben,
die führt man einfach aus. Im Browserfenster notiert man sich die User Konten
(drucken / pdf ) und drückt abschließend den Knopf activate. Damit erfolgt die
Weiterleitung auf die NCP Administrationsseite.
</p>
<p>
Auf dieser Seite läuft man in ein SSL-Zertifikat Problem: der Browser meckert.
Das muss man an der Stelle ignorieren und die vielen Warnungen quittieren. Auf
der Administrationsseite muss man mit der Warnung wohl leben müssen, ich habe
zumindest keinen anderen Weg gefunden. Man müsste eventuell das Zertifikat
komplizierter gestalten.
</p>
<p>
Der Zugriff über einen Namen funktioniert bei mir auch nicht, apache2 ist so
konfiguriert, dass nur private IPv4's, localhost oder domain local
funktionieren.
</p>
<h3 style="text-align: left;">Zugang für nextcloud App</h3>
<p>
Für den nextcloud User Zugriff braucht man unbedingt ein gültiges Zertifikat!
Die Einrichtung braucht es drei Schritte:
</p>
<p></p>
<ol style="text-align: left;">
<li>ein (dynamischer) DNS Eintrag, </li>
<li>Konfiguration im Router und </li>
<li>ein Zertifikat von Let's Encrypt.</li>
</ol>
<p></p>
<h4 style="text-align: left;">dynDNS</h4>
<p>
Ich will nur einen IPv6 Eintrag - da bin ich nur mit dem Anbieter von
<a href="https://www.cloudns.net/">cloudns.net</a> klar gekommen. Da bekommt
man ne ganze Menge für kein Geld. Man registriert sich, richtet eine DNS Zone
ein z.B. name.cloudns.cl, erstellt einen AAAA Record z.B.
cloud.name.cloudns.cl mit der IPv6 Adresse der nextcloud Maschine und nach ein
paar Minuten sollte die Auflösung des Namens mit dem Online Tool <a href="https://toolbox.googleapps.com/apps/dig/#AAAA/" target="_blank">dig</a> funktionieren.
</p>
<h4 style="text-align: left;">Fritzbox Konfiguration</h4>
<p>Portfreigabe</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2uai4agGEpyQYeA2O2KTYh5GZ1J6rk32PkrjAhSCBtblQV0-LHUUVDj6ZWBmI5Uxcaw4HFHfEgsb1r9teUwe5UTm1i-YoyzHikXHvk8XxcQ4nSk4Tj_IizLPa01sJNHNR694RgsorNpxkWbdUMReOS92B2Rz4LKMqrytJQb7oZXO408JH61TAkDuxnusy/s1552/Screenshot%202023-08-06%20150217.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="800" data-original-width="1552" height="206" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2uai4agGEpyQYeA2O2KTYh5GZ1J6rk32PkrjAhSCBtblQV0-LHUUVDj6ZWBmI5Uxcaw4HFHfEgsb1r9teUwe5UTm1i-YoyzHikXHvk8XxcQ4nSk4Tj_IizLPa01sJNHNR694RgsorNpxkWbdUMReOS92B2Rz4LKMqrytJQb7oZXO408JH61TAkDuxnusy/w400-h206/Screenshot%202023-08-06%20150217.png" width="400" /></a>
</div>
<br />
<p>
In der Fritzbox findet man unter - Internet > Freigaben > Gerät für Freigaben hinzufügen - die richtige Stelle
zum Eintragen des Gerätes (oben auswählen) und hier richtet man (nur für IPv6
!) zwei Freigaben (unten neue Freigabe) für Port 443 (HTTPS Server auswählen)
und 80 (HTTP Server) ein.
</p><p>Bitte nicht komplett freigeben (Exposed Host)!</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUFa6m1MebN7mawnWL9B41K46rei8Jt47LCxnDB7UkjGuj8o20YPncEe7mqnF297_-RVGaWw4xLNGr6wH8zWNz5adNbINHdXX_zv7EoyaP1YJu5KpYjm77xrkAt68NrEaqAIS_-WtqJe8kjgnr8PK2QGzEHC5gKQKfS66vq-3obYK16Rrg635U-zOxuN5d/s558/Screenshot%202023-08-06%20150506.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="548" data-original-width="558" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUFa6m1MebN7mawnWL9B41K46rei8Jt47LCxnDB7UkjGuj8o20YPncEe7mqnF297_-RVGaWw4xLNGr6wH8zWNz5adNbINHdXX_zv7EoyaP1YJu5KpYjm77xrkAt68NrEaqAIS_-WtqJe8kjgnr8PK2QGzEHC5gKQKfS66vq-3obYK16Rrg635U-zOxuN5d/s320/Screenshot%202023-08-06%20150506.png" width="320" /></a>
</div>
<br />
<p>Port 80 wird für die automatische Erneuerung des Zertifikates benötigt.</p>
<p>Rebindschutz </p>
<p>
Damit die Auflösung der IPv6 Adresse auch intern funktioniert, muss man im
Menüpunkt Heimnetz > Netzwerk > Netzwerkeinstellungen noch den dynDNS
Namen eintragen. Hat man dies vergessen, gibt es zwei Fehlerbilder:</p><p></p><ol style="text-align: left;"><li>Intern funktioniert der Link auf die dynDNS Adresse nicht.</li><li>Extern kommt beim Zugriff den Fehler "Zugriff über nicht vertraute Domain". Diesen Fehler kann man zwar im ncp Admin im Punkt trusted domain beheben. Der Fehler kommt aber ursächlich weil der nextcloud Host diese Adresse selbst nicht auflösen konnte. </li></ol><p></p>
<p>DNS Abfrage testen</p>
<p>
Jetzt muss man unbedingt die lokale DNS Auflösung an seinem PC im lokalen Netzwerk mit nslookup, host oder ping
-6 testen. Nach meiner Erfahrung funktioniert es mit DIG ziemlich schnell,
lokal kann die Fritzbox und der DNS Cache die Sache etwas kompliziert
gestalten, deshalb: einfach ruhig bleiben und etwas (~ 30 min ) warten!
</p>
<h4 style="text-align: left;">Zertifikat</h4>
<p>Die ncp Admin Oberfläche ist entweder über den Browser <span style="font-family: courier;">https://<IPv4>:4443</span> oder über Terminal (ssh) mit <span style="font-family: courier;">sudo ncp-config</span> erreichbar.</p><p>Die Einstellung für das Zertifikat findet man im
Abschnitt NETWORKING im Punkt letsencrypt.
</p>
<p>
Hier setzt man den Haken bei Active, trägt man den DNS Namen und seine
Emailadresse ein - nach einem Apply sollte die Zertifikatsausstellung und
-übernahme fehlerfrei laufen.
</p>
<p>
Der Zugriff und die Anmeldung mit dem nextcloud user sollte jetzt mit der url
ohne Fehler möglich sein z.B: https://cloud.name.cloudns.cl
</p>
<h4 style="text-align: left;">Erste Anmeldung an der eigenen Cloud</h4>
<p>
Das Nextcloud Administrationsmenü findet man durch klick auf das runde Status
Icon des Benutzers ganz rechts oben in der Ecke.
</p>
<p>
Der ncp User, mit dem wir jetzt angemeldet sind, ist der primäre nextcloud
Administrator (Administration settings, + Apps, Users).
</p>
<p>
Als erste Maßnahme sollte man sich einen normalen Arbeits Hauptbenutzer als
Admin anlegen (klick oben rechts auf den Benutzerstatus > Benutzer) und der
ncp User wird nur noch im Notfall verwendet.
</p>
<p>
Für jedes weitere Familienmitglied wird ein normaler Benutzer ohne Admin
Berechtigung angelegt. Jeder Benutzer ist Herr über seine Daten, der Admin
darf die nextcloud verwalten z.B. zusätzlich Apps installieren usw.
</p>
<h3 style="text-align: left;">Smartphone Anbindung</h3>
<p>
Auf dem Smartphone installiert man die nextcloud App aus dem App Store.
</p>
<p>
Man könnte sich manuell anmelden, einfacher geht es mit QR Code. Den erzeugt
man: Klick oben rechts auf den User > Persönliche Einstellungen >
Sicherheit > ganz unten kann man einen (beliebigen) App-Namen
eintragen und ein Passwort dafür erstellen. Nach der Bestätigung des
eigenen Passwortes wird eine Schaltfläche für den QR Code gezeigt. Den Scannt
man in der App einfach ein und ist verbunden.
</p>
<p>
In der App gibt es oben ein 3 Strich Menü > Einstellungen > Mehr - hier
konfiguriert man Automatisches Hochladen (z.B. Bilder Ordner) und Kontakte
& Kalender Sicherung.
</p>
<p>
Einen Zugriff auf installierte Apps in der nextcloud erhält man über die
Suchleiste ganz oben (was ich erstmal komisch finde).
</p>
<h3 style="text-align: left;">Nacharbeit im System</h3>
<p>dynDNS automatisieren</p>
<p>
Nach der Grund Einrichtung des DNS Eintrages bei cloudns.net ist die
dynamische Aktualisierung noch nicht aktiv!
</p>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPQ1BItO6321qlGYQJw4fyn6fxXZtVXJHHibQy_tdf43IMlzfpO3Pm_1rJgBT2j-45XqRljgsMH5pORobP2o8qOjaY2quaKahCvYpd0j28Pp1SeRTXwWeWq7MXQvgT-wfR959vtJd8VJ1FTtZPlrbBGYpG3kLrNFJDOAPR7UJrlGcPKHiH607uZsqwOw1E/s476/Screenshot%202023-08-06%20145802.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="223" data-original-width="476" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPQ1BItO6321qlGYQJw4fyn6fxXZtVXJHHibQy_tdf43IMlzfpO3Pm_1rJgBT2j-45XqRljgsMH5pORobP2o8qOjaY2quaKahCvYpd0j28Pp1SeRTXwWeWq7MXQvgT-wfR959vtJd8VJ1FTtZPlrbBGYpG3kLrNFJDOAPR7UJrlGcPKHiH607uZsqwOw1E/s320/Screenshot%202023-08-06%20145802.png" width="320" /></a>
</div>
<br />
<p><br /></p>
<p>
Durch einen klick auf die beiden Pfeile an der rechten Seite kann man diese
Aktivieren, es öffnet sich eine Box mit Rückfrage und nach quittierung bekommt
man mehrere Vorschläge wie man vorgehen kann. Ich kopiere die wget Zeile und
verwende einfach einen cronjob.
</p>
<p>Mit crontab -e editiert /erzeugt man den cronjob für den angemeldeten User:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">crontab -e</code></pre>
<p>
Man ergänzt die wget Zeile wie hier im Beispiel (Anfang und Ende), um alle 5
minuten den Eintrag zu aktualisieren und die Ausgabe nicht ins Systemlog
sondern ins nulldevice zu lenken!
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">*/5 * * * * wget -qO /dev/null --read-timeout=0.0 --waitretry=5 --tries=400 --background https://ipv6.cloudns.net/api/dynamicURL/?q=Token > /dev/null</code></pre>
<p>Dieser cronjob benötigt keine besonderen Rechte, man kann mit sudo crontab -e auch einen Job für User root anlegen.</p>
<h3 style="text-align: left;">Nacharbeiten in der nextcloud</h3>
<p>Meldungen in der Verwaltung > Übersicht beseitigen. Bei mir gab es zwei Meldungen, die zwei Aktionen auf Systemebene erfordern.</p>
<p>Telefonregion eintragen</p><p>Die config.php besteht aus einem mehrzeiligen $CONFIG = array (); - dort muss an beliebiger Stelle der Wert <span style="font-family: courier; font-size: x-small;">'default_phone_region' => 'DE',</span> ergänzt werden. Kann man per Hand editieren oder mit einer Zeile Script erledigen:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo sed -i "s/);/ 'default_phone_region' => 'DE',\n);/" /var/www/nextcloud/config/config.php</code></pre>
<p>imageick installieren (php8.1 - Stand nextcloud 27 August 2023)</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt install php8.1-imagick libmagickcore-6.q16-6-extra</code></pre>
<h3 style="text-align: left;">Was dann sonst noch so ist</h3>
<p>Mailfunktion der nextcloud einrichten - postfix konfigurieren. </p>
<p>
Dazu muss in der config Datei eine Zeile editiert und ein paar Zeilen ergänzt
werden. Ich habe dazu ein paar Zeilen Code bereitgestellt. Danach dient der
postfix lediglich als SMTP Sender. Alternativ lässt man den postfix außen vor
und konfiguriert den SMTP Server in den nextcloud Einstellungen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.orig
sudo sed -i "s/^relayhost = /relayhost = smtp.provider.de:587/" /etc/postfix/main.cf
sudo tee -a /etc/postfix/main.cf <<EOF
# Enable auth
smtp_sasl_auth_enable = yes
# Set username and password
smtp_sasl_password_maps = static:user@domain.com:password
smtp_sasl_security_options = noanonymous
EOF
sudo postfix reload</code></pre>
<p>Hinweis: Ich habe hier den Benutzer Account direkt in die main.cf geschrieben. Es ist eventuell besser die vorgeschlagene Variante mit separater Passwortdatei zu verwenden - <a href="https://www.postfix.org/SASL_README.html#client_sasl_enable" target="_blank">siehe hier</a>.</p><p>Anmerkung: Um Systemnachrichten zu erhalten, müsste man noch die virtual / generic Tabelle erstellen. Wenn man das nicht macht bleibt man von vorn herein von den vielen Cronjob Meldungen verschont.</p><p>Eine detaillierte Beschreibung habe ich <a href="https://www.andysblog.de/nextcloudpi-e-mail-konfigurieren" target="_blank">hier</a> gefunden.</p><p>SSD nachrüsten</p>
<p>
Der im Minipc eingebaute eMMC Speicher ist quasi eine nicht auswechselbare SD
Card. Die Lebensdauer wird durch häufige Schreibvorgänge begrenzt. Deswegen
verlagert man alle unnötigen Schreibvorgänge auf eine SSD (HDD). USB Speicher
werden von ncp direkt behandelt, die SSD an der internen SATA Schnittstelle
müssen wir manuell einrichten.
<a href="https://intux.de/2019/02/19/ssd-in-nextcloud-auf-dem-raspberry-pi-einbinden/" target="_blank">Hier</a> gibt es eine bebilderte Erklärung dazu. Die erste interne SSD wird mit
/dev/sda abgebildet (lsblk zum prüfen). Drei Schritte sind notwendig, die ich
hier wieder in Scriptform zeige, wer sicher gehen will macht einzelnen Befehle
lieber "zu Fuß"
</p>
<p></p>
<ol style="text-align: left;">
<li>Partition erzeugen, die gesamte SSD eine Partition.</li>
<li>Dateisystem ext4 erzeugen.</li>
<li>Die SSD dauerhaft einbinden (mounten). </li>
</ol>
<p></p>
<p>Dieses Here Doc sendet Befehle an fdisk, die man auch manuell eingeben kann. </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">disk=sda
# partition erzeugen
sudo fdisk /dev/${disk} <<EOF
n
p
1
w
EOF
# filesystem erzeugen
sudo mkfs.ext4 /dev/${disk}1<br /># mounten
sudo mkdir -p /mnt/${disk}1<br />sudo mount /dev/${disk}1 /mnt/${disk}1<br /># dauerhaft in fstab einbinden
echo "$(sudo blkid | awk '$1=="/dev/${disk}1:" {print $2}') /mnt/${disk}1 ext4 defaults 0 0"|sudo tee -a /etc/fstab</code></pre>
<p><br /></p><p>Die konfigurierte SSD in ncp verwenden</p>
<p>Daten verschieben </p>
<p>
Pfad anlegen dann in der ncp Admin Oberfläche CONFIG > Datenverzeichnis den
neuen Pfad eintragen und aktivieren.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo mkdir -p /mnt/${disk}1/ncdata</code></pre>
<p>Datenbank verlagern</p><p>Pfad anlegen dann in der ncp Admin Oberfläche CONFIG > Datenbank den neuen Pfad eintragen und aktivieren.</p><pre class="language-bash"><code contenteditable="" spellcheck="false">sudo mkdir -p /mnt/${disk}1/ncdatabase</code></pre><p>Swap Datei verlagern</p><p>Bei mir war keine Swap Datei angelegt, keine Änderung notwendig? Prüfung mit </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo swapon --show</code></pre>
<p>Dies und das</p><p>Bei einer geplanten Wartung (Umbau, Stromausfall usw.) sollte man nicht einfach den Stecker ziehen! Ein Shutdown / Restart geht über die ncp Admin Webseite: Oben Rechts ist ein Schalter, nach dem Klick hat man die Wahl zwischen Shutdown oder Reboot. Shutdown bedeutet hier aber nicht PowerOff, dazu muss man ssh bemühen.</p><h3 style="text-align: left;">Hab ich alles richtig gemacht? </h3><p>Man kann von jedem Linux PC die offenen Ports testen:</p><pre class="language-bash"><code contenteditable="" spellcheck="false">nc -w 1 -zv cloud.name.cloudns.nz http https 22 25 4443 7867 2>&1 | grep succeeded</code></pre><p>Ein paar Online Security Scanner </p><p></p><ul style="text-align: left;"><li><a href="https://scan.nextcloud.com/">https://scan.nextcloud.com/</a></li><li><a href="https://mxtoolbox.com/">https://mxtoolbox.com/</a></li><li><a href="https://www.experte.de/security-check">https://www.experte.de/security-check</a></li><li><a href="https://www.ssllabs.com/ssltest/">https://www.ssllabs.com/ssltest/</a></li></ul><p></p><p><br /></p>
<p>ToDo ?</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p><br /></p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com2tag:blogger.com,1999:blog-5611886937451692837.post-4759125453945800132023-08-04T17:28:00.001+02:002023-12-06T11:03:36.132+01:00Remote Cloud - die Cloud direkt in Linux mounten<p>
Wenn man die Suche bemüht findet man primär jede Menge Tools, meist speziell
ein Tool für eine Cloud. Die Technologien sind bei jedem Anbieter ein wenig
anders. Die Technologie ändert sich von Zeit zu Zeit, so sind viele Tools nach
kurzer Zeit veraltet.
</p>
<p>
Es gibt aber ein gut gepflegtes Tool, das erledigt diesen Job für so ziemlich
alle Cloud Anbieter:
<a href="https://rclone.org/" target="_blank">rclone <span></span></a>
</p>
<a name='more'></a>
<p></p>
<h3 style="text-align: left;">Setup</h3>
<p>
Ich habe die Scriptinstallation von
<a href="https://rclone.org/install/" target="_blank">hier </a>gewählt, damit
erhält man die aktuellste Version.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo -v ; curl https://rclone.org/install.sh | sudo bash</code></pre>
<p>
Damit der mount Befehl später ohne Fehler funktioniert, musste ich noch fuse3
nach installieren.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt install fuse3</code></pre>
<p><br /></p>
<h3 style="text-align: left;">Konfiguration</h3>
<p>
Die config datei wird mit rclone in einem interaktiven setup erzeugt. Die
Konfiguration kann man immer wieder durchlaufen und die Datei damit ergänzen.
Bei Google Drive und Onedrive sind dabei weitere Schritte in einem Browser
notwendig. Man ist gut beraten, die Konfiguration auf einem Linux Desktop
System vorzunehmen und diese später auf das Zielsystem zu übertragen. Mit
einigen Tricks kann man auch einen Remote Browser nutzen siehe z.B:
<a href="https://blog.nerdingham.de/2019/03/10/onedrive-auf-linux-server-als-speicherplatz-einbinden/" target="_blank">hier</a>.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">rclone config</code></pre>
<p>
Dabei entsteht eine Datei .config/rclone/rclone.conf im aktuellen user
Verzeichnis. Um alles zu testen kann man schnell mal den Zugriff testen
(config Beispiel
<a href="https://rclone.org/googlephotos/" target="_blank">Google Photos</a>):
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">rclone ls gphoto:media
rclone lsd gphoto:</code></pre>
<p>rclone ist ein umfangreiches Tool und kann ähnlich wie rsync auch zum kopieren / synchronisieren von Strukturen verwendetet werden.</p>
<p>
Will man später die Konfiguration mit einem anderen User verwenden, z.B. die
Cloud als root beim Systemstart einbinden, muss man diese nach kompletter
Konfiguration kopieren und dem rclone Aufruf mitgeben.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo cp .config/rclone/rclone.conf /etc/</code></pre>
<p>
Achtung: in dieser Datei befinden sich sensible Zugangsdaten für die Cloud!
Bitte auf Sicherheit achten!
</p>
<p>
Will man später das mounten mit der option --allow-other zulassen, muss
man das vorbereiten. Durch den sed Befehl wird das Kommentarzeichen entfernt.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo sed -i 's/^#user_allow_other/user_allow_other/' /etc/fuse.conf</code></pre>
<p><br /></p>
<h3 style="text-align: left;">Cloud mounten</h3>
<p>
Jetzt kann man den Zugriff auf die Cloud einmal testen. Das Verzeichnis für
den mount muss existieren und leer sein! Beispiel für onedrive, da ich faul
bin habe ich den Namen in eine Variable geschrieben. Dieser Code setzt voraus,
dass der config Abschnitt und der Pfad gleich heißen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">cloud=onedrive
mkdir /mnt/${cloud}
rclone mount ${cloud}: /mnt/${cloud}</code></pre>
<p>
Um die Cloud beim Systemstart einzubinden, kann man einen "Parameter" Service
erzeugen.
</p>
<p>
Ich mache das gerne als Heredoc und bemühe den systemd editor. Der erledigt am
Ende nämlich daemon-reload. Diesen Block kann man also komplett kopieren und
in das Terminal fallen lassen. Er erzeugt die notwendige unit Datei am
richtigen Ort.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">cat <<EOISERV |sudo SYSTEMD_EDITOR=tee systemctl edit --full --force rclone-mount@.service
[Unit]
# Idee von hier https://gist.github.com/gmag11
Description=rclone FUSE mount for %i
Documentation=http://rclone.org/docs/
After=network-online.target
# externo.mount # This is only needed if you use an external USB hard drive in order to wait for it to be mounted
# Mount point in my system is on a USB drive, don't ask why :))), that's why I have to wait for it to get mounted
# Requires=externo.mount
[Service]
Type=notify
# --vfs-cache-mode full activates cache for writting and reading. Check RClone documentation
ExecStart=/usr/bin/rclone mount %i: /mnt/%i --config=/etc/rclone.conf --vfs-cache-mode full -v --allow-other
ExecStop=/bin/fusermount -uz /mnt/%i
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOISERV</code></pre>
<p>
Jetzt kann man die Dienste ausprobieren und aktivieren. Hat man mehrere geht
das in einer kurzen Schleife:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">array=( onedrive gdrive gphoto )
cmd=start # start, enable, disable usw.
for drive in ${array[*]} ; do
sudo systemctl ${cmd} rclone-mount@${drive}.service
done</code></pre>
<p><br /></p>
<h3 style="text-align: left;">ToDo ?</h3>
<div><br /></div>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p><br /></p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-70065080021041314882023-05-02T16:22:00.009+02:002023-08-28T16:45:29.918+02:00HowTo - live backup und restore einer virtuellen Maschine mit libvirt<h2 style="text-align: left;">Einleitung</h2>
<p>
Das Management User Interface <a href="https://www.libvirt.org/docs.html" target="_blank">libvirt</a> steuert <a href="https://www.qemu.org/" target="_blank">QEMU</a>
welches auf
<a href="https://www.linux-kvm.org/page/Main_Page" target="_blank">KVM</a>
aufsetzt. Die Basis für dieses Backup/Restore bildet
<a href="https://qemu.readthedocs.io/en/latest/interop/live-block-operations.html" target="_blank">die Verkettung von Diskimages</a>.
</p>
<p>
Da
<a href="https://libvirt.org/kbase/live_full_disk_backup.html" target="_blank">hier</a>
und in der restlichen
<a href="https://www.libvirt.org/manpages/virsh.html" target="_blank">Dokumentation</a> nichts über ein restore zu finden ist und das backup bekanntlich erst
nach einem restore erfolgreich sein kann - habe ich ein kurzes HowTo
geschrieben. Das ist noch nicht perfekt! </p><p>Bitte am Ende den Abschnitt ToDo beachten!<span></span>
</p>
<p>
Wem das zu sehr ins Detail geht, es gibt auf GitHub auch
<a href="https://github.com/abbbi/virtnbdbackup/tree/master" target="_blank">ein installierbares Tool</a>
welches die API von libvirt nutzt.
</p>
<a name='more'></a>
<p></p>
<h2 style="text-align: left;">Vorbereitung</h2>
<p></p>
<ol style="text-align: left;">
<li>
Der qemu-guest-agent muss im Gast System installiert werden, damit beim
Backup das Filesystem im Gast kurz angehalten werden kann.
</li>
<li>
Um die Befehle universell zu halten habe ich ein paar Variablen definiert.
</li>
<li>
Zur Steuerung des Backup sind ein paar XML Dateien notwendig, die werden mit
einem kurzen Script erzeugt. (siehe weiter unten im Artikel)
</li>
</ol>
<p></p>
<p>Eine offline Sicherung (virsh shutdown ...) kann man durch Kopie des
Diskimages machen, z.B erste Disk von win2k22 nach ./backup kopieren:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo cp $(virsh domblklist win2k22|awk 'NR >2 && NR < 4 {print $2}') ./backup/ </code></pre>
<p>Das im weiteren beschriebene Verfahren funktioniert nur bei laufender VM. </p><div>Die folgenden Variablen werden in allen folgenden Befehlsfolgen als Grundlage
benötigt! Der Pfad zum backup Verzeichnis muss absolut sein!
</div>
<pre class="language-bash" style="text-align: left;"><code contenteditable="" spellcheck="false">export vm=ubuntu22.04
export path2backup=/backup # mkdir -p $path2backup
export cpname=FirstCheckPoint
export dev=$(virsh domblklist ${vm}|awk 'NR >2 && NR < 4 {print $1}')
export disk=$(virsh domblklist ${vm}|awk -F\/ 'NR >2 && NR < 4 {print $NF}')
bash createxml.sh
</code></pre>
<h2 style="text-align: left;">Full Backup</h2>
<p>
Mit zwei Befehlszeilen sichert man die Definition und erzeugt eine Kopie des
Diskimages.
</p>
<p></p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">virsh dumpxml ${vm} >${path2backup}/${vm}.xml
virsh backup-begin ${vm} b-${vm}.xml</code></pre>
<p>
Ein restore ist ziemlich simpel, man holt das Diskimage aus dem backup,
definiert die Maschine neu und startet wieder.
</p>
<pre class="language-markup" style="text-align: left;"><code contenteditable="" spellcheck="false">sudo cp $(awk -F\' '/target file/{print $2}' b-${vm}.xml) /var/lib/libvirt/images/${disk}
virsh define ${path2backup}/${vm}.xml
virsh start ${vm}
</code></pre>
<h2 style="text-align: left;">Differential Backup</h2>
<p>
Man setzt den Startpunkt für die "Differenz" mit einem Fullbackup und einem
Checkpoint.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">virsh backup-begin ${vm} b-${vm}.xml c-${vm}.xml </code></pre>
<p>
Im weiteren Verlauf wird dann jedes mal der Unterschied zum Checkpoint
gesichert.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">virsh backup-begin ${vm} i-${vm}.xml</code></pre>
<p>
Für ein Restore muss das Fullbackup und die letzte Differenz aus dem Backup
geholt werden. Die gesicherte Definition wird modifiziert, so das eine Disk
Image Kette erzeugt wird. Gestartet wird die Virtuelle Maschine vom Overlay.
Nach erfolgreichem Start kann das Overlay mit dem Backing Image wieder
verschmolzen werden.
</p>
<pre class="language-bash" style="text-align: left;"><code contenteditable="" spellcheck="false">sudo cp $(awk -F\' '/target file/{print $2}' b-${vm}.xml) /var/lib/libvirt/images/${disk}
sudo cp $(awk -F\' '/target file/{print $2}' i-${vm}.xml) /var/lib/libvirt/images/
virsh define ${path2backup}/${vm}.xml
virsh update-device ${vm} d-${vm}.xml
virsh start ${vm}
virsh blockcommit ${vm} ${dev} --active --verbose --pivot
</code></pre>
<h3 style="text-align: left;">Dies und das</h3>
<p>
Für den Test muss man die VM nicht zerstören, ein shutdown vor dem Restore
reicht.
</p>
<p>
Der Befehl backup-begin endet sofort und der Prozess läuft im Hintergrund. Um
diesen abzufragen beziehungsweise in einem Script darauf zu warten, gibt es
folgende Befehle:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">virsh domjobinfo ${vm} --completed
virsh event ${vm} job-completed </code></pre>
<p>
Will man eine VM mit einem Checkpoint entfernen, sollte man zuerst den
Checkpoint entfernen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">virsh checkpoint-list ${vm}
virsh checkpoint-delete ${vm} ${cpname}
virsh shutdown ${vm} # oder virsh destroy ${vm}
virsh undefine ${vm}</code></pre>
<p>
Will man bei backup-begin die Dateien immer wieder überschreiben, muss man
einen zusätzlichen Parameter verwenden: --reuse-external
</p>
<p>Man kann das Backup noch packen und mit einem Zeitstempel versehen. </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">target=$(awk -F\' '/target file/{print $2}' b-${vm}.xml)
gzip -c ${target} > ${target}-$(date "+%F-%s").gz</code></pre>
<h3 style="text-align: left;">Script</h3>
<p>Der Inhalt der Script Datei createxml.sh</p>
<pre class="language-xml"><code contenteditable="" spellcheck="false">cat <<EOI > b-${vm}.xml
<domainbackup>
<disks>
<disk name='${dev}' type='file'>
<driver type='qcow2'/>
<target file='${path2backup}/${disk}.backup'/>
</disk>
#<disk name='sda' backup='no'/>
</disks>
</domainbackup>
EOI
cat <<EOI > i-${vm}.xml
<domainbackup>
<incremental>${cpname}</incremental>
<disks>
<disk name='${dev}' type='file'>
<driver type='qcow2'/>
<target file='${path2backup}/${disk}.backup.inc'/>
</disk>
#<disk name='sda' backup='no'/>
</disks>
</domainbackup>
EOI
cat <<EOI > c-${vm}.xml
<domaincheckpoint>
<name>${cpname}</name>
<description>Completion of updates after OS install</description>
<disks>
<disk name='${dev}' checkpoint='bitmap'/>
#<disk name='sda' checkpoint='no'/>
</disks>
</domaincheckpoint>
EOI
cat <<EOI > d-${vm}.xml
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' discard='unmap'/>
<source file='/var/lib/libvirt/images/${disk}.backup.inc' index='2'/>
<backingStore type='file'>
<format type='qcow2'/>
<source file='/var/lib/libvirt/images/${disk}'/>
</backingStore>
<target dev='vda' bus='virtio'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
</disk>
EOI
</code></pre>
<p>ToDo</p>
<p>
Das Ganze ist noch nicht komplett und funktioniert so nur für virtio
Festplatten (vda).
</p>
<pre class="language-markup"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>text</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-36609674486369767342023-01-26T11:19:00.006+01:002023-05-14T12:59:18.470+02:00Raspberry konservieren<p>
Es gibt verschiedene Überlegungen warum man einen Raspberry mit
"Schreibschutz" ausstatten sollte. Meine war: Hat man Geräte im Einsatz die
eventuell rau behandelt werden und eigentlich keine Daten produzieren, kann
man doch auch jeden Schreibvorgang verhindern.
</p>
<p>
Geht das überhaupt und ist das auch für den Administrator
praxistauglich ? Das Raspberry OS hat sogar (fast) alles vorbereitet:
Stichwort Overlay Filesystem.
</p>
<p><span></span></p>
<a name='more'></a>
<p></p>
<p>
Das Overlay Filesystem bildet zwei Ebenen und präsentiert diese dem System als
eine. Im Unteren liegen die Dateien der SD Card, diese ist read only
eingebunden. Im Oberen ist ein Filesystem im RAM eingebunden. Das System weiß
von alledem nichts und kann in die RAM Disk schreiben. Das hat natürlich seine
Grenzen, vor allem beim ersten Pi, mit nur 500 MB RAM. Nach einem Neustart ist
alles verschwunden, was in die RAM Disk geschrieben wurde.
</p>
<p>
In die Bootpartition wird normalerweise nicht geschrieben. Man kann die
Möglichkeit aber ganz verhindern, indem man diese Partition von vornherein nur
readonly einbindet.
</p>
<p>
Beides kann man mit raspi-config Menügeführt konfigurieren, Punkte: 4 , P3 .
Ich mage das gern auch einfach nur mit der Kommandozeile, auch dafür haben die
Entwickler gesorgt.
</p>
<p>
Die Installation und Konfiguration des Systems muss komplett abgeschlossen
sein. Als letzten Schritt richtet man das OverlayFS und den Schreibschutz ein!
</p>
<h2 style="text-align: left;">Schreibschutz mit OverlayFS aktivieren</h2>
<p>
Damit der RAM nicht zu schnell mit Dateien gefüllt wird, muss man noch etwas
optimieren. Hier können je nach System weitere Schritte notwendig sein!
</p>
<h3 style="text-align: left;">1. Swap ausschalten</h3>
<p>
Die selbsterklärenden Befehle fragen den Zustand ab und final wird swap
komplett deaktiviert.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">swapon -s
swapoff -a
sudo systemctl stop dphys-swapfile
free
sudo systemctl disable dphys-swapfile</code></pre>
<h3 style="text-align: left;">2. Logging verringern</h3>
<p>
Ich habe mit systemd timern gearbeitet und festgestellt, das danach jeder
Zeittrigger 3 nichtssagende Einträge im syslog erzeugt. Die habe ich
abgeschaltet (sollte man immer tun!)
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo sed -i 's/^#LogLevel=.*/LogLevel=notice/' /etc/systemd/system.conf
sudo systemctl daemon-reexec</code></pre>
<h3 style="text-align: left;">3. OverlayFS aktivieren und readonly setzen</h3>
<p>
Zunächst kann man sich noch schnell einen "optischen" Eindruck vom Filesystem
auf der SD Card machen.
</p>
<p>
Zur "Konservierung" benutze ich die vorhandenen Scripts im raspi-config. Der
erste Befehl dauert etwas!
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">df -h
sudo raspi-config nonint enable_overlayfs
sudo raspi-config nonint enable_bootro
sudo reboot</code></pre>
<p>
Nach dem Neustart zunächst wieder ein kurzer Blick auf die veränderte "Optik".
Danach ein Test zum Verhalten. Der Befehl schreibt eine neue Datei im User
Homedir und versucht das Gleiche in der Boot Partition. Die Datei im Homedir
kann man sich mit ls anzeigen lassen, die Datei im /boot/ Directory muss einen
Fehler werfen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">df -h
echo "Test Text"|tee overlay.txt |sudo tee /boot/readonly.txt</code></pre>
<p>
Macht man jetzt noch einen Neustart, sollte die Datei im Homedir wieder
verschwunden sein.
</p>
<h2 style="text-align: left;">Wartungsarbeiten</h2>
<p>
Vor jeder Änderung oder System Aktualisierung muss man den "Schreibschutz"
entfernen. Dies erfordert leider auch einen Neustart! Mit dem Scriptbefehl
geht es aber recht schnell.
</p>
<h3 style="text-align: left;">1. Wartung vorbereiten</h3>
<p>OverlayFS wieder deaktivieren:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo raspi-config nonint disable_overlayfs
sudo reboot</code></pre>
<p>
Nach dem Neustart kann man wieder normal ins rootfs schreiben, die
Bootpartition ist aber immer noch readonly eingebunden, die fstab kann im
vorherigen Schritt nicht geschrieben werden. Hier kommt der echte Vorteil
gegenüber raspi-config "interaktiv" - da müsste man jetzt nochmal neustarten.
Es geht aber temporär auch ohne Neustart, optional mit Test. Vor einem apt
full-upgrade empfiehlt sich dieser Schritt, da unter Umständen Dateien in der
Bootpartition ausgetauscht werden.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo mount -o remount,rw /boot
echo "Test Text"|tee overlay.txt |sudo tee /boot/readwrite.txt</code></pre>
<h3 style="text-align: left;">2. Wartung abschließen</h3>
<p>
Die Wartung wird durch die Reaktivierung des OverlayFS und einen Neustart
abgeschlossen.</p><p>Ein Installation von Kernel Komponenten (z.B. apt full-upgrade) muss man vorher mit einem finalen reboot abschließen! </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo raspi-config nonint enable_overlayfs && sudo reboot</code></pre>
<h3 style="text-align: left;">Alles rückgängig machen</h3>
<p>
Will man OverlayFS und boot Schreibschutz entfernen, muss man zum vorherigen
Schritt 1 noch den Schreibschutz für boot dauerhaft entfernen. Einen extra
Neustart an der Stelle benötigt man nicht!
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo raspi-config nonint disable_bootro</code></pre>
<h2 style="text-align: left;">Laufender Betrieb</h2>
<p>
Im laufenden Betrieb wird, gerade bei wenig RAM, der Speicher schnell knapp werden.
Man muss das unbedingt überwachen und bei Bedarf einfach neu starten. Notfalls erstmal mit einem "wachen Auge".</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">df -h /
free </code></pre>
<p>ToDo</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>
Zum Lesen: <a href="https://github.com/RPi-Distro/raspi-config/blob/master/raspi-config" target="_blank">raspi-config Quelle</a>
</p>
<div><br /></div>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-42805521639825408882023-01-18T17:14:00.010+01:002024-03-24T22:36:31.656+01:00ssh Zugang für fhem über Script einrichten<p>
Ich mache einige Dinge aus dem Docker Container heraus über ssh auf dem Docker
Host, anstatt den Container zu sehr zu verbiegen. (<a href="https://heinz-otto.blogspot.com/2022/04/andocken-dinge-die-man-auerhalb-docker.html" target="_blank">Artikel andocken</a>).
</p>
<p>
Dafür habe ich mal ein Script gebastelt und ein paar Aufruf Varianten
ausgearbeitet. Damit sollte mit wenigen Handgriffen die Einrichtung des ssh
public key Zuganges innerhalb FHEM auf einen anderen Host gelingen.
</p>
<p>
<a href="#Script">Das Script</a> hat nur wenige Zeilen es werden beliebig
Hostnamen oder IP Adressen als Argumente übergeben.
</p>
<p></p>
<ol style="text-align: left;">
<li>
Die eventuell vorhandenen Einträge in known_host werden gelöscht und neu
eintragen.
</li>
<li>
Es wird überprüft ob bereits ein ssh Key vorhanden ist, falls nicht wird ein
Neuer erzeugt.
</li>
<li>
Der public key wird zur möglichen Weiterverarbeitung (in authorized_keys)
ausgegeben.
</li>
</ol>
<p></p>
<p>Ich zeige den Aufruf </p>
<p></p>
<ul style="text-align: left;">
<li>
als komplettes Here Doc, als lokales Script oder Script vom GitHub,
</li>
<li>als anderer User,</li>
<li>oder direkt im Docker Container.</li>
</ul>
<p></p>
<p>
Das eigentliche Ziel: der public key von User fhem auf dem HostA wird dem User
userB auf HostB gegeben damit User fhem sich als userB ohne Passworteingabe an
HostB anmelden / Befehle ausführen kann.
</p>
<p>
Man beachte in allen Beispielen die unterschiedliche Verwendung der Shell
Optionen -c und -s!<span></span>
</p>
<a name='more'></a>
<p></p>
<h3 style="text-align: left;">Erstmal nur zur Übung</h3>
<p>
Ich habe hier einige Varianten herausgegriffen die mir persönlich gefallen, es
gibt eine ungeheure Vielzahl anderer Varianten.
</p>
<p>
Das kurze Here Doc soll erst mal das Prinzip an Hand von einem Einzeiler
demonstrieren:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">bash <<'EOF' -s arg1 arg2
whoami ; for arg in $* ; do echo $arg; done
EOF</code></pre>
<p>Man kann es als andere User ausführen:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo -u fhem bash <<'EOF' -s arg1 arg2
whoami ; for arg in $* ; do echo $arg; done
EOF</code></pre>
<p>
Oder man kann es als ein bestimmter User in einem laufendem Container
ausführen:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker exec -iu fhem ContainerName bash <<'EOF' -s arg1 arg2
whoami ; for arg in $* ; do echo $arg; done
EOF</code></pre>
<p>
Ich habe mal das gleiche Script etwas strukturiert in eine Datei geschrieben
und am Ende zwei Aufrufe analog der Vorherigen als Beispiel angefügt.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">cat <<'EOF' >demo1.sh
whoami
for arg in $* ; do
echo $arg
done
EOF
sudo -u fhem bash demo1.sh arg1 arg2
docker exec -iu fhem ContainerName bash demo1.sh arg1 arg2</code></pre>
<p>
Beachte: Hier werden die Argumente nicht mehr mit der Option -s abgetrennt!
</p>
<p>
Tipp: man kann die Befehle auch manuell
in der Docker Shell ausführen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker exec -itu fhem ContainerName bash</code></pre>
<p>Um die folgenden Codezeilen übersichtlich zu halten, füge ich mal ein paar
Variablen ein. Der erste Befehl ist nützlich um die vorhandenen Containernamen
zu listen. Das Beispielscript habe ich für diesen Teil auf GitHub abgelegt.
Die Variable arguments soll die Hostnamen und/oder IP Adressen enthalten. Ich
habe dafür verschiedene Möglichkeiten ausprobiert, es gibt keine
Universallösung, je nach dem welches System und welche Komponenten installiert
sind. Am Ende habe ich noch ein paar Varianten aufgezeigt.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker ps --format '{{.Names}}'
script_name=https://raw.githubusercontent.com/heinz-otto/scripts/master/Bash/demo1.sh
container_name=dockerbuild-fhem-1
arguments="$(hostname) $(host -t A $(hostname) | awk '{ print $4 }')"</code></pre>
<p>
Man kann jetzt das Script vom Github holen und über stdin der Bash übergeben.
Hier ist zu beachten, dass der Scripttext mit der Option -c abgetrennt wird.
Die beiden letzten Zeilen sollen nur zeigen, wie man das Script lokal
speichern und den Namen aus dem kompletten Pfad extrahieren kann.
</p>
<pre class="language-bash" style="text-align: left;"><code contenteditable="" spellcheck="false">bash -c "$(wget -qO - ${script_name})" -s ${arguments}
docker exec -iu fhem ${container_name} bash -c "$(wget -qO - ${script_name})" -s ${arguments}
# oder erst lokal speichern
wget -O ${script_name##*/} ${script_name}
sudo -u fhem bash ${script_name##*/} ${arguments}
</code></pre>
<h2 style="text-align: left;">Script zur Einrichtung public key Zugang</h2>
<p>
Bisher war alles nur Übung jetzt zur eigentliche Aufgabenstellung: ssh Zugang
für anderen User einrichten.
</p>
<p>
Dem Script wird als Parameter eine Leerzeichen getrennte Liste von Hostnamen und / oder IP-Adressen
übergeben für die Einträge in der known_hosts Datei der FHEM Instanz erzeugt
bzw. bereinigt werden. Damit wird die Sicherheitsabfrage bei der ersten
Verbindung zum anderen anderen Host über ssh vermieden.
</p>
<p>Zunächst das komplette <a name="Script">Script</a> als Here Doc:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker exec -iu fhem dockerbuild-fhem-1 bash <<'EOF' -s odroidxu4 192.168.56.121
key_version=ed25519
for arg in $* ; do
yes '' | ssh-keygen -R ${arg}
ssh-keyscan -t ${key_version} ${arg} 2>/dev/null >> ~/.ssh/known_hosts
done
if ! ls ~/.ssh/id_${key_version}.pub >/dev/null; then
ssh-keygen -f ~/.ssh/id_${key_version} -P "" -t ${key_version}
else
echo "public key of type ${key_version} already in place"
fi
echo "echo $(cat ~/.ssh/id_${key_version}.pub) >>.ssh/authorized_keys"
EOF</code></pre>
<p>
Im Script kann man den Type des erzeugten private Keys einstellen - ed25519 -
sollte als Standard überall passen. Man könnte rsa verwenden, dieser ist aber
nur bei größeren Schlüssellängen wirklich sicher. Von der Verwendung von dsa
wird generell abgeraten.
</p>
<p>
Im Folgenden verwende ich das Script von
<a href="https://github.com/heinz-otto" target="_blank">meinem GitHub</a> und
ich habe die Variablennamen stark gekürzt, um die finale Codezeile kurz zu
halten.
</p>
<a name="DockerHost"><h3 style="text-align: left;">Ausführung auf dem Docker Host</h3></a>
<p>
Scenario: Man ist als der User angemeldet, mit dem aus dem Container auf dem
Docker Host Befehle über ssh ausgeführt werden sollen.
</p>
<p>
Der public key wird am Ende des Scripts ausgegeben, mit grep von den
Statusmeldungen abgetrennt und auf dem Docker Host gleich in die
authorized_keys Datei geschrieben.
</p>
<p>
Tipp: Die Codebox ist editierbar, einfach den Containernamen ändern: c=... den
kompletten Text kopieren (ctrl+a) und ins Terminal werfen - sollte passen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">s=https://raw.githubusercontent.com/heinz-otto/scripts/master/Bash/setupSsh2Host.sh
c=dockerbuild-fhem-1
a="$(hostname) $(host -t A $(hostname) | awk '{ print $4 }')"
docker exec -iu fhem ${c} bash -c "$(wget -qO - ${s})" -s ${a}|grep -Eo 'ssh-.* ' >> ~/.ssh/authorized_keys</code></pre>
<p>Will man den ssh Zugriff vom Container auf einen anderen Host im Netzwerk
einrichten, ruft man das Script ohne Umleitung der Ausgabe auf und verfährt
weiter wie im folgenden Abschnitt. </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">a=ComputerName oder und IP
docker exec -iu fhem ${c} bash -c "$(wget -qO - ${s})" -s ${a}</code></pre>
<h3 style="text-align: left;">Ausführung auf dem FHEM Server</h3>
<p>Scenario: </p>
<p></p>
<ul style="text-align: left;">
<li>Host A - FHEM Server, User fhem</li>
<li>Host B - Zugriff von Host A User fhem als User userB auf HostB</li>
<li>Host x - Zugriff von Host A User fhem als User userX auf HostX</li>
</ul>
<p></p>
<p>Man öffnet pro Host eine Terminalsitzung:</p>
<p>
Sitzung A als beliebiger sudo User auf dem FHEM Server, Sitzung B als userB
auf dem HostB und bei Bedarf weitere Sitzungen analog C als userC auf
dem HostC . Es folgen 2 Schritte:
</p>
<p></p>
<ol style="text-align: left;">
<li>
Man führt das Script in Sitzung A aus und kopiert die letzte Zeile "ssh-..."
in die Zwischenablage.
</li>
<li>In den anderen Sitzungen stellt man zunächst sicher, </li>
<ul>
<li>
dass man sich im Homedir des Benutzers befindet der für die ssh Verbindung
genutzt werden soll,
</li>
<li>dass der Pfad .ssh schon exisitiert (mkdir .ssh) </li>
<li>
und schreibt anschließend den kopierten Key in die Datei
.ssh/authorized_keys - entweder mit einem passenden Editor oder einfach
mit echo <key> >>.ssh/authorized_keys .
</li>
</ul>
</ol>
<div>Hier das Beispiel mit der direkten Ausführung des Scripts vom github:</div>
<p></p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">s=https://raw.githubusercontent.com/heinz-otto/scripts/master/Bash/setupSsh2Host.sh
a="HostB IP-HostB HostX"
sudo -u fhem bash -c "$(wget -qO - ${s})" -s ${a}</code></pre>
<p>
In der Browser GUI von FHEM kann man sich sofort mit folgendem Befehl vom
Erfolg überzeugen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">{qx 'ssh userB@HostB echo vom HostB' }</code></pre>
<p>
Es sollte die Textkette zurück kommen, ansonsten muss man im Log schauen was
schief gelaufen sein könnte.
</p>
<h3 style="text-align: left;">Beispiel um Hostname oder IP zu ermitteln</h3>
<p>
Für die Argumente kann man entweder die Strings direkt übergeben, oder die
Werte beim Aufruf ermitteln lassen, zur Demonstration hier Beispiele mit echo.
Beim Aufruf als Argument einfach das echo weglassen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">h=HostB ; echo "${h} $(host -t A ${h} | awk '{ print $4 }')"
echo $(host -t AAAA $(hostname) | awk '{ print $5 }')
echo $(ping -4c 1 ${hostname} | awk 'NR==1{gsub(/\(|\)/,"",$3);print $3}')</code></pre>
<p>Hat man das Script aus Versehen mehrfach ausgeführt, kann man die entstandenen Doubletten aus der Datei authorized_keys wieder entfernen.</p><pre class="language-bash"><code contenteditable="" spellcheck="false">sort -u ~/.ssh/authorized_keys -o ~/.ssh/authorized_keys</code></pre><p>ToDo</p>
<p><strike>Scriptname GitHub noch finalisieren </strike></p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p><br /></p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-67578208303292310192023-01-11T14:44:00.002+01:002023-01-11T21:06:21.509+01:00SD Card Image anpassen<p>
Man hat ein Image einer großen SD Card gemacht und will dieses Image auf eine
kleinere SD Card speichern. Wie kann man das Image an den eigentlichen
Platzbedarf anpassen ohne den Inhalt der SD Card zu verlieren? Ich habe
sogar ein paar Einzeiler im Netz gefunden, aber die haben alle nicht
funktioniert. Ich habe mit Hilfe
<a href="https://www.hoowl.se/shrinking_an_sd_card_image.html" target="_blank">dieses Artikels</a>
ein paar Schritte entwickelt die hoffentlich leicht nachzuvollziehen und
eindeutig sind.
</p>
<p>Zunächst ganz vereinfacht ein paar Grundlagen</p>
<p></p>
<ul style="text-align: left;">
<li>
Eine gesteckte SD Card stellt ein Blockdevice dar, ein Image davon kann auch
als Blockdevice eingebunden werden. Ein Blockdevice enthält Partitionen,
eine Partion enthält ein Filesystem.
</li>
<li>
Gespeichert wird in Sektoren (Sectorsize 512 Byte), die Sektoren werden in
Blöcken zu 4096 Byte (bzw. 4K Blocksize) organisiert.
</li>
<li>
Die typischen Zahlenangaben für das Filesystem sind Blöcke, für die
Partition sind es Sektoren. Eine 16GB SD Card hat 3.906.250 Blöcke
und 31.250.000 Sektoren.
</li>
<li>
Die Angabe GB basiert auf 1000³, die Angabe GiB basiert auf 1024³
(2^30). 16GB -> 14,9 GiB
</li>
</ul>
<p></p>
<p>
Die gesamte Arbeit erfordert im wesentlichen root Kontext (sudo su). Ich
erarbeite hier Einzeiler und kein komplettes Script, ich habe Ausgabezeilen
eingefügt damit man die Abläufe verfolgen kann.
</p>
<p>
Ich empfehle jede Zeile einzeln auszuführen! Tipp: Meine Codeblöcke sind
editierbar: eigene Pfad- und Dateinamen reinschreiben und direkt copy &
paste.
</p>
<a name='more'></a>
<p></p>
<h3 style="text-align: left;">Einbindung Image als Blockdevice</h3>
<p>
Wo die Imagedatei liegt ist zweitrangig, dies kann auch Netzwerkshare sein.
Die beiden Variablen am Anfang legen den Ort und Namen fest, die notwendigen
Informationen werden ermittelt und auch in Variablen abgelegt. Damit man nicht
blind "fährt" habe ich ein paar Ausgabezeilen eingebaut.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">mp="/mnt/Sicherung"
img="$mp/Images/sdimage.img"
ldev=$(losetup --show -f -P "$img")
arr=($(ls ${ldev}p*))
blk_size=$(lsblk -b|grep ^${ldev##*/}| awk -F' ' '{ print $4 }')
printf "Image %s is connected as %s \ncontains %s partitions: %s \nwith whole space of %.1e\n" ${img##*/} ${ldev} ${#arr[*]} ${arr[*]} ${blk_size}</code></pre>
<p>
Anmerkung: Das Blockdevice wird eingebunden, dass Filesystem wird nicht
gemountet. Prinzipiell können alle folgenden Schritte auch mit jedem
eingebundenem Blockdevice durchgeführt werden: ldev=/dev/sdx . Durch die
vorherige Erzeugung einer Imagedatei von einem Blockdevice (Filesystem nicht
gemountet!) kann die Auswirkung am physikalischen Device auch virtuell geübt
werden!
</p>
<h4 style="text-align: left;">Letzte Partition bearbeiten</h4>
<p>
Für die Größe des Images ist die letzte Partition bestimmend, nur diese wird
untersucht und bearbeitet. Die minimale Größe des Filesystems und die
Blockgröße wird ermittelt. Mit einem Aufschlag von 20% wird die neue
Größe des Filesystems bestimmt.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">size=$(resize2fs -P ${arr[-1]} 2>/dev/null | tee /dev/tty | grep -oE '[0-9]+')
block_size=$(blockdev --getbsz ${arr[-1]})
sector_size=$(blockdev --getss ${arr[-1]})
newsize=$((${size}+${size}/5))
printf "last partition %s \nestimated minimum : %s blocks %.1e bytes\nproposal size: %s blocks %.1e bytes\n" ${arr[-1]} ${size} $((${size}*${block_size})) ${newsize} $((${newsize}*${block_size}))</code></pre>
<p>
Alternativ kann man hier auch eine sinnvolle Vorgabe machen, um dem Zielimage
eine bestimmte Größe zu geben z.B:
newsize=$((8000000000/${block_size})).
</p>
<h3 style="text-align: left;">Das Filesystem wird verkleinert</h3>
<p>
<b> Achtung</b>: Ab hier werden wirklich Veränderungen am Blockdevice
durchgeführt!
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">e2fsck -p -f ${arr[-1]} && resize2fs ${arr[-1]} ${newsize}</code></pre>
<p>
Wenn die obige Zeile einen Fehler liefert, stimmt etwas mit dem Filesystem
nicht. Man kann versuchen mit e2fsck -f ${arr[-1]} eine Reparatur anzustoßen.
</p>
<h3 style="text-align: left;">Die Partition an das Filesystem anpassen</h3>
<p>
Die Partitionsgröße in Sektoren wird errechnet und mittels der scriptfähigen
Variante von fdisk die Partition neu gesetzt. Anmerkung: die Partitionsgröße
kann auch in 4K Blöcken angegeben werden. Der Startsector wird durch
"weglassen" von sfdisk übernommen (echo "start,size"|...).
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">part_size=$((${newsize}*${block_size}/${sector_size}))
printf "Repartitioning: Device %s, PartNumber %s \nPart Size %s sectors %.1e bytes\n" ${ldev} ${#arr[*]} ${part_size} $((${part_size}*${sector_size}))
echo ", ${part_size}" | sfdisk ${ldev} -N ${#arr[*]}</code></pre>
<h3 style="text-align: left;">Die Datei abschneiden</h3>
<p>
Zum Schluss noch die Größe der Imagedatei anpassen. Dazu muss die Einbindung
aufgehoben werden
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">losetup -d ${ldev}</code></pre>
<p>
Mit fdisk wird das Ende der Partitionen ermittelt und dann die Datei nach dem
nächsten Sektor gekürzt.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">END=$(fdisk -l $img | grep ^${img}${#arr[*]} | awk -F" " '{ print $3 }')
truncate -s $(((END+1)*512)) $img</code></pre>
<h2 style="text-align: left;">Notizen</h2>
<p>Imagedatei erzeugen</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">mp="/mnt/Sicherung"
dd if=/dev/sdb of=$mp/Images/sdcard.img bs=1M status=progress</code></pre>
<p>Filesystem mounten</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">ldev="/dev/sdb"
for part in $(ls ${ldev}?) ; do
mkdir -p /mnt/${part##*/}
mount ${part} /mnt/${part##*/}
done</code></pre>
<p>Netzwerkshare mounten</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">mp="/mnt/daten"
mkdir -p $mp
mount -t cifs -o username=UserName,password=Passwort //Server/Share $mp
</code></pre>
<p>ToDo</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p><br /></p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-45203407390435978632022-12-29T20:09:00.000+01:002022-12-29T20:09:27.243+01:00OpenWrt - sysupgrade ohne Bedenken<p>Es gibt ein (für mich) neues Feature bei OpenWrt: <a href="https://openwrt.org/docs/guide-user/installation/attended.sysupgrade" target="_blank">Attended SysUpgrade</a></p><p>Das vereinfacht den Vorgang ein neues Image einzuspielen erheblich, man hat quasi keine Nacharbeit mehr! </p><p>Nachdem ich mich mal wieder mit hotplug und opkg-extras beschäftigt habe, entdeckte ich in <a href="https://openwrt.org/docs/guide-user/advanced/opkg_extras" target="_blank">dem Wiki Artikel</a> ganz zum Schluss den entsprechenden Hinweis. </p><p>Damit braucht man jetzt nur noch zwei Dinge beim sysupgrade: </p><p></p><ol style="text-align: left;"><li>eine angepasstes Backup Archiv Configuration</li><ul><li>Pfade bzw. Dateien eintragen und mit "Open list" prüfen ob alle wichtigen Dateien im Archiv enthalten sind.</li><li>Obwohl das sysUpgrade genau diese Dateien von sich aus behält (Keep Settings...), sollte man immer ein Archiv separat erzeugen und herunterladen!</li></ul><li>Das installierte luci-app-attendedsysupgrade Package.</li></ol><p></p><p>Im Menü System einfach Attended Sysupgrade auswählen, der Rest ist selbsterklärend. Im Reiter Configuration kann man den Advanced Mode einschalten. Damit kann man die Pakete verifizieren und eventuell noch etwas ändern. Man kann auch ein angepasstes Image der bereits installierten Version herunterladen. </p><p>Hinweis: Am Ende bleibt irgendwie die UI hängen, man kann diese schließen und sich nach dem Neustart neu verbinden.</p><p>Ich habe z.B. um folgende Dateien/Pfade ergänzt:</p>
<pre class="language-text"><code contenteditable="" spellcheck="false">/etc/wireguard/
/etc/adblock/ad*list
/root/speedtest
/root/.config</code></pre>
<p>Hatte man hotplug-extras installiert, kann man die installierten Scripts wieder entfernen (auch oben in der Liste):</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">rm /etc/hotplug.d/iface/90-online
rm /etc/hotplug.d/online/10-sleep
rm /etc/hotplug.d/online/50-opkg-restore</code></pre><p>Fehlt noch was?</p>Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-19489749855423299182022-10-15T23:26:00.006+02:002023-09-19T17:45:13.074+02:00iSCSI - ganz minimalistisch<p>
Ich war überrascht wie einfach das funktioniert. Es gibt da eine Menge
erklärender Seiten im Web, die zeigen aber auch ziemlich viel verwirrende
Vielfalt. Ich habe mit einem debian System und einer Windows Maschine mal ein
Target und einen Initiator miteinander verbunden.
</p>
<p>
Ich habe hier ein paar Artikel verlinkt, beim einarbeiten sind mir in diesen
leider ein paar Fehler im Code aufgefallen. Also Vorsicht mit Copy&Paste
aus den verlinkten Artikeln!<span></span>
</p>
<a name='more'></a>
<p></p>
<h2 style="text-align: left;">Target - der Speicherplatz im Netzwerk</h2>
<p>Alle Befehle erfordern erhöhte Rechte: sudo su</p>
<p>
Unter debian benötigt man das tgt Packet und einen leeren, noch nicht
eingebundenen Datenträger.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">apt install tgt</code></pre>
<p>
Zunächst zur Vereinfachung der folgende Befehle zunächst ein paar Variablen.
Der Name des Target soll weltweit eindeutig sein, dies hat im privaten
Netzwerk sicher keine Bedeutung. (<a href="https://www.admin-magazin.de/Online-Artikel/iSCSI-mit-Linux/(offset)/2" target="_blank">siehe</a>)
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">id=2
target_name='iqn.2022-10.scsi.target:test'
storage_name='/storage/test_storage.img'</code></pre>
<p>
Zum Testen kann der Datenträger einfach eine leere Image Datei sein (Beispiel
1,5 GB)
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">mkdir -p ${storage_name%*/*}
dd if=/dev/zero of=${storage_name} bs=1024k count=1500</code></pre>
<p>
Auf einer NAS wird man besser mit
<a href="https://de.wikipedia.org/wiki/Logical_Volume_Manager" target="_blank">LVM</a>
ein logisches Volume anlegen. Beispiel: zwei freie Laufwerke sdb und sdc
vorhanden (<a href="https://www.tecmint.com/setup-iscsi-target-and-initiator-on-debian-9/" target="_blank">siehe auch</a>)
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">pvcreate /dev/sd{b,c}
vgcreate vgroup1 /dev/sd{b,c}
lvcreate -l 50%FREE -n vgroup1_lun1 vgroup1
storage_name='/dev/mapper/vgroup1-vgroup1_lun1'</code></pre>
<p>
Mit tgtadm erzeugen wir online ein target in mehreren Schritten, der Letzte zeigt zur Kontrolle das target an. </p><p></p><ol style="text-align: left;"><li>target erzeugen mit eindeutiger ID und Name</li><li>logicalunit zum Target erzeugen mit eindeutiger ID und Storage Name</li><li>das Target freigeben, All für alle (hier könnten z.B. spezielle IP Adressen stehen)</li></ol><p></p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">tgtadm --lld iscsi --op new --mode target --tid ${id} -T ${target_name}
tgtadm --lld iscsi --op new --mode logicalunit --tid ${id} --lun 1 -b ${storage_name}
tgtadm --lld iscsi --op bind --mode target --tid ${id} -I ALL
tgtadm --lld iscsi --op show --mode target</code></pre>
<p>Tipp: Man kann bei Bedarf weitere LUNs zum gleichen Target erzeugen (<a href="https://www.berrange.com/tags/tgtadm/" target="_blank">Beispiel</a>).</p><p>
Will man die Konfiguration fest verankern, muss man eine Konfigurationsdatei
schreiben. Alle conf Dateien im Pfad /etc/tgt/conf.d werden beim Start von tgt
Service geladen (siehe <a href="https://wiki.ubuntuusers.de/tgtd/" target="_blank">auch</a>).</p>
<p>
Im folgenden erzeugen wir die Datei, löschen das target und aktivieren es
wieder über die Datei. Den Erfolg kann man zwischen jeder Zeile mit dem --op
show Kommando anzeigen lassen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">tgt-admin --dump | grep -v default-driver > /etc/tgt/conf.d/test_storage.conf
tgtadm --lld iscsi --op delete --mode target --tid ${id}
tgtadm --mode target --op show
tgt-admin --update ALL --force
tgtadm --mode target --op show</code></pre>
<p>
Man kann die Verwendung des Targets noch absichern, nur bestimmte Initiatoren
zulassen oder die Autorisierung mittels CHAP. Dazu kann/muss man die conf Datei
mit editieren und wieder anwenden (--update ).
</p>
<h2 style="text-align: left;">Initiator - der Nutzer im Netzwerk</h2>
<h3 style="text-align: left;">Windows</h3>
<p>
Die Nutzung von iSCSI unter Windows ist sehr einfach. Man nutzt die Windows
Taste, tippt iscsi ein und startet die App iSCSI-Initiator. Mit Angabe des
Hostnamens oder der IP wird das Target automatisch gefunden und mit einem
klick verbunden.
</p>
<p>
Mit der Datenträgerverwaltung wird die neue iSCSI Festplatte eingerichtet.
</p>
<p>
Will man die Einbindung eines iSCSI Targets automatisieren, kann man
<a href="https://www.windowspro.de/wolfgang-sommergut/iscsi-verbindungen-powershell-verwalten" target="_blank">Powershell</a>
dafür verwenden.
</p>
<h3 style="text-align: left;">Debian</h3>
<p>Zur Einbindung braucht man das Paket open-iscsi</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">apt install open-iscsi</code></pre>
<p>
Der iscsiadm Befehl dient der Administration ( <a href="https://www.admin-magazin.de/Online-Artikel/iSCSI-mit-Linux/(offset)/4" target="_blank">Beschreibung</a> ). Das discovery legt ein Konfigurationsverzeichnis
in /etc/iscsi/nodes/ ab. Ein erneutes discovery überschreibt die
vorhandenen Dateien, eventuell Änderungen gehen verloren!
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">iscsiadm -m discovery -t st -p <IP des Target Servers></code></pre>
<p>
Der Befehl liefert den Target Namen, dieser wird bei den weiteren Befehl
benötigt. Man kann ihn auch jederzeit später wieder abfragen. Mit dem --login
Befehl kann man die Anbindung testen. Weitere Parameter in der angelegten
default Datei kann man mit dem -o update Befehl setzen, z.B. auch den
automatischen Start. Man kann an
<a href="https://library.netapp.com/ecmdocs/ECMP1654943/html/GUID-8EC685B4-8CB6-40D8-A8D5-031A3899BCDC.html" target="_blank">mehreren Stellen</a> diesen automatischen Start einrichten.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">iscsiadm --mode node
target_name='iqn.2022-10.scsi.target:test'
iscsiadm --mode node --targetname ${target_name} --login
iscsiadm --mode node --targetname ${target_name} -o update -n node.startup -v automatic
</code></pre>
<p>
Mit dem lsblk Befehl kann man den Erfolg überprüfen und nach der Anbindung den
mount und das Dateisystem einrichten. Allerdings funktioniert der automatische
Start so noch nicht, ich weiß noch nicht warum. Ein systemctl restart
open-iscsi im laufenden Betrieb führt die automatic Einträge aus, ein reboot
des Systems nicht.
</p>
<p>Mit diesem Befehl werden alle ermittelten Targets gelöscht.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">iscsiadm -m node -o delete</code></pre>
<p>
Noch ein
<a href="https://comm-tech.org/setting-up-iscsi-with-tgtadm-server-and-using-open-iscsi-client/" target="_blank">Link</a>.
</p>
<p>Nodes auflisten oder session auflisten.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">iscsiadm -m node|session</code></pre>
<p><br /></p>
<h3 style="text-align: left;">Zum Lesen</h3>
<p>
<a href="https://linuxhandbook.com/lvm-guide/" target="_blank">LVM for Beginners</a><br />
</p>
<p>ToDo</p>
<p>Links konsolidieren</p>
<p>automatische Verbindung unter debian klären.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code</code></pre>
<p>Ende</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com1tag:blogger.com,1999:blog-5611886937451692837.post-5366013533906583712022-10-10T00:07:00.005+02:002022-10-10T09:21:11.777+02:00WSL und Docker Desktop - NeuigkeitenMit Windows 11 Build 22000 habe ich mal die Neuigkeiten bei der Installation von
Windows-Subsystem für Linux und die Installation von Docker Desktop getestet.
Die sind am Ende relativ umfangreich - gemessen an
<a href="https://heinz-otto.blogspot.com/search?q=docker+%7C+wsl" target="_blank">meinen früheren Versuchen</a>.
<div>
<ul style="text-align: left;">
<li>
Nicht wirklich neu - aber von mir neu entdeckt:
<a href="https://learn.microsoft.com/de-de/windows/package-manager/winget/" target="_blank">winget</a>
</li>
<li>
Docker Desktop installiert WSL gleich mit - aber nicht ganz perfekt.
</li>
<li>
WSL kann jetzt <a href="https://learn.microsoft.com/de-de/windows/wsl/tutorials/gui-apps" target="_blank">X11 GUI Apps ausführen und direkt in Windows anzeigen</a>.
</li>
</ul>
<span><a name='more'></a></span>
<p>
WSL baut auf Hyper-V Technologie auf. Dazu muss die Hardware die
Virtualisierung unterstützen und diese muss im BIOS aktiviert sein (<a href="https://heinz-otto.blogspot.com/2020/11/wsl-ein-paar-notizen-zur-verwendung.html" target="_blank">siehe auch</a>). Wer die folgenden Tests selbst in einer Hyper-V Umgebung testen will,
muss die nestet Virtualisierung pro VM aktivieren (<a href="https://docs.microsoft.com/en-us/powershell/module/hyper-v/?view=win10-ps" target="_blank">Doku</a>):
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Set-VMProcessor -VMName <Name der VM> -ExposeVirtualizationExtensions $true</code></pre>
<p>
WSL erfordert die Windows-Features VM-Plattform und Windows-Subsystem für
Linux. Der wsl Befehl kann alles mit einem Setup Programm installieren. </p><p>Alle hier gezeigten Befehle funktionieren im Windows "Terminal (Administrator)". Man kann mit winget nach der richtigen ID für die
Installation suchen, Beispiel:
<span style="font-family: courier;">winget search docker</span>
</p>
<p>Das Docker Desktop Setup kann WSL als Voraussetzung mit installieren, aber nicht perfekt.
</p>
<h2 style="text-align: left;">Docker Desktop installieren</h2>
<p>Installiert man sofort Docker Desktop, wäre WSL nicht auf dem neuesten Stand (wsl 2 update fehlt) und alles läuft etwas holprig. Deshalb installiert man zunächst WSL mit dem integrierten Setup, dies funktioniert nicht ohne eine Linux Distribution. </p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">wsl --install -d debian
Restart-Computer
winget install Docker.DockerDesktop</code></pre>
<p>
Die WSL Installation erfordert einen Neustart. Nach dem Neustart und der
Anmeldung wird die Installation automatisch fortgesetzt. Das Debian System kann fertig
konfiguriert werden (Username, Passwort).
</p>
<p>
Nach der Docker Installation muss man sich ab und wieder anmelden, die
docker Kommandos benötigen kein administratives Terminal. Der Zugriff auf
Ports innerhalb der Docker Umgebung ist über http://localhost:Portnummer
ohne Manipulation der Microsoft Windows Firewall möglich.
</p>
<p>
Docker Desktop für Windows eignet sich sicher gut für Test und Entwicklung
von Containern ohne Hardware Zugriff. Man arbeitet aber irgendwie in der 3.
Virtualisierung: VM-Plattform - WSL - Docker
</p>
<h2 style="text-align: left;">WSL Installation</h2>
<p>
Der empfohlene Befehl installiert in einem Zug neben dem Windows
Subsystem for Linux Update auch Windows Subsystem for Linux
<a href="https://github.com/microsoft/wslg" target="_blank">WSLg </a>preview
und Ubuntu.
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">wsl --install</code></pre>
<p>
Hat man eine alte WSL Umgebung kann man diese auf den neusten Stand
bringen:
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">wsl --update</code></pre>
<p>Damit wird auch WSLg installiert. Auf Ausgaben bezüglich Neustart achten!
</p>
<p>Man kann jederzeit eine weitere Linux Distribution installieren:
</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">wsl --install -d ubuntu</code></pre>
<p>
Test der grafischen (x11) Tools im wsl Terminal</p><p>Als Beispiel kann man die x11-apps installieren
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt install x11-apps</code></pre>
<p>und mit dem grafischen Taschenrechner testen. Nach Eingabe von</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">xcalc</code></pre>
<p>
erscheint nach 3 Warnungen im Terminal und etwas Wartezeit (beim ersten mal)
der grafische Taschenrechner auf der Windows Oberfläche.
</p>
<h2 style="text-align: left;">Alles loswerden</h2>
<p>Hier tritt die "Vielfalt" der Schnittstellen von Windows zu Tage: wie installiert wird.</p><p>WSL Instanzen kann man mit exit beenden, Docker Desktop läuft nach dem Start im Hintergrund
und kann über die rechte Maustaste im Infobereich der Taskleiste beendet werden. </p><p>Deinstallieren kann man Ubuntu, Docker-Desktop sowie WSL, WSL update und
WSLg über "Apps und Features". Die Grundlage muss man über Systemsteuerung
"Windows-Features" entfernen: VM-Plattform und Windows-Subsystem für Linux. </p><p>Tipp: Beide Setup Punkte findet man einfach über Windows Taste und Suche des
Begriffes.
</p>
<p>Winget deinstalliert ziemlich perfekt </p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">winget uninstall Docker.DockerDesktop</code></pre>
<p>Für das WSL System benötigen wir 3 Schritte:</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Get-AppxPackage *debian* | Remove-AppxPackage
Get-Package *subsystem for linux* | Uninstall-Package
Disable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform,Microsoft-Windows-Subsystem-Linux
Restart-Computer</code></pre>
<p>Am Ende ist wieder ein Neustart fällig.</p>
<p>ToDo</p><p>Hab da was zur <a href="https://www.xda-developers.com/wsl-connect-usb-devices-windows-11/" target="_blank">USB Unterstützung</a> - Stichwort usbipd - gefunden.</p>
<pre class="language-powershell"><code contenteditable="" spellcheck="false">Code</code></pre>
<p>Ende</p>
</div>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-90961673554267919422022-08-31T00:35:00.045+02:002023-01-17T12:00:13.424+01:00Wie funktioniert Wireguard im Detail<p>
Ich habe pivpn mit wireguard installiert und das hat einfach funktioniert.
Also wirklich einfach! Jetzt bin ich etwas tiefer vorgedrungen, um zu
verstehen wie man die Konfiguration lesen muss und um Konfigurationen sichern
und übertragen zu können. Für pivpn gibt es eine simple
<a href="https://docs.pivpn.io/wireguard/#migrating-pivpn-wireguard" target="_blank">Backup/Restore Beschreibung</a> (mit Stolperstellen <a href="https://heinz-otto.blogspot.com/2022/02/wireguard-verbundene-netzwerke.html" target="_blank">siehe auch</a>).
</p>
<ul style="text-align: left;">
<li>
Wireguard unterscheidet in der Installation nicht zwischen Server und Client
- nur die Konfiguration bestimmt: wer mit wem.
</li>
<li>
Wireguard implementiert im System ein vollwertiges Netzwerkinterface mit
Tunnel - quasi eine virtuelle Netzkarte mit virtuellem Kabel. Die
Netzwerkadministration erfolgt mit Standard Boardmitteln.
</li>
<li>
Die Endpunkte authentifizieren sich mit einer <a href="https://de.wikipedia.org/wiki/Public-Key-Authentifizierung">Public-Key-Authentifizierung</a>.
</li>
<li>
Soll der Endpunkt ein VPN Router sein, muss er entweder schon der Router im
Netzwerk sein oder NAT aktiviert haben.
</li>
</ul>
<p>
Die Konfigurationsdatei für einen Endpunkt wird normal im INI Format erstellt
- bei OpenWrt ist sie in der network config integriert.
</p>
<p>
OpenWrt kann sowohl Server als auch Client Funktionalität abbilden, ich habe
mich hier zunächst auf OpenWrt Router als VPN Einwahl Server beschränkt.<span></span>
</p>
<p>
<b>Nachtrag</b> 7.9.2022: Während ich noch immer am Artikel schreibe bringt
die neue Version OpenWrt 22.03 jede Menge Änderungen und meine ganzen Scripts
für Wireguard sind hinfällig!?
</p>
<a name='more'></a>
<p></p>
<h2 style="text-align: left;">Elemente der wireguard Konfiguration</h2>
<p>
Der Abschnitt <b>Interface</b> konfiguriert den lokalen Endpunkt und
damit das Netzwerkinterface. Er enthält
</p>
<p></p>
<ul style="text-align: left;">
<li>PrivateKey - der private Schlüssel des lokalen Endpunktes, </li>
<li>Address - die Tunnel IP der lokalen Maschine mit Netzwerkmaske,</li>
<li>ListenPort - optional, wireguard startet selbst bei 51820,</li><li>MTU - optional, default Wert ist 1420</li>
</ul>
<p></p>
<p>
Der Abschnitt <b>Peer</b> konfiguriert die Netzwerkverbindung. Er
enthält
</p>
<p></p>
<ul style="text-align: left;">
<li>
PublicKey - den öffentlichen Schlüssel des anderen Endpunktes zum Aufbau des Tunnels,
</li>
<li>AllowedIPs - </li>
<ul>
<li>die IP die im Tunnel zulässig für die Verbindung ist,</li>
<li>die Netzwerke die durch den Tunnel erreichbar sind,</li>
<li>
ist hier 0.0.0.0/0 eingetragen soll der gesamte Traffic durch den Tunnel
gehen.
</li>
</ul>
<li>
EndPoint - die IP und Port des anderen Endpunktes zum Aufbau des
Tunnels.
</li>
<li>
PresharedKey - optional als zusätzliche Sicherheit, dieser Key muss auf
beiden Seiten gleich eingetragen werden.
</li>
</ul>
<p></p>
<p><br /></p>
<pre class="language-ini"><code contenteditable="" spellcheck="false">[Interface]
PrivateKey = xxx # local endpoints private key
Address = 10.6.0.3/24 # host address & network segment for tunnel
# ListenPort = 51820 # optional, startpoint
# MTU = 1420 # optional, default
[Peer]
PublicKey = xxx # remote endpoints public key
AllowedIPs = 192.168.2.0/24, 10.6.0.0/24
</code></pre>
<p>
Für maximale Sicherheit verbleibt der private key immer auf dem Endpunkt wo er
erzeugt und verwendet wird. Der daraus abgeleitete public key wird den anderen
Endpunkten zur Anmeldung ausgehändigt. Das Ganze entspricht damit der
typischen Verteilungsform im ssh public key Verfahren.
</p>
<p>Mehrere <b>Peer </b>Abschnitte repräsentieren beim "Server" die Clients.</p><h3 style="text-align: left;">Typische Server / Client Einträge</h3><p>Sowohl der [Interface]-Eintrag <i>Address </i>als auch der [Peer]-Eintrag <i>AllowedIPs </i>kann die Routing Tabelle des lokalen Endpunktes verändern und bestimmt somit das Routing durch den Tunnel!</p><p>Address - eine Host Adresse mit Netzwerksegment- oder Host-Maske aus dem <a href="https://de.wikipedia.org/wiki/Private_IP-Adresse" target="_blank">privaten Bereich</a> !</p><p>AllowedIPs - ist in Senderichtung wie eine Routingtabelle in Empfangsrichtung wie eine Zugangskontrolle. </p><h4 style="text-align: left;">Auswirkung auf Routing</h4><p>Address: </p><p></p><ul style="text-align: left;"><li>Hostadresse mit Netzwerksegmentmaske im Interface Abschnitt Endpoint S - damit ist das gesamte Tunnelsegment erreichbar.</li><li>Hostadresse mit Hostmaske im Interface Abschnitt Endpoint C - damit wird Verbindung aufgebaut.</li></ul><p></p><p>AllowedIPs : </p><p></p><ul style="text-align: left;"><li><b>Hostadresse </b>des Endpoint C im Peer Abschnitt Endpoint S <b>(<a href="https://www.wireguard.com/#:~:text=Cryptokey%20%20Routing" target="_blank">Dazu den Artikel beachten)</a></b></li><li><b>Netzwerkadresse </b>des Tunnels im Peer Abschnitt Endpoint C - damit wird das Tunnelsegment erreichbar. Diese kann weggelassen werden, dann müssen weiter Adressen eingetragen werden die über den Tunnel genutzt werden sollen.</li><li>Zusätzliche weitere Netzwerksegmente die über diesen Tunnel erreichbar sein sollen, geht für beide Richtungen.</li><li>Wird im Endpoint C 0.0.0.0/0 eingetragen, wird der komplette ausgehende Verkehr durch den Tunnel geroutet - damit ist dieser Endpoint im lokalen Netzwerk nicht mehr erreichbar! </li></ul><p></p><h3 style="text-align: left;">Konkretes Beispiel </h3>
<p><i><b>
Hinweis</b>: Diese folgende funktionierende Konfigurationen bitte nicht per Copy
& Paste verwenden - sonst ist das Netzwerk zwar virtuell aber nicht mehr
privat!</i> Die eigenen Keys werden mit dem wg genkey|pubkey|genpsk Kommando
erzeugt. Der <a href="https://heinz-otto.blogspot.com/2022/02/wireguard-verbundene-netzwerke.html#autostart" target="_blank">Start einer Konfiguration</a> erfolgt mit dem wireguard Tool wg-quick. </p><p>Hier im Beispiel kommen zwei Key Pärchen zum Einsatz, diese werden so
auf die INI Dateien verteilt:
</p>
<p><b>Serverkonfiguration</b></p>
<pre class="language-ini"><code contenteditable="" spellcheck="false">[Interface]
PrivateKey = CPQJyuFRCoospbw6q23aOV6NENCzPDpvJc6Dr9ibg1A= # server private key
Address = 10.6.0.1/24 # host ip & tunnel network segment
MTU = 1420
ListenPort = 51820
[Peer]
PublicKey = emqkXECnmtkbnVDNU0UHBgSuDNXQeqp/fcPoRHW/8GM= # first remote client public key
AllowedIPs = 10.6.0.2/32
[Peer]
PublicKey = xxx # second remote clients public key
AllowedIPs = 10.6.0.3/32</code></pre>
<p>Eine passende <b>Client Konfiguration</b></p>
<pre class="language-ini"><code contenteditable="" spellcheck="false">[Interface]
PrivateKey = 2M8G4JTwXgGiSYrVXLESSb9GGer8P7Zrs5hMQqrKJl4= # first remote client private key
Address = 10.6.0.2/32 # host ip
[Peer]
PublicKey = pGN89OLvIF9CVpCwRGUUiAiN38mFT/aQ8ND+8T8lsCI= # server public key
AllowedIPs = 10.6.0.0/24
Endpoint = server.ip:51820</code></pre>
<h2 style="text-align: left;">Clientkonfiguration erzeugen</h2>
<p>
Typischerweise generiert man einen privaten key (wg genkey), erzeugt
daraus einen public key (wg pubkey), der wird am Server eingetragen und final
komplettiert man seine Client-Konfiguration mit dem public key vom Server
sowie der Peer IP-Adresse.
</p>
<h3 style="text-align: left;">Interaktiv OpenWrt GUI</h3><p>OpenWrt (ab Version 22.03): Die Erzeugung einer Clientkonfiguration ist jetzt in Luci eingebaut (Network / Interface / VPN Interface / Edit / Registerkarte Peers / Add peer) und man kann diese auch als QR Code ausgeben (Edit Peer / Configuration Export). Allerdings nicht vollständig, man muss manuell nacharbeiten. Auch der Import einer conf Datei ist möglich (anstatt Add peer - Import configuration as peer). </p><p>OpenWrt (bis Version 21.02): Man muss in etwa so vorgehen:
</p>
<p></p>
<ol style="text-align: left;">
<li>
private key: Mit dem Wireguard Client einen neuen Tunnel erstellen oder den
QR-Code auf der OpenWrt wireguard Statusseite einscannen (der QR Code
wechselt bei jedem Refresh).
</li>
<li>
Der WG Client erzeugt immer den public key und zeigt diesen an: in die
Zwischenablage kopieren.
</li>
<li>
Im Browser zum Webinterface OpenWrt verbinden und anmelden, Network /
Interface / VPN Interface / Edit / Registerkarte Peers / add peer,
</li>
<li>
den public key aus Zwischenablage einfügen, IP Addresse bestimmen und
eintragen, speichern, save & apply, network service neu starten.
</li>
<li>
Zum Abschluss am Client die Konfiguration mit IP Adresse und Endpunkt
vervollständigen,
</li>
<li>final die Verbindung testen (z.B. mobiles Netzwerk).</li>
</ol>
<p></p>
<p>
... klingt umständlich - funktioniert aber! Wenn man weiß was man tun muss.
</p>
<h3 style="text-align: left;">
pivpn arbeitet per CLI</h3><p>Man kann per Befehl einen neuen Client am Server
erzeugen, sich die komplette config ausgeben lassen und am Client importieren.
Die komplette config, inklusive privater Schlüssel, wird auf dem Server
gespeichert. Das macht die Verteilung an mobile Clients einfach (QR Code
einscannen).
</p>
<h3 style="text-align: left;">Linux Client in der Konsole erzeugen. </h3><p>Ich habe dafür mal zwei Einzeiler gemacht</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">printf "[Interface]\nPrivateKey = $(wg genkey)\nAddress = \n\n[Peer]\nPublicKey = \nEndpoint = \nAllowedIPs = \nPersistentKeepalive = 25\n"|tee wg1.conf
cat wg1.conf|grep PrivateKey|awk '{printf($3)}'|wg pubkey</code></pre>
<p>Die erste Zeile erzeugt eine conf Datei als Gerüst, diese kann man mit nano editieren und vervollständigen.</p><p>Die zweite Zeile zeigt den PublicKey vom Peer um ihn per copy & paste in die Server Konfiguration einzutragen.</p>
<h2 style="text-align: left;">Split Tunnel und Routing</h2>
<p>(<b>ToDo</b>) <i>Bisher nur Notizen</i></p>
<p>Split Tunnel: AllowedIPs mit einzelnen Segmenten z.B. 192.168.178.0/24
bewirken eine Teilung des Netzwerkverkehrs. </p>
<p>DNS Namensauflösung lokal, im Internet oder im Tunnel. Diese Konfiguration muss man sich je nach Verwendung des Tunnels gut überlegen. <a href="https://www.procustodibus.com/blog/2022/03/wireguard-dns-config-for-systemd/" target="_blank">Hier </a>habe ich ein paar Erklärungen gefunden. </p>
<p>
Wenn man aus dem Tunnel wieder "heraus" will: muss Routing am Endpunkt
aktiv sein (net.ipv4.ip_forward). Ist der Endpunkt nicht der Router im
Netzwerk, muss <a href="https://www.karlrupp.net/de/computer/nat_tutorial" target="_blank">NAT aktiviert </a>werden.</p>
<h2 style="text-align: left;">Start des wireguard Interfaces</h2>
<p>(<b>ToDo</b>) <i>Bisher nur Notizen</i></p>
<p>Bei pivpn und OpenWrt wird das wireguard Interface automatisch gestartet. Bei einer manuellen Konfiguration von wireguard wird dieser Start nur vorbereitet, siehe meinem Beitrag
<a href="https://heinz-otto.blogspot.com/2022/02/wireguard-verbundene-netzwerke.html#autostart" target="_blank">verbundene Netzwerke</a>.
</p>
<p>
Der Tunnel wird nur bei Bedarf aktiviert. Für Tests auf Verbindung muss man
ihn verwenden - eine IP im Tunnel anpingen, oder z.B. den DNS Server so
setzen, dass der Tunnel verwendet wird.
</p>
<h2 style="text-align: left;">Ein paar Scripts für OpenWrt</h2>
<p>
Zur einfacheren Konfiguration auf einem OpenWrt Router habe ich ein
<a href="https://github.com/heinz-otto/scripts/tree/master/uci" target="_blank">paar Scripts</a>
geschrieben. Der Code wurde inspiriert von <a href="https://openwrt.org/docs/guide-user/services/vpn/wireguard/server" target="_blank">Beispielen im OpenWrt Wiki</a>. Die Scripts sind sicher nicht perfekt und nur in meinem Anwendungsfall
getestet!
</p>
<p>
Leider ist wget in OpenWrt nur ein Link auf uclient-fetch und damit
eingeschränkt, z.B. fehlt Brace Expansion und Parameter -N. Damit muss jede
Datei einzeln laden:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">wget https://raw.githubusercontent.com/heinz-otto/scripts/master/uci/wireguard-import-key.sh
wget https://raw.githubusercontent.com/heinz-otto/scripts/master/uci/wireguard-export-conf.sh
wget https://raw.githubusercontent.com/heinz-otto/scripts/master/uci/wireguard-setup-server.sh
chmod +x wireguard-*.sh</code></pre>
<h3 style="text-align: left;">
Wireguard Server Interface auf dem OpenWrt Router erzeugen
</h3>
<p>
Mit dem Script "setup-server" kann man einen neuen wireguard Server auf
OpenWrt erzeugen.
</p>
<p>
Beim OpenWrt Router erzeugt man ein Netzwerkinterface! Deshalb ist es wichtig
diesem Interface eine Netzwerkadresse und keine Hostadresse zu geben (mask
< 32), ansonsten entsteht kein Eintrag in der Routingtabelle. Man kann sich
zwar verbinden aber diese Verbindung ist nutzlos.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false"># einen neuen Server mit default Werten: $(wg genkey) IP 192.168.9.1/24, Port 51820 und dem Namen vpn erzeugen
./wireguard-setup-server.sh
# einen Server mit vorhandenen Werten erzeugen
./wireguard-setup-server.sh 'CPQJyuFRCoospbw6q23aOV6NENCzPDpvJc6Dr9ibg1A=' '10.6.0.1/24' 51820 wg0</code></pre>
<h3 style="text-align: left;">
Wireguard Peer auf dem OpenWrt Router importieren
</h3>
<p>
Das Script "import-key" dient dazu einen Peer zu importieren, der public key
genügt, zusätzlich kann ein Name und ein PresharedKey sinnvoll sein. Hat
man einen existierenden peer kann man so leicht den public key auf dem OpenWrt
Router importieren und anschließend die fehlenden config Werte mit dem Script
"export-conf" ausgeben.
</p>
<p>
Beim Import selbst wird kein Key extra direkt im Dateisystem gespeichert -
alles wandert in die OpenWrt Konfiguration! In der folgenden Codebox sind 3
Beispiele zur Verwendung. Mit dem letzten Beispiel kann man das pivpn Scenario
nachbilden bzw. Werte von einem pivpn Server übertragen. Im Beispiel 2 und 3
wird der erzeugte private key im Dateisystem gespeichert.
</p>
<p>
<b>Achtung</b>! das flashen eines neues OpenWrt Images erhält zwar die
Konfiguration, aber alle "eigenen" Daten im Dateisystem (auch installierte
Software) gehen verloren!
</p>
<pre class="language-bash" style="text-align: left;"><code contenteditable="" spellcheck="false"># 1. vorhandene public key importieren
./wireguard-import-key.sh "pGN89OLvIF9CVpCwRGUUiAiN38mFT/aQ8ND+8T8lsCI="
# 2. neuen User anlegen - Speicher Ort für private key anlegen
mkdir -p /etc/wireguard/keys
./wireguard-import-key.sh $(wg genkey | tee /etc/wireguard/keys/vpnUser1_priv | wg pubkey) $(wg genpsk) "vpnUser1"
# 3. neuen User mit preshared key erzeugen (oder Werte aus einem wireguard Server nehmen)
username='vpnSuperUser1'
PublicKey=$(wg genkey | tee /etc/wireguard/keys/${username}_priv | wg pubkey)
PresharedKey=$(wg genpsk)
# die Werte in OpenWrt importieren
echo "$PublicKey $PresharedKey $username"|xargs ./wireguard-import-key.sh</code></pre>
<p>
Das jeweilige wireguard Interface muss nach dem import / neu anlegen neu
gestartet werden. Entweder über die WebGUI oder per Kommadozeile (alternative
Beispiele):
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">ifdown wg0 && ifup wg0
ubus call network.interface.wg0 down && ubus call network.interface.wg0 up</code></pre>
<h4 style="text-align: left;">Konfiguration ausgeben</h4>
<p>
Bei pivpn kann man sich eine config als Text oder QR Code ausgeben lassen. Das
Script "export-conf" bildet dies Funktion nach. Mit dem Script kann man sich
eine bestimmte (sucht nach public key oder Name) - oder alle
configs - als Text oder QR Code ausgeben lassen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">./wireguard-export-conf.sh [<PublicKey|Name>] [-qr]</code></pre>
<h3 style="text-align: left;">Konfigurationen kopieren</h3>
<p>
Mit ein paar Zeilen Code, die man auf dem pivpn Server ausführt, kann man die
wireguard Konfiguration auf den OpenWrt Router übertragen. Das Script
"setup-server" wird dabei remote über ssh auf dem OpenWrt Router gestartet.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">export remote=user@host
sudo -sE <<-'EOS'
WG_IF=wg0
WG_KEY=$( wg showconf $WG_IF|grep PrivateKey| awk '{printf($3)}' )
WG_ADDR=$( ip addr show $WG_IF|grep 'inet '|grep -oE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'| tr -d $'\n' )/32
WG_PORT=$( wg showconf $WG_IF|grep ListenPort| awk '{printf($3)}' )
# transfer to OpenWrt Router
echo "$WG_KEY $WG_ADDR $WG_PORT $WG_IF"|ssh ${remote} 'xargs ./wireguard-setup-server.sh'
EOS</code></pre>
<p>
Mit dem schon erwähnten "import-key" Script kann man in gleicher Art und Weise
auch sämtliche Peer Konfigurationen von pivpn auf den OpenWrt Router
übertragen. Achtung: Die private keys der peers bleiben exklusiv auf dem pivpn
Server! Auch hier wird das Script "import-key" remote per ssh auf dem OpenWrt
Router gestartet.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo -sE <<-'EOS'
for username in $( cat /etc/wireguard/wg0.conf|grep "### begin " | awk '{printf ($3 " ")}' ); do
for var in PublicKey PresharedKey AllowedIPs; do
val=$( cat /etc/wireguard/wg0.conf|grep "### begin ${username}" -A4|grep ${var}| awk '{printf($3)}' )
eval "${var}='${val}'"
done
echo "$PublicKey $PresharedKey $username $AllowedIPs"|ssh ${remote} 'xargs ./wireguard-import-key.sh'
done
ssh ${remote} '/etc/init.d/network restart'
EOS</code></pre>
<h3 style="text-align: left;"><a name="backuprestore">Backup & Restore</a></h3>
<p>
Ohne weiteres zutun wäre nach einem sysupgrade (<i>flash new firmware</i>)
oder einem <i>Reset to defaults</i>, auch bei vorhandenem Standard Backup
Archive, jegliche Erweiterung an installierter Software und vor allem die in
/etc/wireguard erzeugten privaten Keys verloren! Um das zu verhindern gibt es
eine kleine Erweiterung, beschrieben im <a href="https://openwrt.org/docs/guide-user/troubleshooting/backup_restore#preserving_packages" target="_blank">OpenWrt Wiki</a>.
</p>
<p>
Zusätzlich wird noch der Pfad /etc/wireguard in der Datei sysupgrade.conf
aufgenommen, damit gelangen auch die Keys in das Backup Archiv. Diese Datei
kann auch über Luci WebUI eingesehen/editiert werden: System / backup Flash
Firmware / Reiter Configuration. Alle Befehle kurz und bündig:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">opkg update
opkg install libustream-mbedtls
uclient-fetch -O opkg-extras.sh "https://openwrt.org/_export/code/docs/guide-user/advanced/opkg_extras?codeblock=0"
. ./opkg-extras.sh
uclient-fetch -O hotplug-extras.sh "https://openwrt.org/_export/code/docs/guide-user/advanced/hotplug_extras?codeblock=0"
. ./hotplug-extras.sh
echo "/etc/wireguard/ >>/etc/sysupgrade.conf"</code></pre>
<p>
Ein ganz normales <i>Backup Generate Archive </i>erzeugt jetzt ein Archiv mit
dem erwarteten Inhalt. Ich bin allerdings noch nicht sicher, ob man nach der
Installation von Software Paketen einmalig das "Opkg
<a href="https://openwrt.org/docs/guide-user/advanced/opkg_extras#commands" target="_blank">Profile</a>" sichern muss (erzeugt offenbar eine Datei /etc/config/opkg):
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">opkg save</code></pre>
<p>
Die Wiederherstellung des alten Zustandes dauert "einen kleinen Moment", nach
dem ersten Neustart erfolgt noch ein Zweiter und Dritter, die dafür
zuständigen <a href="https://openwrt.org/docs/guide-user/advanced/hotplug_extras#implementation" target="_blank">hotplug extras</a>
enthalten bei einen schnellen Blick 10 Sekunden Pause - also ruhig bleiben und
mit der ersten Anmeldung warten. Bei mir waren es bei Versuchen mit einer VM
ca. 1,5 min.
</p>
<p>ToDo? </p>
<p>Variablen Namen vereinheitlich.</p>
<p>Literatur</p>
<p>
<a href="https://www.thomas-krenn.com/de/wiki/WireGuard_Grundlagen#Funktionsweise">https://www.thomas-krenn.com/de/wiki/WireGuard_Grundlagen#Funktionsweise</a>
</p>
<p>Code</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Text</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com1tag:blogger.com,1999:blog-5611886937451692837.post-45761890169565936852022-08-19T16:49:00.012+02:002024-03-07T22:06:01.990+01:00HowTo - FHEM Umzug von System A nach System B<p>Scenario: Umzug auf neues System <br /></p>
<ul style="text-align: left;">
<li>System Alt: altes Linux, alte Hardware ...</li>
<li>System Neu: neues Linux, neue/andere Hardware Plattform ...</li>
</ul>
<p>
Zwei verschiedenen Hardware Systeme sind etwas einfacher zu handhaben, es geht
aber auch auf der gleichen Hardware (z.B. Raspberry Pi mit SD Card Wechsel
oder
<a href="https://heinz-otto.blogspot.com/2021/02/bootstick-fur-den-raspberrypi.html" target="_blank">USB-Bootstick</a>). Ich habe alle Schritte mit einem Raspberry Pi(<i>Raspberry OS Lite</i>)
und einer Virtuellen Maschine(debian 11 netinst) getestet. Dieses HowTo ist
auch eine Ergänzung zu meinem vorjährigen <a href="https://heinz-otto.blogspot.com/2021/12/fhem-auf-neues-system-umziehen.html" target="_blank">Artikel</a>.
</p>
<p>
Mit dem
<a href="https://www.raspberrypi.com/software/" target="_blank">Raspberry Pi Imager</a>
kann man eine neue SD Card effektiv vorbereiten und das System grundlegen
konfigurieren (Zahnradsymbol am rechten unteren Rand <i>nachdem </i>man das OS
ausgewählt hat)
</p>
<p>
Es gab von mir schon ein paar ähnliche Artikel, dieser hier soll ganz gezielt
Schritt für Schritt zeigen was zu tun ist.
<a href="https://heinz-otto.blogspot.com/2018/06/windows-hat-jetzt-ssh.html" target="_blank">Windows 10 hat ssh und scp eingebaut</a>, andere Tools braucht man nicht. Wer nicht mit Windows CMD arbeiten will
findet die Codezeilen für Schritt 1 am Ende auch für Linux und Powershell.
</p>
<p>
Man kann alle Schritte beliebig oft wiederholen / durchspielen und dabei
lernen.<span></span></p><p><b><span style="color: red;">Achtung (03.2024): Das FHEM Installermodul wird leider nicht mehr gepflegt, es häufen sich die Meldungen, das mein hier gezeigtes Verfahren der Ermittlung der fehlenden Debianpakete nicht mehr funktioniert. Ich habe derzeit keine Problem Behebung!</span></b></p><a name='more'></a>
<p></p>
<p>
<b>Achtung</b>: In der Shell alle Codezeilen immer einzeln ausführen! Mehrere
Zeilen auf einmal kann funktionieren - muss aber nicht!</p><div>
</div>
<h2 style="text-align: left;">Schritt 1 - kopieren der notwendigen Dateien</h2>
<p>Arbeiten unter Windows in der CMD Shell - Windows Taste + cmd + enter</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">REM ein paar Variablen setzen
set "alt=pi@raspib3" # username und host vom alten System
set "neu=otto@vmdebianfhem" # username und host vom neuen System
set "pfad=/opt/fhem" # der Pfad in dem FHEM installiert ist
REM aktuellstes Backup ermitteln
for /f %i in ('ssh %alt% -t "ls -rt1 %pfad%/backup | tail -1"') do set datei=%i
REM alternativ eine Variante mit Umweg über eine Datei
REM ssh %alt% -t "ls -rt1 %pfad%/backup | tail -1" > datei.txt
REM set /p datei= < datei.txt
REM die Dateien vom alten System holen
scp %alt%:%pfad%/\{backup/%datei%,fhem.cfg\} .
REM eventuell die Hardware umbauen
REM die Dateien aufs neue System schaffen
scp %datei% fhem.cfg %neu%:
REM Ab jetzt interaktiv auf dem neuen System - anmelden
ssh %neu%</code></pre>
<h2 style="text-align: left;">
Schritt 2 - das neue System vorbereiten und die fhem.cfg testen
</h2>
<p>Ich habe drei Scripte erstellt: </p>
<p>
Das erste Script konfiguriert Sprache, Zeitzone, Hostname. Dies war
ursprünglich für das Standard Raspberry Image gedacht. Konfiguriert man das
System beim Setup (debian netinst) oder mit dem Raspberry Pi Imager, braucht
man dieses Script nicht.
</p>
<p>
Arbeitet man auf einem Raspberry und hat ein UART Modul im Einsatz
(HM-MOD-RPI-PCB, Busware COC oder ähnliches) kann man das System mit dem
zweite Script konfigurieren. Danach muss man einen reboot machen.
</p>
<p>
Das letzte Script installiert und konfiguriert ein aktuelles FHEM, testet die
oben kopierte fhem.cfg und gibt Informationen über fehlende Pakete aus.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false"># Scripts vom GitHub holen
wget -N https://raw.githubusercontent.com/heinz-otto/raspberry/master/setup{Basic.sh,Uart.sh,Prereq.sh}
# Nur ausführen wenn das neue System noch eingerichtet werden muss: Sprache, Zeitzone, Hostname
#bash setupBasic.sh
#bash setupUart.sh # nur bei Raspberry Pi Systemen mit Aufsteckmodulen nötig
bash setupPrereq.sh</code></pre>
<p>
Jetzt installiert man die fehlenden Debian Pakete: zur einfachen Handhabung
erzeugt das Script eine Datei "DebianPaket" im aktuellen Verzeichnis.
</p>
<p>
Nach der Installation startet man FHEM neu und führt zur Kontrolle nochmal das
letzte Script aus.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false"># entsprechend der Ausgabe Pakete installieren
sudo apt install $(<DebianPaket)
sudo systemctl restart fhem
# zur Kontrolle
bash setupPrereq.sh</code></pre>
<p>
Debian Pakete sollten jetzt keine mehr vermisst werden. Fehlen weiterhin Perl
Module, muss man diese mit cpan installieren. Meist ist das etwas
langwieriger.
</p>
<p>
Die folgende Beschreibung ist nur ein Ansatz, es kann sein, das die Module
auch völlig anders installiert werden müssen. Siehe dazu auch im
<a href="https://wiki.fhem.de/wiki/CPAN" target="_blank">Wiki</a>.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt install make curl
sudo cpan CPAN
sudo cpan install $(<PerlModul)</code></pre>
<h2 style="text-align: left;">
Schritt 3 - testen ob ein restore vom produktiven FHEM läuft
</h2>
<p>Jetzt erfolgt der erste Test ob FHEM nach einem restore läuft.</p>
<p>
<b> Empfehlung</b>: Altes FHEM System vorher beenden, um Probleme im Netzwerk
zu vermeiden! (Cloudsystem mögen doppelte Anmeldung nicht usw.)
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo systemctl stop fhem
sudo tar -xvzf $(ls -rt1 FHEM*.tar.gz | tail -1) -C /opt/fhem/
sudo systemctl start fhem</code></pre>
<h2 style="text-align: left;">Schritt 4 - finale Umstellung</h2>
<p>War der vorherige Test erfolgreich - wird umgestellt:</p>
<p></p>
<ol style="text-align: left;">
<li>stop fhem und exit im neuen System, </li>
<li>
backup im Browser für das alte System starten und auf Abschluss
warten,
</li>
<li>
die neue backup Datei vom alten auf das neue System kopieren (Schritt
1),
</li>
<li>
FHEM auf dem alten System beenden (ssh %alt% sudo systemctl stop
fhem),
</li>
<li>mit dem neuen System verbinden (ssh %neu%), </li>
<li>restore machen und FHEM starten (Schritt 3). </li>
</ol>
<p></p>
<p>
Die entsprechenden Befehlszeilen stehen in den Abschnitten Schritt 1 und
Schritt 3.
</p>
<h3 style="text-align: left;">Andere Shell für Schritt 1</h3>
<p>
Der Syntax unterscheidet an sich leicht - die Schritte an sich sind gleich!
</p>
<p>Linux Shell :</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false"># Variable setzen
alt=pi@raspib3
neu=otto@vmdebianfhem
pfad=/opt/fhem
# letztes Backup ermitteln
datei=$( ssh $alt -t "ls -rt1 $pfad/backup | tail -1|tr -d '\n'" )
# die Dateien holen
scp $alt:$pfad/\{backup/$datei,fhem.cfg\} .
# die Dateien aufs neue System schaffen
scp $datei fhem.cfg $neu:
# Ab jetzt interaktiv auf dem neuen System - anmelden
ssh $neu</code></pre>
<p>
In der Windows Powershell kann man die Variablen leichter setzen als in der
CMD, dafür ist es immer wieder ein Abenteuer Programme (ssh scp) mit ein paar
Parametern aufzurufen:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false"># Variable setzen
$alt='pi@raspib3'
$neu='otto@vmdebianfhem'
$pfad='/opt/fhem'
# letztes Backup ermitteln
$datei=$( ssh $alt -t "ls -rt1 $pfad/backup | tail -1|tr -d '\n'" )
# die Dateien holen - die Setzung der Klammern und Hochkommas ist eine echte Hürde
scp "${alt}:${pfad}/{backup/${datei},fhem.cfg}" .
# die Dateien aufs neue System schaffen
scp ${datei} fhem.cfg ${neu}:
# Ab jetzt interaktiv auf dem neuen System - anmelden
ssh $neu</code></pre>
<p>
Es gibt verschiedene Möglichkeiten Strings aus Zeichen und Variablen
zusammenzusetzen. Die Zeile mit scp berücksichtigt folgendes:
</p>
<p></p>
<ul style="text-align: left;">
<li>
Die Parameterübergabe an scp erfordert zwei getrennte Strings: quelle und
ziel.
</li>
<li>
Die doppelten Anführungszeichen erzeugen einen String und ermöglichen die
Auflösung von Variablen innerhalb.
</li>
<li>
Die geschweifte Klammern (braces) ${variable} grenzen den Namen von den
anderen Zeichenketten ab. Beim Doppelpunkt ist das existenziell, beim
Schrägstrich könnte man es auch weglassen.
</li>
<li>
Achtung: zwei geschweifte Klammern im String "pfad/{datei1,datei2}" bewirken
im Linux die "Brace Expansion" und haben nichts mit Variablen zu tun.
Interessanterweise muss man sie, im Gegensatz zur Linuxshell, in der
Powershell nicht schützen/escapen.
</li>
<li>
Konsequenterweise müsste das Ziel (der Punkt) auch in "." gesetzt werden, es
funktioniert aber ohne.
</li>
</ul>
<p></p>
<p>ToDo?</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Das ist mein Platzhalter für Erweiterungen.</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com23tag:blogger.com,1999:blog-5611886937451692837.post-64632505327657267652022-08-10T12:00:00.132+02:002022-08-20T18:41:06.905+02:00Scripts anheften<p>
will man sich Abläufe per Script (cmd oder ps1) leicht erreichbar machen,
möchte man diese an die Taskleiste oder an den Start anheften. Dies
funktioniert leider nicht direkt mit einem Link auf das Script, man muss den
Aufruf komplett in den Link schreiben.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">C:\WINDOWS\system32\cmd.exe c:\tools\scripts\script1.cmd</code></pre>
<p>
Man kombiniert damit den kompletten Pfad des aufrufenden Programmes mit dem
kompletten Pfad zum Script in einem Link und jetzt kann man auch noch ein anderes Symbol
zuordnen. <span></span>
</p>
<a name='more'></a>
<p></p>
<h3 style="text-align: left;">Link interaktiv erstellen</h3>
<p>Schnell erledigt:</p>
<p></p>
<ul style="text-align: left;">
<li>
Link auf das Script erstellen - Windows 11: rechte Maustaste / weitere
Optionen / Verknüpfung erstellen.
</li>
<li>Die Linkdatei entsteht im gleichen Pfad. Eigenschaften öffnen.</li>
<li>An erster Stelle das aufrufenden Programm schreiben, Beispiel: cmd</li>
<li>
Übernehmen drücken, Windows ersetzt den Programmnamen mit dem kompletten
Pfad.
</li>
<li>Nach Belieben kann man jetzt noch </li>
<ul>
<li>den Namen der Verknüpfung, </li>
<li>den Pfad in dem gestartet werden soll und </li>
<li>das Symbol geändert werden. </li>
</ul>
<li>Final kann man mit der rechten Maustaste: </li>
<ul>
<li>An Start anheften, </li>
<li>weitere Optionen anzeigen / an Taskleiste anheften</li>
<li>den Link an einen anderen Ort kopieren: weitere Optionen anzeigen / senden an / Desktop</li>
</ul>
</ul>
Symboldateien findet man z.B.:
<p></p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">%systemroot%\system32\shell32.dll
%systemroot%\system32\wmploc.dll</code></pre>
<p>Es gibt aber noch andere Symboldateien: <a href="https://www.netzwelt.de/anleitung/180100-windows-10-so-aendert-icons-programmen-ordnern.html" target="_blank">Link</a></p>
<h3 style="text-align: left;">Link an anderem Ort erstellen</h3>
<p>
Man kann natürlich auch beim erstellen eines neuen Links einfach den
kompletten Aufruf mitgeben.
</p>
<p>Der Pfad zum Programm findet man in der cmd</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">where cmd
C:\Windows\System32\cmd.exe
where powershell
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</code></pre>
<p>alternativ auch in der Powershell</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">gcm cmd.exe|select source
Source
------
C:\WINDOWS\system32\cmd.exe
gcm powershell|select source
Source
------
C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe</code></pre>
<h3 style="text-align: left;">Menüs in der Taskleiste unter Windows 11</h3>
<p>
Die gibt es leider nicht mehr. Ich hatte einen Pfad mit Verknüpfungen zu all
meinen ssh Host drin. Diesen Pfad kann man ersatzweise an den Start oder an
den Schnellzugriff (Kontextmenü vom Dateiexplorer) anheften - nicht ganz so
schön aber ein Würgaround.
</p>
<p>Das ist mein Platzhalter für Erweiterungen.</p>
<p>noch zu tun?</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Ende</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com1tag:blogger.com,1999:blog-5611886937451692837.post-91355781482161064552022-08-02T12:00:00.012+02:002022-10-07T13:06:17.706+02:00UEFI Start manipulieren<p>
Mal eben von einem externen Laufwerk ein anderes System starten: USB Laufwerk
einstecken, Restart ausführen - Mist - wie war die Taste für das Bootmenü? Ach
ja: F7 - Mist zu langsam gedrückt - neuer Versuch.
</p>
<p>Dieses Vorgehen ist doch echt nervig!? </p>
<p>
Es geht eventuell auch anders: Mit BCDEdit (Windows) und efibootmgr (Linux) hat man
Tools um per Kommandozeile den (nächsten) Start des Rechners zu beeinflussen.
Also neuer Versuch: USB Laufwerk einstecken, Script für den Restart ausführen
und entspannt zuschauen wie präzise das gewünschte System ausgeführt wird. So
könnte es gehen - mal schauen wie weit ich komme. Das wird erstmal ein
Arbeitsdokument.<span></span>
</p>
<a name='more'></a>
<p></p>
<h2 style="text-align: left;">Nächster Start: einen EFI Eintrag starten</h2><h3 style="text-align: left;">Erster Versuch für Windows</h3><p>Zunächst muss man die aktuelle Konfiguration ermitteln (CMD oder Powershell im Admin Kontext):</p><pre class="language-bash"><code contenteditable="" spellcheck="false">bcdedit /enum firmware</code></pre><p>Was man hier sieht ist wieder stark vom BIOS abhängig. Ein gesteckter bootfähiger USB Stick wird erst nach einem Neustart gelistet. Manches BIOS enthält aber funktionierende "Platzhalter" für UEFI: USB Stick, UEFI: DVD Laufwerk usw. die können auch ohne extra Neustart sofort funktionieren. </p><p>Mann braucht im Folgenden die UID aus dem Bezeichner (ist lokalisiert), die description (ist immer english) verrät einem eventuell Details. Mit Powershell könnte man einen exakt bekannten Eintrag auslesen (Idee)</p><pre class="language-bash"><code contenteditable="" spellcheck="false">bcdedit /enum firmware|Select-String "UEFI: JetFlashTranscend 16GB 1.00" -Context 1,1|%{ $_.context.Precontext[0]}</code></pre><div>Das folgende Script prüft am Anfang ob es erhöhte Rechte besitzt und startet sich selbst neu. Der Befehl erzeugt einen neuen Eintrag bootsequence, der beim nächsten Start wieder gelöscht wird.</div><p><b>Achtung</b>: Für bcdedit in PS muss man die Parameter in den Klammern {} in Anführungszeichen setzen "{}".</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Start-Process PowerShell -Verb RunAs "-NoProfile -ExecutionPolicy Bypass -Command `"cd '$pwd'; & '$PSCommandPath';`"";
exit;
}
bcdedit /set "{fwbootmgr}" bootsequence "{4bfeac0b-4770-11ea-a143-806e6f6e6963}"
shutdown /r /t 01</code></pre>
<p>Hilfe: bekommt man mit bcdedit /? und weitere z.B. bcdedit /? set, bcdedit /? types, bcdedit /? formats</p><h3 style="text-align: left;">Zweiter Versuch für Linux </h3><p>Mit dem Tool efibootmgr erhält man die Liste der Einträge und der aktuellen Reihenfolge. Mit efibootmgr -n <Eintrag in HEX> kann man die Reihenfolge für den nächsten Start ändern. Man bekommt dies auch einfach angezeigt. Mit bcdedit /enum firmware wird sie auch angezeigt allerdings in UIDs und damit schwierig lesbar.</p><pre class="language-bash"><code contenteditable="" spellcheck="false">efibootmgr -n 0000</code></pre><p>Die EFI Bootreihenfolge statisch ändern</p><p>efibootmgr -o 5,2,3,4,1,0 </p><p>bcdedit /set {fwbootmgr} displayorder {bootmgr/oder UID} /addfirst</p><h3 style="text-align: left;">Fazit</h3><p>Leider hat jedes UEFI - sehr Herstellerspezifisch - ein gewisses "Eigenleben". Oder sind das Bugs in der Firmware? Wenn man die obigen Befehle in einer Hyper-V Gen2 Maschine testet funktioniert alles nachvollziehbar. Auf einer Hardware mit EFI Bios lief es unklar... </p><p>Ich bin noch nicht sicher ob man dies wirklich präzise beherrschen kann. </p>
<p>Noch ein paar Links</p><p><a href="http://www.mistyprojects.co.uk/documents/BCDEdit/files/examples4.htm" target="_blank">http://www.mistyprojects.co.uk/documents/BCDEdit/files/examples4.htm</a><br /></p><p><a href="https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order">https://github.com/mmseng/bcdedit-revert-uefi-gpt-boot-order</a></p>
<p><a href="https://oofhours.com/2022/02/15/windows-11-includes-new-bcd-powershell-cmdlets/">
https://oofhours.com/2022/02/15/windows-11-includes-new-bcd-powershell-cmdlets/
</a></p>
<p><a href="https://stackoverflow.com/questions/16903460/bcdedit-bcdstore-and-powershell">
https://stackoverflow.com/questions/16903460/bcdedit-bcdstore-and-powershell
</a></p><p><a href="https://aps2.support.emea.dynabook.com/kb0/TSB1203QJ0000R01.htm">https://aps2.support.emea.dynabook.com/kb0/TSB1203QJ0000R01.htm</a></p>
<p>noch zu tun?</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Das ist mein Platzhalter für Erweiterungen.</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-45550275167155800932022-06-10T13:50:00.006+02:002022-06-11T12:23:12.135+02:00Headless Setup Raspberry 2022RaspiOS hat im April 2022 ein paar einschneidende Änderungen erfahren:
<div>
<ol style="text-align: left;">
<li>Andere Kompression des Images, früher zip jetzt img.xz</li>
<li>
Kein Standardbenutzer mehr im System, damit ändert sich das
<a href="https://www.raspberrypi.com/documentation/computers/configuration.html#setting-up-a-headless-raspberry-pi" target="_blank">Headless Setup</a>.
</li>
</ol>
</div>
<p>An dieser Stelle ein paar Tipps:<span></span></p><a name='more'></a><p></p>
<p>
Man sollte unter Windows jetzt nur noch mit dem <a href="https://www.raspberrypi.com/software/" target="_blank">Raspberry Pi Imager</a> arbeiten, der ermöglicht neben dem download der aktuellen Version auch das Headless Setup und die Einrichtung des
Benutzers! Der Imager erzeugt ein einmalig auszuführendes Shell Script. </p><p>Alternativ arbeitet man mit 2-3 zusätzlichen Text Dateien in der boot Partition:</p>
<p>
Für Linux habe ich
<a href="https://heinz-otto.blogspot.com/2021/02/bootstick-fur-den-raspberrypi.html" target="_blank">hier</a> im Nachtrag einen Weg für die Kommandozeile aufgezeigt.
</p>
<p>Möchte man die alten Wege in Windows nicht verlassen, kann man auch so arbeiten:</p>
<p></p>
<ul style="text-align: left;">
<li>Das img.xz Image mit 7-zip entpacken.</li>
<li>Die img Datei mit dem gewohnten windisk32imager auf die SD Card schreiben.</li>
<li>
Die Dateien ssh, userconf.txt und bei Bedarf die wpa_supplicant.conf in das
Laufwerk mit der Boot Partition kopieren. </li></ul>Den Inhalt der Datei userconf.txt
kann man sich leicht mit dem persönlichen Standarduser in einer Linux Konsole
vorbereiten.<br /><ul style="text-align: left;">
</ul>
<div>Hat man im Netzwerk einen Linux Rechner, kann man alles zusammen auch in der cmd von Windows erledigen:</div>
<p></p>
<pre class="language-markup"><code contenteditable="" spellcheck="false">set lw=E
echo " " >%lw%:\ssh
(
echo|set/p=user:
ssh pi@raspib3 "echo 'password' | openssl passwd -6 -stdin"
)>%lw%:\userconf.txt</code></pre>
<p>
Hinweis: der erste Start von der so vorbereiteten SD Card dauert bei einem Pi3+ bis zu ca. 10 min bis zum login!</p><p><br /></p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-51254966026231193942022-04-06T16:15:00.009+02:002023-12-19T17:13:41.299+01:00andocken - Dinge die man außerhalb docker braucht<p>Netzwerke, Laufwerke und seriellen Geräte funktionieren relativ einfach in der Containerumgebung. Mit Sound, Bluetooth, Wake on Lan usw. wird es schon schwieriger. Die sind nicht vorgesehen. Docker soll Softwarepakete/Applikationen isolieren und dicht "packen". Das man seine PC Umgebung dort hineinverlegt war so nicht unbedingt gedacht. Und es gibt natürlich "Übergangsbereiche" - Smarthome zum Beispiel. Ich habe ein paar Anforderungen für die ich eine Lösung brauche. Vielleicht ist es ja gar keine Behelfslösung sondern eine clevere Alternative? Folgende Themen habe ich bisher gefunden:</p>
<ol>
<li><a href="#sound">Sound</a></li>
<li><a href="#bluetooth">Bluetooth</a></li>
<li><a href="#wol">WakeOnLan bzw. ssh nutzen </a></li>
</ol>
<a name='more'></a>
<h2 style="text-align: left;"><a id="sound"></a>Sound</h2>
<p>Ich habe ein paar Varianten gefunden, für mich aber beschlossen den Pulseaudioserver über das Netzwerk zu nutzen. <a href="https://github.com/mviereck/x11docker/wiki/Container-sound:-ALSA-or-Pulseaudio" target="_blank">Link</a>.</p>
<p>Vorbereitung: <a href="https://heinz-otto.blogspot.com/2022/03/debian-setup-mal-nicht-all-inclusive.html#pulseaudio" target="_blank">Pulseaudio einrichten</a>, als system-wide Service mit Netzwerkschnittstelle.</p>
<p>Im Docker Container ist nicht viel zu tun:</p>
<ul style="text-align: left;">
<li>Im Image selbst muss natürlich Pulseaudio enthalten sein, das bläht das Image leider erheblich auf (in meinen Versuchen mehr als 300 MB). </li>
<li>Umgebungsvariable setzen: vor jede Applikation oder gleich beim Bau des Containers. </li>
</ul>
<p>3 Beispiele: direkter Aufruf, docker run ..., docker-compose.yml</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">"PULSE_SERVER=hostname play https://cdn.smartersoft-group.com/various/pull-bell-short.mp3"
-e PULSE_SERVER=hostname
environment:
- PULSE_SERVER=hostname</code></pre>
<p>Bei mir hat das ohne weitere Konfiguration sofort funktioniert.</p>
<h2 style="text-align: left;"><a id="bluetooth"></a>Bluetooth - Anwesenheit feststellen</h2>
<p>Bluetooth ist von der Technik her ein Netzwerkdienst, Netzwerkdienste haben eine besondere Behandlung im Docker, ein direktes Durchreichen der Hardware für Netzwerke ist nicht vorgesehen. Obwohl Bluetooth Hardware häufig über serielle Schnittstellen angebunden ist, ist auch vom Linux System die Zugänglichkeit von Bluetooth über ein serielles Interface nicht vorgesehen. Man muss also die Bluetooth Schnittstelle auf dem Host nutzen und die Ergebnisse zum Container weiterreichen, am einfachsten über Netzwerk. Für die Anwesenheitserkennung gibt es ein Perlscript welches auch eine Schnittstelle zum PRESENCE Modul hat. Ich zeige kurz wie man das Script als Systemd Dienst im Host installiert und die Abfrage im Docker einbindet.</p>
<p>Falls noch nicht erfolgt: bluetooth nachinstallieren.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt update
sudo apt install bluetooth
</code></pre><p>Das Perlscript presenced laden.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo -s <<EOI
mkdir -p /opt/scripts
wget -O /opt/scripts/presenced https://svn.fhem.de/fhem/trunk/fhem/contrib/PRESENCE/presenced
EOI</code></pre>
<p>Einen Service einrichten</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">service=presenced
cat <<EOISERV |sudo SYSTEMD_EDITOR=tee systemctl edit --full --force $service
[Unit]
Description=$service Daemon
Wants=network.target
After=network.target
[Service]
Type=forking
WorkingDirectory=/opt/scripts
ExecStart=/usr/bin/perl presenced -d
Restart=always
[Install]
WantedBy=multi-user.target
EOISERV</code></pre>
<p>Den Service aktivieren und starten</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo systemctl enable --now $service</code></pre>
<p>FHEM Device anlegen</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">define Name PRESENCE lan-bluetooth 11:22:33:44:55:66 192.168.x.x:5111</code></pre>
<p>Mal sehen ob ich noch mehr finde.</p>
<h2 style="text-align: left;"><a id="wol"></a>Wake on Lan - oder Limitierungen im Netzwerk umgehen</h2>
<p>UDP Broadcasts wie sie für WOL verwendet werden, funktionieren aus Docker heraus ins allgemeine Netzwerk nicht. Es gibt auch andere Applikationen, wo man auf einen anderen Rechner zugreifen muss. Der ssh Zugriff ist hierbei ein weitverbreitetes Mittel der Wahl. Damit man diesen Zugriff transparent im Hintergrund und trotzdem sicher machen kann, muss man den Prozess (User) mit einem Austausch der öffentlichen Schlüssel und Host Informationen einmalig einrichten. Ich habe die Einrichtung "ssh mit publickey" <a href="https://heinz-otto.blogspot.com/2020/09/ssh-mit-public-key.html" target="_blank"><strong>hier</strong> </a>schon ausführlich beschrieben. Natürlich kann man aus dem Container auch auf den Dockerhost per ssh zugreifen. Viele Module in FHEM haben die Möglichkeit schon eingebaut. </p>
<p><b>Vorbereitung: </b><a href="https://heinz-otto.blogspot.com/2020/09/ssh-mit-public-key.html" target="_blank"><b>ssh public key Zugriff </b></a>auf den gewünschten Host (Dockerhost) einrichten. Auf dem Host selbst muss nichts extra installiert werden.</p>
<p>Der ssh Zugriff an sich ist vielseitig nutzbar. Viele FHEM Module haben die Nutzung direkt eingebaut. Ich zeige 3 Varianten für WOL, wobei Variante 2 nicht mit ssh arbeitet. Die Variante 1 kann völlig unabhängig auch für andere Aufgaben dienen. Ich habe deswegen auch den Einzeiler in einen Here String verpackt, man kann auf die Art in den meisten Fällen 1:1 den Code aus Shell Scripts übernehmen!</p>
<h3 style="text-align: left;">Variante 1 - sub in der myUtils</h3>
<p>Für FHEM habe ich eine sub in der 99_myUtils verankert, die am Ende ein bash Script per ssh ausführt. Man hat hierbei die Schwierigkeit, in den einzelnen Schritten richtig mit Variablen und deren Auflösung umzugehen. Deswegen habe ich aus dem Shell Code eine function mit Aufrufparametern gemacht und diese in einen single quoted Here String gepackt. Am Ende habe ich diesen String um den Aufruf der function mit Parametern erweitert, da diese Erweiterung double quoted ist, werden die übergebenen Perl Variablen aufgelöst. Prinzipiell lässt sich über den "Here String" shell code 1:1 verwenden.</p>
<pre class="language-perl"><code contenteditable="" spellcheck="false">sub wol {
my $usage = 'use: wol \'user@host\',\'aa:bb:cc:11:22:33\'';
my $ziel = shift // return $usage;
my $mac = shift // return $usage;
my $broadcast = shift || '255.255.255.255';
my $port = shift || '9';
my $script = <<'EOF';
wake_on () { echo -e $(echo $(printf 'f%.0s' {1..12}; printf "$(echo $1 | sed 's/://g')%.0s" {1..16}) | sed -e 's/../\\x&/g') | nc -w1 -u -b $2 $3 ; }
EOF
$script .= "wake_on $mac $broadcast $port";
system('ssh',$ziel,$script);
}</code></pre>
<p>Beispielhaft die Definition in FHEM mit der Perl Sub</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">define myPC WOL 11:22:33:44:AB:CD 192.168.22.33 CMD
attr myPC wolCmd {wol ('user@host', '$MAC', '$BC')}</code></pre>
<h3 style="text-align: left;">Variante 2 - Weckruf über die Fritzbox und tr064</h3>
<p>Hat man eine Fritzbox kann man diese mit dem Fritzbox Modul für WOL verwenden.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">attr myPC wolCmd get Fritzbox tr064Command Hosts:1 hosts X_AVM-DE_WakeOnLANByMACAddress NewMACAddress $MAC</code></pre>
<p>ToDo: Voluminöse Rückmeldung des tr064 Kommandos unterdrücken. </p>
<h3 style="text-align: left;">Variante 3 - Script auf einem Host (Dockerhost) ausführen </h3>
<p>Man kann ein Bash Script auch auf dem Dockerhost ablegen und dort per ssh ausführen. </p>
<p>Im Terminal auf dem Dockerhost das Script erzeugen, oder ein anderes Script herunterladen und dort ablegen (<a href="https://forum.fhem.de/index.php/topic,115793.msg1101835.html#msg1101835" target="_blank">siehe Beitrag</a>).</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">cat <<'EOF' > wake_on
echo -e $(echo $(printf 'f%.0s' {1..12}; printf "$(echo $1 | sed 's/://g')%.0s" {1..16}) | sed -e 's/../\\x&/g') | nc -w1 -u -b $2 $3
EOF</code></pre>
<p>Das Modul hat die ssh Möglichkeit eingebaut (separat für aufwachen und shutdown).</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">attr myPC sshHost user@192.168.2.22
attr myPC wolCmd "bash wake_on $MAC $BC 9"</code></pre>
<p>Zu beachten ist, dass hier wolCmd den Regeln von Fhem Kommandos entspricht.</p>
<h2 style="text-align: left;">ToDo </h2>
<p>noch zu tun?</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>Das ist mein Platzhalter für Erweiterungen.</p>Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-74320576019741868112022-03-28T14:11:00.031+02:002023-07-24T13:44:31.438+02:00debian - Setup mal nicht all inclusive<p>
Ich bin es ja gewöhnt so etwas wie Raspberry OS Lite zu installieren. Da ist
eigentlich erstmal alles dabei. Wenn man mal andere Hardware hat und mit einem
<a href="https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/">debian-xxx-netinst.iso</a> beginnt, merkt man schnell was so alles "fehlt".
</p>
<p>
Es geht schon beim Setup los, wenn die Bemerkung kommt: Es werden
Treiber/Firmware benötigt - hätte man dann eventuell mit einem
<a href="https://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/current/" target="_blank">"inoffiziellen Firmware" Image </a>starten sollen? Wenn man Glück hat, läuft die Installation erstmal durch,
dann sollte (muss?) man später nacharbeiten.
<a href="https://www.debian.org/releases/stable/amd64/ch06s04" target="_blank">Link</a>.
</p>
<p>
Anmerkung: inoffziell oder non-free bezieht sich mehr oder weniger auf die
Lizenzbedingungen unter der einige Hersteller ihre Linux Firmware
veröffentlichen (war bei mir z.B. für Realtek und Intel Netzwerkadapter der
Fall)
</p>
<p>
Dieser Artikel ist in den dargestellten Schritten schon nutzbar, an ihm wird
aber aktuell gearbeitet!
</p>
<a name='more'></a>
<p></p>
<h2 style="text-align: left;">Grundsetup</h2>
<p>
<span>Auf der
<a href="https://www.debian.org/releases/jessie/i386/apas02.html.de" target="_blank">debian Installer Seite</a>
liest es sich einfach: Man soll einfach das ISO Image auf einen USB Stick
schreiben. Aber wie genau? Unter Windows funktioniert das mit dem
portablen <a href="https://rufus.ie/de" target="_blank">Tool Rufus</a>.
Man braucht nichts installieren und die Bedienung ist intuitiv.</span>
</p><p><b>Nachtrag Juli 2023</b>: Mit debian bookworm wird die erforderliche Firmware direkt ausgeliefert (das netinst Image ist jetzt nicht mehr 3xx MB sondern 6xx MB groß). Die folgenden Schritte in diesem Abschnitt sind nicht mehr notwendig.</p>
<p>
<span><b>Achtung</b>: Verwendet man ein "Firmware" Image, muss man bei der
abschließenden Frage nach dem Schreibmodus den dd-Modus wählen! Ansonsten
ist das Firmware Image nutzlos, die zusätzliche Firmware wird vom Installer
nicht erkannt.</span>
</p>
<p>
<span>Mit meinem MeLe Quieter2Q (J4125/8 GB Ram/256 GB eMMC) lief das Setup mit
einem kleinen <a href="https://www.debian.org/CD/http-ftp/" target="_blank">CD Image </a>trotz fehlender Firmware erstmal durch, ich hatte auch eine
Netzwerkverbindung. Wenn das nicht funktioniert wäre man mit einem "netinst"
Image natürlich aufgeschmissen. Dann braucht man entweder eines
<a href="https://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/current/amd64/iso-cd/" target="_blank">mit Firmware</a> oder lädt ein komplettes Image herunter.</span>
</p>
<p>
<span>Mit dmesg konnte ich aber im Nachgang 3 Meldungen zu fehlender Firmware
finden. Ich habe die </span>/etc/apt/sources.list um non-free contrib erweitert und die Firmware
nachinstalliert:
</p>
<p>
Die sed Codezeile kann die Erweiterung direct in der sources.list vornehmen, diese
Version ist zum Test. Wenn der erfolgreich ist, kann man mit sed -i ...
wirklich ausführen. (alle Zeilen erfordern sudo )
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">cp /etc/apt/sources.list /etc/apt/sources.list.sav
sed '/^deb/ s/$/ non-free contrib/' /etc/apt/sources.list
apt update
apt install firmware-linux-nonfree firmware-realtek firmware-iwlwifi</code></pre>
<p>
Die Fehlermeldung "firmware: failed to load iwl-debug-yoyo.bin" ist allerdings
geblieben, das ist wohl ein Bug in der Firmware selbst. </p><p><b>Nachtrag Juli 2023</b>: offenbar ist der Fehler ab Bullseye behoben. </p>
<a name="sound"><h2 style="text-align: left;">Sound</h2></a>
<p>
Da ist erstmal gar nichts installiert. Bei Raspberry OS hat das immer sofort
funktioniert. Also erstmal einlesen <a href="https://wiki.debian.org/Sound" target="_blank">https://wiki.debian.org/Sound</a>
</p>
<p>
Ich habe bisher (vor allem im Zusammenhang mit Bluetooth Lautsprechern) nie
ganz verstanden warum es so viele Soundsysteme bei Linux gibt. Das muss ich
jetzt wohl ansatzweise nachholen.
</p>
<h3 style="text-align: left;">Grundlage alsa</h3>
<p>
Ich hoffe diese Pakete bilden die richtige Grundlage (vielleicht braucht man
das empfohlene Paket libasound2-plugins nicht? Alsa funktioniert beim zweiten
Versuch erstmal ohne)
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt update
sudo apt install libasound2 alsa-utils
# apt install libasound2-plugins</code></pre>
<p></p>
<p>
Von Raspberry OS weiß ich noch, da gibt es ein paar Sounddateien und einen
Speakertest (Vorsicht! u.U. sehr laut! ctrl+c bereithalten):
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">aplay /usr/share/sounds/alsa/Noise.wav
speaker-test -t sine -f 440 -c 2 -s 1</code></pre>
<p></p>
<p>
Nichts zu hören - ok mit aplay -l oder cat /proc/asound/cards kann man die
Soundkarten auflisten. Da gibt es bei mir viele Einträge: Karte 0 - mit 5 HDMI
Kanälen und Karte 1 als USB gekennzeichnet, letztere ist der Analogausgang.
Damit dieser als default verwendet wird, muss man eine Datei /etc/asound.conf
erstellen: (kurze Version <a href="https://www.alsa-project.org/wiki/Setting_the_default_device" target="_blank">Link</a> )
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo sh -c 'cat > /etc/asound.conf' <<EOI
defaults.pcm.card 1
defaults.ctl.card 1
EOI</code></pre>
<p>
Jetzt ist der Speakertest laut zu hören, denn mein User ist in der Gruppe
audio! Die Lautstärke kann man mit dem alsamixer herunterregeln.
</p>
<p>
Hinweis: Man kann das Audiodevice auch über die Umgebung
setzen: AUDIODEV=hw:1
</p>
<p>
Damit man außer wav Dateien auch andere Sounds (z.B. mp3) wiedergeben kann,
braucht man einen Player. Der oft verwendete mplayer hat bei mir in der
Vergangenheit keinen guten Eindruck hinterlassen, er ist auch zu "groß". Ich
installiere den schmalen sox player und teste sofort mit einer Sounddatei aus
dem Internet:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt install sox libsox-fmt-all
play https://cdn.smartersoft-group.com/various/pull-bell-short.mp3
play -q https://cdn.smartersoft-group.com/various/pull-bell-short.mp3 2>/dev/null</code></pre>
<p></p>
<p></p>
<p></p>
<p>
Anmerkung: Die erste play Zeile liefert neben allen Details auch eine
permanente Warnung "play WARN alsa: can't encode 0-bit Unknown or not
applicable", die bekommt man nur mit der Umleitung ins Null Device weg.
2>/dev/null
</p>
<h3 style="text-align: left;"><a name="pulseaudio">PulseAudio</a></h3>
<p>
Ich habe keine einfache Beschreibung gefunden. Überall wird es so beschrieben
als läuft alles automatisch und es ist überflüssig darüber zu schreiben. Viele
Beschreibungen gehen von Desktop Systemen aus, mag sein dass dort alles
komplett funktioniert und keiner weiß warum. Ob das ein paar Jahre alte
<a href="https://forum.fhem.de/index.php/topic,50967.msg428810.html#msg428810" target="_blank">Tutorial für FHEM</a> von der Zeit überholt wurde?
</p>
<p>
<a href="https://wiki.debian.org/PulseAudio" target="_blank">Hier </a>steht
wenigsten das Basis Setup.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo apt install pulseaudio</code></pre>
<p>
Jetzt kann man pulseaudio als "default Sound" einrichten - ob das sinnvoll ist
kann ich nicht sagen, es funktioniert - nach abmelden und wieder anmelden. Die
Warnung aus dem vorherigen Abschnitt kommt nicht mehr.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo sh -c 'cat > /etc/asound.conf' <<EOI
pcm.default pulse
ctl.default pulse
EOI</code></pre>
<p>
Achtung! Der pulseaudio Server läuft jetzt nur im user mode, d.h jeweils nur
wenn ein Benutzer angemeldet ist! Kein Benutzer angemeldet, keine Sound! Ein
Service user fhem kann den pulseaudio Sound so nicht benutzen!
</p>
<p>
Ich wollte eigentlich pulseaudio "remote" bzw. aus docker nutzen.
<a href="https://comp0016-team-24.github.io/dev/problem-solving/2020/10/30/passing-audio-into-docker.html" target="_blank">Hier </a>steht: pulseaudio wäre der richtige Weg! Nach einigen Versuchen wird mir
klar: Das Beste für mein Vorhaben wäre ein Dienst, der unabhängig vom User
läuft und eine Netzwerkschnittstelle zur Verfügung stellt.
</p>
<h4>PulseAudio Server</h4>
<p>
In dieser Betriebsart startet der Service mit dem System und lauscht auf Port
4713 auf Clientverbindungen.
</p>
<p>Ein schneller Test</p>
<p>
Man kann man den user pulseaudio Prozess beenden und einen system-wide Prozess
starten. Dieser übersteht Ab- und Anmeldung und läuft so unabhängig vom
User.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">pulseaudio -k
sudo pulseaudio --daemonize=yes --system --realtime --log-target=journal --load="module-native-protocol-tcp auth-anonymous=1"</code></pre>
<p>
Auf einem Client, der ebenfalls pulseaudio installiert hat, kann man jetzt
einfach über die Umgebungsvariable das Audiosignal umleiten:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">PULSE_SERVER=ServerName <Befehl wie play, speakertest></code></pre>
<p>
An den Berechtigungen / Gruppen musste ich nichts ändern, zumindest die
Soundausgabe läuft mit der Gruppe audio.</p>
<h4 style="text-align: left;">PulseAudio Service Setup</h4>
<p>
Um diesen Modus final zu aktivieren gäbe es mehrere Wege. Auf alle Fälle muss
man den User Service am Start hindern und einen systemd Services
aktivieren. <a href="https://wiki.archlinux.org/title/PulseAudio#Starting_system-wide_on_boot" target="_blank">Link1</a> <a href="https://rudd-o.com/linux-and-free-software/how-to-make-pulseaudio-run-once-at-boot-for-all-your-users" target="_blank">Link2</a>
</p>
<p>Alle bisherigen PulseAudio Prozesse beenden und die user-level Services abschalten:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo kill $(pidof pulseaudio)
sudo systemctl --global mask pulseaudio.service pulseaudio.socket</code></pre>
<p>
Die system Service Unit schreiben: ich trage die erforderlichen Parameter
einfach hier ein und spare mir die extra Konfiguration in den
<a href="https://linux.die.net/man/1/pulseaudio" target="_blank">Konfigurationsdateien</a>. Diese kurze Script erzeugt mit einem einzigen C&P die unit Datei am
richtigen Ort und führt ein daemon-reload aus.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">service=pulseaudio
cat <<EOISERV |sudo SYSTEMD_EDITOR=tee systemctl edit --full --force $service
[Unit]
Description=$service Service
# DO NOT ADD ConditionUser=!root
[Service]
# Note that notify will only work if --daemonize=no
Type=notify
ExecStart=/usr/bin/pulseaudio --daemonize=no --system --realtime --log-target=journal --load="module-native-protocol-tcp auth-anonymous=1"
Restart=always
[Install]
WantedBy=default.target
EOISERV</code></pre>
<p>Den neuen pulseaudio Service aktivieren:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo -s <<EOI
systemctl --system enable $service
systemctl --system start $service
EOI</code></pre>
<p>Das Setup ist erstmal funktionsfähig.</p>
<h4 style="text-align: left;">Der Weg zur Erkenntnis</h4>
<p>
Folgendes Setup hat erstmal funktioniert (<a href="https://rotelok.com/configuring-pulse-audio-to-use-a-remote-server/" target="_blank">der entscheidende Hinweis</a>):
</p>
<p>
Auf dem Server muss man einen Eintrag im Abschnitt network access aktivieren
(# entfernen) und ergänzen:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">load-module module-native-protocol-tcp auth-anonymous=1</code></pre>
<p>Die Änderung macht man <i>entweder </i>manuell mit nano:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">sudo nano /etc/pulse/default.pa</code></pre>
<p><i>oder </i>automatisch mit sed:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">string='load-module module-native-protocol-tcp'; sed -i "/^#$string$/ s/$/ auth-anonymous=1/;s/^#$string/$string/" /etc/pulse/default.pa</code></pre>
<p>
Nach einem Neustart des pulseaudio daemon (pulseaudio -k ; pulseaudio -D)
lauscht pulseaudio auf Port 4713.
</p>
<p>
Auf einem Client, der ebenfalls pulseaudio installiert hat, kann man jetzt
einfach über die Umgebung das Audiosignal umleiten:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">PULSE_SERVER=ServerName speaker-test -t sine -f 440 -c 2 -s 1</code></pre>
<p>Erstmal geschafft. Was funktioniert jetzt?</p>
<p>
Mit der veränderten asound.conf kann man jetzt aus mehreren Applikationen
gleichzeitig Sound abspielen zusätzlich auch über das Netzwerk. Mit
AUDIODEV=hw:1 funktioniert weiterhin der <b>exklusive </b>Zugriff auf alsa
direkt, allerdings nicht wenn etwas über pulseaudio läuft (Fehlermeldung).
</p>
<h2 style="text-align: left;">ToDo </h2>
<p>noch besser recherchieren und Beschreibung ausbauen</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p>text</p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0tag:blogger.com,1999:blog-5611886937451692837.post-31533063087823761732022-03-03T21:57:00.029+01:002022-04-03T12:51:03.897+02:00Dockerfile - Image für den Container selbst bauen<p>
Das hier ist mehr ein persönliche Machbarkeitsstudie und soll kein Ansatz für
ein dauerhaft gepflegtes Dockerimage werden. Ich wollte wissen wie es geht und
den Vorgang verstehen. herausgekommen ist erstmal ein kurzes Beispiel und ein
minimales FHEM Image.<span></span>
</p>
<p>
Kurz vornweg: Hier ein <a href="https://github.com/heinz-otto/raspberry/blob/master/Docker/buildFHEM.sh" target="_blank">Script </a>welches die gesamte docker Umgebung und das FHEM Image baut. Damit hat man
auf einem Intel PC in weniger als 2 min (Pi3 ca. 6 min) ein funktionierendes
FHEM.
</p>
<a name='more'></a>
<p></p>
<p>
Man braucht nicht viel: Ein
<a href="https://docs.docker.com/engine/reference/builder/" target="_blank">Dockerfile</a>, dazu eine Umgebung (Context) - das ist der Pfad mit dem Dockerfile und
ein paar Scipts o.ä.
</p>
<p>
<b>Achtung</b>: Der Context (das Verzeichnis wo das Dockerfile liegt) wird
beim build Prozess an den docker Prozess gesendet, dieser sollte also nur die
notwendigen Dateien enthalten! Sehr lesenswert ist dieses
<a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/" target="_blank">dockerfile best practice Guide</a>.
</p>
<h3 style="text-align: left;">Fingerübung zum Einstieg</h3>
<p>
Ein erstes praktisches Beispiel: ein aktueller debian Container mit ein paar
Packages. Zunächst einen leeren Context erzeugen.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">myPath=fingerExercise && mkdir -p $myPath && cd $myPath</code></pre>
<p>Man erzeugt eine Datei Dockerfile mit diesem Inhalt.</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">FROM debian
RUN apt update && apt install -y \
sendemail \
libcpanel-json-xs-perl \
libcrypt-rijndael-perl \
libfile-homedir-perl \
libhtml-treebuilder-xpath-perl \
libimage-librsvg-perl \
libnet-telnet-perl \
libsoap-lite-perl \
libxml-simple-perl \
libxml-xpath-perl \
&& rm -rf /var/lib/apt/lists/*</code></pre>
<p>
Anschließend wird das Image gebaut, entweder namenlos oder mit Namen (tag) und
Version. Der Punkt steht für den Pfad wo das Dockerfile liegt, den kann man
auch komplett angeben.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker build .
docker build -t debiantest:Basis .</code></pre>
<p>
Dieses Image ist nur nützlich, um es interaktiv auszuführen, es tut (startet)
selbst nichts.
</p>
<p>Beispiel: starte eine shell:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker run -it debiantest /bin/sh</code></pre>
<p><br /></p>
<h3 style="text-align: left;">Minimales FHEM Image</h3>
<p>Grundlage ist ein Alpine Image, in dem Dockerfile werden </p>
<p></p>
<ul style="text-align: left;">
<li>einige Pakete installiert, </li>
<li>ein paar Einstellungen (Zeitzone, Konsole) gemacht, </li>
<li>der User fhem erzeugt,</li>
<li>ein Startscript und ein Hilfscript eingebaut. </li>
</ul>
<p></p>
<p>2 Möglichkeiten</p>
<p></p>
<ol style="text-align: left;">
<li>
Man zieht den Dockerfile (und ev. die Scripts) vom <a href="https://github.com/heinz-otto/fhem-docker" target="_blank">Github </a>, kann Anpassungen vornehmen und der build Befehl ist analog zu oben.
</li>
<li>Oder man baut das Image einfach direkt mit der url ohne context:</li>
</ol>
<p></p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker build -t minifhem https://raw.githubusercontent.com/heinz-otto/fhem-docker/main/Dockerfile</code></pre>
<p>
Anmerkung: Es gibt viele Varianten wie man docker build aufrufen kann:
siehe <a href="https://docs.docker.com/engine/reference/commandline/build/" target="_blank">Dokumentation.</a>
</p>
<p>
Der build Vorgang kann mit der Option --build-arg PACKAGE_SIZE=full
angepasst werden.
</p>
<p>
Jetzt kann man einen FHEM Container starten, dazu wird noch ein Volume- und
Port-Mapping angefügt. Will man eine vorhandene FHEM Installation verwenden,
muss die vor dem Start nach ${HOME}/docker/fhem kopiert werden.
</p>
<p>Den (leeren) FHEM Arbeitspfad erzeugen:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">mkdir -p ~/docker/fhem</code></pre>
<p>
Entweder den Pfad mit einer frischen Version initialisieren oder ein Backup, im Homedir oder im lokalen /opt/fhem/backup mit restore einbinden:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker run -v "${HOME}/docker/fhem:/opt/fhem" -p "8083:8083" minifhem init tar
tar -xvzf ${HOME}/FHEM-20xxxxxx_xxxxxx.tar.gz -C ${HOME}/docker/fhem/
tar -xvzf /opt/fhem/backup/FHEM-20xxxxxx_xxxxxx.tar.gz -C ${HOME}/docker/fhem/</code></pre>
<p>FHEM Container starten:</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker run -v "${HOME}/docker/fhem:/opt/fhem" -p "8083:8083" minifhem</code></pre>
<h3 style="text-align: left;">FHEM Image auf debian Basis</h3>
<p>
Das wird sicher auf Dauer besser ankommen und zu pflegen sein. Ich habe hier
auch noch ein paar Erweiterungen zum Test eingebaut. Der Start erfolgt analog
zu oben.
</p>
<p>Argument PACKAGE_SIZE:</p><p></p><ul style="text-align: left;"><li>small - fhem.cfg.demo läuft, das Installermodul sagt: es fehlt an nichts!</li><li>full - meine FHEM Umgebung läuft damit (als default im Dockerfile gesetzt)</li><li>full_audio - pulseaudio integriert und Sound über Pulseaudio möglich (Imagesize fast verdoppelt)</li></ul><p></p><p><br /></p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker build -t debianfhem --build-arg PACKAGE_SIZE=small https://raw.githubusercontent.com/heinz-otto/fhem-docker/main/DockerfileDeb
docker run -v "${HOME}/docker/fhem:/opt/fhem" -p "8083:8083" --name testfhem debianfhem</code></pre>
<p>
Mit dem Installer Modul kann man mit diesem Image seine cfg testen. Diese muss
dazu einfach im docker/fhem Pfad (auf dem Host) liegen: Im Beispiel
<span style="font-family: courier;">fhem.cfg.test</span>
</p>
<p>
Achtung: Im aktuellen Homedir (Arbeitspfad) braucht man auch das ausführbare
<a href="https://github.com/heinz-otto/fhemcl" target="_blank">Script fhemcl.sh</a>.
</p>
<p>So sieht der Testablauf aus:</p>
<p>InstallerModul im frischen FHEM definieren </p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">echo "define installer Installer"|./fhemcl.sh
echo "attr installer installerMode developer"|./fhemcl.sh</code></pre>
<p>
apt-file aktualisieren (einmalig zur Laufzeit des Containers), dann die
fehlenden Module ermitteln.
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker exec testfhem apt-file update
cfg='fhem.cfg.test'
s=$(./fhemcl.sh 8083 "get installer checkPrereqs $cfg"|grep -oE 'installPerl.*&fwcsrf'|grep -oE '\s[a-z,A-Z,:]+\s')
echo $s|tr ' ' "\n"|sed '/^JSON/d;s/$/./;s/^/\//'|docker exec -i testfhem apt-file search -l -f -</code></pre>
<p>
Hat man die benötigten Module gefunden, kann man sie selbst im DockerfileDeb
im Abschnitt "full" integrieren und anschließend sein persönliches Image
erzeugen.
</p>
<p>Den Testcontainer kann man per FHEM Kommando auch wieder beenden</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">echo "shutdown"|./fhemcl.sh </code></pre>
<p><br /></p>
<h4 style="text-align: left;">Was läuft?</h4>
<p></p>
<ul style="text-align: left;">
<li>
FHEM läuft grundlegend, ich habe keine weiteren Modulabhängigkeiten
getestet. Aber es ist simpel weitere System Packages in das Image
einzubinden.
</li>
<li>FHEM wird wie "im richtigen Leben" mit user fhem gestartet</li>
<li>
Beim Aufruf des Containers kann das default Kommando
<i>start</i> überschrieben werden. Details dazu gibt es in der Readme in
github. Man kann z.B. das verbundene Verzeichnis (${HOME}/docker/fhem)
initialisieren:
</li>
<ul>
<li>Entweder über svn checkout die aktuelle Version,</li>
<li>oder der tarball 6.1 von der fhem.de Homepage.</li>
</ul>
<li>
Um FHEM zu überwachen wird
<span style="font-family: courier;">attr global pidfilename ./log/fhem.pid</span>
gesetzt. Die damit verbundene, eventuelle Veränderung der Konfiguration wird
nicht gespeichert. Achtung: Ist der Eintrag nicht in der config, klappt ein
shutdown restart nicht.
</li>
<li>
Das Eigentumsrecht des gesamten gemappten Pfades
(${HOME}/docker/fhem) wird beim Start auf User fhem gesetzt.
</li>
<li>
Telnetport 7072 wird nicht benötigt, es wird alles über HTTP Port 8083
gesteuert. Sollte dies mit allowed geschützt werden, müsste das Script
entry.sh angepasst werden.
</li>
</ul>
<p></p>
<h4 style="text-align: left;">Größe der Basis</h4>
<p>In debian ist von Haus aus wesentlich mehr drin.</p>
<p>
debian latest xxx 5 weeks
ago 100MB
</p>
<p>
alpine latest xxx 3 months
ago 3.81MB
</p>
<p>
Tipp: In den "Bauphasen" empfehle ich jedesmal vorm build ein löschen der
"Build Cache Umgebung"
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker image rm debianfhem -f
docker system prune</code></pre>
<p>
Wenn das Dockerfile fehlerhaft ist und "parse" Fehler auftreten, muss man den
build Prozess mit --force-rm starten:
</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">docker build --force-rm ...</code></pre>
<p><br /></p>
<p>ToDo?</p>
<pre class="language-bash"><code contenteditable="" spellcheck="false">Code Block</code></pre>
<p><br /></p>
Ottohttp://www.blogger.com/profile/11648355618659397396noreply@blogger.com0