<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Docker on SecretMine.de</title><link>https://secretmine.de/tags/docker/</link><description>Recent content in Docker on SecretMine.de</description><generator>Hugo -- gohugo.io</generator><language>de-DE</language><lastBuildDate>Mon, 10 Aug 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://secretmine.de/tags/docker/index.xml" rel="self" type="application/rss+xml"/><item><title>Planka - leider keine Empfehlung mehr</title><link>https://secretmine.de/blog/2026/2026-08-10-planka-keine-empfehlung-mehr/</link><pubDate>Mon, 10 Aug 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-08-10-planka-keine-empfehlung-mehr/</guid><description>&lt;p&gt;Ich habe Planka lange gerne eingesetzt. Das hat sich leider geändert, da sich die Entwickler dazu entschlossen haben, Single-Sign-On in die kostenpflichtige Pro-Version zu verschieben und aus der Community-Version zu entfernen. Die Erläuterung der Entwickler lässt sich hier nachlesen: &lt;a class="link" href="https://github.com/plankanban/planka/issues/1754" target="_blank" rel="noopener"
 &gt;https://github.com/plankanban/planka/issues/1754&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;SSO ist für mich ein ziemlich grundlegendes Feature, vor allem bei OIDC. Ich kann generell auch verstehen, wenn Entwickler nicht alle Features kostenfrei anbieten möchten, aber ein bereits bestehendes Feature aus der kostenfreien Version zu entfernen bzw. kostenpflichtig zu machen, gefällt mir gar nicht. Außerdem ist SSO bei mir quasi Voraussetzung, vor allem bei den Tools, die meine Partnerin ebenfalls nutzt.&lt;/p&gt;
&lt;p&gt;Daher suche ich gerade eine Alternative. Mein Bruder ist mit Vikunja soweit glücklich, das werde ich mir selbst genauer ansehen. Auch gibt es Fork von einer früheren Version von Planka, das steht auch auf der Liste. Eine Migration ist für mich leider nicht so ganz einfach, da ich bspw. mit dem &lt;a class="link" href="https://secretmine.de/blog/2025/2025-09-20-plankaprinter-bondrucker/" &gt;PlankaPrinter&lt;/a&gt; die API von Planka nutze, um damit zu interagieren. Nextcloud Deck ist für mich leider keine Alternative, das kann zu wenig.&lt;/p&gt;
&lt;p&gt;Es wird ein weiterer Post folgen, wenn ich mich für etwas entschieden habe.&lt;/p&gt;</description></item><item><title>Firefly III - Self-Hosted und Open Source Haushaltsbuch</title><link>https://secretmine.de/blog/2026/2026-06-06-firefly-iii/</link><pubDate>Sat, 06 Jun 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-06-06-firefly-iii/</guid><description>&lt;p&gt;Firefly III ist ein Open-Source Tool zur Verwaltung persönlicher Finanzen. Es eignet sich ideal als Haushaltsbuch für den privaten Einsatz oder geteilte Konten in der Familie (oder für Paare) und bietet detaillierte Berichte für einen klaren Überblick.&lt;/p&gt;
&lt;h2 id="warum-überhaupt-so-ein-tool"&gt;Warum überhaupt so ein Tool?
&lt;/h2&gt;&lt;p&gt;Vorher fand das ganze in einer Excel-Tabelle statt, die wurde aber mit der Zeit immer komplexer. Deshalb habe ich mir eine Software dafür gesucht.&lt;/p&gt;
&lt;p&gt;Voraussetzung war aufgrund der Sensibilität ganz klar, dass ich es selbst betreiben können muss. Außerdem wollte ich ein verbreitetes System haben, wofür es auch schon Apps und ähnliches gibt. Gute Auswertungsmöglichkeiten waren mir auch wichtig.&lt;/p&gt;
&lt;p&gt;Firefly III ist eher auf Niveau einer Buchhaltungssoftware als ein Haushaltsbuch. Es gibt auch einfachere Tools wie beispielsweise Actual Budget. Alternativen hatten für mich aber zu wenig Features.&lt;/p&gt;
&lt;h2 id="installation-und-betrieb"&gt;Installation und Betrieb
&lt;/h2&gt;&lt;p&gt;Wie bei den meisten Dingen gibt es auch hierfür fertige Docker-Container, man findet auch offizielle Compose-Vorlagen. Der Stack besteht dabei aus der Anwendung, einer Datenbank (MariaDB) sowie einem Cron-Container. Von der Ressourcenauslastung her ist es eher auf der schlankeren Seite, also mehr als vertretbar.&lt;/p&gt;
&lt;h2 id="bedienung"&gt;Bedienung
&lt;/h2&gt;&lt;p&gt;Durch die Komplexität bzw. den Featureumfang ist Firefly anfangs etwas gewöhnungsbedürftig. Grundsätzlich bedient es sich aber ziemlich gut - Bestandskonten anlegen, danach kann man schon mit dem Anlegen von Transaktionen anfangen. Das lässt sich in Kategorien einteilen, Tags zuweisen und auch Budgets z.B. pro Monat definieren. Ich selbst nutze Firefly III nun seit 3 Jahren aktiv, dabei gemischt zwischen Rechner und Handy (via Waterfly III für mich und Abacus für die gemeinsamen Finanzen). Mittlerweile ist auch meine Partnerin von einer simplen Excel-Tabelle auf Firefly umgestiegen.&lt;/p&gt;
&lt;p&gt;Die Auswertungen gefallen mir sehr gut, ich kriege schnell einen guten Überblick darüber, wie der aktuelle Monat im Vergleich zu anderen dasteht und wohin das Geld geflossen ist. Über die Daueraufträge habe ich alle regelmäßigen Buchungen abgedeckt, was den Aufwand deutlich reduziert. Mit den Regeln lassen sich zusätzlich auch Kategorien, Tags und noch mehr automatisch anhand beispielsweise des Buchungstitels festlegen. So landen bei den gemeinsamen Finanzen alle Buchungen, die &lt;code&gt;&amp;lt;Laden&amp;gt; Lebensmittel&lt;/code&gt; als Titel haben, automatisch in der entsprechenden Kategorie und werden dem passenden Budget zugeordnet.&lt;/p&gt;
&lt;p&gt;Die UI ist nichts besonderes, erfüllt aber auf verschiedenen Bildschirmgrößen gut ihren Zweck.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Firefly III gehört für meine Partnerin und mich zu den zentralen Anwendungen, die am meisten verwendet werden. Wir nutzen es dabei fast täglich.&lt;/p&gt;</description></item><item><title>Matrix selbst hosten - Synapse, Element und warum das mehr als nur ein Messenger ist</title><link>https://secretmine.de/blog/2026/2026-05-29-matrix/</link><pubDate>Fri, 29 May 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-05-29-matrix/</guid><description>&lt;p&gt;Messenger gibt es viele. Matrix ist dabei eine Besonderheit, da es nicht direkt eine App meint, sondern ein offenes Protokoll für dezentrale Echtzeitkommunikation, auf dem verschiedene Clients und Server miteinander sprechen können.&lt;/p&gt;
&lt;h2 id="was-ist-matrix"&gt;Was ist Matrix?
&lt;/h2&gt;&lt;p&gt;Matrix ist ein offenes, föderiertes Kommunikationsprotokoll für Chat, Gruppenräume, Sprach- und Videokommunikation. Synapse ist dabei der klassische Matrix-Homeserver, also die Server-Software, die das eigenes Matrix-System betreibt.&lt;/p&gt;
&lt;p&gt;Als Client wird sehr häufig Element genutzt, weil es auf Desktop und Mobilgeräten breit verfügbar ist und den größten Teil der üblichen Messenger-Funktionen abdeckt und sich wie andere bekannte Messenger anfühlt. Es gibt auch diverse andere Clients wie z.B. Cinny, was von der UI her näher an Discord ist.&lt;/p&gt;
&lt;p&gt;Der größte Unterschied zu klassischen Messengern ist die Dezentralität. Man ist nicht an einen einzigen Anbieter gebunden, sondern kann mit anderen Matrix-Servern kommunizieren, ähnlich wie beispielsweise auch E-Mail über viele Anbieter hinweg funktioniert.&lt;/p&gt;
&lt;p&gt;Dazu kommt die offene Architektur: Der Server ist selbst hostbar und man kann den Client frei wählen. Das macht Matrix auch nicht nur für die private Kommunikation interessant, auch in Unternehmen und co bietet sich die Nutzung an. Dort kann man beispielsweise auch die Förderation für rein interne Kommunikation deaktivieren.&lt;/p&gt;
&lt;p&gt;Aber: Durch die Architektur und auch die Ende-zu-Ende-Verschlüsselung ist Matrix komplizierter in der Einrichtung, was schnell abschreckend wirkt.&lt;/p&gt;
&lt;h3 id="politischer-kontext"&gt;Politischer Kontext
&lt;/h3&gt;&lt;p&gt;Ja, ein Thema was ich sonst nicht betrachte. Finde ich hier aber erwähnenswert.&lt;/p&gt;
&lt;p&gt;Matrix passt ziemlich gut in die aktuelle Diskussion um digitale Souveränität, Datenschutz und unabhängige (Kommunikations-)Infrastruktur. Gerade in Europa und auch in Deutschland ist das Interesse an offenen Alternativen zu großen Plattformen seit Jahren hoch und auch diverse öffentliche Einrichtungen und Hochschulen nutzen Matrix als sicheren Messenger.&lt;/p&gt;
&lt;h2 id="installation"&gt;Installation
&lt;/h2&gt;&lt;p&gt;Ein alltagstaugliches Matrix-Setup besteht aus mehreren Komponenten:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Synapse als Homeserver (es gibt auch andere, aber Synapse ist der gängigste)&lt;/li&gt;
&lt;li&gt;Element als Frontend im Browser&lt;/li&gt;
&lt;li&gt;Synapse-Admin zur Benutzerverwaltung&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Von der Domaingestaltung habe ich bei mir etwa folgendes Setup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Synapse unter &lt;code&gt;matrix.example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Element unter &lt;code&gt;chat.example.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Wobei &lt;code&gt;example.com&lt;/code&gt; als Basis-URL für die Identitäten dient, das wird über eine &lt;code&gt;.well-known&lt;/code&gt; an die Subdomain &lt;code&gt;matrix.example.com&lt;/code&gt; delegiert&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Die Delegation hat den großen Vorteil, dass die Hauptdomain als Matrix-Adresse genutzt werden kann, aber nicht von Synapse belegt wird. Über eine kleine &amp;ldquo;Hinweis-Datei&amp;rdquo; auf der Hauptdomain wissen Clients (und andere Homeserver) dann, dass diese sich zu &lt;code&gt;matrix.example.com&lt;/code&gt; verbinden müssen.&lt;/p&gt;
&lt;p&gt;In diesem Fall wird Synapse mit sqlite installiert. Für kleine Setups ist das vollkommen in Ordnung, ich selbst nutze Postgres als Datenbank.&lt;/p&gt;
&lt;h3 id="docker"&gt;Docker
&lt;/h3&gt;&lt;p&gt;Wie das meiste betreibe ich Matrix in Docker. Meine Compose (&lt;code&gt;10.0.0.2&lt;/code&gt; ist die interne IP dieses Servers):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;synapse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;docker.io/matrixdotorg/synapse:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;SYNAPSE_CONFIG_PATH=/data/homeserver.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./data:/data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;10.0.0.2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8008&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8008&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;element&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;vectorim/element-web:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./config/element-config.json:/app/config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;10.0.0.2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8009&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;80&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;synapse-admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;ghcr.io/etkecc/synapse-admin:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./config/synapse-admin-config.json:/app/config.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;10.0.0.2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8010&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Die grundlegende Konfiguration für Synapse lässt sich generieren:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose run --rm -e &lt;span class="nv"&gt;SYNAPSE_SERVER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;example.com synapse generate
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Die relevanten Config-Files:&lt;/p&gt;
&lt;p&gt;Element (&lt;code&gt;config/element-config.json&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;default_server_config&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;m.homeserver&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;base_url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://matrix.example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;disable_custom_urls&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;disable_guests&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;brand&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Mein Chatserver&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Synapse-Admin (&lt;code&gt;config/synapse-admin-config.json&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;restrictBaseUrl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;https://matrix.example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Die eigentliche Config von Synapse (&lt;code&gt;data/homeserver.yaml&lt;/code&gt;) habe ich minimal modifiziert:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Configuration file for Synapse.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# This is a YAML file: see [1] for a quick introduction. Note in particular&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# that *indentation is important*: all the elements of a list or dictionary&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# should have the same indentation.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;#&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# For more information on how to configure Synapse, including a complete accounting of&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# each option, go to docs/usage/configuration/config_documentation.md or&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;server_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;example.com&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;pid_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/data/homeserver.pid&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8008&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;compress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;client&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;federation&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;tls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;http&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;x_forwarded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;sqlite3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/data/homeserver.db&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;log_config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/data/example.com.log.config&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;media_store_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;/data/media_store&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;registration_shared_secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;[...]&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;macaroon_secret_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;[...]&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;form_secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;[...]&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;signing_key_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/data/example.com.signing.key&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;trusted_key_servers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;server_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;matrix.org&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c"&gt;# Modifikationen&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;public_baseurl &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://matrix.example.com&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# URL, über die Synapse von außen erreichbar ist&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;report_stats&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;enable_registration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="reverse-proxy"&gt;Reverse-Proxy
&lt;/h3&gt;&lt;p&gt;Ich habe Caddy als Reverse-Proxy im Einsatz. Die relevante Konfiguration in der Caddyfile sieht bei mir so aus:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;matrix.example.com {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reverse_proxy 10.0.0.2:8008
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chat.example.com {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reverse_proxy 10.0.0.2:8009
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;synapse-admin.example.com {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # siehe https://caddyserver.com/docs/caddyfile/directives/basic_auth
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; basic_auth {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; # User hier
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reverse_proxy 10.0.0.2:8010
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Synapse-Admin habe ich hinter Basic-Auth versteckt. Das ist an sich meiner Meinung nach nicht notwendig, aber fühlt sich besser an.&lt;/p&gt;
&lt;h3 id="delegation-einrichten"&gt;Delegation einrichten
&lt;/h3&gt;&lt;p&gt;Bei der Hauptdomain &lt;code&gt;example.com&lt;/code&gt; müssen einige Dateien angelegt werden.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;.well-known/matrix/server&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;m.server&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;matrix.example.com:443&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;.well-known/matrix/client&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;m.homeserver&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;base_url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://matrix.example.com&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Damit sollte nun Förderation auch funktionieren. Mit dem Federation Tester (&lt;a class="link" href="https://federationtester.matrix.org/" target="_blank" rel="noopener"
 &gt;federationtester.matrix.org&lt;/a&gt;) lässt sich das prüfen.&lt;/p&gt;
&lt;h3 id="initialen-user-erstellen"&gt;Initialen User erstellen
&lt;/h3&gt;&lt;p&gt;Mittels&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose &lt;span class="nb"&gt;exec&lt;/span&gt; -it synapse register_new_matrix_user http://localhost:8008 -c /data/homeserver.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;lässt sich nun der initiale Admin-User (und auch weitere User natürlich) anlegen.&lt;/p&gt;
&lt;h2 id="clients-einrichten"&gt;Clients einrichten
&lt;/h2&gt;&lt;p&gt;An den Clients sollte ein Login auf &lt;code&gt;example.com&lt;/code&gt; nun funktionieren. Durch die Delegation werden Clients zu &lt;code&gt;matrix.example.com&lt;/code&gt; weitergeschickt.&lt;/p&gt;</description></item><item><title>Verteilter Speicher im Homelab</title><link>https://secretmine.de/blog/2026/2026-05-17-verteilter-speicher-im-homelab/</link><pubDate>Sun, 17 May 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-05-17-verteilter-speicher-im-homelab/</guid><description>&lt;p&gt;Ich habe bekanntlich seit einiger Zeit Docker Swarm im Einsatz. Als Storage war anfangs ein mit NFS geteiltes DRBD-Volume im Einsatz, also replizierter Blockspeicher. Funktioniert hat das, war aber langsam.&lt;/p&gt;
&lt;p&gt;Daher habe ich mir diverse Lösungen für verteilten bzw. replizierten Speicher angesehen und ausprobiert. Ziel war einerseits, replizierten und ausfallsicheren Storage für Docker Swarm zu bekommen, andererseits aber auch, einen größeren Speicherbereich für unwichtige Daten zu erhalten.&lt;/p&gt;
&lt;h2 id="anforderungen"&gt;Anforderungen
&lt;/h2&gt;&lt;p&gt;Um eine vernünftige Auswahl treffen zu können, sollten vorher natürlich die konkreten Anforderungen klar sein.&lt;/p&gt;
&lt;p&gt;Muss:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unterstützung von verteiltem und repliziertem Storage&lt;/li&gt;
&lt;li&gt;Hochverfügbarkeit (weiterhin funktionsfähig bei Ausfall von 1/3 Nodes)&lt;/li&gt;
&lt;li&gt;Kostenfrei nutzbar&lt;/li&gt;
&lt;li&gt;(halbwegs) aktives Projekt, nicht abgekündigt bzw. sichtbar inaktiv&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Soll:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open Source&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kann:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Metriken/Monitoring&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="softwarelösungen"&gt;Softwarelösungen
&lt;/h2&gt;&lt;h3 id="ceph"&gt;Ceph
&lt;/h3&gt;&lt;p&gt;Ceph ist eine gängige Lösung für hochverfügbaren Speicher und wird im sehr großen Stil eingesetzt. Es ist zudem in Proxmox VE integriert, womit sich schnell ein hyperconverged Cluster einrichten lässt.&lt;/p&gt;
&lt;p&gt;Die Performance hat mir sehr gut gefallen, es war die schnellste getestete Lösung. Ceph lässt sich auch super konfigurieren und Pools mit verschiedenen Replikationsregeln erstellen. Der Ausfall einer Node wurde gut verkraftet, nach dem Hinzufügen war die Redundanz auch sehr schnell wiederhergestellt.&lt;/p&gt;
&lt;p&gt;Problematisch für mich ist hier allerdings der Ressourcenbedarf. Ceph hat mit allen Komponenten pro Node 2-3 GB an RAM verbraucht, das ist mir mit den Thin Clients zu viel. Außerdem ist Ceph bekannt dafür, eine hohe Schreiblast auf den Datenträgern zu erzeugen. Auf Dauer könnte Ceph aber trotzdem die präferierte Lösung sein.&lt;/p&gt;
&lt;h3 id="glusterfs"&gt;GlusterFS
&lt;/h3&gt;&lt;p&gt;Im Vergleich zu Ceph arbeitet GlusterFS auf Datei- und nicht auf Blockebene. Replizierte und verteilte Volumes werden unterstützt, auch erasure-code-basierte Volumes sind möglich. Es ist trotzdem weniger flexibel als Ceph, was die Replikationsoptionen angeht. Monitoring ist leider auch eher schwierig, es gibt aber einen halbwegs gepflegten Prometheus-Exporter.&lt;/p&gt;
&lt;p&gt;GlusterFS wurde irgendwann von Red Hat gekauft, die es dann neben der Open-Source-Version als Red Hat Gluster Storage vermarktet haben. Das Red Hat Produkt hat allerdings Ende 2024 das Ende seines Lebenszyklus erreicht. Die Aktivität bei Github ist in den letzten Jahren auch stark gesunken, letztes Jahr waren es ~20 Commits im Repo. Das spricht deutlich gegen GlusterFS.&lt;/p&gt;
&lt;p&gt;Vom Ressourcenbedarf her ist es angenehm, ich sehe kaum nennenswerten RAM- und CPU-Bedarf. Die Performance ist insgesamt auch okay, wenn auch geringer als bei Ceph.&lt;/p&gt;
&lt;h3 id="moosefs"&gt;MooseFS
&lt;/h3&gt;&lt;p&gt;Vom Prinzip her gefällt mir MooseFS. Man kann pro Verzeichnis die Anzahl der Kopien festlegen, beim über- oder unterschreiten durch Entfernen bzw. Hinzufügen von Volumes wird dann automatisch nachgesteuert. Die Performance ist ebenfalls in Ordnung, auch wenn es primär für Medien und andere größere Dateien ausgelegt ist. Bei vielen kleinen Dateien habe ich - zumindest bei den Forks von MooseFS - deutlich geringere Performance als bei Ceph gesehen.&lt;/p&gt;
&lt;p&gt;Das Ausschlusskriterium für MooseFS war allerdings die fehlende Hochverfügbarkeit in der Open-Source-Version. Für dieses Feature benötigt man eine Pro-Lizenz.&lt;/p&gt;
&lt;h3 id="lizardfs"&gt;LizardFS
&lt;/h3&gt;&lt;p&gt;Das ist ein Fork von MooseFS, der von den Funktionen her ziemlich gleich ist, allerdings auch Hochverfügbarkeit enthält. LizardFS wird allerdings seit mehreren Jahren nicht mehr weiterentwickelt, das Repo bei Github ist inaktiv.&lt;/p&gt;
&lt;h3 id="leilfs-vorher-saunafs"&gt;LeilFS (vorher SaunaFS)
&lt;/h3&gt;&lt;p&gt;LeilFS ist ein Fork von LizardFS, laut den Infos, die ich finden konnte, sind wohl diverse Entwickler von LizardFS dort nun aktiv. Prinzipiell sieht LeilFS gut aus, es gibt bisher allerdings nur für Ubuntu fertige Pakete. Ich habe aber mit wenig Aufwand Pakete für Debian 13 kompilieren können.&lt;/p&gt;
&lt;p&gt;Die Dokumentation lässt (zumindest bisher) auch sehr zu wünschen übrig. Das meiste habe ich mir bei LizardFS angesehen und nur die entsprechenden Bezeichnungen angepasst. Trotzdem hinterlässt das einen etwas faden Beigeschmack.&lt;/p&gt;
&lt;p&gt;Dennoch ist es eine flexible und eher ressourcensparsame Option.&lt;/p&gt;
&lt;h3 id="weitere-lösungen"&gt;Weitere Lösungen
&lt;/h3&gt;&lt;p&gt;Folgende Möglichkeiten möchte ich zumindest erwähnt haben, auch wenn ich nicht im Detail darauf eingehen werde:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LINSTOR&lt;/strong&gt;: Verteilte Block-Devices, basiert auf DRBD&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S3 plus JuiceFS&lt;/strong&gt;: Mit hochverfügbarem S3 in Verbindung mit JuiceFS lässt sich theoretisch auch ein hochverfügbares Dateisystem aufsetzen&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DRBD plus NFS&lt;/strong&gt;: Etwas klassischer, aber funktioniert&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ZFS mit Replikation&lt;/strong&gt;: Proxmox bietet Unterstützung dafür. Nicht direkt volles HA, aber für Homelab und kleine Produktion wahrscheinlich ausreichend&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Ceph ist eine gebräuchliche Lösung, weit verbreitet, aktiv gepflegt und auch schnell. Also eigentlich ideal. Es benötigt aber leider zu viele Ressourcen, ist also bei den aktuellen RAM-Preise eher eine Lösung für &amp;ldquo;irgendwann&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Aktuell wird jetzt DRBD erst einmal durch GlusterFS ersetzt. Ich habe damit in der Vergangenheit viel zu tun gehabt und kenne mich weit genug aus, auch wenn es seine Nachteile hat. Regelmäßige Sicherungen mache ich natürlich, daher halte ich das Risiko für Datenverlust für überschaubar.&lt;/p&gt;
&lt;p&gt;Für Massenspeicher kommt neben GlusterFS auch LeilFS zum Einsatz, da liegen z.B. ISOs/Templates für Proxmox, Medien und anderer Kram darauf. Ich habe mir verschiedene Storage-Klassen konfiguriert, die teilweise auch hochverfügbar sind. Dazu aber in einem weiteren Beitrag mehr.&lt;/p&gt;
&lt;p&gt;GlusterFS ist für mich trotzdem nur eine Zwischenlösung, auf Dauer bleibt Ceph (inkl. CephFS) das Ziel. Einfach weil es verbreiteter und besser gepflegt ist. Aber das wird auf niedrigere RAM-Preise warten müssen.&lt;/p&gt;</description></item><item><title>Hochverfügbarkeit mit Keepalived</title><link>https://secretmine.de/blog/2026/2026-05-03-hochverfuegbarkeit-mit-keepalived/</link><pubDate>Sun, 03 May 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-05-03-hochverfuegbarkeit-mit-keepalived/</guid><description>&lt;p&gt;Wer schon einmal mit mehreren Servern gearbeitet hat, kennt das Problem: Ein Dienst soll zwecks Ausfallsicherheit auf mehreren Servern laufen und parallel unter einer festen IP erreichbar sein. Natürlich mit Failover.&lt;/p&gt;
&lt;p&gt;An dieser Stelle kommt Keepalived ins Spiel. Das kleine, aber mächtige Tool übernimmt die Verwaltung von Floating IPs (oder Virtual IPs, kurz VIPs) und sorgt so für Hochverfügbarkeit für theoretisch beliebige Dienste.&lt;/p&gt;
&lt;h2 id="wie-funktioniert-das"&gt;Wie funktioniert das?
&lt;/h2&gt;&lt;p&gt;Keepalived setzt auf das VRRP-Protokoll (Virtual Router Redundancy Protocol), um eine virtuelle IP-Adresse an genau einen Master-Knoten zu vergeben.&lt;/p&gt;
&lt;p&gt;Wenn der Master ausfällt, erkennt Keepalived das automatisch und weist die IP einem Backup-Knoten zu. Meistens passiert das innerhalb von wenigen Sekunden. Dienste hinter dieser IP bleiben dadurch durchgängig erreichbar.&lt;/p&gt;
&lt;h2 id="typische-szenarien"&gt;Typische Szenarien
&lt;/h2&gt;&lt;h3 id="dns"&gt;DNS
&lt;/h3&gt;&lt;p&gt;Ein Klassiker. DNS hat zwar an sich durch die Angabe mehrerer DNS-Server schon auf der Ebene Ausfallsicherheit integriert, hier lässt sich aber auch Keepalived gut einsetzen. Zwei (oder mehr) Server sind dabei identisch eingerichtet und können beide jederzeit DNS-Anfragen beantworten.&lt;/p&gt;
&lt;p&gt;Keepalived sorgt hier nun für eine virtuelle IP, die immer auf einen der beiden Server gebunden ist und damit beim Ausfall des aktuell aktiven Servers innerhalb von kurzer Zeit auf den zweiten umgeschaltet wird.&lt;/p&gt;
&lt;h3 id="webserver"&gt;Webserver
&lt;/h3&gt;&lt;p&gt;Eigentlich exakt das selbe Prinzip wie bei DNS, hier müssen nur die Website-Daten auch auf einem gemeinsamen Storage liegen oder anderweitig allen Nodes bekannt sein.&lt;/p&gt;
&lt;h2 id="keepalived-und-docker-swarm"&gt;Keepalived und Docker Swarm
&lt;/h2&gt;&lt;p&gt;Hier wirds cool.&lt;/p&gt;
&lt;p&gt;Swarm hat Mesh Routing. Das heißt, dass jede Node Anfragen zu einem Service entgegen nehmen kann und intern dann zum richtigen Knoten weiterleitet. Heißt, es ist egal, welche Node man anspricht, die Antwort kommt auf jeden Fall.&lt;/p&gt;
&lt;p&gt;In Verbindung mit Keepalived kann man so Services in Docker Swarm wirklich hochverfügbar machen. Die virtuelle IP zeigt immer auf einen der Knoten, das interne Mesh-Routing erledigt dann den Rest. Wenn ein Knoten ausfällt, wird die IP umgeschaltet, parallel sorgt Swarm dafür, dass alle Services weiterhin verfügbar sind und bei Bedarf auf einem anderen Knoten neu gestartet werden.&lt;/p&gt;
&lt;p&gt;DNS-Einträge können damit immer auf die virtuelle IP eingestellt werden, alles weitere passiert automatisch.&lt;/p&gt;
&lt;h3 id="beispielkonfiguration"&gt;Beispielkonfiguration
&lt;/h3&gt;&lt;p&gt;Hier eine kurze Beispielconfig:&lt;/p&gt;
&lt;p&gt;Node &lt;code&gt;swarm-1&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;global_defs &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; router_id swarm-1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vrrp_instance VI_SWARM &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; state MASTER
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; interface eth0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; virtual_router_id &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; priority &lt;span class="m"&gt;255&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; advert_int &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; authentication &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; auth_type PASS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; auth_pass meinsicherespw
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; virtual_ipaddress &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 192.168.1.60/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Node &lt;code&gt;swarm-2&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;global_defs &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; router_id swarm-2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vrrp_instance VI_SWARM &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; state BACKUP
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; interface eth0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; virtual_router_id &lt;span class="m"&gt;60&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; priority &lt;span class="m"&gt;254&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; advert_int &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; authentication &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; auth_type PASS
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; auth_pass meinsicherespw
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; virtual_ipaddress &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 192.168.1.60/24
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Die &lt;code&gt;router_id&lt;/code&gt; ist hierbei immer Node-spezifisch. Die virtual_router_id ist letztendlich die Instanzkennung. Bei mir ist &lt;code&gt;swarm-1&lt;/code&gt; normalerweise der Master, hier ist durch die höhere Priorität auch ein Fail-Back (also das Zurückschalten von einer der anderen Nodes zurück zu &lt;code&gt;swarm-1&lt;/code&gt;) konfiguriert. Wenn die Prioritäten identisch sind, passiert kein Fail-Back.&lt;/p&gt;
&lt;p&gt;Die restlichen Optionen sind weitestgehend selbsterklärend, ansonsten findet man im Internet auch genügend Informationen zu Keepalived.&lt;/p&gt;
&lt;h3 id="kubernetes"&gt;Kubernetes
&lt;/h3&gt;&lt;p&gt;Bei Kubernetes lässt sich dieses Konstrukt mit MetalLB im Layer-2-Modus ziemlich identisch umsetzen. Die Erkennung von ausgefallenen Nodes läuft etwas anders, aber das Endergebnis (virtuelle IP, unter der immer eine Node erreichbar ist) ist das selbe.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Mir gefällt das Setup in dieser Kombination wirklich gut. Swarm kümmert sich um die Services, Keepalived sorgt für eine einheitliche IP für alle Services. Und dabei braucht Keepalived auch fast nichts an Ressourcen.&lt;/p&gt;</description></item><item><title>Latenzmessungen mit Smokeping</title><link>https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/</link><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/</guid><description>&lt;p&gt;Ich nutze nun schon seit vielen Jahren Smokeping zur Überwachung von Latenzen zu diversen Zielen. Primär mit dem Ziel, die Performance meiner Internetanbindung zu überwachen und Probleme gut identifizieren zu können, daneben aber auch, um Änderungen am Routing zwischen meinem Internetprovider und dem entsprechenden Ziel anhand von Latenzänderungen zu erkennen.&lt;/p&gt;
&lt;p&gt;Das Tool ist an sich recht alt, bietet aber trotzdem einen super Einblick in die Latenzen.&lt;/p&gt;
&lt;h2 id="ping-ziele"&gt;Ping-Ziele
&lt;/h2&gt;&lt;p&gt;Neben meinem Router (und dem Router im Keller im zweiten Homelab) pinge ich regelmäßig diverse Ziele im Internet. Dazu gehören neben den DNS-Servern von Google, Cloudflare und Quad9 auch die Test-Targets von Hetzner an allen derer Standorte, alle meine eigenen Server auch das VPN-Gateway meines Arbeitgebers.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Generische Internet-Ziele" class="gallery-image" data-flex-basis="317px" data-flex-grow="132" height="547" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/targets_internet.png" width="723"&gt;&lt;/p&gt;
&lt;h2 id="konfiguration"&gt;Konfiguration
&lt;/h2&gt;&lt;p&gt;Die gesamte Konfiguration liegt unter &lt;code&gt;/etc/smokeping/&lt;/code&gt;, wenn Smokeping einfach als Systempaket installiert wurde. In der Datei &lt;code&gt;/etc/smokeping/config.d/Targets&lt;/code&gt; lassen sich die Ziele definieren, die Syntax ist dabei recht einfach. Hier ein Auszug aus meiner Config:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;+ Local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Local&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Local Network&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;++ Gateway&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Gateway&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Gateway&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;192.168.1.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;+ Internet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Internet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Internet&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;++ GoogleDNS1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Google DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Google DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;8.8.8.8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;++ CloudflareDNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Cloudflare DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Cloudflare DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1.1.1.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;++ Quad9DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Quad9 DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;Quad9 DNS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;9.9.9.9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Viel mehr außer die Targets habe ich nicht modifiziert, es lassen sich aber viel mehr Dinge noch konfigurieren.&lt;/p&gt;
&lt;h2 id="statistiken"&gt;Statistiken
&lt;/h2&gt;&lt;p&gt;Hier ein Beispiel von einem Ping-Ziel. Die Daten gehen dabei über ein Jahr zurück. Bei den längeren Statistiken sieht man hier und da ein bisschen Packetloss, das kann bei größeren Downloads bzw. generell Auslastung der Internetleitung zwischenzeitlich passieren.&lt;/p&gt;
&lt;p&gt;Schön zu sehen ist auch ein genereller Internetausfall im Juni für mehrere Tage mit Fallback zu LTE.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Google - 3 Stunden" class="gallery-image" data-flex-basis="542px" data-flex-grow="225" height="397" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_1.png" srcset="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_1_hu_5bcc754b4c99f4cd.png 800w, https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_1.png 897w" width="897"&gt; &lt;img alt="Google - 30 Stunden" class="gallery-image" data-flex-basis="542px" data-flex-grow="225" height="397" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_2.png" srcset="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_2_hu_f3160cd446fc58d4.png 800w, https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_2.png 897w" width="897"&gt; &lt;img alt="Google - 10 Tage" class="gallery-image" data-flex-basis="542px" data-flex-grow="225" height="397" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_3.png" srcset="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_3_hu_2e3e6119a934b626.png 800w, https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_3.png 897w" width="897"&gt; &lt;img alt="Google - 365 Tage" class="gallery-image" data-flex-basis="542px" data-flex-grow="225" height="397" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_4.png" srcset="https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_4_hu_9d09d21ac71ee715.png 800w, https://secretmine.de/blog/2026/2026-04-18-latenzmessungen-mit-smokeping/images/google_4.png 897w" width="897"&gt;&lt;/p&gt;
&lt;h2 id="alternativen-zu-smokeping"&gt;Alternativen zu Smokeping
&lt;/h2&gt;&lt;p&gt;Als Alternativen zu Smokeping für Latenz-, Jitter- und Packetloss-Monitoring bietet sich Uptime Kuma oder der Blackbox Exporter an.&lt;/p&gt;
&lt;p&gt;Uptime Kuma ist ein selfhostbares Tool mit simplem Docker-Setup, das Ping-Monitoring inklusive Latenz, Packetloss und Up/Down-Status bietet – ergänzt durch schöne Dashboards, Status-Seiten und Notifications via Discord oder diverser anderer Kanäle. Jitter ist hier zwar nicht so detailliert wie bei Smokeping, aber die moderne Web-UI ist mobilfreundlich und ideal für Homelabs, wo man schnell loslegen will, ohne viel Konfigurationsaufwand. Uptime Kuma ist generell ein schönes Monitoring-Tool, mit dem man seine selbst betriebenen (oder auch externe) Dienste überwachen kann.&lt;/p&gt;
&lt;p&gt;Wenn man eh schon den klassischen Metriken-Stack mit Prometheus und Grafana hat, ist der Blackbox Exporter einen Blick wert. Der kann neben ICMP auch diverse andere Messungen bzw. Tests ausführen und Ziele überwachen. Durch die Nutzung von Grafana sind deutlich umfangreichere Visualisierungen möglich, auch mehrere Probe-Quellen sind gut umzusetzen. Der initiale Aufwand ist natürlich höher als bei Smokeping oder Uptime Kuma, aber der Blackbox Exporter skaliert deutlich weiter und kann am Ende mehr.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Obwohl die Software eher alt ist und visuell auch nicht die schönste ist, ist es trotzdem ein zentrales Tool in meinem Netzwerkmonitoring. Und das seit bald 10 Jahren. Das Tool funktioniert einfach, ist wartungsarm und liefert gute (wenn auch alt aussehende) Graphen. Daher wird es bei mir auch nicht in absehbarer Zeit abgelöst.&lt;/p&gt;</description></item><item><title>Memos - Notizen und Tagebuch</title><link>https://secretmine.de/blog/2026/2026-04-04-memos/</link><pubDate>Sat, 04 Apr 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-04-04-memos/</guid><description>&lt;p&gt;Ich nutze nun seit über zwei Jahren Memos (&lt;a class="link" href="https://usememos.com/" target="_blank" rel="noopener"
 &gt;https://usememos.com/&lt;/a&gt;) als Tool im Homelab. Es dient mir zum Notieren von Gedanken und Ideen, zusätzlich nutze ich es auch als eine Art unregelmäßig gepflegtes Tagebuch. Alles wird lokal gespeichert, es ist schlicht, braucht wenig Ressourcen und &amp;ldquo;just works&amp;rdquo; - perfekt, um mal eben etwas zu notieren.&lt;/p&gt;
&lt;h2 id="deployment"&gt;Deployment
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;memos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;neosmemo/memos:stable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;5230&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;5230&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./data/:/var/opt/memos/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&amp;hellip; ja, das wars schon. Davor sitzt dann noch Caddy als Reverse-Proxy, um SSL zu machen und das ganze erreichbar zu bekommen. In Caddy ist auch noch eine zusätzliche Authentifizierungsschicht eingebaut, dazu schreibe ich irgendwann noch mal mehr.&lt;/p&gt;
&lt;h2 id="nutzung-im-alltag"&gt;Nutzung im Alltag
&lt;/h2&gt;&lt;p&gt;Ich habe Memos als Lesezeichen auf dem Rechner, auf dem Handy ist es als PWA installiert. Damit habe ich es immer griffbereit, um mir schnell etwas zu notieren und es später auch wiederzufinden. Dazu sind die Tags super hilfreich, damit kann man die Memos schön organisieren. Anhänge wie Bilder sind auch vorgesehen, diese lassen sich lokal, in der Datenbank oder in einem S3-Bucket speichern. Ich nutze dabei die lokale Option, das reicht vollkommen aus. Standardmäßig kommt Memos mit SQLite als Datenbank. Hier werden aber auch andere Datenbanktypen unterstützt.&lt;/p&gt;
&lt;p&gt;Zur Formatierung ist Markdown vorgesehen, das mag ich generell. Markdown ist für mich ein guter Mittelweg zwischen reinen Textdateien und erweiterten Formaten wie AsciiDoc oder LaTeX, kann aber trotzdem für das allermeiste genug.&lt;/p&gt;
&lt;p&gt;Auch die gemeinsame Nutzung ist vorgesehen - dafür gibt es mehrere Sichtbarkeitsstufen für einzelne Einträge. &lt;code&gt;Private&lt;/code&gt; ist nur für den Ersteller sichtbar, &lt;code&gt;Protected&lt;/code&gt; können angemeldete Benutzer sehen und &lt;code&gt;Public&lt;/code&gt; ist öffentlich. Gruppen oder ähnliches sind nicht vorgesehen, das fehlt mir allerdings auch nicht.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Mir gefällt Memos und ich nutze es im Alltag regelmäßig. Daher fand ich einen Post nach all der Zeit angemessen, vor allem, da es ein eher wenig bekanntes Open-Source-Produkt ist. Als Wiki-Lösung nutze ich allerdings zusätzlich noch eine andere Software, dazu folgt wahrscheinlich auch mal ein Beitrag.&lt;/p&gt;</description></item><item><title>Storage-Cluster - Part 2: Erster PoC und Planänderungen</title><link>https://secretmine.de/blog/2026/2026-03-28-storage-cluster-poc-und-planaenderungen/</link><pubDate>Sat, 28 Mar 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-03-28-storage-cluster-poc-und-planaenderungen/</guid><description>&lt;h1 id="storage-cluster---ein-erster-poc"&gt;Storage-Cluster - Ein erster PoC
&lt;/h1&gt;&lt;p&gt;Der Plan sieht Futro S740er mit SATA-Controllern vor. Einen entsprechenden Controller auf Basis des ASM1166 (energieeffizienter und gut unterstützter SATA-Controller) habe ich gekauft und mit einem NVMe-Adapter verbaut.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Proof of Concept" class="gallery-image" data-flex-basis="229px" data-flex-grow="95" height="2000" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-03-28-storage-cluster-poc-und-planaenderungen/images/storage_poc.jpg" srcset="https://secretmine.de/blog/2026/2026-03-28-storage-cluster-poc-und-planaenderungen/images/storage_poc_hu_1b3a6d9d9ab42c7c.jpg 800w, https://secretmine.de/blog/2026/2026-03-28-storage-cluster-poc-und-planaenderungen/images/storage_poc_hu_2fb146a9c9fd2dbc.jpg 1600w, https://secretmine.de/blog/2026/2026-03-28-storage-cluster-poc-und-planaenderungen/images/storage_poc.jpg 1915w" width="1915"&gt;&lt;/p&gt;
&lt;p&gt;Zugegeben, der PoC sieht etwas wild aus. Am HBA hängen drei SSDs, den Strom bekommen die SSDs über USB zu SATA-Strom-Adapter. Das funktioniert, da 2,5-Zoll-Laufwerke normalerweise nur 5V und keine 12V benötigen, SATA hat eigentlich auch 12V anliegen.&lt;/p&gt;
&lt;p&gt;Auf dem Futro läuft Proxmox, der Thin Client ist in meinen normalen Cluster eingebunden.&lt;/p&gt;
&lt;h2 id="ergebnisse-vom-poc"&gt;Ergebnisse vom PoC
&lt;/h2&gt;&lt;p&gt;Erst habe ich Ceph getestet. Hier hat sich schnell gezeigt, dass 4GB RAM für Ceph einfach zu wenig ist. Das ist schade, da ich Ceph eigentlich gerne genutzt hätte. Es war aber absehbar, dass das nicht klappt.&lt;/p&gt;
&lt;p&gt;Ohne Proxmox und weitere Services würde es vermutlich knapp passen, es ist mir allerdings zu heikel.&lt;/p&gt;
&lt;h2 id="alternative-zu-ceph"&gt;Alternative zu Ceph
&lt;/h2&gt;&lt;p&gt;Ich brauche eine Lösung, die halbwegs brauchbare IOPS liefern kann. SaunaFS ist zwar sehr flexibel und kann natürlich auch Replikation, erreicht aber nicht die IOPS-Werte, die ich benötige.&lt;/p&gt;
&lt;p&gt;Daher kommt vorerst GlusterFS zum Einsatz, das benutze ich auch jetzt schon für meinen Docker Swarm für persistenten Speicher. GlusterFS ist sehr viel schlanker als Ceph, allerdings auch langsamer und insgesamt schlechter zu administrieren. Ob es tatsächlich die bessere Wahl für mich ist wird sich mit der Zeit zeigen.&lt;/p&gt;
&lt;h2 id="wie-es-weitergeht"&gt;Wie es weitergeht
&lt;/h2&gt;&lt;p&gt;Ich habe die weitere Hardware für den Cluster hier schon liegen, von daher dürfte zeitnahe auch der Post zum vollständigen Setup kommen. Nebenbei bin ich dabei, Ansible-Rollen für die diversen Services zu entwickeln, da ich keine Lust habe, das meiste von Hand zu machen.&lt;/p&gt;
&lt;p&gt;Auch habe ich ein 3D-Modell für eine alternative Abdeckung mit großer Öffnung für die SATA-Kabel erstellt, das habe ich auch schon gedruckt und getestet. Damit kann ich die Futros trotzdem schließen und muss die originale Abdeckung nicht beschädigen.&lt;/p&gt;
&lt;p&gt;Zusätzlich habe ich auch ein Modell erstellt, was als Halterung für die Futros und die SSDs/HDDs dient. Davon passen dann auch drei nebeneinander in ein Kallax-Fach. Das dürfte insgesamt für mehr Ordnung sorgen und trotzdem Zugriff zu allem ermöglichen.&lt;/p&gt;</description></item><item><title>Code-Server</title><link>https://secretmine.de/blog/2026/2026-03-21-code-server/</link><pubDate>Sat, 21 Mar 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-03-21-code-server/</guid><description>&lt;p&gt;Ich nutze für meinen Blog mittlerweile Code-Server zum Schreiben und Bearbeiten der Beiträge. Da sich das für mich als überaus praktisch herausgestellt hat, möchte ich die Lösung hier einmal vorstellen.&lt;/p&gt;
&lt;h2 id="hintergrund"&gt;Hintergrund
&lt;/h2&gt;&lt;p&gt;Dieser Blog basiert auf Hugo, einem Static Site Generator. Ich habe ein Git-Repo, wo der gesamte Content (und natürlich Dinge wie CI-Files) enthalten sind. Bislang habe ich auf jedem Rechner, wo ich am Blog arbeiten möchte, Visual Studio Code und Hugo (sowie ein paar weitere Tools dafür) installiert. Ich musste auch immer daran denken, im Repo zu committen und zu pushen, wenn ich an einem anderen Rechner weiterarbeiten wollte. Das hat mehrfach dazu geführt, dass ich Merge-Konflikte hatte und auf verschiedenen Rechnern verschiedene Stände.&lt;/p&gt;
&lt;h2 id="meine-lösung"&gt;Meine Lösung
&lt;/h2&gt;&lt;p&gt;Ich kenne Code-Server schon einige Zeit und habe es in anderem Kontext schon verwendet. Letztendlich handelt es sich &amp;ldquo;einfach nur&amp;rdquo; um ein VS Code im Webbrowser, was auf einem Server läuft. Das habe ich in einem LXC installiert, daneben natürlich noch die notwendigen Tools wie Hugo.
Als Reverse-Proxy sitzt Caddy dazwischen, die Authentifizierung bzw. Absicherung ist über Forward-Auth zusammen mit Authentik gelöst. Damit kann ich sicher von überall auf den Code-Server zugreifen und an meinem Blog schreiben und bin nicht vom Rechner selbst abhängig.&lt;/p&gt;
&lt;h3 id="proxy-für-preview"&gt;Proxy für Preview
&lt;/h3&gt;&lt;p&gt;Standardmäßig lassen sich auf einem Subpfad von Code-Server freigegebene Ports (z.B. der integrierte Preview-Server von Hugo) unter &lt;code&gt;/proxy/&amp;lt;port&amp;gt;&lt;/code&gt; aufrufen. Hugo hat hier allerdings ein Problem, da der Subpfad für Hugo nicht sichtbar ist. Damit laden Assets wie CSS und JS nicht.&lt;/p&gt;
&lt;p&gt;Abhilfe schafft hier die Nutzung von &lt;code&gt;/absproxy/&amp;lt;port&amp;gt;&lt;/code&gt;, in Verbindung mit den Argumenten &lt;code&gt;--baserURL=https://coder.local/absproxy/1313/ --appendPort=false&lt;/code&gt; beim Aufruf von Hugo, damit einerseits der Subpfad vor Hugo nicht versteckt wird und andererseits Hugo für die Nutzung auf diesem Subpfad konfiguriert wird.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Der neue Workflow funktioniert für mich wirklich gut, ich kann auch während der Schreibphase für einen neuen Post problemlos zwischen Rechnern wechseln und habe immer die selbe Codebasis zur Verfügung. Das hat den Overhead durch genannte Merge-Konflikte (oder das Hochfahren von einem anderen Rechner, um die Änderungen noch ins Repo zu schreiben) spürbar reduziert.&lt;/p&gt;
&lt;p&gt;Ob das auf Dauer gut funktioniert weiß ich nicht, aber es sind mittlerweile 4 Monate, seit dem ich Code-Server nutze. Code-Server lässt sich auch für vieles anderes (und deutlich aufwändigeres) nutzen, als ich hier tue.&lt;/p&gt;</description></item><item><title>Planka - einfach nur Kanban</title><link>https://secretmine.de/blog/2026/2026-03-08-planka/</link><pubDate>Sun, 08 Mar 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-03-08-planka/</guid><description>&lt;blockquote class="alert alert-note"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📝&lt;/span&gt;
 &lt;span class="alert-title"&gt;Hinweis&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;Dieser Post entspricht nicht mehr dem aktuellen Stand, mehr dazu &lt;a class="link" href="https://secretmine.de/blog/2026/2026-08-10-planka-keine-empfehlung-mehr/" &gt;hier&lt;/a&gt;&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;p&gt;Ich war lange auf der Suche nach einer ToDo-Lösung für mich.&lt;/p&gt;
&lt;h2 id="ein-bisschen-historie"&gt;Ein bisschen Historie
&lt;/h2&gt;&lt;p&gt;Ganz früher habe ich Wunderlist verwendet (heute Microsoft Todo), das hat aber nicht sonderlich lange funktioniert. Dann hatte ich über mehrere Jahre einen eigenen Jira-Server - das lief soweit gut, war aber für den normalen Alltag so viel Overkill wie nur geht. Klar, die Integration mit Confluence und auch die mobilen Apps dazu waren gut, trotzdem ist Jira eher für größeres Projektmanagement als für die eigene ToDo gebaut. Und die Server-Lizenzen für wenige Dollar gibts auch schon lange nicht mehr, Atlassian stellt die selbst hostbaren Produkte ja nach und nach komplett ein. Also zurück zu Microsoft Todo. Das war aber irgendwie immernoch nicht das Wahre. Auf der Suche nach einer weiteren neuen Lösung habe ich mir dann einige Softwareprodukte angesehen. Und gelandet bin ich am Ende bei Planka.&lt;/p&gt;
&lt;h2 id="was-kann-planka"&gt;Was kann Planka?
&lt;/h2&gt;&lt;p&gt;Ganz ehrlich? Nicht viel. Planka kann Kanban-Boards, genau dafür ist es entwickelt worden. Und abseits davon gibts auch nicht viel zu sehen. Aber die Boards sind übersichtlich, Planka braucht eher wenig Ressourcen, lässt sich mit SSO gut integrieren, hat fürs Handy zumindest die Möglichkeit für eine PWA und &lt;em&gt;just works&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Im Vergleich zu anderen Kanban-Lösungen ist Planka minimalistisch gehalten und konzentriert sich auf den Kerngedanken. Gefällt mir gut.&lt;/p&gt;
&lt;h2 id="wie-nutze-ich-planka"&gt;Wie nutze ich Planka?
&lt;/h2&gt;&lt;p&gt;Ich habe ein großes Board, mit Spalten für Irgendwann, Zeitnahe, Morgen, Heute, In Arbeit, Blocked und Fertig. Das ist also angelehnt an klassisches Kanban, aber mehr auf die Nutzung als persönliche ToDo getrimmt. Das ganze ist mit einer eigenen Software (&lt;a class="link" href="https://secretmine.de/blog/2025/2025-09-20-plankaprinter-bondrucker/" &gt;Plankaprinter&lt;/a&gt;) auch halbwegs automatisiert und bindet z.B. meinen Kalender an (und druckt ToDos für heute automatisch auf einem Kassenbondrucker aus). Dadurch kann ich auch sagen, dass sich die API gut nutzen lässt.&lt;/p&gt;
&lt;p&gt;Ich habe Planka als Web-App auf allen Rechnern &amp;ldquo;installiert&amp;rdquo;, auf dem Handy genauso. Die mobile Nutzung ist nicht perfekt, aber brauchbar.&lt;/p&gt;
&lt;p&gt;Das ganze funktioniert so gut, dass meine Partnerin jetzt ebenfalls von Microsoft Todo zu Planka gewechselt hat und Planka einer der zentralen Dienste neben Nextcloud und HomeAssistant geworden ist.&lt;/p&gt;
&lt;h2 id="was-fehlt-mir"&gt;Was fehlt mir?
&lt;/h2&gt;&lt;p&gt;Zugegeben, das neue Planka v2 habe ich mir noch nicht großartig angeschaut. Daher bezieht sich alles auf v1.&lt;/p&gt;
&lt;p&gt;Die mobile Nutzung ist nicht optimal. Vor allem die Meldung, dass die Serververbindung unterbrochen wurde, nachdem man die &amp;ldquo;App&amp;rdquo; eine Weile nicht benutzt hat, nervt. Verschieben von Karten funktioniert, teilweise scrollt der Ausschnitt aber zu weit zur Seite und man trifft nicht die korrekte Spalte.&lt;/p&gt;
&lt;p&gt;Auch das, was bei Jira die Epics sind, fehlt mir ein wenig. Also größere Aufgaben, zu der dann mehrere Karten gehören. Aber das ist eben nicht das Ziel von Planka, es ist kein volles Projektmanagement-Tool.&lt;/p&gt;
&lt;p&gt;Ansonsten wüsste ich aber nicht viel. Eigentlich funktioniert Planka wirklich solide.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Planka hat sich jetzt über mehrere Monate hinweg als hilfreich für die eigene Organisation erwiesen. Es kann genug (aber auch nicht zu viel), um als Kanban-Lösung für den Zweck ziemlich gut zu passen. Was will man mehr?&lt;/p&gt;</description></item><item><title>Storage-Cluster - Part 1: Der Plan</title><link>https://secretmine.de/blog/2026/2026-02-28-storage-cluster-der-plan/</link><pubDate>Sat, 28 Feb 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-02-28-storage-cluster-der-plan/</guid><description>&lt;h1 id="storage-cluster---der-plan"&gt;Storage-Cluster - der Plan
&lt;/h1&gt;&lt;p&gt;Wer regelmäßig mit Virtualisierung, Containern und Selfhosting arbeitet, kennt das Problem: der Storage wächst einem über den Kopf. Auch bei mir sind die bisherigen Nodes inzwischen so stark ausgelastet, dass für größere Storage-Aufgaben schlicht kein Platz mehr ist. Zeit also für den nächsten Ausbauschritt in meinem Homelab – ein (weitestgehend) dedizierter, energieeffizienter und möglichst robuster Storage-Cluster.&lt;/p&gt;
&lt;h2 id="das-ziel"&gt;Das Ziel
&lt;/h2&gt;&lt;p&gt;Wie auch in größeren IT-Projekten üblich, beginnt alles mit der Zielsetzung bzw. der Erfassung der Anforderungen.&lt;/p&gt;
&lt;p&gt;Ich brauche einerseits Storage, der schnell ist und den Ausfall einer von drei geplanten Nodes verkraftet, andererseits Massenspeicher für z.B. Medien, LXC-Templates, ISOs und co, der nicht hochverfügbar sein muss und auch nicht die selben Geschwindigkeiten erreichen muss. Auf dem schnellen Speicher sollen wichtige VMs/LXCs liegen (bspw. DNS und HomeAssistant), daneben soll dieser Bereich auch als Speicher für Docker Swarm dienen.&lt;/p&gt;
&lt;p&gt;Am liebsten hätte ich hier natürlich vollständige Hochverfügbarkeit, also keinen einzelnen Single-Point-of-Failure (redundantes Netzwerk, redundante Stromversorgung, &amp;hellip;). Das ist für Zuhause aber einerseits overkill und andererseits weder finanziell noch energetisch sinnvoll. Daher möchte ich eine möglichst gute Verfügbarkeit erreichen, ohne dabei komplett in den Enterprise-Bereich vorzudringen.&lt;/p&gt;
&lt;p&gt;Die bisherigen Nodes sind mit ihren eigentlichen Aufgaben zu stark ausgelastet, um hier sinnvoll auch noch Storage machen zu können. Das ist so gerade zwar im Einsatz, ich merke allerdings, dass ich mich damit zu nahe an der Grenze bewege.&lt;/p&gt;
&lt;h2 id="der-plan"&gt;Der Plan
&lt;/h2&gt;&lt;p&gt;Ich habe über die letzten Wochen einen Plan erarbeitet, PoCs aufgesetzt und vieles ausprobiert. Bisher ist der Cluster noch nicht aufgebaut, aber ich denke, dass ich mit der Auswahl an Hardware und Software mein Ziel erreiche.&lt;/p&gt;
&lt;h3 id="hardware-natürlich-thin-clients"&gt;Hardware. Natürlich Thin-Clients
&lt;/h3&gt;&lt;p&gt;Die Hardwarebasis bilden drei Fujitsu Futro S740 Thin Clients. Dass ich die Dinger mag, ist bekannt. Die Wahl fiel auf dieses Modell, da es günstig ist, sehr energieeffizient läuft und genügend Erweiterungsmöglichkeiten bietet. Der Plan ist hierbei, in der ersten Ausbaustufe den WiFi-Slot für einen SATA-Controller zu nutzen. Später soll der SATA-Controller dann in den SSD-Slot (der laut Internet neben SATA auch PCIe-Anbindung hat) wandern und der WiFi-Slot für eine 2,5 GBit/s Netzwerkkarte genutzt werden.&lt;/p&gt;
&lt;p&gt;Geplanter Ausbau pro Node:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;4 GB RAM&lt;/li&gt;
&lt;li&gt;1x 16/32GB für das OS (meistens dabei)&lt;/li&gt;
&lt;li&gt;1× 480 GB SSD (für Ceph)&lt;/li&gt;
&lt;li&gt;1× 1 TB HDD (für SaunaFS oder Alternativen)&lt;/li&gt;
&lt;li&gt;SATA-Controller über den WiFi-Slot (Adapterlösung)&lt;/li&gt;
&lt;li&gt;Später Upgrade auf 2,5 Gbit/s LAN&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Das Netzwerk wird anfangs über meine bestehende 1 GBit/s-Infrastruktur gelöst, später ist hier ein zusätzlicher 2,5 GBit/s Switch geplant. Ich rechne ohne Datenträger mit Kosten von ca 75 € pro Knoten, was ich für nicht viel halte. Ohne Datenträger bekomme ich damit für etwas über 200 € einen weitestgehend redundanten Storage-Cluster.&lt;/p&gt;
&lt;h3 id="software"&gt;Software
&lt;/h3&gt;&lt;p&gt;Für den Storage-Cluster sollen zwei Software-Lösungen zum Einsatz kommen. Ceph wird für den schnellen Speicher genutzt, der Massenspeicher wird nach aktuellem Stand auf SaunaFS aufbauen. Ceph habe ich ausgesucht, da es von Proxmox nativ unterstützt wird und dort sogar gut integriert ist. Neben Blockspeicher kann ich dort über CephFS auch Freigaben auf Dateiebene erzeugen, was ich für Docker Swarm benötige. Es ist zudem performant und im Enterprise-Bereich stark vertreten. Für den langsameren Speicher habe ich lange überlegt, was ich nutzen möchte. Erst hatte ich GlusterFS vorgesehen. Mittlerweile habe ich mich hier aber umentschieden und möchte SaunaFS einsetzen. Das ist ein Fork von LizardFS, was wiederum ein Fork von MooseFS ist. Es ist für verteilten Massenspeicher ausgelegt, hat eher wenig Overhead und bietet sogar die Option, die Anzahl der Replikas pro Ordner festzulegen.&lt;/p&gt;
&lt;p&gt;Auf jedem der Futros wird dementsprechend Proxmox VE installiert und die Nodes in den bisherigen Cluster eingefügt. Die SSDs werden als OSDs für Ceph genutzt, die zusätzlichen Datenträger dann als Mountpoints an einen LXC pro Node angebunden. Dort wird dann SaunaFS installiert. SaunaFS kann ich aufgrund der Voraussetzung von Ubuntu als OS leider nicht direkt auf den Knoten installieren, die Variante mit SaunaFS habe ich jetzt aber auch schon eine Weile im Haupt-Cluster im Testbetrieb erfolgreich genutzt.&lt;/p&gt;
&lt;p&gt;Das SaunaFS-Volume wird dann von einem Knoten via Samba und NFS freigegeben. Das hat den Hintergrund, dass es mit vielen Dingen kompatibel ist und sich so z.B. auch in Proxmox als Speicher für Templates und ISOs gut einbinden lässt.&lt;/p&gt;
&lt;h2 id="weitere-ideen-und-mögliche-dienste"&gt;Weitere Ideen und mögliche Dienste
&lt;/h2&gt;&lt;p&gt;Wenn die Performance passt, sollen auf dem Storage-Cluster später auch leichte Dienste laufen und damit die bestehenden Nodes etwas entlastet werden. Kandidaten dafür sind Dinge wie der Proxmox Backup Server oder auch Komponenten von meinem Monitoring-Stack.&lt;/p&gt;
&lt;p&gt;Ob das mit 4 GB RAM pro Node praktikabel ist, wird sich erst zeigen - mehr RAM kaufen ist aber aufgrund der Lage am Markt gerade keine Option.&lt;/p&gt;
&lt;h2 id="nächste-schritte"&gt;Nächste Schritte
&lt;/h2&gt;&lt;p&gt;Ich habe Hardware bestellt, um einen Futro mal mit einem SATA-Controller auszustatten und damit schonmal als Storage (ohne Ceph oder Replikation oder so) einzusetzen. Das dient als erster Test. Wenn das so funktioniert, wie ich mir das vorstelle, werden weitere Futro S740er gekauft und der Cluster aufgebaut.&lt;/p&gt;
&lt;p&gt;Ich nehme dafür den Futro, den ich eigentlich für den 3D-Drucker gekauft hatte. Dort kommt einfach wieder der S520 hin. Das bietet sich an, da ich für den 3D-Drucker wenig Leistung brauche, der Futro S520 eh nichts zu tun hat und ich so gut etwas Geld sparen kann.&lt;/p&gt;</description></item><item><title>Authentifizierung und Single-Sign-On im Homelab mit Authentik</title><link>https://secretmine.de/blog/2026/2026-02-22-authentifizierung-und-sso-im-homelab-mit-authentik/</link><pubDate>Sun, 22 Feb 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-02-22-authentifizierung-und-sso-im-homelab-mit-authentik/</guid><description>&lt;p&gt;Zentrale Authentifizierung bringt selbst im Homelab klare Vorteile: Einmalige Anmeldung spart Zeit, erhöht die Sicherheit durch weniger Passwörter und erleichtert die Verwaltung von Zugriffsrechten – perfekt für ein Homelab mit vielen Services. Nebenbei bekommt man damit auch Anwendungen, die zwar SSO können, aber keine Multifaktorauthentisierung beherrschen, mit MFA ausgestattet.&lt;/p&gt;
&lt;h2 id="vorteile-gegenüber-anderen-lösungen-keycloak"&gt;Vorteile gegenüber anderen Lösungen (Keycloak)
&lt;/h2&gt;&lt;p&gt;Ich hatte früher Keycloak im Einsatz, was mir aber aufgrund seiner Komplexität im Homelab einfach zu überladen war. Keycloak kann sicherlich mehr als Authentik (denke ich zumindest), ist für mich zuhause allerdings overkill. Authentik ist zwar auch nicht trivial, trotzdem empfinde ich die Konfiguration als angenehmer. Für mich ist der Hauptzweck im Homelab OpenID Connect (OIDC), andere Protokolle wie SAML spielen bei mir keine Rolle.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Admin-Oberfläche von Authentik" class="gallery-image" data-flex-basis="460px" data-flex-grow="191" height="800" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-02-22-authentifizierung-und-sso-im-homelab-mit-authentik/images/admin.png" srcset="https://secretmine.de/blog/2026/2026-02-22-authentifizierung-und-sso-im-homelab-mit-authentik/images/admin_hu_3af7f69f9b865def.png 800w, https://secretmine.de/blog/2026/2026-02-22-authentifizierung-und-sso-im-homelab-mit-authentik/images/admin.png 1534w" width="1534"&gt;&lt;/p&gt;
&lt;h2 id="outposts"&gt;Outposts
&lt;/h2&gt;&lt;p&gt;Ein weiterer großer Vorteil von Authentik sind die sogenannten Outposts, mit denen neben SSO-Protokollen auch LDAP-Dienste, Remotedesktop-Zugriff und Proxy-Authentifizierung angeboten werden.&lt;/p&gt;
&lt;p&gt;Über den Proxy-Outpost kann man die Authentifizierung direkt in einem Reverse-Proxy bzw. Webserver integrieren. Dadurch lassen sich interne Anwendungen sehr sicher über das Internet erreichbar machen. Bei mir laufen viele Anwendungen mit OIDC-Anbindung, einige interne Dienste sind zudem über Caddy mit Forward-Auth abgesichert. Mein Proxmox-Cluster ist sogar direkt per LDAP-Outpost an Authentik angebunden, was den Sync von Usern und Gruppen einfach macht.​ Ob das sinnvoll ist, ist allerdings eine andere Sache, immerhin bin ich der einzige Benutzer. Andere Services wie beispielsweise Nextcloud oder Planka nutze ich hingegen nicht nur alleine.&lt;/p&gt;
&lt;p&gt;Relativ neu ist der Remote Access Control (RAC) Outpost, womit sich Remotedesktop-Dienste anbinden lassen. Die Technik dahinter ist am Ende allerdings &amp;ldquo;nur&amp;rdquo; ein Apache Guacamole, den ich schon &lt;a class="link" href="https://secretmine.de/blog/2025/2025-06-09-guacamole/" &gt;anderweitig betreibe&lt;/a&gt; und durch den getrennten Betrieb bessere Kontrolle und mehr Konfigurationsmöglichkeiten erhalte.&lt;/p&gt;
&lt;h3 id="konfiguration-für-forward-auth-mit-caddy"&gt;Konfiguration für Forward-Auth mit Caddy
&lt;/h3&gt;&lt;p&gt;Hier ein kurzes Config-Snippet für Auth mit Caddy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(authentik_forwardauth) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reverse_proxy /outpost.goauthentik.io/* http://proxy-outpost:9000
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; forward_auth http://proxy-outpost:9000 {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; uri /outpost.goauthentik.io/auth/caddy
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; trusted_proxies private_ranges
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;proxmox.example.com {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; import authentik_forwardauth
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reverse_proxy 192.168.0.2:8006 {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; transport http {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; tls_insecure_skip_verify
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In Authentik muss Proxmox mit der entsprechenden Domain als Proxy-Provider angelegt werden, mit dem Modus &amp;ldquo;Forward Auth&amp;rdquo;. Beim Outpost selbst muss dieser Provider dann noch zugewiesen werden, danach sollte alles schon funktionieren.&lt;/p&gt;
&lt;p&gt;Der Proxy Outpost kann wohl auch direkt Proxy spielen - mit der Lösung via Caddy und Forward-Auth kann ich allerdings mehrere Anwendungen anbinden, ohne mehrere Outposts zu benötigen.&lt;/p&gt;
&lt;h2 id="weitere-praktische-features"&gt;Weitere praktische Features
&lt;/h2&gt;&lt;p&gt;Neben der eigentlichen Authentifizierung zeigt Authentik die eingerichteten Anwendungen auch auf einer übersichtlichen Hub-Oberfläche an. Die Anwendungen lassen sich in Gruppen ordnen, es werden auch nur die Anwendungen angezeigt, die zu denen der entsprechende Benutzer Zugang hat. Das erspart den Betrieb von einer getrennten Homepage bzw. Hub-Oberfläche.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Authentik Hub" class="gallery-image" data-flex-basis="482px" data-flex-grow="200" height="672" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-02-22-authentifizierung-und-sso-im-homelab-mit-authentik/images/hub.png" srcset="https://secretmine.de/blog/2026/2026-02-22-authentifizierung-und-sso-im-homelab-mit-authentik/images/hub_hu_c68b7ce971da903d.png 800w, https://secretmine.de/blog/2026/2026-02-22-authentifizierung-und-sso-im-homelab-mit-authentik/images/hub.png 1350w" width="1350"&gt;&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Nach mehreren Jahren im Betrieb funktioniert Authentik zuverlässig und stabil. Es ist eine empfehlenswerte Alternative zu Keycloak, wenn man eine sichere, moderne Authentifizierungslösung mit erträglichem Konfigurationsaufwand im Homelab sucht.​ Vor allem die Outposts sind ein klarer Vorteil von Authentik gegenüber anderer Lösungen.&lt;/p&gt;</description></item><item><title>Harbor als lokale Container-Registry</title><link>https://secretmine.de/blog/2026/2026-02-06-harbor-als-lokale-container-registry/</link><pubDate>Fri, 06 Feb 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-02-06-harbor-als-lokale-container-registry/</guid><description>&lt;p&gt;Harbor ist eine Open-Source-Container-Registry-Plattform, die Docker-Images und Helm-Charts speichert und verwaltet. Neben der Nutzung als normale Registry zum Speichern von Images kann Harbor auch als Proxy-Registry dienen. Das ist bei mir der primäre Einsatzzweck. Nebenbei kann Harbor auch die Images mit Trivy auf bekannte Schwachstellen scannen. Die Übersichtsseite leuchtet leider schnell wie ein Weihnachtsbaum - man sieht schnell, welche Images lange nicht mehr aktualisiert wurden oder veraltete Softwareversionen nutzen. Trivy ist hierbei einer der gängigen Scanner, der die im Image vorhandenen Komponenten gegen Datenbanken mit bekannten Schwachstellen prüft (nicht nur normale Pakete, es werden bei diversen Programmiersprachen auch die verwendeten Libraries geprüft).&lt;/p&gt;
&lt;p&gt;Registries wie Docker Hub haben oft Pull-Limits, besonders bei häufigen Updates im Homelab ist das schnell nervig. Mit Harbor dazwischen reduziere ich die Anzahl der Pulls direkt von Docker Hub und kann auch schon gespeicherte Images oder Layer schneller ausliefern. Vor allem durch meine Verwendung von Docker Swarm ist das von Vorteil, da sonst bei der Migration eines Services von einer Node zu einer anderen das Image neu von der Quelle heruntergeladen wird. Mit Harbor als Proxy bzw. Cache kommt das Image dann direkt aus dem lokalen Netz.&lt;/p&gt;
&lt;h2 id="installation"&gt;Installation
&lt;/h2&gt;&lt;p&gt;Die Einrichtung ist unkompliziert, allerdings etwas anders, als man es von anderen containerisierten Diensten kennt. Man benötigt den Harbor-Installer von z.B. Github. Dann muss noch die harbor.yml erstellt bzw. angepasst werden (Hostname, HTTPS, Admin-Passwort), dann wird der Installer ausgeführt. Die Services sind am Ende ein normaler Docker Compose Stack.&lt;/p&gt;
&lt;p&gt;Sinnvoll ist hier auch die Nutzung eines Reverse-Proxies mit SSL, da Docker (und auch andere Container-Runtimes) Pulls aus unsicheren (=http) Registries ohne weitere Konfiguration verweigern. Am einfachsten ist ein Zertifikat von bspw. Lets Encrypt, mit der DNS-Verifizierungsmethode geht das dann auch, ohne dass Harbor von außen erreichbar ist. Selbstsignierte Zertifikate (z.B. via ACME von [Step-CA]({&amp;laquo; ref &amp;ldquo;/blog/2025/2025-02-28-lokale-ssl-zertifikate-mit-caddy-und-step-ca/index.md&amp;rdquo; &amp;raquo;})) sind möglich, dann muss das entsprechende Root-Zertifikat allerdings auf jedem System, das die lokale Registry nutzen soll, hinterlegt werden.&lt;/p&gt;
&lt;h2 id="cache-repo-einrichten"&gt;Cache-Repo einrichten
&lt;/h2&gt;&lt;p&gt;Damit man ein Cache-Repository einrichten kann, muss zuerst die Upstream-Registry unter Administration -&amp;gt; Registries hinzugefügt werden. Wenn ein Cache für Docker Hub angelegt werden soll, ist es hierbei empfehlenswert, Zugangsdaten mit anzugeben, um von den höheren Pull-Limits zu profitieren.&lt;/p&gt;
&lt;p&gt;Danach kann unter Projekte ein neues Projekt mit aktivem &lt;code&gt;Proxy Cache&lt;/code&gt; eingerichtet werden und der entsprechende Upstream (z.B. die angelegte Docker-Hub-Registry) ausgewählt werden.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cache-Repository" class="gallery-image" data-flex-basis="460px" data-flex-grow="191" height="763" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2026/2026-02-06-harbor-als-lokale-container-registry/images/cache_repo.png" srcset="https://secretmine.de/blog/2026/2026-02-06-harbor-als-lokale-container-registry/images/cache_repo_hu_c1ee0ab411e3d054.png 800w, https://secretmine.de/blog/2026/2026-02-06-harbor-als-lokale-container-registry/images/cache_repo.png 1464w" width="1464"&gt;&lt;/p&gt;
&lt;h2 id="client-einrichten"&gt;Client einrichten
&lt;/h2&gt;&lt;p&gt;In Harbor lassen sich Robot-Zugänge unter Administration anlegen. Bei den Berechtigungen habe ich folgendes vergeben:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Artifact: Auflisten, Lesen&lt;/li&gt;
&lt;li&gt;Repository: Auflisten, Pull, Lesen&lt;/li&gt;
&lt;li&gt;Tag: Auflisten&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Danach muss nur noch der Client (hier Docker) angemeldet werden.&lt;/p&gt;
&lt;p&gt;Im Fall von Docker ist das schnell gemacht:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker login harbor.local
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Danach zieht man Images einfach über &lt;code&gt;harbor.local/dockerhub-cache/image:tag&lt;/code&gt; (natürlich mit korrektem Hostnamen und Registry-Namen) - Harbor übernimmt den Rest automatisch. In Compose-Dateien lässt sich die Cache-Registry dann natürlich auch nutzen.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Harbor funktioniert bei mir ziemlich gut, allerdings waren auch schon 1-2 Mal die Container morgens nicht mehr gestartet. Man schafft sich damit leider auch einen Single Point of Failure, da der Betrieb von allen Containern im Lab von der Registry abhängt. Vor allem beim Betrieb von vielen Containern oder bei Nutzung eines Orchestrators (wie Kubernetes oder Docker Swarm) ist ein lokaler Cache zur Verminderung von Pulls aber definitiv sinnvoll und verringert die Startzeiten von Containern auf neuen Nodes spürbar.&lt;/p&gt;</description></item><item><title>Outline als (persönliches) Wiki</title><link>https://secretmine.de/blog/2026/2026-01-31-outline/</link><pubDate>Sat, 31 Jan 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-01-31-outline/</guid><description>&lt;p&gt;Lange Zeit habe ich Confluence als Wiki genutzt. Funktionsreich, hübsch und mit Jira integriert. Aber irgendwann kamen die bekannten Punkte: hoher Ressourcenbedarf und aktiver Rückbau der selbstgehosteten Version durch Entfernung der günstigen Lizenzen (und zukünftig auch aller selbsthostbaren Varianten). Also begann die Suche nach einer Alternative, die möglichst schlank, aber trotzdem gut nutzbar sein sollte.&lt;/p&gt;
&lt;p&gt;Ich habe mir dabei diverses angesehen. XWiki kannte ich von der Arbeit, gefiel mir aber weder optisch noch von der Bedienung her. Von den Ressourcen war es auch eher auf dem Level von Confluence. MediaWiki hat für nicht funktioniert - als Wiki generell nicht schlecht, für &amp;ldquo;mal eben&amp;rdquo; aber irgendwie unhandlich. Wiki.js habe ich mir ebenfalls angesehen, aber auch damit bin ich nicht so wirklich warm geworden. Die Bedienung ging nicht so von der Hand, wie ich mir das vorgestellt habe.&lt;/p&gt;
&lt;p&gt;Dann hat mir mein Bruder Outline gezeigt. Was für mich ziemlich perfekt aussah. Minimalistisch, schnell, gute und intuitive Bedienung. Es fühlt sich modern an, ohne überladen zu sein. Und ist auch noch Markdown-basiert. Eine native App gibt es zwar nicht, die PWA funktioniert aber gut.&lt;/p&gt;
&lt;p&gt;Der Funktionsumfang und auch Gestaltungsmöglichkeiten sind natürlich deutlich unter dem, was Confluence kann, aber davon vermisse ich auch nach vielen Jahren wenig.&lt;/p&gt;
&lt;h2 id="betrieb"&gt;Betrieb
&lt;/h2&gt;&lt;p&gt;Selfhosting bei Outline ist nicht so einfach wie bei anderen Softwareprodukten. Neben einer Postgres-Datenbank wird Redis benötigt - soweit so gut. Zwingend erforderlich ist aber auch ein externer Auth-Provider - in meinem Fall OIDC via Authentik. Früher war auch ein S3-Bucket als Speicher für Anhänge erforderlich, die Anforderung ist aber dank dem neu hinzugekommenen lokalen Storage nicht mehr verpflichtend. Trotzdem fühlt es sich so an, als ob Selfhosting zwar offiziell unterstützt wird, der Hersteller aber den Fokus klar auf dem eigenen SaaS-Angebot in der Cloud hat.&lt;/p&gt;
&lt;p&gt;Hat man das Setup aber einmal laufen, ist Outline sehr stabil. Ich nutze es nun seit gut drei Jahren in meiner Umgebung, und es ist dabei geblieben – einfach, weil es funktioniert.&lt;/p&gt;
&lt;h2 id="fazit"&gt;Fazit
&lt;/h2&gt;&lt;p&gt;Outline hat sich bei mir nun wirklich bewährt. Minimalistisch, aber trotzdem genügend Features; selbst hostbar, gute Bedienung. Alternativ lohnt sich ein Blick auf Bookstack. Das habe ich mir zwar lange nicht mehr angesehen, war aber der Alternativkandidat, falls Outline mir nicht gefallen hätte.&lt;/p&gt;</description></item><item><title>Docker Swarm nach zwei Monaten</title><link>https://secretmine.de/blog/2026/2026-01-03-docker-swarm-nach-einem-monat/</link><pubDate>Sat, 03 Jan 2026 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2026/2026-01-03-docker-swarm-nach-einem-monat/</guid><description>&lt;p&gt;Auch, wenn der &lt;a class="link" href="https://secretmine.de/blog/2025/2025-12-17-containerorchestrierung-im-homelab/" &gt;Blog-Post zu Docker Swarm&lt;/a&gt; noch keinen Monat her ist, ist Swarm jetzt seit November bei mir im Einsatz. Ich möchte hier einmal ein Zwischenfazit geben.&lt;/p&gt;
&lt;h2 id="wie-das-setup-aussieht"&gt;Wie das Setup aussieht
&lt;/h2&gt;&lt;p&gt;Ich habe pro physischem Host eine Swarm-VM, die drei VMs sind auch alle als mögliche Master-Nodes konfiguriert. Damit findet die Auswahl eines neuen Masters statt, sobald der bisherige Master nicht mehr erreichbar sein sollte. Storage ist über NFS abgebildet, das basiert auf zwei VMs (plus eine Witness-Node) mit Pacemaker, Corosync und DRBD. Das läuft soweit auch stabil, auch wenn die Performance etwas besser sein könnte. Vor allem bei Random Access merkt man doch deutlich den Unterschied zu lokalem Storage. Fairerweise muss ich dazu aber auch sagen, dass das wahrscheinlich primär an der verwendeten Hardware liegt, die Kombination aus Thin Client und günstiger SSD ist da sicherlich nicht hilfreich. Ich muss leider auch die Verzeichnisse auf dem NFS-Server händisch anlegen, damit ich diese in Volumes referenzieren kann. Das geht besser, bin ich von Kubernetes mit dem NFS-Provisioner auch anders gewohnt. Alternative Storage-Lösungen wie Ceph oder ähnliche sind mir fürs Homelab allerdings auch zu komplex. Mit dem Punkt kann ich aber generell gut leben.&lt;/p&gt;
&lt;p&gt;Zum Management nutze ich Portainer CE. Das ist eins der wenigen Tools, die auch mit Swarm umgehen können, wobei wohl bei Komodo in einer zukünftigen Version Swarm auch unterstützt werden soll. Zwecks Monitoring läuft auf den Nodes jeweils der Node-Exporter und ein Docker-Exporter. Der Docker-Exporter kann zwar nicht nativ mit Swarm umgehen, erfasst aber trotzdem dann pro Node die laufenden Container inkl. der benötigten Ressourcen. Das reicht mir.&lt;/p&gt;
&lt;h2 id="was-mir-im-betrieb-aufgefallen-ist"&gt;Was mir im Betrieb aufgefallen ist
&lt;/h2&gt;&lt;p&gt;Der Scheduler ist sehr grundlegend. Nach dem, was ich im Internet finden konnte, wird aus den Nodes, die die Constraints und die Ressourcen-Requirements erfüllen, die Node mit den wenigsten Containern ausgewählt und der Task dort gestartet. Wirklich gut steuern lässt sich das auch nicht, es gibt nur harte Constraints und keine weichen. Das kann Kubernetes sehr viel besser. By Design werden Service auch nach dem Joinen einer neuen Node (oder eine bestehende Node war z.B. wegen Wartungsarbeiten offline) nicht neu verteilt, das machen andere Lösungen wie Kubernetes aber auch nicht anders. Um das auszugleichen bin ich aktuell dabei, einen Rebalancer zu entwickeln, der diesen Zustand erkennt und gezielt Services neu startet, um ein Rescheduling zu erzwingen. Das ist aber noch nicht fertig.&lt;/p&gt;
&lt;h2 id="wie-es-weitergeht"&gt;Wie es weitergeht
&lt;/h2&gt;&lt;p&gt;Ich bin weiterhin dabei, Services zum Swarm-Cluster zu migrieren, insgesamt bin ich mit der Lösung soweit glücklich. Storage wird von der Performance her irgendwann wahrscheinlich zum Flaschenhals, aber darum mache ich mir dann Gedanken, wenn es soweit ist.&lt;/p&gt;
&lt;p&gt;Ich trauere tatsächlich noch ein wenig Kubernetes hinterher, vor allem weil ich es beruflich gewohnt bin. Für Zuhause ist es allerdings meiner Meinung nach komplett overkill.&lt;/p&gt;</description></item><item><title>Containerorchestrierung im Homelab</title><link>https://secretmine.de/blog/2025/2025-12-17-containerorchestrierung-im-homelab/</link><pubDate>Wed, 17 Dec 2025 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2025/2025-12-17-containerorchestrierung-im-homelab/</guid><description>&lt;p&gt;Wie die meisten anderen auch habe ich in meinem Homelab einiges an Containern mit Docker in Betrieb. Bisher verwalte ich das in mehreren VMs in Form von Docker-Compose-Stacks händisch - was eher unbequem ist und auch für Ausfallsicherheit und ähnliches nicht förderlich ist. Es ist außerdem aufwändig, Services zwischen den Nodes zu verschieben.&lt;/p&gt;
&lt;h2 id="orchestrierungstools"&gt;Orchestrierungstools
&lt;/h2&gt;&lt;p&gt;Das hier ist natürlich keine vollständige Auflistung, es sind nur die Optionen, die ich in Betracht gezogen habe.&lt;/p&gt;
&lt;h3 id="docker-compose-stacks"&gt;Docker Compose Stacks
&lt;/h3&gt;&lt;p&gt;&amp;hellip;also die bisherige Lösung.&lt;/p&gt;
&lt;p&gt;Letztendlich einfach nur ein Ordner mit Unterordnern pro Compose-Stack bzw. pro Service.&lt;/p&gt;
&lt;p&gt;Vorteile:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;leicht verwaltbar&lt;/li&gt;
&lt;li&gt;Tools wie Watchtower funktionieren problemlos&lt;/li&gt;
&lt;li&gt;viele Softwareprodukte bieten fertige Compose-Files an&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nachteile:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keine Redundanz bzw. Failover&lt;/li&gt;
&lt;li&gt;Unübersichtlich, was wo läuft&lt;/li&gt;
&lt;li&gt;Traffic muss von außen an die korrekte VM geleitet werden&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="kubernetes"&gt;Kubernetes
&lt;/h3&gt;&lt;p&gt;Beruflich hantiere ich täglich mit Kubernetes, ich bin also mit der Funktionsweise und auch den Tools vertraut. Ausprobiert habe ich k3s und Talos, sowohl mit Longhorn als auch mit NFS als Storage. Compose-Stacks lassen sich mit dem Tool Kompose leicht konvertieren. Mich hat hier allerdings der Overhead gestört. Eine Worker-Node ohne jegliche Workload hat ~10 % CPU-Auslastung erzeugt, was vor allem bei den Thin Clients einfach zu viel ist. Auch ist mir die Verwaltung für zuhause eigentlich zu komplex.&lt;/p&gt;
&lt;p&gt;Vorteile:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;gängiges Orchestrierungstool&lt;/li&gt;
&lt;li&gt;Helm-Charts für viele gängige Softwareprodukte verfügbar&lt;/li&gt;
&lt;li&gt;gutes Scheduling bzw. Lastmanagement, Scheduling auch sehr gut beeinflussbar&lt;/li&gt;
&lt;li&gt;Kompatibel mit vielen Storage-Lösungen&lt;/li&gt;
&lt;li&gt;hohe Anzahl an Tools (GUIs und andere Lösungen)&lt;/li&gt;
&lt;li&gt;Ingress bzw. Overlay-Netzwerk - Services lassen sich problemlos auf allen Nodes erreichbar schalten, intern wird zur korrekten Node geroutet&lt;/li&gt;
&lt;li&gt;Secret-Management mit vielen Optionen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nachteile:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Komplex in der Verwaltung&lt;/li&gt;
&lt;li&gt;Hoher Ressourcenoverhead&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="docker-swarm"&gt;Docker Swarm
&lt;/h3&gt;&lt;p&gt;Docker Swarm ist eine Möglichkeit, mehrere Docker-Daemons miteinander zu vernetzen und zu einer Einheit zu kombinieren. Es ist von der Komplexität her irgendwo zwischen einfachem Docker und Kubernetes, bietet dabei aber auch längst nicht so viele Optionen wie Kubernetes. Der Ressourcenverbrauch ist erfreulich niedrig und die Arbeit mit dem Tool fällt recht leicht, wenn man Compose gewohnt ist. Die Migration von Services ist auch einfach - die Compose-File minimal modifizieren, Storage anlegen und Inhalte übertragen und deployen.&lt;/p&gt;
&lt;p&gt;Vorteile:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simpel zu nutzen, ähnlich zu Docker Compose&lt;/li&gt;
&lt;li&gt;Compose-Files lassen sich nahezu unverändert einsetzen&lt;/li&gt;
&lt;li&gt;Overlay-Netzwerk - Services sind auf allen Nodes erreichbar, intern wird zur korrekten Node geroutet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Nachteile:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;wenig verbreitet, wenig Tools&lt;/li&gt;
&lt;li&gt;Scheduling ist rudimentär (nur harte Constraints möglich, keine Präferenzen bzw. weiche Constraints)&lt;/li&gt;
&lt;li&gt;Weniger Support für verschiedene Storage-Lösungen&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="meine-entscheidung"&gt;Meine Entscheidung
&lt;/h2&gt;&lt;p&gt;Bisher läuft eigentlich alles mit normalen Compose-Stacks. Ich habe erst Kubernetes mit verschiedene Distributionen evaluiert (Talos und k3s) - und obwohl mir das eigentlich gut gefällt und für mich gewohnte Tools sind, ist mir der CPU-Overhead für meinen Wunsch nach Energieeffizienz einfach zu groß; auch wenn die Vorteile ansonsten überwiegen.&lt;/p&gt;
&lt;p&gt;Am Ende fühlt sich Docker Swarm für meinen Einsatzzweck ideal an:
leichtgewichtig, bekanntes Compose-Ökosystem, dazu Clustering und Failover. Durch den zentralen NFS-Storage (DRBD-basiert) kann ich Workloads problemlos verschieben, und das Deployment neuer Stacks ist sehr unkompliziert.&lt;/p&gt;
&lt;p&gt;Der größte Nachteil ist tatsächlich die Tool-Landschaft. Portainer ist aktuell praktisch das einzige gepflegte GUI-Tool – aber es deckt alles ab, was ich brauche. Früher habe ich Swarmpit genutzt, aber dort passiert im Repo leider kaum noch etwas.&lt;/p&gt;
&lt;p&gt;Alles in allem ist Swarm für mein Homelab der beste Kompromiss aus Redundanz, Energieeffizienz und administrativem Aufwand. Ich werde jetzt nach und nach meine Services migrieren, mal schauen, ob ich dabei noch auf Probleme stoße.&lt;/p&gt;</description></item><item><title>Lokales Multiroom-Audio mit dem Lyrion Music Server und Squeezelite</title><link>https://secretmine.de/blog/2025/2025-07-29-lyrion-music-server-und-squeezelite/</link><pubDate>Tue, 29 Jul 2025 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2025/2025-07-29-lyrion-music-server-und-squeezelite/</guid><description>&lt;p&gt;Ich bin vor einer Weile über Lyrion Music Server (&lt;a class="link" href="https://lyrion.org/" target="_blank" rel="noopener"
 &gt;https://lyrion.org/&lt;/a&gt;) gestolpert und fand das Konzept sehr spannend. Lyrion Music Server ist die Weiterentwicklung von Logitech Media Server, einem lokalen Musikserver für die Verwendung mit dafür gebauten Abspielgeräten (Squeezeboxen). Squeezeboxen gibt es abseits vom Gebrauchtmarkt nicht mehr, einen Softwarenachbau für die Player in Form von beispielsweise Squeezelite jedoch bereits vorhanden.&lt;/p&gt;
&lt;p&gt;Was die Software besonders macht ist das Feature, dass mehrere Player synchron bespielt werden können, wie es mit Multiroom-Setups von anderen Herstellern möglich ist. Primär ist Lyrion dafür gebaut, lokale Mediatheken und auch Radio abzuspielen, es gibt jedoch auch ein Plugin, mit dem das ganze über Spotify Connect direkt via Spotify ansteuerbar ist.&lt;/p&gt;
&lt;h2 id="hardware"&gt;Hardware
&lt;/h2&gt;&lt;p&gt;Ich habe aktuell in vier Räumen Player installiert. In einem weiteren Raum ist geplant, zumindest eine Buchse zum Anschluss von z.B. einer Bluetooth-Box izu installieren.&lt;/p&gt;
&lt;h3 id="arbeitszimmer"&gt;Arbeitszimmer
&lt;/h3&gt;&lt;p&gt;Hier stecken meine PC-Lautsprecher einfach über ein Klinke-Y-Kabel sowohl an meinem PC als auch an dem Thin Client, der LMS beherbergt. Dort läuft Squeezelite als Docker in LXC, das Audiogerät ist vom Host an den LXC und Docker durchgereicht und wird von dort bespielt.&lt;/p&gt;
&lt;h3 id="wohnzimmer"&gt;Wohnzimmer
&lt;/h3&gt;&lt;p&gt;Im Wohnzimmer ist ein Raspberry Pi 1b mit piCorePlayer wie im Arbeitszimmer, ebenfalls mit einem Y-Kabel, an das Soundsystem des Fernsehers angeschlossen. Via Homeassistant wird automatisch das Soundsystem eingeschaltet, sobald Musik abgespielt wird.&lt;/p&gt;
&lt;h3 id="schlafzimmer"&gt;Schlafzimmer
&lt;/h3&gt;&lt;p&gt;Hier befindet sich ein selbstgebauter Player. Dieser besteht aus einem Raspberry Pi 1b mit piCorePlayer, einem Verstärker-Board und Regallautsprechern. Der Verstärker kann über ein Relais vom Pi aus ein- und ausgeschaltet werden, um Grundrauschen oder andere Geräusche auf den Lautsprechern zu vermeiden, wenn keine Musik abgespielt wird. Nebenbei spart das natürlich auch Strom. Angetrieben wird das ganze von einem 19V Laptop-Netzteil.&lt;/p&gt;
&lt;h3 id="küche"&gt;Küche
&lt;/h3&gt;&lt;p&gt;Hier ist ähnlich wie im Schlafzimmer ein selbstgebauerter Player platziert, hier allerdings mit einem Raspberry Pi 3. Auch hier ist es ein günstiges Verstärker-Board, schaltbar über ein Relais. Ich hatte auch für diesen Pi erst einen WLAN-Stick bestellt und erst beim Einrichten von piCorePlayer festgestellt, dass der Pi 3 WLAN integriert hat und ich den Stick gar nicht brauche.&lt;/p&gt;
&lt;h2 id="software"&gt;Software
&lt;/h2&gt;&lt;p&gt;Der Lyrion Music Server läuft als Docker, hier ist einmal meine Compose-Datei inkl. des Squeezelite-Players:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;lms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;lmscommunity/lyrionmusicserver:dev&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;network_mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;host&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./config:/config:rw&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./music:/music:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./playlist:/playlist:rw&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/etc/localtime:/etc/localtime:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/etc/timezone:/etc/timezone:ro&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;HTTP_PORT=9000&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;squeezelite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;giof71/squeezelite:latest-alsa&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;devices&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;/dev/snd:/dev/snd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;USER_MODE=yes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;PUID=0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;PGID=0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;AUDIO_GID=29&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;SQUEEZELITE_NAME=Arbeitszimmer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;SQUEEZELITE_AUDIO_DEVICE=&amp;#34;hw:CARD=PCH,DEV=0&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;./sl-config/:/config/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Bei den Plugins habe ich einerseits Spotty für Spotify Connect installiert, andererseits auch ein Plugin, um Gruppen vordefinieren zu können. Ich habe hierbei hauptsächlich eine Gruppe mit allen Lautsprechern definiert, ansonsten werden die Räume in der Regel nur einzeln genutzt.&lt;/p&gt;
&lt;h2 id="soundqualität-und-generelle-erfahrung"&gt;Soundqualität und generelle Erfahrung
&lt;/h2&gt;&lt;p&gt;Die Player mit eigenem Verstärker haben leider ein gutes Maß an Grundgeräuschen, hauptsächlich dürfte das von Spannungswandlern von 19V auf 5V für die Pis kommen. Bei den Playern, wo Soundsysteme angeschlossen sind, habe ich damit keine Probleme.&lt;/p&gt;
&lt;p&gt;Ich (bzw. wir) nutze das System hauptsächlich mit Spotify Connect. Das funktioniert nicht unbedingt perfekt - die Wiedergabe bleibt leider regelmäßig nach Ende eines Songs hängen und muss dann erstmal händisch wieder gestartet werden. Eine Lösung dafür habe ich bislang noch nicht, das Problem beim Spotty-Plugin ist allerdings bekannt. Playlists über die Integration in LMS und nicht via Spotify Connect zu starten soll das Problem beheben, ist für uns allerdings eher unpraktisch.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update&lt;/em&gt;: Beim Plugin, was für Spotify zum Einsatz kommt, wurde aufgrund von API-Änderungen bei Spotify der Connect-Modus vorerst entfernt, seit dem nutzen wir die Integration. Das funktioniert auch fehlerfrei, das System spielt stundenlang ohne einen einzigen Fehler Musik ab.&lt;/p&gt;
&lt;p&gt;Ansonsten funktioniert das System gut, die Lautsprecher laufen weitestgehend synchron. Zeitweise gab es mal mit einem Lautsprecher Probleme, weil aus irgendeinem Grund der WLAN-Empfang in der genauen Position des Players schlecht war, das hat dann dazu geführt, dass das gesamte System regelmäßig out of sync war und die Wiedergabe kurz unterbrochen wurde. Verschieben des Players um einige Zentimeter hat das beseitigt.&lt;/p&gt;</description></item><item><title>Webbasierter Remotezugriff mit Guacamole</title><link>https://secretmine.de/blog/2025/2025-06-09-guacamole/</link><pubDate>Mon, 09 Jun 2025 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2025/2025-06-09-guacamole/</guid><description>&lt;p&gt;Ich habe schon eine ganze Weile mit verschiedenen Möglichkeiten experimentiert, von unterwegs und ohne dabei einen eigenen Client zu benötigen. Dabei bin ich irgendwann auf &lt;strong&gt;Apache Guacamole&lt;/strong&gt; gestoßen, einem webbasierten Remotedesktop-Tool, das im Browser läuft und RDP, VNC und SSH unterstützt. Und sich mit 2FA sichern lässt. Also alles abdeckt, was ich benötige.&lt;/p&gt;
&lt;p&gt;Guacamole läuft bei mir als Docker-Container im Homelab und bietet mir über einen gesicherten Webzugang die Möglichkeit, sowohl meine Windows- als auch meine Linux-VMs zu nutzen. Ein Browser (und Internet) reicht, und ich habe Zugriff auf eine vollständige Desktop-Umgebung – mit gewohnter Software, Dateiablage und allem Drum und Dran. Das funktioniert in den meisten Fällen auch mit restriktiven Firewalls/Proxies, da alles über HTTPS und Websockets abgewickelt wird. Durch Zwei-Faktor-Authentifizierung und restriktive Firewall-Regeln ist das Ganze auch sicher genug, um es von außen erreichbar zu machen. Und es funktioniert meistens sogar hinter restriktiven Firewalls, solange Websockets funktionieren, und eignet sich damit auch für den Zugriff von z.B. der Arbeit oder der Schule/Uni - vorausgesetzt, die vorliegenden Regelungen lassen es zu.&lt;/p&gt;
&lt;h2 id="schematischer-aufbau"&gt;Schematischer Aufbau
&lt;/h2&gt;&lt;p&gt;Technisch ist das ganze eigentlich recht simpel aufgebaut:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Grober Aufbau" class="gallery-image" data-flex-basis="395px" data-flex-grow="164" height="644" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2025/2025-06-09-guacamole/images/guacamole.png" srcset="https://secretmine.de/blog/2025/2025-06-09-guacamole/images/guacamole_hu_2ef0e3a094d815c7.png 800w, https://secretmine.de/blog/2025/2025-06-09-guacamole/images/guacamole.png 1062w" width="1062"&gt;&lt;/p&gt;
&lt;p&gt;Guacamole ist das Herzstück vom ganzen, es stellt das Webinterface bereit, kümmert sich um das Benutzermanagement und verwaltet auch die Verbindungen. Guacamole wiederum steuert Guacd an, das ist ein Dienst, der diverse Protokolle wie RDP und VNC in ein allgemeineres Format übersetzt. Für die Benutzer- und Verbindungsverwaltung wird auch noch eine MySQL-Datenbank benötigt. Davor steht bei mir ein Caddy, aber jeder beliebige andere Reverse-Proxy tut es auch.&lt;/p&gt;
&lt;h2 id="einrichtung"&gt;Einrichtung
&lt;/h2&gt;&lt;h3 id="docker-compose"&gt;Docker-Compose
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;guacdb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;guacamoledb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mariadb:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;9ngmZtFToD3Ll4ncBA6V&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;guacamole_db&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;guacamole_user&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;qi1tqoSTRGx5eD4ghCAG&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;./db-data:/var/lib/mysql&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="s1"&gt;&amp;#39;./initdb.sql:/docker-entrypoint-initdb.d/initdb.sql&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;guacd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;guacd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;guacamole/guacd:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;guacamole&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;container_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;guacamole&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;guacamole/guacamole:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;unless-stopped&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;GUACD_HOSTNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;guacd&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_HOSTNAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;guacdb&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;guacamole_db&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_USER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;guacamole_user&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;qi1tqoSTRGx5eD4ghCAG&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;TOTP_ENABLED&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# optional, forciert 2FA&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;depends_on&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;guacdb&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;guacd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Vor dem Start muss allerdings die Datenbank noch befüllt werden. Das Container-Image bringt ein Script mit, um den nötigen Dump zu erzeugen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sh" data-lang="sh"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql &amp;gt; initdb.sql
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Nun kann mit &lt;code&gt;docker compose up -d&lt;/code&gt; der Stack gestartet werden. Der MariaDB-Container importiert beim ersten Start alles, was unter &lt;code&gt;/docker-entrypoint-initdb.d/&lt;/code&gt; liegt in alphabetischer Reihenfolge - und damit auch den Dump, den wir eben angelegt haben.&lt;/p&gt;
&lt;h3 id="reverse-proxy"&gt;Reverse Proxy
&lt;/h3&gt;&lt;p&gt;Guacamole müsste nun unter dem angegebenen Port (hier 8080) erreichbar sein, es muss der Pfad &lt;code&gt;/guacamole&lt;/code&gt; aufgerufen werden. Jetzt kann noch ein beliebiger Reverse-Proxy auf Guacamole verwiesen werden, beispielsweise Caddy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;guacamole.example.com {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; rewrite / /guacamole
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; reverse_proxy http://192.168.1.2:8080
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Ich habe hierbei auch einen Rewrite von &lt;code&gt;/&lt;/code&gt; zu &lt;code&gt;/guacamole&lt;/code&gt; hinzugefügt, damit man den Pfad nicht händisch angeben muss.&lt;/p&gt;
&lt;h3 id="konfiguration"&gt;Konfiguration
&lt;/h3&gt;&lt;p&gt;Die initialen Logindaten sind &lt;code&gt;guacadmin&lt;/code&gt;/&lt;code&gt;guacadmin&lt;/code&gt;. Sofern TOTP über die Umgebungsvariablen aktiviert wurde, wird nun direkt nach einem zweiten Faktor gefragt. Oben rechts unter Einstellungen lässt sich dann eine Verbindung anlegen. Bei RDP lohnt es sich, den Haken bei &lt;code&gt;Grössenänderungs-Methode: Display Update&lt;/code&gt; zu setzen. Die Haken unten bei Geschwindigkeit kann man setzen, wie man möchte - ich hab hier &lt;code&gt;Desktophintergrund aktivieren&lt;/code&gt; und &lt;code&gt;Schriftartglättung (ClearType) aktivieren&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="nutzung"&gt;Nutzung
&lt;/h2&gt;&lt;p&gt;Auf der Startseite sollte nun die Verbindung angezeigt werden. Nach einem Klick sollte die Verbindung stehen und sich auch mit Änderung der Fenstergröße automatisch anpassen.&lt;/p&gt;
&lt;h3 id="performance"&gt;Performance
&lt;/h3&gt;&lt;p&gt;Nach meiner Erfahrung ist die Performance primär von der Single-Thread-Performance des Hosts abhängig - auf den Futros läuft Guacamole langsamer als auf dem Mini-PC mit Ryzen-Prozessor. Aber beides ist definitiv nutzbar, auch wenn ich nicht 24/7 darüber arbeiten wollen würde.&lt;/p&gt;</description></item><item><title>TS3-Server inkl. Autostart installieren - 2.0 (Docker-Basis)</title><link>https://secretmine.de/blog/2024/2024-02-26-ts3-installationsanleitung/</link><pubDate>Mon, 26 Feb 2024 00:00:00 +0000</pubDate><guid>https://secretmine.de/blog/2024/2024-02-26-ts3-installationsanleitung/</guid><description>&lt;p&gt;&lt;strong&gt;Hinweis&lt;/strong&gt;: Nutzung auf eigene Gefahr.&lt;/p&gt;
&lt;h1 id="einleitung"&gt;Einleitung
&lt;/h1&gt;&lt;p&gt;Das alte Tutorial zum Installieren von einem TS3-Server basierte ja auf einer direkten Installation auf dem System. Das
hat den Vorteil, dass es schlank ist - aber dafür ist auch mehr manuell zu pflegen. Ich habe kürzlich für jemanden einen
TS3-Server inkl. automatischen Updates auf Dockerbasis aufgesetzt und finde das Setup eleganter als die bisherige
Lösung, daher möchte ich es auch anderen zur Verfügung stellen.&lt;/p&gt;
&lt;h1 id="voraussetzungen"&gt;Voraussetzungen
&lt;/h1&gt;&lt;p&gt;Auf dem Server muss Docker installiert sein. Sofern das noch nicht der Fall ist, lässt sich das einfach mit&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wget -O- https://get.docker.com | sudo bash
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;durchführen. (Ja, das direkte Ausführen von fremdem Code als Root ist böse, aber die Quelle ist vertrauenswürdig.
Trotzdem ist es empfehlenswert, das heruntergeladene Script einmal zu prüfen, bevor man es ausführt).&lt;/p&gt;
&lt;p&gt;Sollte &lt;code&gt;wget&lt;/code&gt; noch nicht ins alliert sein, geht das schnell mit&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get update
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo apt-get -y install wget
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Das Tool, was zum Updaten des Containers genutzt wird, kann dir via Discord Webhooks (und diverse andere Varianten)
Benachrichtigungen zu durchgeführten Updates schicken. Lege dazu einen Channel an und generiere dir einen Webhook - ich
verwende hier im Beispiel die Webhook-URL &lt;code&gt;https://discord.com/api/webhooks/asd/fgh&lt;/code&gt;.&lt;/p&gt;
&lt;h1 id="erstellen-vom-datenverzeichnis"&gt;Erstellen vom Datenverzeichnis
&lt;/h1&gt;&lt;p&gt;Die Daten für den Server sollen später unter &lt;code&gt;/opt/teamspeak3/data&lt;/code&gt; liegen, die Compose-Datei im darüberliegenden
Verzeichnis. Das lässt sich schnell mit&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p /opt/teamspeak3/data/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;anlegen.&lt;/p&gt;
&lt;h1 id="erzeugung-der-docker-compose-datei"&gt;Erzeugung der Docker-Compose-Datei
&lt;/h1&gt;&lt;p&gt;Zur Verwaltung der Container nutze ich in solchen Fällen gerne Docker-Compose. Dafür muss eine Datei angelegt werden (
die &lt;code&gt;docker-compose.yml&lt;/code&gt;), die die zu erstellenden Container inkl. Konfiguration beinhaltet. Ich nutze hier das
offizielle TS3-Container-Image (von hier: &lt;a class="link" href="https://hub.docker.com/_/teamspeak" target="_blank" rel="noopener"
 &gt;https://hub.docker.com/_/teamspeak&lt;/a&gt;). Um
das ganze möglichst pflegeleicht zu gestalten, stelle ich noch einen Watchtower-Container (von
hier: &lt;a class="link" href="https://hub.docker.com/r/containrrr/watchtower" target="_blank" rel="noopener"
 &gt;https://hub.docker.com/r/containrrr/watchtower&lt;/a&gt;) dazu. Watchtower
sorgt dafür, dass der TS3-Container immer auf dem aktuellsten Stand gehalten wird. Dazu wird in gewissen Abständen
geprüft, ob es eine neue Version vom Container-Image gibt. Sofern ein Update verfügbar ist, wird das gezogen und der
TS3-Container einmal frisch erzeugt.&lt;/p&gt;
&lt;p&gt;Um den TS3-Server später nutzen zu können, musst du die Lizenzbedingungen explizit akzeptieren. Die Bedingungen kannst
du dir mit dem Befehl&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker run --rm -it -e TS3SERVER_LICENSE=view teamspeak
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;ansehen.&lt;/p&gt;
&lt;p&gt;Lege also die Datei &lt;code&gt;docker-compose.yml&lt;/code&gt; unter &lt;code&gt;/opt/teamspeak3/&lt;/code&gt; beispielsweise
mit &lt;code&gt;nano /opt/teamspeak3/docker-compose.yml&lt;/code&gt; an. Der Inhalt sollte wie folgt aussehen:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-gdscript3" data-lang="gdscript3"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;3.8&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;teamspeak&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;teamspeak&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;9987&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9987&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;udp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;10011&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;10011&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;30033&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;30033&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/opt/teamspeak3/data:/var/ts3server/&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TS3SERVER_LICENSE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="c1"&gt;# &amp;#34;view&amp;#34; durch &amp;#34;accept&amp;#34; ersetzen, um die Lizenzbedingungen zu akzeptieren&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;watchtower&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;containrrr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;watchtower&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;always&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WATCHTOWER_SCHEDULE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;0 0 5 * * *&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# Update-Prüfung täglich um 05:00 Uhr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WATCHTOWER_NOTIFICATIONS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;slack&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://discord.com/api/webhooks/asd/fgh/slack&amp;#39;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Watchtower&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;WATCHTOWER_NOTIFICATION_SLACK_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;#watchtower&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;volumes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sock&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Die Zeilen, die mit &lt;code&gt;WATCHTOWER_NOTIFICATIONS&lt;/code&gt; beginnen, sind für die Notifications zuständig. An die Webhook-URL muss,
wie im Beispiel sichtbar, noch &lt;code&gt;/slack&lt;/code&gt; angefügt werden.&lt;/p&gt;
&lt;h1 id="erster-start"&gt;Erster Start
&lt;/h1&gt;&lt;p&gt;Wechsle zuerst in das Verzeichnis vom Server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cd /opt/teamspeak3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;starte nun einmal den TS3-Server im Attached-Modus, damit du den Serveradmin-Token sehen kannst:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose up teamspeak
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Nach einigen Sekunden kannst du den Server mit &lt;code&gt;Strg + c&lt;/code&gt; wieder beenden. Das sieht dann etwa so aus:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Ausgabe vom TeamSpeak3-Server" class="gallery-image" data-flex-basis="516px" data-flex-grow="215" height="652" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://secretmine.de/blog/2024/2024-02-26-ts3-installationsanleitung/images/initialisierung.png" srcset="https://secretmine.de/blog/2024/2024-02-26-ts3-installationsanleitung/images/initialisierung_hu_9938e39dac14c22c.png 800w, https://secretmine.de/blog/2024/2024-02-26-ts3-installationsanleitung/images/initialisierung.png 1402w" width="1402"&gt;&lt;/p&gt;
&lt;p&gt;In der Ausgabe findest du neben dem Admin-Token auch die Zugangsdaten für die Query-Schnittstelle. &lt;strong&gt;Bewahre diese Daten
gut auf!&lt;/strong&gt;&lt;/p&gt;
&lt;h1 id="finaler-start"&gt;Finaler Start
&lt;/h1&gt;&lt;p&gt;Mit&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;docker compose up -d
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;startest du nun den Server. Der Server wird auch automatisch bei Systemstart mit gestartet, also dort ist nichts weiter
zu tun.&lt;/p&gt;
&lt;p&gt;Damit sollte der Server nun erreichbar sein und das Tutorial ist beendet. Viel Spaß!&lt;/p&gt;</description></item></channel></rss>