<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Docker – teqqy</title><link>https://www.teqqy.de/tags/docker/</link><description>Ein Blog über Technik und mehr</description><language>de</language><managingEditor>teqqy</managingEditor><lastBuildDate>Fri, 31 Jul 2026 22:33:33 +0000</lastBuildDate><generator>Hugo 0.164.0</generator><atom:link href="https://www.teqqy.de/tags/docker/index.xml" rel="self" type="application/rss+xml"/><item><title>GitOps ohne Komodo: Webhook-basiertes Auto-Deployment für Docker Compose</title><link>https://www.teqqy.de/gitops-ohne-komodo/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0200</pubDate><lastBuildDate>Wed, 03 Jun 2026 00:00:00 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/gitops-ohne-komodo/</guid><description>Wer meinen letzten Beitrag zum Homelab Setup 2025 gelesen hat, weiß dass ich dort Komodo (externer Link) als GitOps-Werkzeug für meine Docker Compose Stacks einsetze. Das Prinzip dahinter ist gut: Git als Single Source of Truth, Renovate für automatische Version-Updates, und bei einem neuen Commit deployed Komodo die Änderungen auf das Zielsystem. Funktioniert im Grunde auch – aber Komodo hat mich mit einer Sache regelmäßig zur Weißglut gebracht: File Permissions. Das funktioniert einfach nicht konsistent. Entweder stimmen die Berechtigungen auf dem Host nicht, oder Komodo meckert beim Deployment, oder irgendwas dazwischen. Nach dem x-ten Mal hatte ich genug und wollte eine schlankere Lösung.</description><content:encoded>&lt;![CDATA[<p>Wer meinen<a href="/selfhosted-setup-2025-mein-neuer-workflow-mit-proxmox-komodo-und-gitops/">letzten Beitrag zum Homelab Setup 2025</a>
gelesen hat, weiß dass ich dort<a href="https://komo.do/" target="_blank" rel="noopener noreferrer">Komodo<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
als GitOps-Werkzeug für meine Docker Compose Stacks einsetze. Das Prinzip dahinter ist gut: Git als Single Source of Truth, Renovate für automatische Version-Updates, und bei einem neuen Commit deployed Komodo die Änderungen auf das Zielsystem. Funktioniert im Grunde auch – aber Komodo hat mich mit einer Sache regelmäßig zur Weißglut gebracht: File Permissions. Das funktioniert einfach nicht konsistent. Entweder stimmen die Berechtigungen auf dem Host nicht, oder Komodo meckert beim Deployment, oder irgendwas dazwischen. Nach dem x-ten Mal hatte ich genug und wollte eine schlankere Lösung.</p><p>Die Anforderung ist dabei überschaubar: Wenn Renovate einen neuen Commit in das Repo pusht (nach meinem Merge des Pull Requests), soll die compose-Datei auf dem Server aktualisiert und die betroffenen Container neu gestartet werden. Kein Kubernetes, kein weiteres Framework. Einfach git pull und docker compose up.</p><h2 id="das-grundprinzip">Das Grundprinzip<a href="#das-grundprinzip" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Das Setup basiert auf drei Komponenten die zusammenspielen:</p><ol><li><strong><a href="https://about.gitea.com/" target="_blank" rel="noopener noreferrer">Gitea<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a></strong> – mein selbst gehosteter Git-Server, auf dem die Compose-Dateien liegen</li><li><strong><a href="https://docs.renovatebot.com/" target="_blank" rel="noopener noreferrer">Renovate<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a></strong> – überprüft alle vier Stunden per Cronjob die verwendeten Image-Tags gegen die jeweiligen Container-Registries und öffnet bei neuen Versionen automatisch Pull Requests. Ich merge den PR, der Commit landet auf<code>main</code>.</li><li><strong><a href="https://github.com/adnanh/webhook" target="_blank" rel="noopener noreferrer">webhook<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a></strong> – ein einzelnes Go-Binary, das auf dem Zielserver einen HTTP-Endpunkt bereitstellt. Gitea feuert bei jedem Push einen Webhook dorthin, woraufhin das Deploy-Script ausgeführt wird.</li></ol><p>Der Datenfluss sieht so aus:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>Renovate erkennt neues Image-Tag
→ PR in Gitea
→ Merge
→ Gitea feuert Webhook
→ webhook-Binary ruft deploy.sh auf
→ git pull + docker compose up -d</code></pre></div><p>Kein Polling, kein Daemon der irgendwelche Container-Registries beobachtet, kein Framework das eigene Meinungen zu File Permissions hat.</p><h2 id="warum-nicht-einfach-watchtower-oder-ein-cron-script">Warum nicht einfach Watchtower oder ein Cron-Script?<a href="#warum-nicht-einfach-watchtower-oder-ein-cron-script" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Bevor ich zu webhook gegriffen habe, hatte ich kurz zwei andere Ansätze im Kopf.</p><p><strong><a href="https://containrrr.dev/watchtower/" target="_blank" rel="noopener noreferrer">Watchtower<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a></strong> überwacht laufende Container und zieht neue Images automatisch. Das Problem: Watchtower reagiert auf neue Images in der Registry, nicht auf Git-Commits. Wenn Renovate einen PR öffnet und ich den merge, hat Watchtower davon keine Ahnung – der zieht einfach irgendwann wenn er selbst nachschaut. Das passt nicht zu einem Setup bei dem Git die einzige Quelle der Wahrheit sein soll. Außerdem will ich den Merge-Zeitpunkt kontrollieren, nicht Watchtower.</p><p><strong>Cron-Script mit<code>git fetch</code></strong> wäre die andere Möglichkeit – alle paar Minuten nachschauen ob es Änderungen gibt und dann deployen. Funktioniert, hat aber einen konzeptionellen Nachteil: Es ist Polling. Ich baue mit Gitea bereits eine Infrastruktur auf die Push-Events liefern kann, die sollte ich auch nutzen. Ein Webhook reagiert innerhalb von Sekunden, ein Cron-Job mit 5-Minuten-Intervall verzögert unnötig.</p><p>webhook ist der sauberste Weg: Event-getrieben, kein Extra-Daemon, ein einzelnes Binary ohne Abhängigkeiten.</p><h2 id="repo-struktur">Repo-Struktur<a href="#repo-struktur" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Ich habe pro Server ein eigenes Repository:</p><ul><li><code>apps-stack</code> für den<code>docker01</code> – dort laufen Tools wie<a href="https://docs.paperless-ngx.com/" target="_blank" rel="noopener noreferrer">Paperless-ngx<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
,<a href="https://immich.app/" target="_blank" rel="noopener noreferrer">Immich<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
,<a href="https://github.com/dani-garcia/vaultwarden" target="_blank" rel="noopener noreferrer">Vaultwarden<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
und ähnliches</li><li><code>media-stack</code> für den<code>media01</code> – dort leben alle<code>*arr</code>-Container und was sonst noch zum Medien-Stack gehört</li></ul><p>Jedes Repo enthält einfach die<code>compose.yaml</code> sowie ggf. weitere Konfigurationsdateien die einzelne Anwendungen benötigen. Nichts Besonderes.</p><h3 id="renovate-in-den-repos">Renovate in den Repos<a href="#renovate-in-den-repos" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Renovate läuft selfhosted und überprüft per Cronjob alle vier Stunden die Image-Tags in den Compose-Dateien. Dafür reicht eine minimale<code>renovate.json</code> im Repo-Root:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">json</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="json"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{</span></span><span style="display:flex;"><span><span style="color:#7ee787">"$schema"</span>:<span style="color:#a5d6ff">"https://docs.renovatebot.com/renovate-schema.json"</span>,</span></span><span style="display:flex;"><span><span style="color:#7ee787">"extends"</span>: [<span style="color:#a5d6ff">"config:base"</span>],</span></span><span style="display:flex;"><span><span style="color:#7ee787">"docker-compose"</span>: {</span></span><span style="display:flex;"><span><span style="color:#7ee787">"enabled"</span>:<span style="color:#79c0ff">true</span></span></span><span style="display:flex;"><span> }</span></span><span style="display:flex;"><span>}</span></span></code></pre></div></div><p>Renovate erkennt dann automatisch die Image-Tags in der Compose-Datei und öffnet PRs wenn eine neuere Version verfügbar ist. Bei Software die semantische Versionierung verwendet (also<code>major.minor.patch</code>) lässt sich das besonders fein steuern – z. B. nur Patch-Updates automatisch mergen, bei Minor-Updates erst schauen was sich geändert hat.</p><p>Für Postgres-Container würde ich Renovate übrigens ausschließen. Major-Upgrades zwischen Postgres-Versionen erfordern einen manuellen Datenbankdump und -import, das soll mir kein Bot automatisch reinschießen.</p><h2 id="webhook-installieren-und-konfigurieren">webhook installieren und konfigurieren<a href="#webhook-installieren-und-konfigurieren" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><code>webhook</code> gibt es als einzelnes Binary, alternativ auch als Paket:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>apt install webhook</span></span></code></pre></div></div><p>Die Konfiguration liegt unter<code>/etc/webhook/webhook.conf</code>:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span>-<span style="color:#7ee787">id</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">deploy</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">execute-command</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">/opt/scripts/deploy.sh</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">command-working-directory</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">/opt/media-stack</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">trigger-rule</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">match</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">type</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">payload-hmac-sha256</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">secret</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"{{getenv \"WEBHOOK_SECRET\"}}"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">parameter</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">source</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">header</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">X-Gitea-Signature</span></span></span></code></pre></div></div><p>Ein paar Anmerkungen dazu:</p><p><strong>Header-Name:</strong> Gitea schickt die Signatur als<code>X-Gitea-Signature</code> – ohne<code>-256</code>-Suffix und ohne<code>sha256=</code>-Präfix im Wert. Das klingt trivial, hat mich aber beim ersten Versuch einen Debugging-Durchgang gekostet.</p><p><strong>Secret als Umgebungsvariable:</strong> Das HMAC-Secret gehört nicht im Klartext in die Konfigurationsdatei, erst recht nicht wenn die Datei im Repo versioniert ist. Deshalb wird es per<code>getenv</code> aus der Umgebung gelesen.</p><p>Das Secret generieren:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>openssl rand -hex<span style="color:#a5d6ff">32</span></span></span></code></pre></div></div><p>Und in eine Secrets-Datei schreiben die nur root lesen kann:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># /etc/webhook/secrets.env</span></span></span><span style="display:flex;"><span><span style="color:#79c0ff">WEBHOOK_SECRET</span><span style="color:#ff7b72;font-weight:bold">=</span>dein-generierter-string</span></span></code></pre></div></div><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>chmod<span style="color:#a5d6ff">600</span> /etc/webhook/secrets.env</span></span></code></pre></div></div><h3 id="systemd-unit">Systemd-Unit<a href="#systemd-unit" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><div class="code-block"><div class="code-block-header"><span class="code-lang-label">ini</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="ini"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># /etc/systemd/system/webhook.service</span></span></span><span style="display:flex;"><span><span style="color:#ff7b72">[Unit]</span></span></span><span style="display:flex;"><span>Description<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">Webhook Receiver</span></span></span><span style="display:flex;"><span>After<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">network.target</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#ff7b72">[Service]</span></span></span><span style="display:flex;"><span>User<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">teqqy # Hier den eigenen Usernamen eintragen</span></span></span><span style="display:flex;"><span>EnvironmentFile<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">/etc/webhook/secrets.env</span></span></span><span style="display:flex;"><span>ExecStart<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">/usr/bin/webhook -hooks /etc/webhook/webhook.conf -port 9000</span></span></span><span style="display:flex;"><span>Restart<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">on-failure</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#ff7b72">[Install]</span></span></span><span style="display:flex;"><span>WantedBy<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">multi-user.target</span></span></span></code></pre></div></div><p><code>User=teqqy</code> sorgt dafür dass der webhook-Daemon und damit auch das Deploy-Script nicht als root laufen. Das ist mir wichtig – Prozesse die nur git pull und docker compose up ausführen müssen haben nichts als root verloren. Den Usernamen natürlich durch den eigenen ersetzen; der User braucht Zugriff auf das Repo-Verzeichnis und muss Mitglied der<code>docker</code>-Gruppe sein.</p><p><code>EnvironmentFile</code> lädt die<code>secrets.env</code> und stellt<code>WEBHOOK_SECRET</code> als Umgebungsvariable bereit, bevor der Prozess startet – so kommt das Secret sauber in den<code>getenv</code>-Aufruf der Konfiguration.<code>Restart=on-failure</code> sorgt dafür dass der Daemon bei einem unerwarteten Absturz automatisch neu startet, ohne dass man manuell eingreifen muss.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>systemctl enable --now webhook</span></span></code></pre></div></div><h2 id="gitea-webhook-einrichten">Gitea Webhook einrichten<a href="#gitea-webhook-einrichten" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>In Gitea unter<code>Repository → Einstellungen → Webhooks → Webhook hinzufügen → Gitea</code>:</p><ul><li><strong>Ziel-URL:</strong><code>http://media01.example.com:9000/hooks/deploy</code></li><li><strong>Secret:</strong> denselben String den du oben generiert hast</li><li><strong>Trigger:</strong> Nur<code>Push</code>-Events reichen aus</li></ul><p>Gitea berechnet bei jedem Push automatisch eine HMAC-SHA256-Signatur über den Request-Body und schickt sie als<code>X-Gitea-Signature</code>-Header mit. Das webhook-Binary verifiziert die Signatur bevor es das Script ausführt – ein simpler Authorization-Header wäre hier deutlich unsicherer, weil man den Payload damit nicht gegen Manipulation absichert.</p><p>Port 9000 sollte nicht direkt ins Internet exponiert sein. In meinem Setup sind Gitea und der webhook-Daemon im selben internen Netz, der Port ist von außen nicht erreichbar. Wer den Endpunkt für eine externe Gitea-Instanz oder GitHub erreichbar machen muss, sollte das zumindest hinter einem Reverse Proxy mit IP-Beschränkung tun.</p><h2 id="das-deploy-script">Das Deploy-Script<a href="#das-deploy-script" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#8b949e;font-weight:bold;font-style:italic">#!/bin/bash</span></span></span><span style="display:flex;"><span>set -euo pipefail</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#79c0ff">REPO</span><span style="color:#ff7b72;font-weight:bold">=</span>/opt/media-stack</span></span><span style="display:flex;"><span><span style="color:#79c0ff">LOG</span><span style="color:#ff7b72;font-weight:bold">=</span>/opt/deploy-logs/deploy-<span style="color:#ff7b72">$(</span>date +%Y%m%d-%H%M%S<span style="color:#ff7b72">)</span>.log</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>exec &gt;&gt;<span style="color:#a5d6ff">"</span><span style="color:#79c0ff">$LOG</span><span style="color:#a5d6ff">"</span> 2&gt;&amp;<span style="color:#a5d6ff">1</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>echo<span style="color:#a5d6ff">"=== Deploy</span><span style="color:#ff7b72">$(</span>date<span style="color:#ff7b72">)</span><span style="color:#a5d6ff"> ==="</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>cd<span style="color:#a5d6ff">"</span><span style="color:#79c0ff">$REPO</span><span style="color:#a5d6ff">"</span></span></span><span style="display:flex;"><span>git pull origin main</span></span><span style="display:flex;"><span>docker compose up -d --remove-orphans</span></span><span style="display:flex;"><span>docker compose ps</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>echo<span style="color:#a5d6ff">"=== Done ==="</span></span></span></code></pre></div></div><p><code>set -euo pipefail</code> sorgt dafür dass das Script bei jedem Fehler sofort abbricht und einen Exit-Code ≠ 0 zurückgibt. Den loggt webhook dann ebenfalls, sodass<code>journalctl -u webhook</code> bei Problemen der erste Anlaufpunkt ist.</p><p>Das Log-Verzeichnis muss dem ausführenden User gehören:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir -p /opt/deploy-logs</span></span><span style="display:flex;"><span>chown teqqy:teqqy /opt/deploy-logs</span></span></code></pre></div></div><h2 id="stolpersteine-die-ich-unterwegs-getroffen-habe">Stolpersteine die ich unterwegs getroffen habe<a href="#stolpersteine-die-ich-unterwegs-getroffen-habe" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><strong><code>.git</code>-Verzeichnis Ownership:</strong> Wenn das Repo irgendwann mal als anderer User geklont oder gepullt wurde, verweigert Git den Zugriff mit einer Warnung zu &ldquo;dubiosen Besitzverhältnissen&rdquo;. Fix:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>chown -R teqqy:teqqy /opt/media-stack/.git</span></span></code></pre></div></div><p><strong><code>safe.directory</code>:</strong> In manchen Setups hilft zusätzlich:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git config --global --add safe.directory /opt/media-stack</span></span></code></pre></div></div><p><strong><code>/var/log</code> Permissions:</strong> Der ausführende User hat dort keine Schreibrechte. Deshalb das Log-Verzeichnis in einen Pfad legen der dem User gehört – ich nutze<code>/opt/deploy-logs</code>.</p><p><strong><code>*arr</code>-Container und UID/GID:</strong> Meine<code>*arr</code>-Container laufen mit<code>99:100</code> (Unraid-kompatibel wegen NFS). Beim allerersten Deployment legt Docker die Bind-Mount-Verzeichnisse mit<code>1000:1000</code> an wenn sie noch nicht existieren. Einmalig vor dem ersten Start:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>chown -R 99:100 /mnt/data/arr/</span></span></code></pre></div></div><p>Danach ist das kein Thema mehr da die Verzeichnisse bereits existieren.</p><h2 id="monitoring">Monitoring<a href="#monitoring" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Ich setze<a href="https://uptime.kuma.pet/" target="_blank" rel="noopener noreferrer">Uptime Kuma<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
ein und beobachte dort ob die Container nach einem Deployment noch sauber laufen. Das reicht für meinen Use Case: Wenn ein Container nach einem fehlgeschlagenen Update nicht mehr antwortet, schlägt Uptime Kuma an. Das deploy.log und<code>journalctl -u webhook</code> liefern dann die Details warum es schiefgelaufen ist.</p><p>Ein Dead-Man&rsquo;s-Switch (z. B. über Healthchecks.io) wäre der nächste sinnvolle Schritt wenn man auch merken will wenn ein Deploy einfach<em>ausbleibt</em> – aber für einen Media-Stack ist das für mich nicht kritisch genug um extra Aufwand zu treiben.</p><h2 id="fazit">Fazit<a href="#fazit" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Das Setup ist jetzt seit kurzem in Betrieb und macht genau was es soll – ohne dass ich irgendwas an Komodo debuggen muss. Das webhook-Binary ist stabil, der Deployment-Flow ist deterministisch, und der Gesamtoverhead beschränkt sich auf ein paar Konfigurationsdateien und ein Shell-Script.</p><p>Wer ähnliche Anforderungen hat und kein Kubernetes betreiben möchte: Das ist meiner Meinung nach der pragmatischste Weg. Keine Magie, keine Frameworks, kein Overengineering. Nur git pull und docker compose up.</p><p>Bei Fragen oder Anmerkungen erreichst du mich über die Links in der Menüleiste.</p>
]]></content:encoded><category>selfhosted</category><category>gitops</category><category>docker</category><category>gitea</category><category>renovate</category><category>homelab</category></item><item><title>Traefik http3 aktivieren</title><link>https://www.teqqy.de/traefik-http3-aktivieren/</link><pubDate>Tue, 06 Feb 2024 00:00:00 +0000</pubDate><lastBuildDate>Tue, 06 Feb 2024 00:00:00 +0000</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/traefik-http3-aktivieren/</guid><description>Wie langjährige Leser meines Blogs oder Zuschauer meines YouTube Kanals wissen, nutze ich primär Traefik als Reverse Proxy unter Docker. Über die letzten Jahre hat sich entsprechend etwas an Know how angesammelt. Durch einen Beitrag (externer Link) auf Mastodon von Thomas Leister (externer Link) bin ich darauf gekommen auch mal http3 zu aktivieren. Was du entsprechend tun musst, um das bei dir ebenfalls einzurichten habe ich hier aufgeschrieben.</description><content:encoded>&lt;![CDATA[<p>Wie langjährige Leser meines Blogs oder Zuschauer meines YouTube Kanals wissen, nutze ich primär Traefik als Reverse Proxy unter Docker. Über die letzten Jahre hat sich entsprechend etwas an Know how angesammelt. Durch einen<a href="https://metalhead.club/@thomas/111833215602688918#." target="_blank" rel="noopener noreferrer">Beitrag<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
auf Mastodon von<a href="https://thomas-leister.de" target="_blank" rel="noopener noreferrer">Thomas Leister<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
bin ich darauf gekommen auch mal http3 zu aktivieren. Was du entsprechend tun musst, um das bei dir ebenfalls einzurichten habe ich hier aufgeschrieben.</p><h2 id="vorteile-von-http3">Vorteile von http3<a href="#vorteile-von-http3" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><a href="https://en.wikipedia.org/wiki/HTTP/3" target="_blank" rel="noopener noreferrer">HTTP/3<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
ist die neueste Version des Hypertext Transfer Protocols (HTTP) und bringt mehrere Vorteile gegenüber seinen Vorgängerversionen, insbesondere HTTP/1.1 und HTTP/2, mit sich. Hier sind einige der wichtigsten Vorteile von HTTP/3:</p><ol><li><p><strong>Schnellerer Verbindungsaufbau:</strong> HTTP/3 verwendet das<a href="https://en.wikipedia.org/wiki/QUIC" target="_blank" rel="noopener noreferrer">QUIC<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
-Protokoll (Quick UDP Internet Connections), das auf UDP (User Datagram Protocol) basiert. Im Vergleich zu TCP (Transmission Control Protocol), das in vorherigen HTTP-Versionen verwendet wurde, ermöglicht QUIC einen schnelleren Verbindungsaufbau. Es beseitigt die Latenz, die durch den sogenannten &ldquo;Handshake&rdquo; in TCP verursacht wird.</p></li><li><p><strong>Multiplexing ohne Head-of-Line-Blocking:</strong> HTTP/3 unterstützt effizientes Multiplexing von Anfragen und Antworten. Im Gegensatz zu HTTP/1.1, bei dem eine Verbindung nur eine Anfrage gleichzeitig behandeln kann (Head-of-Line-Blocking), können bei HTTP/3 mehrere Anfragen und Antworten gleichzeitig übertragen werden. Dies verbessert die Effizienz und verkürzt die Ladezeiten von Webseiten.</p></li><li><p><strong>Bessere Leistung bei Netzwerkproblemen:</strong> HTTP/3 wurde entwickelt, um besser mit Netzwerkproblemen umzugehen. Das QUIC-Protokoll ermöglicht es, Verbindungen beizubehalten, auch wenn sich die Netzwerkbedingungen ändern. Dies trägt dazu bei, dass die Leistung aufrechterhalten wird, selbst wenn es zu Paketverlusten oder Netzwerkwechseln kommt.</p></li><li><p><strong>Adaptivität:</strong> HTTP/3 wurde entwickelt, um sich besser an verschiedene Netzwerkbedingungen anzupassen. Es kann sich automatisch an veränderte Latenzen und Bandbreiten anpassen, um eine optimale Leistung zu gewährleisten.</p></li><li><p><strong>Verbesserte Sicherheit:</strong> HTTP/3 unterstützt standardmäßig Verschlüsselung durch Transport Layer Security (TLS). Die Integration von TLS in den Kern des Protokolls trägt zur Sicherheit der Datenübertragung bei.</p></li><li><p><strong>Flexibilität:</strong> HTTP/3 ist so konzipiert, dass es besser mit den Anforderungen moderner Webanwendungen und Dienste umgehen kann. Durch die kontinuierliche Entwicklung des Protokolls können zukünftige Anforderungen besser erfüllt werden.</p></li></ol><p>Es ist wichtig zu beachten, dass die Einführung von HTTP/3 nicht nur von den Vorteilen, sondern auch von der Unterstützung auf Server- und Clientseite abhängt. Nicht alle Webserver und Browser unterstützen möglicherweise bereits HTTP/3, aber die Akzeptanz nimmt stetig zu.</p><h2 id="anpassen-der-traefik-konfiguration">Anpassen der traefik Konfiguration<a href="#anpassen-der-traefik-konfiguration" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Ich verwendet primär die<code>traefik.yml</code> Datei um alles zu konfigurieren. Nutzt du mehr Labels, musst du das natürlich umbauen. Mit traefik 2.11 und 3 muss noch die experimentelle Funktion aktiviert werden. Dies kann zu einem späterern Zeitpunkt nicht mehr notwendig sein.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#7ee787">experimental</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">http3</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span></span></span></code></pre></div></div><p>Nun sind noch die Entrypoints anzupassen. meiner heißt<code>websecure</code> für die Verbindung von https. Entsprechend brauchen wir hier nur</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">http3</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">advertisedPort</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">'443'</span></span></span></code></pre></div></div><p>hinzuzufügen. Der vollständigkeit halber sieht mein kompletter Block so aus:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#7ee787">entryPoints</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ping</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">address</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">':88'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">web</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">address</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">':80'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">http</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">redirections</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">entryPoint</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">to</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">websecure</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">scheme</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">https</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">websecure</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">address</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">':443'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">http</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">http3</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">advertisedPort</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">'443'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">proxyProtocol</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">trustedIPs</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">10.0.0.0</span><span style="color:#a5d6ff">/8</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">172.16.0.0</span><span style="color:#a5d6ff">/12</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">192.168.0.0</span><span style="color:#a5d6ff">/16</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">forwardedHeaders</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">trustedIPs</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">10.0.0.0</span><span style="color:#a5d6ff">/8</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">172.16.0.0</span><span style="color:#a5d6ff">/12</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">192.168.0.0</span><span style="color:#a5d6ff">/16</span></span></span></code></pre></div></div><p>Natürlich reicht das nicht ganz aus. Wie ihr seht, veröffentliche ich Port<code>443</code> um http3 auszuliefern. Da http3 aber via QUIC über UPD kommuniziert, muss auch die<code>docker-compose.yaml</code> Datei angepasst werden.</p><p>Die Portkonfiguration sieht dann entsprechen so aus:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ports</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#7ee787">target</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">80</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">published</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">80</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">protocol</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">tcp</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">mode</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">host</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#7ee787">target</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">published</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">protocol</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">tcp</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">mode</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">host</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#7ee787">target</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">published</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">protocol</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">udp</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">mode</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">host</span></span></span></code></pre></div></div><p>Der letzte<code>target</code> Block ist der wichtige. Hier wird Port 443 auf udp ausgeliefert. Abschließend noch den Container neu starten</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose rm -sf<span style="color:#ff7b72;font-weight:bold">&amp;&amp;</span> docker compose up -d</span></span></code></pre></div></div><p>Solltest du mehr als nur Traefik in der Datei haben, werden diese Services entsprechend auch neu gestartet. Ich empfehle zukünftig traefik zu separieren.</p>
]]></content:encoded><category>selfhosted</category><category>traefik</category><category>docker</category><category>networking</category></item><item><title>FreshRSS Setup: RSS Reader selbst hosten (Docker Guide 2025)</title><link>https://www.teqqy.de/freshrss-rss-reader-zum-selber-hosten/</link><pubDate>Sun, 06 Aug 2023 12:05:00 +0200</pubDate><lastBuildDate>Sun, 06 Aug 2023 12:05:00 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/freshrss-rss-reader-zum-selber-hosten/</guid><description>Du willst deine RSS-Feeds selbst verwalten, ohne auf Drittanbieter angewiesen zu sein? FreshRSS ist ein kostenloser, selbst gehosteter RSS-Reader, der dir volle Kontrolle über deine Nachrichtenquellen gibt. Die Open-Source-Software lässt sich in wenigen Minuten mit Docker installieren und funktioniert perfekt mit Apps wie Reeder (iOS) oder FeedMe (Android).
In dieser Anleitung zeige ich dir Schritt für Schritt, wie du FreshRSS einrichtest – von der Docker-Installation über das Importieren bestehender Feeds bis zur Einbindung mobiler Apps. Das Beste daran: FreshRSS bietet eine vollständige API-Unterstützung, sodass du deine Feeds überall synchronisiert nutzen kannst.</description><content:encoded>&lt;![CDATA[<p>Du willst deine RSS-Feeds selbst verwalten, ohne auf Drittanbieter angewiesen zu sein?<strong>FreshRSS ist ein kostenloser, selbst gehosteter RSS-Reader</strong>, der dir volle Kontrolle über deine Nachrichtenquellen gibt. Die Open-Source-Software lässt sich in wenigen Minuten mit Docker installieren und funktioniert perfekt mit Apps wie Reeder (iOS) oder FeedMe (Android).</p><p>In dieser Anleitung zeige ich dir Schritt für Schritt, wie du FreshRSS einrichtest – von der Docker-Installation über das Importieren bestehender Feeds bis zur Einbindung mobiler Apps. Das Beste daran: FreshRSS bietet eine<strong>vollständige API-Unterstützung</strong>, sodass du deine Feeds überall synchronisiert nutzen kannst.</p><p>Für mich persönlich war genau dieses API-Feature der entscheidende Grund, auf FreshRSS zu setzen. Nach Jahren der Nutzung kann ich sagen: Es ist die zuverlässigste selbst gehostete RSS-Lösung, die ich kenne.</p><p>Diejenigen die immer noch RSS nutzen wissen es sehr zu schätzen. Es gibt zwar mittlerweile viele Dienste die einen über neue Informationen auf Seiten benachrichtigen, aber wenn man „nur“ Blogs liest ist das Abonnement von RSS Feeds die wohl bessere Wahl.
Feedreader, eines der alten Google Produkte, war sicherlich ein Vorreiter auf diesem Gebiet. Im laufe der ganzen Jahre kamen und gingen dann viele andere Produkte und Onlinedienste. Ich setze schon seit Jahre auf eine selbst gehostete Variante mit<a href="https://freshrss.org" target="_blank" rel="noopener noreferrer">FreshRSS<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
.</p><p>In der Szene der Open Source RSS Tools gibt es natürlich viele weitere Programme die sicherlich auch alle sehr gut sind. Für mich gab es nie den Grund mir andere detaillierter anzusehen da ich mit FreshRSS sehr gut zurecht komme. Zudem bietet es ein Feature an, dass für mich ein entscheidendes Kriterium ist. Dazu aber später noch mehr.</p><h2 id="installation-von-freshrss">Installation von FreshRSS<a href="#installation-von-freshrss" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Wie viele andere Softwareprodukte, die ich hier vorstelle, kann FreshRSS auch unter Docker installiert werden. Glückerlicherweise gibt der Entwickler einem die Wahl ob man mit der integrierten SQLite arbeiten möchte, oder eine MySQL bzw. PostgresDB Datenbank anbinden möchte. Je nachdem wie die heimische Infrastruktur so aufgestellt ist, empfiehlt sich das eine oder andere mehr.</p><p>Für diejenigen die nichts mit Docker oder Containerisierung anfangen können, gibt es sogar noch die klassische Installation. Allerdings möchte ich in diesem Beitrag eher auf die Variante in Docker zurückgreifen.</p><h3 id="freshrss-mit-docker-compose">FreshRSS mit Docker Compose<a href="#freshrss-mit-docker-compose" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Ich habe hier mal eine<code>docker-compose.yaml</code> Datei vorbereitet die mit PostgresDB als Datenbankbackend arbeitet. Eine Anpassung auf MySQL/MariaDB ist recht einfach vorzunehmen. Lassen wir die DB weg, können wir auch einfach bei der Installation die SQLite Variante auswählen.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">freshrss-db</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">postgres:17</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">fressrss-db</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">unless-stopped</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/localtime:/etc/localtime:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/timezone:/etc/timezone:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/docker/freshrss/db:/var/lib/postgresql/data</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">POSTGRES_USER=freshrss</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">POSTGRES_PASSWORD=${POSTGRES_PASSWORD}</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">POSTGRES_DB=freshrss</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">freshrss-app</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">freshrss/freshrss:latest</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">freshrss-app</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">unless-stopped</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">depends_on</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">freshrss-db</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/localtime:/etc/localtime:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/timezone:/etc/timezone:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/docker/freshrss/data:/var/www/FreshRSS/data</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/docker/freshrss/extensions:/var/www/FreshRSS/extensions</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">CRON_MIN=*/20</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ports</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">80</span>:<span style="color:#a5d6ff">80</span></span></span></code></pre></div></div><p>Wer das ganze mittels Traefik auch sauber mit Zertifikaten etc hosten möchte, verweise ich einfach auf meine<a href="https://github.com/cbirkenbeul/docker-homelab/tree/master/compose-files-traefik-predefined/freshrss" target="_blank" rel="noopener noreferrer">vorbereitete Version auf GitHub<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
.</p><h3 id="webinstallation">Webinstallation<a href="#webinstallation" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Leider müssen wir noch ein paar Schritte unternehmen um den RSS-Reader wirklich komplett installieren zu können. Die Installation erkennt nicht die Datenbankparameter oder ähnliches sodass wir die Schritte manuell durchführen müssen.</p><p>Sobald das alles durch ist, können wir uns mit den Zugangsdaten anlegen die wir anfangs angegeben haben. Unser erster Nutzer ist nämlich direkt Administrator der Seite.</p><h3 id="erste-schritte-nach-der-installation">Erste Schritte nach der Installation<a href="#erste-schritte-nach-der-installation" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Grundsätzlich kann die Software direkt verwendet werden. Allerdings habe ich noch einen kleinen Tipp der das Leben im Nachgang einfacherer macht. Wer nämlich wie ich die Feeds nicht über den Browser konsumieren möchte, sondern mittels eine Anwendung muss die API frei schalten.
Dafür gehen wir rechts oben auf das Zahnrad und dann auf Authentifizierung. Hier setzen wir das Häkchen bei * API-Zugriff erlauben (für mobile Anwendungen benötigt)* und klicken auf<strong>Speichern</strong>
Nun müssen wir noch das API Kennwort für unseren Nutzer festlegen. Das machen wir in unserem Profil das ihr links oben direkt findet. Im unteren Bereich unter<em>API-Verwaltung</em> tragt ihr einfach ein Passwort ein. Sicherer wäre es, wenn ihr ein anderes verwendet als für euren Login.</p><h2 id="nutzung-von-freshrss">Nutzung von FreshRSS<a href="#nutzung-von-freshrss" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><h3 id="löschen-des-freshrss-feeds-optional">Löschen des FreshRSS Feeds (optional)<a href="#l%c3%b6schen-des-freshrss-feeds-optional" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Nachdem wir die grundlegenden Schritte durchgeführt haben, können wir endlich die Software nutzen. Wir sollten zurück zur Startseite gehen - Klick links oben auf den Produktnamen. Anschließend wählen wir die ** Abonnementverwaltung** aus. Hier sollte bis auf den Feed der Software selbst nichts weiteres angezeigt werden.</p><p>Wenn ihr den Feed nicht benötigt, könnt ihr den natürlich löschen. Mit einem Klick auf das Zahnrad und dann rechts<strong>Entfernen</strong>.</p><h3 id="import-von-bestehenden-rss-abonnements-optional">Import von bestehenden RSS Abonnements (optional)<a href="#import-von-bestehenden-rss-abonnements-optional" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Natürlich kann man auch von seinem bestehenden RSS Feedreader die Feeds importieren. Also zumindest solange der bisherige auch ein Export in zum Beispiel OPML Format unterstützt. Alles mir bisher gängigen haben das beherrscht.
Hierzu klicken wir wieder auf<strong>Abonnementverwaltung</strong> und dann auf **Importieren / Exportieren **. Nun können wir rechts eine Datei unter<em>Importieren</em> auswählen und auf<strong>Importieren</strong> klicken.</p><h3 id="feeds-hinzufügen">Feeds hinzufügen<a href="#feeds-hinzuf%c3%bcgen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Um neue Feeds hinzuzufügen, wie zum Beispiel den von teqqy.de, klickt man links oben auf das<strong>+</strong> Symbol. Anschließend kopiert man die Feed-URL in das Feld und klickt auf<strong>Hinzufügen</strong> Wer möchte, kann natürlich vorher noch eine<em>Kategorie</em> erstellen um gegebenenfalls eine größere Menge an Feeds besser zu verwalten.</p><h2 id="3rd-party-apps">3rd Party Apps<a href="#3rd-party-apps" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Da meine primären Endgeräte auf Apple Basis laufen, kann ich hier leider keine große Liste aufzeigen die ich empfehlen kann. Falls jemand ein guten RSS Client kennt der mit FreshRSS zusammen arbeitet, kann er mir den Tipp gerne zukommen lassen.</p><h3 id="macos-und-iosipados">MacOS und iOS/iPadOS<a href="#macos-und-iosipados" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Unter den Betriebssystemen verwende ich seit Jahren<a href="https://reederapp.com" target="_blank" rel="noopener noreferrer">Reeder<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
als RSS Reader App. Mittlerweile in Version 5 angekommen hatte es mich immer gut begleitet.
Seit in einer der letzten Versionen auch eine korrekte Unterstützung von FreshRSS via API hinzugekommen ist, war natürlich ein weiterer Grund auf die Liste gekommen.</p><p><img src="images/reeder5-freshrss-setup.webp" alt="Reeder5 FreshRSS Setup" loading="eager" fetchpriority="high" decoding="async"/><p>Um Reeder einzurichten brauchen wir wie<a href="/freshrss-rss-reader-zum-selber-hosten/#erste-schritte-nach-der-installation">oben beschrieben</a>
ein<em>API-Passwort</em>. In Reeder selbst gehen wir dann auf<strong>Accounts</strong> und<strong>Add Account</strong>. Ganz unten findet man dann FreshRSS zur Auswahl. Nun tragen wir die benötigten Daten ein und klicken auf<strong>Sign in</strong>. Anschließend zieht sich Reeder alle Informationen und würde noch ungelesene Artikel anzeigen.</p><h2 id="häufig-gestellte-fragen-zu-freshrss">Häufig gestellte Fragen zu FreshRSS<a href="#h%c3%a4ufig-gestellte-fragen-zu-freshrss" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><h3 id="was-ist-freshrss">Was ist FreshRSS?<a href="#was-ist-freshrss" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>FreshRSS ist ein kostenloser, Open-Source RSS-Reader, den du auf deinem eigenen Server installieren kannst. Anders als Cloud-Dienste behältst du die volle Kontrolle über deine Daten und Feeds.</p><h3 id="ist-freshrss-wirklich-kostenlos">Ist FreshRSS wirklich kostenlos?<a href="#ist-freshrss-wirklich-kostenlos" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Ja, FreshRSS ist komplett kostenlos und Open Source. Du benötigst lediglich einen Server oder Computer, auf dem du die Software installieren kannst. Es fallen keine Lizenzkosten an.</p><h3 id="welche-apps-kann-ich-mit-freshrss-nutzen">Welche Apps kann ich mit FreshRSS nutzen?<a href="#welche-apps-kann-ich-mit-freshrss-nutzen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>FreshRSS unterstützt verschiedene mobile Apps über seine API. Beliebte Optionen sind Reeder (iOS/macOS), FeedMe (Android) und NetNewsWire (iOS/macOS). Alle Apps, die mit Google Reader kompatibel waren, funktionieren meist auch mit FreshRSS.</p><h3 id="wie-viel-speicherplatz-benötigt-freshrss">Wie viel Speicherplatz benötigt FreshRSS?<a href="#wie-viel-speicherplatz-ben%c3%b6tigt-freshrss" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Die Installation selbst benötigt etwa 50-100 MB. Je nach Anzahl deiner Feeds und gespeicherten Artikeln solltest du 500 MB bis 2 GB Speicherplatz einplanen. Bei sehr vielen Feeds können es auch mehr werden.</p><h3 id="kann-ich-freshrss-ohne-docker-installieren">Kann ich FreshRSS ohne Docker installieren?<a href="#kann-ich-freshrss-ohne-docker-installieren" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Ja, FreshRSS lässt sich auch klassisch per PHP auf einem Webserver installieren. Die Anforderungen sind: PHP 7.4+, Apache oder Nginx, und optional MySQL/PostgreSQL. Die Docker-Variante ist jedoch einfacher zu verwalten.</p>
]]></content:encoded><category>selfhosted</category><category>rss</category><category>docker</category><category>homelab</category></item><item><title>Blogumzug von Wordpress zu Jekyll</title><link>https://www.teqqy.de/2023-07-blogumzug-von-wordpress-zu-jekyll/</link><pubDate>Mon, 31 Jul 2023 22:29:57 +0200</pubDate><lastBuildDate>Mon, 31 Jul 2023 22:29:57 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/2023-07-blogumzug-von-wordpress-zu-jekyll/</guid><description>In den letzten Jahren habe ich immer wieder aus verschiedenen Gründen die Blogsoftware gewechselt. Dieses Mal bin ich von Wordpress zu Jekyll umgezogen. Mein Vorgehen und Gründe möchte ich in diesem Beitrag erläutern.
Was ist Jekyll? Jekyll ist eine Blogsoftware bzw. ein sogenannter Static Site Generator. Primär wird Jekyll von GitHub Pages verwendet. Die meisten Tutorials die man so im Internet finden beziehen auch genau darauf. Grundlegend baut die Software Markdown-Dateien zu statischen HTML Dateien um diese mit einem einfachen Webserver ausliefern zu können. Im bequemsten Fall sogar mit dem integriertem.</description><content:encoded>&lt;![CDATA[<p>In den letzten Jahren habe ich immer wieder aus verschiedenen Gründen die Blogsoftware gewechselt. Dieses Mal bin ich von Wordpress zu Jekyll umgezogen. Mein Vorgehen und Gründe möchte ich in diesem Beitrag erläutern.</p><h2 id="was-ist-jekyll">Was ist Jekyll?<a href="#was-ist-jekyll" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Jekyll ist eine Blogsoftware bzw. ein sogenannter Static Site Generator. Primär wird Jekyll von GitHub Pages verwendet. Die meisten Tutorials die man so im Internet finden beziehen auch genau darauf. Grundlegend baut die Software Markdown-Dateien zu statischen HTML Dateien um diese mit einem einfachen Webserver ausliefern zu können. Im bequemsten Fall sogar mit dem integriertem.</p><h2 id="gründe-für-meinen-wechsel">Gründe für meinen Wechsel<a href="#gr%c3%bcnde-f%c3%bcr-meinen-wechsel" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Gründe könnten mannigfaltig sein. Schlussendlich läuft es aber darauf hinaus, dass Wordpress immer mächtiger wird. Das hat seine Vor- und Nachteile. Sicherlich ist es sehr praktisch für jeden Anwendungsfall Wordpress verwenden zu können, denn die verschiedenen Plugins und Themes machen das möglich. Viele großen Webseiten basieren auf Wordpress und mit dem notwendigen Know-How und Ressourcen lassen sich auch sehr Performance Webseiten bauen.
Der Nachteil der Erweiterbarkeit liegt entsprechend auch in der Pflege und den Bemühungen einen guten Wert für den LCP zu erreichen. Mir ist es im Laufe der Zeit nicht gelungen einen guten Wert zu erreichen. Am Hoster<a href="https://www.netcup.de/?ref=60644" target="_blank" rel="noopener noreferrer">Netcup<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
liegt es nicht, da ich hier auch verschiedene ausprobiert habe.
Zudem bin ich im Moment dabei mich von verschiedenen großen Softwareprodukten zu trennen und auf freiere Software zu setzen.</p><p>In der Webentwicklung steht LCP für &ldquo;Largest Contentful Paint&rdquo;. Es handelt sich um eine wichtige Metrik für die Ladeleistung einer Webseite. LCP misst die Zeit, die benötigt wird, um den größten sichtbaren Inhalt im Viewport eines Nutzers während des Seitenladens zu rendern. Ein guter LCP-Wert ist wichtig, um sicherzustellen, dass Webseiten schnell und reibungslos geladen werden und Benutzer eine bessere Erfahrung haben.
{:.note title=&ldquo;Was ist LCP?&rdquo;}</p><h2 id="installation-von-jekyll">Installation von Jekyll<a href="#installation-von-jekyll" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Die Installation von Jekyll kann unter verschiedenen Betriebssystemen durchgeführt werden. Allerdings ist Windows nicht mit dabei. Wenn man allerdings den Umweg über WSL2 geht, kann man der regulären Linux Installation für die verwendete Linux-Distribution folgen. In dieser Anleitung gehe ich erst mal auf die Installation unter MacOS ein, da ich persönlich dieses Betriebssystem verwende.
Alternative Installationen finden sich natürlich in der offiziellen Dokumentation. Gern kann dort diese entsprechend verwendet werden.</p><h3 id="installation-unter-macos">Installation unter MacOS<a href="#installation-unter-macos" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><h4 id="installation-des-paketmanagers-brew">Installation des Paketmanagers brew<a href="#installation-des-paketmanagers-brew" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h4><p>MacOS Nutzer haben in der Regel schon den Paketmanager<code>brew</code> installiert. Falls du das noch nicht getan hast, lässt sich das mittels</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>/bin/bash -c<span style="color:#a5d6ff">"</span><span style="color:#ff7b72">$(</span>curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh<span style="color:#ff7b72">)</span><span style="color:#a5d6ff">"</span></span></span></code></pre></div></div><p>erledigen. Grundsätzlich sollte aber immer beim Ausführen von Programmen direkt aus dem Internet vorsichtig sein! Sobald das erledigt ist, brauchen wir jetzt den Ruby Installer denn Jekyll ist in der entsprechenden Programiersprache geschrieben.</p><h4 id="installation-von-ruby">Installation von ruby<a href="#installation-von-ruby" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h4><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>brew install chruby ruby-install xz</span></span></code></pre></div></div><p>Dies kann durchaus ein paar Minuten dauern, das ist nicht ungewöhnlich. Nun installieren wir noch ruby selbst.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ruby-install ruby 3.2.2</span></span></code></pre></div></div><p>Beachte, dass die Version 3.2.2 die zum Zeitpunkt des Artikels die aktuellste Version ist, dass kann zum jetzigen Zeitpunkt anders sein.
Der nächste Schritt ist, dass wir ruby und die ganzen Environment Variablen noch aktivieren und in die MacOS Konfiguration speichern</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>echo<span style="color:#a5d6ff">"source</span><span style="color:#ff7b72">$(</span>brew --prefix<span style="color:#ff7b72">)</span><span style="color:#a5d6ff">/opt/chruby/share/chruby/chruby.sh"</span> &gt;&gt; ~/.zshrc</span></span><span style="display:flex;"><span>echo<span style="color:#a5d6ff">"source</span><span style="color:#ff7b72">$(</span>brew --prefix<span style="color:#ff7b72">)</span><span style="color:#a5d6ff">/opt/chruby/share/chruby/auto.sh"</span> &gt;&gt; ~/.zshrc</span></span><span style="display:flex;"><span>echo<span style="color:#a5d6ff">"chruby ruby-3.2.2"</span> &gt;&gt; ~/.zshrc<span style="color:#8b949e;font-style:italic"># run 'chruby' to see actual version</span></span></span></code></pre></div></div><h4 id="installation-von-jekyll-1">Installation von Jekyll<a href="#installation-von-jekyll-1" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h4><p>Endlich kommen wir zu dem Punkt, dass wir Jekyll selbst installieren können.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>gem install jekyll</span></span></code></pre></div></div><p>Auch der Schritt kann einige Zeit lang brauchen. Anschließend haben wir Jekyll installiert.</p><h2 id="jekyll-webseite-anlegen">Jekyll Webseite anlegen<a href="#jekyll-webseite-anlegen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Sobald wir also eine lauffähige Version von Jekyll haben, können wir nun eine Webseite anlegen. Wir suchen uns also einen entsprechenden Ordner aus in dem die Installation durchgeführt werden soll. Ich mache sowas immer in einem Unterordner in meinem Homeverzeichnis.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cd ~</span></span></code></pre></div></div><p>Den Namen den wir im install Befehl mitgeben wird auch der Name des Ordners sein. Natürlich kann der Prozess beliebig oft ausgeführt werden, falls euch das nicht gefällt.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>jekyll new blog</span></span></code></pre></div></div><p>Es entsteht dann eine ungefähr solche Ausgabe</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Running bundle install in /Users/teqqy/blog...</span></span><span style="display:flex;"><span> Bundler: Fetching gem metadata from https://rubygems.org/............</span></span><span style="display:flex;"><span> Bundler: Resolving dependencies...</span></span><span style="display:flex;"><span> Bundler: Fetching rouge 4.1.3</span></span><span style="display:flex;"><span> Bundler: Installing rouge 4.1.3</span></span><span style="display:flex;"><span> Bundler: Bundle complete!<span style="color:#a5d6ff">7</span> Gemfile dependencies,<span style="color:#a5d6ff">33</span> gems now installed.</span></span><span style="display:flex;"><span> Bundler: Use<span style="color:#a5d6ff">`</span>bundle info<span style="color:#ff7b72;font-weight:bold">[</span>gemname<span style="color:#ff7b72;font-weight:bold">]</span><span style="color:#a5d6ff">`</span> to see where a bundled gem is installed.</span></span><span style="display:flex;"><span>New jekyll site installed in /Users/teqqy/blog.</span></span><span style="display:flex;"><span><span style="color:#ff7b72;font-weight:bold">[</span>21:31:33<span style="color:#ff7b72;font-weight:bold">]</span><span style="color:#ff7b72;font-weight:bold">[</span>cost 3.162s<span style="color:#ff7b72;font-weight:bold">]</span> jekyll new blog</span></span></code></pre></div></div><p>Nun wechseln wir in das Verzeichnis und gucken mal was so für Dateien und Ordner dort hinterlegt sind.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#ff7b72;font-weight:bold">[</span>21:32:50<span style="color:#ff7b72;font-weight:bold">]</span><span style="color:#ff7b72;font-weight:bold">[</span>~/blog<span style="color:#ff7b72;font-weight:bold">]</span> ❱❱❱ ls -l</span></span><span style="display:flex;"><span>total<span style="color:#a5d6ff">48</span></span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">419</span><span style="color:#a5d6ff">31</span> Jul 21:31 404.html</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">1309</span><span style="color:#a5d6ff">31</span> Jul 21:31 Gemfile</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">2052</span><span style="color:#a5d6ff">31</span> Jul 21:31 Gemfile.lock</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">2079</span><span style="color:#a5d6ff">31</span> Jul 21:31 _config.yml</span></span><span style="display:flex;"><span>drwxr-xr-x<span style="color:#a5d6ff">3</span> teqqy staff<span style="color:#a5d6ff">96</span><span style="color:#a5d6ff">31</span> Jul 21:31 _posts</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">539</span><span style="color:#a5d6ff">31</span> Jul 21:31 about.markdown</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">175</span><span style="color:#a5d6ff">31</span> Jul 21:31 index.markdown</span></span></code></pre></div></div><p>Wie man sieht, sind das nicht viele Dateien. Nun sollten wir die<code>_config.yml</code> anpassen. Die Begriffe sollten selbsterklärend sein. Die Werte sind aber erst mal keine Pflicht.
Um jetzt die HTML Dateien bauen zu lassen verwenden wir folgenden Befehl</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>jekyll serve</span></span></code></pre></div></div><p>Es erscheinen diverse Fehlermeldungen und Warnungen auf Grund von veralteten Abhängigkeiten. Leider sind diese immer noch nicht sauber gefixt. Die letzte Ausgabe sollte etwas in der Art von</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Run in verbose mode to see all warnings.</span></span><span style="display:flex;"><span><span style="color:#ff7b72">done</span> in 0.401 seconds.</span></span><span style="display:flex;"><span> Auto-regeneration: enabled<span style="color:#ff7b72">for</span><span style="color:#a5d6ff">'/Users/teqqy/blog'</span></span></span><span style="display:flex;"><span> Server address: http://127.0.0.1:4000/</span></span><span style="display:flex;"><span> Server running... press ctrl-c to stop.</span></span></code></pre></div></div><p>Enthalten. Jetzt könnt ihr euren Browser öffnen und die URL<code>http://127.0.0.1:4000</code> verwenden.</p><p>Wir brechen dann wieder den laufenden Server mit<code>CTRL-C</code> ab. Wenn wir jetzt nochmal die Verzeichnisse auflisten sehen wir, dass dort ein neuer Ordner<code>_site</code> erstellt worden ist.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#ff7b72;font-weight:bold">[</span>21:40:43<span style="color:#ff7b72;font-weight:bold">]</span><span style="color:#ff7b72;font-weight:bold">[</span>~/blog<span style="color:#ff7b72;font-weight:bold">]</span> ❱❱❱ ls -l</span></span><span style="display:flex;"><span>total<span style="color:#a5d6ff">48</span></span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">419</span><span style="color:#a5d6ff">31</span> Jul 21:31 404.html</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">1309</span><span style="color:#a5d6ff">31</span> Jul 21:31 Gemfile</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">2052</span><span style="color:#a5d6ff">31</span> Jul 21:31 Gemfile.lock</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">2079</span><span style="color:#a5d6ff">31</span> Jul 21:31 _config.yml</span></span><span style="display:flex;"><span>drwxr-xr-x<span style="color:#a5d6ff">3</span> teqqy staff<span style="color:#a5d6ff">96</span><span style="color:#a5d6ff">31</span> Jul 21:31 _posts</span></span><span style="display:flex;"><span>drwxr-xr-x<span style="color:#a5d6ff">8</span> teqqy staff<span style="color:#a5d6ff">256</span><span style="color:#a5d6ff">31</span> Jul 21:35 _site</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">539</span><span style="color:#a5d6ff">31</span> Jul 21:31 about.markdown</span></span><span style="display:flex;"><span>-rw-r--r--<span style="color:#a5d6ff">1</span> teqqy staff<span style="color:#a5d6ff">175</span><span style="color:#a5d6ff">31</span> Jul 21:31 index.markdown</span></span></code></pre></div></div><p>Dieser Ordner ist nun schlussendlich das wichtige. Dieser kann auf einen Webserver kopiert und ausgeliefert werden.</p><h3 id="webseite-bereitstellen">Webseite bereitstellen<a href="#webseite-bereitstellen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Viele Tutorials im Internet verwenden den<code>jekyll serve</code> Befehl um die Webseite auszuliefern und richten einen Webserver wie NGINX oder apache2 als reverse proxy ein. Dies ist allerdings nicht der vom Hersteller empfohlene Weg. Ich für meinen Teil habe das Verzeichnis auf meinen Webserver kopiert und liefere es mit einem Nginx Docker-Container aus. Dieser hat entsprechende Traefik Labels, welches sich um die Zertifikate etc kümmert. Sicherlich kein Setup für jeden.</p><h4 id="nginx-docker-container">Nginx Docker Container<a href="#nginx-docker-container" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h4><p>Meine verwendete<code>docker-compose.yaml</code> Datei kannst du natürlich übernehmen wenn du möchtest. Du müsstest nur die Werte entsprechend anpassen.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">version</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"3.8"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">nginx</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">nginx</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">nginx</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">./_site:/usr/share/nginx/html</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">./nginx.conf:/etc/nginx/conf.d/www_nginx.conf</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">labels</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.enable=true"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.middlewares.nginx-https.redirectscheme.scheme=https"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.middlewares.nginx-compress.compress=true"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.nginx-http.entrypoints=web"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.nginx-http.rule=Host(`www.example.com`) || Host(`example.com`)"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.nginx-http.middlewares=teqqy-https@docker"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.nginx.entrypoints=websecure"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.teqqy.rule=Host(`www.example.com``) || Host(`example.com``)"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.nginx.tls=true"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.nginx.tls.certresolver=default"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.nginx.middlewares=secHeaders@file"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.nginx.middlewares=teqqy-compress"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.services.nginx.loadbalancer.server.port=80"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">teqqywp</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">traefik_proxy</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik_proxy</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">external</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">traefik_proxy</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">teqqywp</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">driver</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">bridge</span></span></span></code></pre></div></div><h4 id="nginx-konfiguration">Nginx Konfiguration<a href="#nginx-konfiguration" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h4><p>Ich binde noch eine eigene<code>nginx.conf</code> Datei ein in der ich noch Anpassungen für Caching und anderes mache.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">conf</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="conf"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code class="language-conf" data-lang="conf">server {
listen 80;
server_name example.com www.example.com
root /usr/share/nginx/html;
index index.html index.htm;
if (!-f "${request_filename}index.html") {
rewrite ^/(.*)/$ /$1 permanent;
}
if ($request_uri ~* "/index.html") {
rewrite (?i)^(.*)index\.html$ $1 permanent;
}
if ($request_uri ~* ".html") {
rewrite (?i)^(.*)/(.*)\.html $1/$2 permanent;
}
error_page 404 /404.html;
location / {
try_files $uri $uri.html $uri/ =404;
}
location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
expires 30d;
add_header Pragma public;
add_header Cache-Control "public";
}
# reduce the data that needs to be sent over network -- for testing environment
gzip on;
# gzip_static on;
gzip_min_length 10240;
gzip_comp_level 1;
gzip_vary on;
gzip_disable msie6;
gzip_proxied expired no-cache no-store private auth;
gzip_types
# text/html is always compressed by HttpGzipModule
text/css
text/javascript
text/xml
text/plain
text/x-component
application/javascript
application/x-javascript
application/json
application/xml
application/rss+xml
application/atom+xml
font/truetype
font/opentype
application/vnd.ms-fontobject
image/svg+xml;
# allow the server to close connection on non responding client, this will free up memory
reset_timedout_connection on;
# request timed out -- default 60
client_body_timeout 10;
# if client stop responding, free up memory -- default 60
send_timeout 2;
# server will close connection after this time -- default 75
keepalive_timeout 30;
# number of requests client can make over keep-alive -- for testing environment
keepalive_requests 100000;
}</code></pre></div><p>Nun kann der Container gestartet werden und nach kurzer Zeit könnt ihr die Seite über die angegebene URL aufrufen.</p><h2 id="wordpress-daten-exportieren">Wordpress Daten exportieren<a href="#wordpress-daten-exportieren" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Für den Export habe ich das Wordpress Plugin<a href="https://de.wordpress.org/plugins/jekyll-exporter/" target="_blank" rel="noopener noreferrer">Wordpress to Jekyll Exporter<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
verwendet. Es nicht das beste Plugin aber für mich hat es gereicht. In Wordpress können wir dann unter<strong>Werkzeuge</strong> den Export ausführen und bekommen eine ZIP-Datei zum Download.
Die Inhalte können wir direkt in unser Jekyll Verzeichnis kopieren und die Seiten neu genierieren lassen.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>jekyll serve</span></span></code></pre></div></div><p>Nun können wir den Ordner<code>_site</code> wieder auf unseren Webserver kopieren. Den Container müssen wir nicht neu starten, denn nginx liefert die Dateien direkt aus. Ein einfacher reload im Browser reicht dafür aus.</p><h2 id="jekyll-anapssen">Jekyll anapssen<a href="#jekyll-anapssen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Jetzt liegt es an euch, Jekyll entsprechend den Bedürfnissen anzu passen. Heißt ein Theme herunter zu laden oder mit Plugins zu erweitern.</p>
]]></content:encoded><category>wordpress</category><category>jekyll</category><category>nginx</category><category>docker</category></item><item><title>Teslamate Setup: Docker, Fleet API &amp; Grafana</title><link>https://www.teqqy.de/teslamate-datenlogger-fur-tesla-fahrzeuge/</link><pubDate>Mon, 27 Mar 2023 20:19:57 +0200</pubDate><lastBuildDate>Mon, 01 Dec 2025 00:00:00 +0000</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/teslamate-datenlogger-fur-tesla-fahrzeuge/</guid><description>Update Dezember 2025: Dieser Artikel wurde überarbeitet und berücksichtigt die wichtigen Änderungen der Tesla Fleet API sowie aktuelle Teslamate-Versionen.
Moderne Fahrzeuge bieten mittlerweile eine API-Schnittstelle, um alle möglichen Daten auslesen zu können. Tesla war einer der ersten Hersteller, der dies umfangreich zur Verfügung stellt. Entsprechend sind Softwareprodukte wie Teslamate entstanden. Teslamate ist ein selbstgehosteter Open-Source-Datenlogger, der deine Tesla-Daten kontinuierlich erfasst, speichert und mit Grafana visualisiert.
Was hat sich 2025 geändert? Die wichtigsten Updates auf einen Blick:</description><content:encoded>&lt;![CDATA[<p><strong>Update Dezember 2025:</strong> Dieser Artikel wurde überarbeitet und berücksichtigt die wichtigen Änderungen der Tesla Fleet API sowie aktuelle Teslamate-Versionen.</p><p>Moderne Fahrzeuge bieten mittlerweile eine API-Schnittstelle, um alle möglichen Daten auslesen zu können. Tesla war einer der ersten Hersteller, der dies umfangreich zur Verfügung stellt. Entsprechend sind Softwareprodukte wie Teslamate entstanden. Teslamate ist ein selbstgehosteter Open-Source-Datenlogger, der deine Tesla-Daten kontinuierlich erfasst, speichert und mit Grafana visualisiert.</p><h2 id="was-hat-sich-2025-geändert">Was hat sich 2025 geändert?<a href="#was-hat-sich-2025-ge%c3%a4ndert" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Die wichtigsten Updates auf einen Blick:</p><p><strong>Tesla Fleet API:</strong> Tesla hat die inoffizielle &ldquo;Owner API&rdquo; durch die offizielle Fleet API ersetzt. Seit Februar 2025 gilt ein Pay-per-Use-Modell mit monatlichem $10-Freikontingent. Für Privatnutzer mit 1-2 Fahrzeugen reicht das Kontingent meist aus, zusätzliche Kosten liegen bei etwa $2-5/Monat bei intensiver Nutzung.</p><p><strong>PostgreSQL 17:</strong> Teslamate benötigt nun mindestens PostgreSQL 16.7 oder 17.3. Die Entwickler empfehlen PostgreSQL 17.</p><p><strong>Fleet Telemetry:</strong> Neu ist die Möglichkeit, dass das Fahrzeug Daten direkt streamt. Das ist präziser und günstiger als klassisches Polling, aber komplexer in der Einrichtung. Fleet Telemetry erfordert einen eigenen Server-Endpunkt und TLS-Zertifikate. Die Daten werden dann vom Fahrzeug per WebSocket gestreamt, sobald sich Werte ändern. Das spart API-Kosten, da du nicht mehr aktiv pollen musst. Besonders bei Fahrten erhältst du hochfrequente Daten mit minimaler Latenz. Für die meisten Nutzer funktioniert das bewährte Polling jedoch weiterhin problemlos und ist deutlich einfacher einzurichten.</p><h2 id="teslamate--installieren-oder-einkaufen">Teslamate – Installieren oder einkaufen?<a href="#teslamate--installieren-oder-einkaufen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Teslamate ist keine Software-as-a-Service, sondern wird vom Nutzer selbst installiert. Ob im heimischen Homelab oder auf einem VPS-Server in der Cloud, z. B. bei<a href="https://www.netcup.de/?ref=60644" target="_blank" rel="noopener noreferrer">Netcup<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
– beides funktioniert. Ich hoste die Software auf meinem eigenen Server im Heimnetzwerk.</p><p>Die Installation ist mit<a href="/wordpress-docker-performance/">Docker</a>
sehr einfach. Du benötigst eine Datenbank (PostgreSQL) und den Anwendungscontainer. Für die Visualisierung setzt Teslamate auf Grafana mit fertig konfigurierten Dashboards.</p><h2 id="voraussetzungen">Voraussetzungen<a href="#voraussetzungen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><strong>Hardware &amp; Software:</strong></p><ul><li>Server mit mindestens 2 GB RAM (Raspberry Pi 4/5, NAS, VPS)</li><li>Docker und Docker Compose installiert</li><li>Dauerhaft aktive Internetverbindung</li></ul><p><strong>Tesla-Account:</strong></p><ul><li>Tesla-Konto mit Zwei-Faktor-Authentifizierung</li><li>Tesla Developer Account (kostenlos bei<a href="https://developer.tesla.com" target="_blank" rel="noopener noreferrer">developer.tesla.com<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
)</li></ul><h2 id="tesla-developer-account-einrichten">Tesla Developer Account einrichten<a href="#tesla-developer-account-einrichten" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Seit der Umstellung auf die Fleet API brauchst du einen Developer Account:</p><ol><li>Melde dich bei<a href="https://developer.tesla.com" target="_blank" rel="noopener noreferrer">developer.tesla.com<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
mit deinem Tesla-Konto an</li><li>Erstelle eine neue Application (z.B. &ldquo;Teslamate Homelab&rdquo;)</li><li>Gib eine kurze Beschreibung an</li><li>Bei lokaler Nutzung kannst du localhost als Domain verwenden</li></ol><p>Die Prüfung dauert ein paar Tage, für private Zwecke erfolgt die Freigabe normalerweise problemlos. Das monatliche $10-Guthaben ist ein echtes Guthaben – du musst keine Kreditkarte hinterlegen, solange du darunter bleibst.</p><h2 id="token-erstellung">Token-Erstellung<a href="#token-erstellung" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Früher funktionierte die Anmeldung mit Benutzerdaten. Heute benötigst du einen „Refresh Token" und „Access Token". Diese generierst du am einfachsten mit Apps:</p><ul><li><strong>iOS:</strong> &ldquo;Auth for Tesla&rdquo; (Apple AppStore)</li><li><strong>Android:</strong> &ldquo;Tesla Tokens&rdquo; oder &ldquo;Auth for Tesla&rdquo;</li><li><strong>Windows/Mac:</strong> &ldquo;Tesla Auth&rdquo; oder Web-basierte Tools</li></ul><p><strong>Vorgehensweise:</strong></p><ol><li>App installieren und mit Tesla-Benutzernamen anmelden</li><li>Passwort eingeben</li><li>Beim zweiten Prompt deinen 2FA-Code eingeben (nicht nochmal das Passwort!)</li><li>App zeigt Refresh Token und Access Token – beide sicher aufbewahren</li></ol><p>Die Tokens bleiben mehrere Monate gültig. Teslamate erneuert den Access Token automatisch.</p><p><img src="/teslamate-datenlogger-fur-tesla-fahrzeuge/images/teslamate-tesla-token_hu_b53628674ab82b23.webp" srcset="/teslamate-datenlogger-fur-tesla-fahrzeuge/images/teslamate-tesla-token_hu_ecfb7a72ba31093e.webp 384w, /teslamate-datenlogger-fur-tesla-fahrzeuge/images/teslamate-tesla-token_hu_b53628674ab82b23.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="" loading="eager" fetchpriority="high" decoding="async" width="768" height="595"/><h2 id="installation-mit-docker-compose">Installation mit Docker Compose<a href="#installation-mit-docker-compose" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Die einfachste Installation erfolgt über Docker Compose. Falls du Docker Compose noch nicht installiert hast:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># Auf Ubuntu/Debian</span></span></span><span style="display:flex;"><span>sudo apt install docker-compose-plugin</span></span><span style="display:flex;"><span>docker compose version</span></span></code></pre></div></div><p>Erstelle ein Arbeitsverzeichnis:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir ~/teslamate<span style="color:#ff7b72;font-weight:bold">&amp;&amp;</span> cd ~/teslamate</span></span></code></pre></div></div><p>Ich verweise auf die<a href="https://docs.teslamate.org/docs/installation/docker" target="_blank" rel="noopener noreferrer">offizielle Dokumentation<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
, da sich die Konfiguration regelmäßig ändert.</p><p><strong>Wichtige Anpassungen für 2025:</strong></p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#7ee787">version</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"3"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">teslamate</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">teslamate/teslamate:latest</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">always</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">ENCRYPTION_KEY=dein_sicherer_schluessel</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">DATABASE_USER=teslamate</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">DATABASE_PASS=sicheres_passwort</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">DATABASE_NAME=teslamate</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">DATABASE_HOST=database</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">TZ=Europe/Berlin</span><span style="color:#6e7681"/><span style="color:#8b949e;font-style:italic"># Deine Zeitzone!</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">MQTT_DISABLE=true</span><span style="color:#6e7681"/><span style="color:#8b949e;font-style:italic"># Falls kein MQTT benötigt</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ports</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">4000</span>:<span style="color:#a5d6ff">4000</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">cap_drop</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">all</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">database</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">postgres:17</span><span style="color:#6e7681"/><span style="color:#8b949e;font-style:italic"># Mindestens 16.7 oder 17.3!</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">always</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">POSTGRES_USER=teslamate</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">POSTGRES_PASSWORD=sicheres_passwort</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">POSTGRES_DB=teslamate</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">teslamate-db:/var/lib/postgresql/data</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">grafana</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">teslamate/grafana:latest</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">always</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">DATABASE_USER=teslamate</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">DATABASE_PASS=sicheres_passwort</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">DATABASE_NAME=teslamate</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">DATABASE_HOST=database</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ports</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">3000</span>:<span style="color:#a5d6ff">3000</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">teslamate-grafana-data:/var/lib/grafana</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">teslamate-db</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#a5d6ff">teslamate-grafana-data:</span></span></span></code></pre></div></div><p><strong>MQTT für Home Assistant:</strong></p><p>Wenn du die Daten an einen MQTT-Server weiterleiten willst (z. B. für<a href="/tesla-ueberschussladen-mit-home-assistant/">Home-Assistant</a>
), ersetze<code>MQTT_DISABLE=true</code> durch<code>MQTT_HOST=mosquitto</code> und füge einen Mosquitto-Container hinzu.</p><p><strong>Container starten:</strong></p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose up -d</span></span></code></pre></div></div><p>Teslamate ist anschließend unter<code>http://{IP-deines-Servers}:4000</code> erreichbar. Beim ersten Aufruf gibst du die zuvor generierten Tokens ein. Nach 1-2 Minuten (ggf. Fahrzeug mit der App aufwecken) sollten erste Daten angezeigt werden.</p><h2 id="auswertung-mit-grafana">Auswertung mit Grafana<a href="#auswertung-mit-grafana" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Ein großer Vorteil der vordefinierten Docker-Compose-Datei: Grafana ist direkt mit dabei. Grafana läuft standardmäßig unter<code>http://{IP-deines-Servers}:3000</code>.</p><p>Standard-Login (sofort ändern!):</p><ul><li>Benutzername:<code>admin</code></li><li>Passwort:<code>admin</code></li></ul><p><a href="/docker-monitoring-mit-prometheus-und-grafana/">Grafana</a>
hat die PostgreSQL-Datenbank als Datenquelle bereits konfiguriert und alle Dashboards sind importiert. Bei Nutzung einer eigenen Grafana-Instanz musst du die JSON-Dateien aus dem<a href="https://www.github.com/cbirkenbeul" target="_blank" rel="noopener noreferrer">GitHub<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Repository manuell importieren.</p><p><strong>Wichtige Dashboards:</strong></p><ul><li><strong>Overview:</strong> Gesamtübersicht aller Kennzahlen – der perfekte Einstieg</li><li><strong>Drives:</strong> Fahrtenauswertung mit interaktiven Karten, zeigt Route, Geschwindigkeit und Verbrauch</li><li><strong>Charges:</strong> Detaillierte Ladehistorie mit Kostenanalyse pro Ladevorgang, Vergleich verschiedener Ladestationen</li><li><strong>Battery Health:</strong> Langzeitentwicklung der Batteriekapazität, zeigt Degradation über Zeit und Kilometer</li><li><strong>Efficiency:</strong> Verbrauchsanalysen nach Geschwindigkeit, Temperatur, Höhenmetern – erkenne was deine Reichweite beeinflusst</li><li><strong>Vampire Drain:</strong> Standby-Verbrauch im geparkten Zustand, hilft Phantom Drain zu identifizieren</li><li><strong>Locations:</strong> Häufige Aufenthaltsorte, automatische Geofencing-Erkennung</li><li><strong>Updates:</strong> Historie aller Software-Updates mit Zeitstempeln</li></ul><h2 id="langzeitnutzung-und-erkenntnisse">Langzeitnutzung und Erkenntnisse<a href="#langzeitnutzung-und-erkenntnisse" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Der wahre Wert zeigt sich nach mehreren Monaten. Hier konkrete Beispiele aus meiner Nutzung:</p><p><strong>Batteriedegradation:</strong> Mein Model Y zeigte nach 50.000 km etwa 4% Kapazitätsverlust. Typisch sind 3-5% in den ersten 50.000 km, danach verlangsamt sich die Degradation deutlich. Mit Teslamate siehst du die exakte Entwicklung und kannst Ausreißer (z.B. durch BMS-Kalibrierung) erkennen.</p><p><strong>Saisonale Unterschiede:</strong> Im Winter (Temperaturen um 0°C) liegt mein Verbrauch bei ca. 20-22 kWh/100km, im Sommer bei 15-17 kWh/100km. Das sind rund 30% Mehrverbrauch durch Heizung und kalte Batterie. Diese Daten helfen bei der Routenplanung.</p><p><strong>Kostenoptimierung:</strong> Heimladen (0,30 €/kWh) vs. Supercharger (0,52 €/kWh) – der Unterschied summiert sich. Bei 15.000 km jährlich spare ich durch Heimladen etwa 400 € pro Jahr. Noch besser:<a href="/tesla-ueberschussladen-mit-home-assistant/">PV-Überschussladen</a>
reduziert die Kosten auf ca. 0,08 €/kWh.</p><p><strong>Effizienz:</strong> Überraschend war, dass mein optimaler Geschwindigkeitsbereich bei 90-110 km/h liegt, nicht wie erwartet bei 70 km/h. Unter 70 km/h steigt der relative Verbrauch durch Hilfsaggregate wieder leicht an.</p><h2 id="troubleshooting">Troubleshooting<a href="#troubleshooting" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><strong>Teslamate zeigt &ldquo;offline&rdquo; statt &ldquo;asleep&rdquo;:</strong>
Das ist seit Tesla-Firmware 2024.8+ normal. Tesla hat die API-Rückmeldung geändert – kein Teslamate-Bug.</p><p><strong>Token wird nicht akzeptiert:</strong>
Verwende den Refresh Token (der längere der beiden Strings), nicht den Access Token.</p><p><strong>Keine Daten:</strong>
Prüfe die Docker-Logs mit<code>docker compose logs teslamate</code>. Häufige Ursachen: Fahrzeug im Tiefschlaf, falsche Zeitzone, Netzwerkprobleme.</p><p><strong>Hohe API-Kosten:</strong>
Reduziere die Polling-Frequenz, nutze Fleet Telemetry oder prüfe auf unnötige Wake-Befehle.</p><h2 id="sicherheit-und-backup">Sicherheit und Backup<a href="#sicherheit-und-backup" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><strong>Netzwerk:</strong></p><ul><li>Nicht direkt ins Internet exponieren</li><li>Reverse Proxy mit HTTPS nutzen (Nginx, Caddy, Traefik)</li><li>Firewall-Regeln aktivieren</li></ul><p><strong>Backup:</strong></p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose exec database pg_dump -U teslamate teslamate &gt; backup.sql</span></span></code></pre></div></div><p><strong>Updates:</strong></p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose pull</span></span><span style="display:flex;"><span>docker compose up -d</span></span></code></pre></div></div><h2 id="häufige-fragen">Häufige Fragen<a href="#h%c3%a4ufige-fragen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><strong>Kostet Teslamate Geld?</strong>
Die Software ist kostenlos. Tesla API-Kosten fallen an, werden aber meist vom $10-Freikontingent abgedeckt. Nur bei intensiver Nutzung entstehen ca. $2-5/Monat zusätzlich.</p><p><strong>Funktioniert es mit der neuen Fleet API?</strong>
Ja, vollständig kompatibel und aktuell gehalten.</p><p><strong>Entlädt es die Batterie?</strong>
Nein, der Zusatzverbrauch ist vernachlässigbar.</p><p><strong>Mehrere Fahrzeuge möglich?</strong>
Ja, jedes wird separat erfasst.</p><h2 id="fazit">Fazit<a href="#fazit" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Teslamate ist für mich die beste Lösung für umfassende Fahrzeugdatenanalyse. Die Vorteile:</p><ul><li>Volle Datenkontrolle durch Self-Hosting</li><li>Detaillierte Analysen mit Grafana</li><li>Geringe Kosten dank Freikontingent</li><li>Aktive Community</li><li>Perfekt für Home-Assistant-Integration</li></ul><p>Die Nachteile: Technisches Know-how erforderlich, eigener Server nötig, kein offizieller Support.</p><p>Für Tesla-Besitzer mit Smart-Home- oder Homelab-Affinität ist Teslamate eine hervorragende Software. Nach einigen Monaten Nutzung werden die Auswertungen besonders interessant, da sich Tendenzen und Langzeitentwicklungen zeigen. Selbst während der Fahrt liefern die Grafana-Dashboards diverse interessante Daten.</p><h2 id="tipps-für-fortgeschrittene">Tipps für Fortgeschrittene<a href="#tipps-f%c3%bcr-fortgeschrittene" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><strong>Reverse Proxy Setup:</strong>
Für sicheren Zugriff von unterwegs empfehle ich einen Reverse Proxy mit Let&rsquo;s Encrypt SSL-Zertifikat. Traefik oder Caddy automatisieren den Prozess komplett.</p><p><strong>Datenbank-Optimierung:</strong>
Bei sehr alten Installationen kann ein manuelles Vacuum der Datenbank helfen:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose exec database vacuumdb -U teslamate -d teslamate -z -v</span></span></code></pre></div></div><p><strong>Custom Dashboards:</strong>
Grafana bietet unendliche Möglichkeiten. Du kannst beispielsweise Vergleiche mit anderen Tesla-Fahrern erstellen oder Korrelationen zwischen Wetter und Verbrauch visualisieren.</p><p><strong>Weiterführende Links:</strong></p><ul><li><a href="https://docs.teslamate.org" target="_blank" rel="noopener noreferrer">Teslamate Dokumentation<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a></li><li><a href="https://github.com/teslamate-org/teslamate" target="_blank" rel="noopener noreferrer">GitHub Repository<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a></li><li><a href="https://github.com/teslamate-org/teslamate/discussions" target="_blank" rel="noopener noreferrer">Community Forum<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a></li></ul>
]]></content:encoded><category>selfhosted</category><category>tesla</category><category>docker</category><category>grafana</category><category>homelab</category></item><item><title>Portainer Tutorial (für Version 2.x)</title><link>https://www.teqqy.de/portainer-tutorial-fuer-version-2-x/</link><pubDate>Tue, 22 Mar 2022 20:13:14 +0100</pubDate><lastBuildDate>Tue, 22 Mar 2022 20:13:14 +0100</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/portainer-tutorial-fuer-version-2-x/</guid><description>In der heutigen Welt, in der Containerisierung und die Nutzung von Docker für viele Entwickler und IT-Experten zum Alltag gehören, ist es entscheidend, effiziente und benutzerfreundliche Tools zu haben, um diese komplexen Systeme zu verwalten. Hier kommt Portainer ins Spiel – ein leistungsstarkes und intuitives Verwaltungstool, das die Arbeit mit Docker-Containern und -Stacks erheblich vereinfacht. Portainer bietet eine grafische Benutzeroberfläche (GUI), mit der sowohl Anfänger als auch erfahrene Entwickler ihre Container, Images, Netzwerke und Volumes verwalten können, ohne tief in die Kommandozeile eintauchen zu müssen.</description><content:encoded>&lt;![CDATA[<p>In der heutigen Welt, in der Containerisierung und die Nutzung von Docker für viele Entwickler und IT-Experten zum Alltag gehören, ist es entscheidend, effiziente und benutzerfreundliche Tools zu haben, um diese komplexen Systeme zu verwalten. Hier kommt<strong>Portainer</strong> ins Spiel – ein leistungsstarkes und intuitives Verwaltungstool, das die Arbeit mit Docker-Containern und -Stacks erheblich vereinfacht. Portainer bietet eine grafische Benutzeroberfläche (GUI), mit der sowohl Anfänger als auch erfahrene Entwickler ihre Container, Images, Netzwerke und Volumes verwalten können, ohne tief in die Kommandozeile eintauchen zu müssen.</p><p>In diesem<strong>Portainer-Tutorial</strong> führen wir dich Schritt für Schritt durch die Installation, Einrichtung und die wichtigsten Funktionen des Tools. Egal, ob du gerade erst in die Welt der Containerisierung einsteigst oder bereits Erfahrung mit Docker hast – dieses Tutorial hilft dir, Portainer effektiv zu nutzen, um deine Container-Infrastruktur effizienter und übersichtlicher zu gestalten. Am Ende wirst du in der Lage sein, deine Docker-Umgebung problemlos zu überwachen, zu konfigurieren und zu steuern. Mach dich bereit, deine Docker-Workflows auf das nächste Level zu heben!</p><h2 id="voraussetzungen">Voraussetzungen<a href="#voraussetzungen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Voraussetzungen für dieses<a href="https://www.portainer.io" target="_blank" rel="noopener noreferrer">Portainer<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Tutorial gibt es eigentlich fast keine. Wir beschränken uns in diesem Beitrag allerdings auf die Verwaltung von Docker. Entsprechend solltest du ein Linux-Server mit installiertem Docker vorbereitet haben. Alles weitere werden wir zusammen erarbeiten.</p><h2 id="installation-von-portainer">Installation von Portainer<a href="#installation-von-portainer" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Eine wirkliche Installation findet ja nicht statt. Wir starten Portainer als Docker Container und müssen uns eigentlich nur gegen diesen verbinden. Du findest eine vorgefertigte docker-compose.yaml-Datei in<a href="https://github.com/cbirkenbeul/docker-homelab" target="_blank" rel="noopener noreferrer">meiner Compose-Sammlung<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
. Die für die Docker GUI sieht zum Beispiel so aus.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">version</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">'3.3'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">portainer</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">portainer/portainer-ce:2.11.1</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">portainer</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">unless-stopped</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/localtime:/etc/localtime:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/timezone:/etc/timezone:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/run/docker.sock:/var/run/docker.sock</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/docker/portainer:/data</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ports</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">9000</span>:<span style="color:#a5d6ff">9000</span></span></span></code></pre></div></div><p>Den Datenspeicherort der Portainer-Konfiguration kannst du dir natürlich nach Belieben anpassen (4. Zeile bei den Volumes). Anschließend können wir den Container auch schon starten.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose up</span></span></code></pre></div></div><p>Nach ein paar Sekunden sollte die Anwendung dann vollständig gestartet sein.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>portainer | INFO 2022/03/22 18:18:21 Encryption key file `portainer` not present
portainer | INFO 2022/03/22 18:18:21 Proceeding without encryption key
portainer | INFO 2022/03/22 18:18:21 Loading PortainerDB: portainer.db
portainer | level=info msg="2022/03/22 18:18:21 [INFO] [internal,ssl] [message: no cert files found, generating self signed ssl certificates]"
portainer | 2022/03/22 18:18:22 server: Reverse tunnelling enabled
portainer | 2022/03/22 18:18:22 server: Fingerprint 8f:41:d0:fc:b7:fe:45:23:9d:f1:31:5d:70:f8:38:76
portainer | 2022/03/22 18:18:22 server: Listening on 0.0.0.0:8000...
portainer | INFO 2022/03/22 18:18:22 [INFO] [cmd,main] Starting Portainer version 2.11.1
portainer |
portainer | level=info msg="2022/03/22 18:18:22 [INFO] [http,server] [message: starting HTTPS server on port :9443]"
portainer | level=info msg="2022/03/22 18:18:22 [DEBUG] [chisel, monitoring] [check_interval_seconds: 10.000000] [message: starting tunnel management process]"
portainer | level=info msg="2022/03/22 18:18:22 [DEBUG] [internal,init] [message: start initialization monitor ]"
portainer | level=info msg="2022/03/22 18:18:22 [INFO] [http,server] [message: starting HTTP server on port :9000]"</code></pre></div><p>Ab jetzt können wir mit der Einrichtung beginnen.</p><h2 id="einrichtung-von-portainer">Einrichtung von Portainer<a href="#einrichtung-von-portainer" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Hierzu öffnen wir einen neuen Tab im Browser (oder gern auch ein neues Fenster) und geben die IP-Adresse des Docker-Servers gefolgt vom Port ein. Uns sollte so etwas begrüßen.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-welcome-page_hu_d662a93a51852aab.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-welcome-page_hu_b303ff26af239814.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-welcome-page_hu_d662a93a51852aab.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Portainer Tutorial Wellcome Page" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="464">
Wenn du möchtest, kannst du den Administrator-Account gerne einen anderen Nutzernamen geben. Andernfalls lass einfach das „admin“ in der ersten Zeile stehen. Anschließend tippst du bitte zwei Mal ein selbst gewähltes Passwort ein. Nun noch unten auf „Create user“ klicken und schon erscheint der nächste Bildschirm.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-quick-setup_hu_2b0a56284aed3b31.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-quick-setup_hu_465afbd8813534d6.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-quick-setup_hu_2b0a56284aed3b31.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Portainer Tutorial Quick Setup" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="464">
Solltest du mehrere Docker<a href="/proxmox-backup-server/">Server</a>
damit verwalten wollen, wäre „Add Environment“ das Richtige. Allerdings wollen wir in diesem Portainer Tutorial lediglich den lokalen Docker Server verwalten. Wir klicken also auf „Get Started“ und landen direkt beim nächsten Fenster.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-chose-environment_hu_24548e2d0a37e454.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-chose-environment_hu_ba686a68e2a039eb.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-chose-environment_hu_24548e2d0a37e454.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Poratiner Tutorial Environment" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="464">
Es werden hier eine Liste der möglichen Docker-Umgebungen dargestellt. Da wir natürlich nur auf die Lokale Zugriff haben, können wir nur „local“ auswählen. Genau dieses wollen wir natürlich auch.</p><p>Anschließend ist die Einrichtung auch schon abgeschlossen.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-setup-finish_hu_2ef1a1804948a2e0.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-setup-finish_hu_54aac2f31beab326.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-setup-finish_hu_2ef1a1804948a2e0.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Portainer Tutorial Setup finish" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="464"/><h2 id="anwendungen-hinzufügen">Anwendungen hinzufügen<a href="#anwendungen-hinzuf%c3%bcgen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Docker Container bzw. die Anwendungen werden als Stack in Portainer verwaltet. Entsprechend ist die Benennung hier ein wenig anders als du das vielleicht gewohnt bist. In diesem Portainer Tutorial gehe ich auf zwei Methoden ein eine neue Anwendung hinzuzufügen, nämlich per copy &amp; paste der docker-compose.yaml-Datei und per Import von<a href="https://www.github.com/cbirkenbeul" target="_blank" rel="noopener noreferrer">GitHub<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
.</p><h3 id="per-copy--paste">Per Copy &amp; Paste<a href="#per-copy--paste" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Diese Methode ist wohl die einfachste. Du kannst bestehende docker-compose.yaml-Dateien fast immer einfach hier rein kopieren. Allerdings ist aufzupassen, dass keine Variablen verwendet werden. Diese können in der Methodik nämlich nicht ausgefüllt werden. Gegebenenfalls ersetzt du einfach die Variablen durch die eigentlichen Werte, dann funktioniert das auch.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-stack-name_hu_17ddc63e74a44c9c.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-stack-name_hu_b7df9c89a3db2755.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-stack-name_hu_17ddc63e74a44c9c.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Portainer Stack Name" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="62">
Als erstes vergeben wir einen Namen. Dieser Name ist eineindeutig für die jeweiligen Umgebungen. Zudem dürfen keine Umlaute oder Leerzeichen verwendet werden. Binde- oder Unterstriche, wie im Beispiel zu sehen, sind natürlich erlaubt.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-build-method_hu_83214c49cdf21472.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-build-method_hu_2a145d0ef92cbf2a.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-build-method_hu_83214c49cdf21472.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Portainer build method" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="413">
Für dieses Beispiel deployen wir das Ghost CMS. Wir nehmen also einfach eine docker-compose.yaml-Datei (wie diese aus meiner Sammlung) und fügen den Inhalt einfach ein.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-ev-ac-deploy_hu_6ebb07fbea81fca3.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-ev-ac-deploy_hu_2e5f516274b0a5e1.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-ev-ac-deploy_hu_6ebb07fbea81fca3.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="portainer cp ev ac" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="257">
In unserem einfachen Beispiel müssen wir nichts weiter beachten und lassen alle anderen Felder und Möglichkeiten außer Acht. Wir müssen also nur noch auf „Deploy the stack“ klicken und Portainer zieht das Image aus der Registry und startet den Container.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-deployed-ghost_hu_9eae626caf703f5a.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-deployed-ghost_hu_2ecc2cc084de5b92.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-deployed-ghost_hu_9eae626caf703f5a.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Portainer deployed Ghost" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="464">
So einfach war die Copy &amp; Paste-Methode. Anschließend fügen wir jetzt noch eine compose-Datei aus<a href="https://www.github.com/cbirkenbeul" target="_blank" rel="noopener noreferrer">GitHub<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
hinzu.</p><h3 id="compose-datei-aus-github">Compose Datei aus GitHub<a href="#compose-datei-aus-github" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Diese Methode kann verwendet werden, wenn man keine Lust auf Copy &amp; Paste hat. Allerdings hat sie nicht wirklich große Vorteile. Zumal der Stack dann auch nicht vollständig über Portainer verwaltet werden kann. Auf der anderen Seite wird der Stack über die originale Datei auf GitHub synchronisiert und entsprechend aktuell gehalten (wenn man das möchte).</p><p>Auch hier geben wir dem Stack einen Namen.</p><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-stack-name_hu_17ddc63e74a44c9c.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-stack-name_hu_b7df9c89a3db2755.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-cp-stack-name_hu_17ddc63e74a44c9c.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Portainer CP Stack Name" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="62"/><p><img src="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-github-config_hu_7cf882ee6c5132c9.webp" srcset="/portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-github-config_hu_8adfb2adbdffbfbc.webp 384w, /portainer-tutorial-fuer-version-2-x/images/portainer-tutorial-github-config_hu_7cf882ee6c5132c9.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Portainer GitHub config" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="461">
Natürlich kann hier jede Art von git-Repository verwendet werden. GitHub ist nur das prominenteste Beispiel der Cloud Anbieter für git-Repositories.</p><p>Als Repository-URL gibst du den Standardpfad bzw. URL des Repos ein. Das ist meist die Startseite. Die „Repository reference“ kannst du leer lassen, denn diese nimmt immer die Dateien aus dem Master Branch. Wenn du das nicht möchtest, weißt du sicherlich selbst, was du hier einzutragen hast.</p><p>Der „Compose path“ ist im Standard nur eine einfach „docker-compose.yml“-Angabe. Ich habe für dieses Beispiel eine Anwendung aus meiner Sammlung genommen und muss entsprechend den Pfad dorthin genau angeben.</p><p>Auch hier müssen wir anschließend nur auf „Deploy the Stack“ unten klicken und schon wird die compose-Datei aus dem Repo geklont und die Anwendung deployt.</p><h2 id="fazit">Fazit<a href="#fazit" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Portainer erweist sich als unverzichtbares Tool für jeden, der mit Docker arbeitet, egal ob Anfänger oder erfahrener Profi. Durch seine benutzerfreundliche grafische Oberfläche wird die Verwaltung von Containern, Images und Netzwerken erheblich vereinfacht, ohne dabei auf Flexibilität und Funktionsvielfalt zu verzichten. Besonders vorteilhaft ist, dass Portainer nicht nur für kleinere Umgebungen, sondern auch in größeren, produktiven Setups problemlos einsetzbar ist. Es hilft, komplexe Docker-Architekturen übersichtlich zu strukturieren und bietet umfassende Verwaltungs- und Überwachungsmöglichkeiten, die weit über das hinausgehen, was die Kommandozeile bietet.</p><p>In diesem Tutorial haben wir die Grundlagen von Portainer beleuchtet – von der Installation über die wichtigsten Funktionen bis hin zu praktischen Anwendungsszenarien. Damit solltest du nun bestens gerüstet sein, Portainer in deinem eigenen Docker-Setup erfolgreich einzusetzen und deine Workflows effizienter zu gestalten.</p><p>Abschließend lässt sich sagen, dass Portainer nicht nur Zeit und Mühe spart, sondern auch dazu beiträgt, die Container-Verwaltung sicherer und kontrollierter zu gestalten. Wer Docker nutzt, sollte Portainer als Ergänzung auf jeden Fall in Betracht ziehen, um das Beste aus seiner Container-Umgebung herauszuholen.</p>
]]></content:encoded><category>selfhosted</category><category>portainer</category><category>docker</category></item><item><title>Traefik letsencrypt Tutorial</title><link>https://www.teqqy.de/traefik-letsencrypt-tutorial/</link><pubDate>Tue, 01 Feb 2022 22:49:13 +0100</pubDate><lastBuildDate>Tue, 01 Feb 2022 22:49:13 +0100</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/traefik-letsencrypt-tutorial/</guid><description>Mit diesem Traefik letsencrypt Tutorial möchte ich dir helfen einfach und sauber Zertifikate via freier CA Let’s Encrypt zu beantragen und zu verwalten. In diesem Tutorial gehe ich auf die Punkte http-challenge, dns-challenge sowie weiteres Zertifikatsmanagement ein. Sollte Dir ein Punkt fehlen, schreibe mir dazu gerne in Kommentare.
Solltest Du auf dieses Tutorial gestoßen sein, weil du Docker nutzt, kann ich dir meine docker-compose Sammlung auf GitHub (externer Link) sehr ans Herz legen. Dort sind gerade für das Thema Homelab sehr viele Softwareprodukte hinterlegt die eine direkte Traefik (externer Link) Anbindung realisieren. Sicherlich ist auch meine Traefik Konfiguration ein guter Startpunkt für ein gutes Gelingen.</description><content:encoded>&lt;![CDATA[<p>Mit diesem Traefik letsencrypt Tutorial möchte ich dir helfen einfach und sauber Zertifikate via freier CA Let’s Encrypt zu beantragen und zu verwalten. In diesem Tutorial gehe ich auf die Punkte http-challenge, dns-challenge sowie weiteres Zertifikatsmanagement ein. Sollte Dir ein Punkt fehlen, schreibe mir dazu gerne in Kommentare.</p><p>Solltest Du auf dieses Tutorial gestoßen sein, weil du Docker nutzt, kann ich dir meine<a href="https://github.com/cbirkenbeul/docker-homelab" target="_blank" rel="noopener noreferrer">docker-compose Sammlung auf GitHub<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
sehr ans Herz legen. Dort sind gerade für das Thema<a href="/mein-homelab-dashboard-2022/">Homelab</a>
sehr viele Softwareprodukte hinterlegt die eine direkte<a href="https://traefik.io" target="_blank" rel="noopener noreferrer">Traefik<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Anbindung realisieren. Sicherlich ist auch meine Traefik Konfiguration ein guter Startpunkt für ein gutes Gelingen.</p><p><img src="https://teqqy.de/wp-content/uploads/2021/04/traefik-architecture.webp" alt="Traefik letsencrypt tutorial" loading="eager" fetchpriority="high" decoding="async"/><h2 id="traefik-grundkonfiguration">Traefik Grundkonfiguration<a href="#traefik-grundkonfiguration" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Traefik lässt sich über mehrere Wege konfigurieren. Hierbei spielt es keine Rolle ob man sämtliche Befehle und Konfigurationen direkt in die docker-compose Datei oder in separate Dateien packt. Ich für meinen Teil verwende dedizierte um eine einfachere und übersichtliche Konfiguration zu haben. Solltest du einen anderen Weg bevorzugen ist dies für dieses Traefik<a href="https://letsencrypt.org/de/" target="_blank" rel="noopener noreferrer">letsencrypt<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Tutorial nicht wichtig. Du musst natürlich nur die Einstellungen adaptieren.</p><p>Das ist ist meine Docker Compose Beispielkonfiguration welche ich normalerweise einsetze. Je nach Umgebung kann diese aber natürlich ein wenig variieren. Ich gebe auch immer http3 mit aus, einfach weil ich es mag neue Standard direkt mit zu implentieren.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">traefik:v3</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">traefik</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/localtime:/etc/localtime:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/timezone:/etc/timezone:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/run/docker.sock:/var/run/docker.sock</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/log/auth.log:/var/log/auth.log:ro</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/log/traefik:/var/log/traefik</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">./config:/etc/traefik</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">traefik_proxy</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">default</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ports</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#7ee787">target</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">80</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">published</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">80</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">protocol</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">tcp</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">mode</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">host</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#7ee787">target</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">published</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">protocol</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">tcp</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">mode</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">host</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#7ee787">target</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">published</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">protocol</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">udp</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">mode</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">host</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">unless-stopped</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik_proxy</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">external</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">driver</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">bridge</span></span></span></code></pre></div></div><p>Anschließend brauchen wir natürlich noch die zwei Dateien die wir oben als Volume angegeben haben. Starten wir mit der<code>traefik.yaml</code> Diese beinhaltet alle notwenigen Eigenschaften um<a href="/interne-namensaufloesung-bei-docker-mit-traefik/">Traefik</a>
sauber ans laufen zu bekommen.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">log</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">level</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"INFO"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">filePath</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"/var/log/traefik/traefik.log"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">accessLog</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">filePath</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"/var/log/traefik/access.log"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">bufferingSize</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">100</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">providers</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">docker</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">endpoint</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"unix:///var/run/docker.sock"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">exposedByDefault</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">false</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">network</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"traefik_proxy"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">file</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">filename</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"/etc/traefik/dynamic.yml"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">watch</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">api</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">dashboard</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">false</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">entryPoints</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ping</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">address</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">':88'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">web</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">address</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">':80'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">http</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">redirections</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">entryPoint</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">to</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">websecure</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">scheme</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">https</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">websecure</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">address</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">':443'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">http3</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">proxyProtocol</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">trustedIPs</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">10.0.0.0</span><span style="color:#a5d6ff">/8</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">172.16.0.0</span><span style="color:#a5d6ff">/12</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">192.168.0.0</span><span style="color:#a5d6ff">/16</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">forwardedHeaders</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">trustedIPs</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">10.0.0.0</span><span style="color:#a5d6ff">/8</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">172.16.0.0</span><span style="color:#a5d6ff">/12</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">192.168.0.0</span><span style="color:#a5d6ff">/16</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">certificatesResolvers</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">acme</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">email</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"deine@email-adresse.example"</span><span style="color:#6e7681"/><span style="color:#8b949e;font-style:italic">#Email Adresse hier anpassen</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">storage</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"/etc/traefik/ACME/acme.json"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">httpChallenge</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">entryPoint</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">web</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">tls_resolver</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">acme</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">email</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"deine@email-adresse.example"</span><span style="color:#6e7681"/><span style="color:#8b949e;font-style:italic">#Email Adresse hier anpassen</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">storage</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"/etc/traefik/ACME/acme.json"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">tlsChallenge</span>:<span style="color:#6e7681"/>{}</span></span></code></pre></div></div><p>Gehen wir die Punkt einmal durch:</p><h3 id="log">[log]<a href="#log" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Das Loglevel sollte für den produktiven Betrieb so gewählt werden, dass nach Möglichkeit nicht die Festplatte voll läuft. Für den Beginn ist es evtl. ratsam hier auf<strong>DEBUG</strong> umzustellen um mehr zu sehen und um Fehler leichter erkennen zu können.</p><h3 id="providers">[providers]<a href="#providers" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Wir nutzen für diese Beispielkonfiguration Docker. Wir möchten allerdings nicht, dass grundsätzlich alle<a href="/docker-befehle-fuer-den-alltag/">Docker</a>
Container via Traefik veröffentlicht werden (exposedByDefault = false) und setzen die jeweiligen Anpassungen für jeden Container dediziert. Traefik lassen wir auf den Docker Socket hören um zu wissen was Traefik so machen muss. Gegebenenfalls musst du den Parameter „network“ anpassen. Ich nutze hierfür immer „traefik_proxy“ als Netzwerk. Möchtest du das ebenfalls nutzen musst du</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker network create traefik_proxy</span></span></code></pre></div></div><p>ausführen und das Netzwerk anzulegen.</p><h3 id="api">[api]<a href="#api" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Das Dashboard brauchen wir hierfür nicht, wird also deaktiviert</p><h3 id="entrypoints">[entryPoints]<a href="#entrypoints" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Die entryPoints sind die Ports und Protokolle auf die Traefik hört. Stand jetzt kann Traefik nur HTTP/HTTPS Traffic. Weitere Protokolle sollen in Zukunft kommen. Wir lauschen natürlich auch auf Port 80 (HTTP) und machen eine direkte Weiterleitung auf Port 443 (HTTPS). Unverschlüsselte Kommunikation sollte nur in Ausnahmefällen noch erlaubt sein.</p><p>Wie du siehst binden wir auch eine dynamic.yml Datei ein. Diese hat folgenden Aufbau</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">tls</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">options</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">minVersion</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">VersionTLS12</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">cipherSuites</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">TLS_AES_128_GCM_SHA256</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">TLS_AES_256_GCM_SHA384</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">TLS_CHACHA20_POLY1305_SHA256</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">curvePreferences</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">CurveP521</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">CurveP384</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">sniStrict</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">http</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">middlewares</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">chain</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">middlewares</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">default-security-headers</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">gzip</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default-security-headers</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">headers</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">browserXssFilter</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">contentTypeNosniff</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">forceSTSHeader</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">frameDeny</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">stsIncludeSubdomains</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">stsPreload</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">stsSeconds</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">31536000</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">customFrameOptionsValue</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"SAMEORIGIN"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">gzip</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">compress</span>:<span style="color:#6e7681"/>{}</span></span></code></pre></div></div><p>Die dynamic.yml ist zur Konfiguration aller Sicherheitsmerkmale gedacht. Bitte passe diese nach den aktuellen Gegebenheiten an, da sich gerade die Cipher Suites häufig ändern können! Die restlichen Werte sind nach langjähriger Erfahrung von mir so zusammen getragen und müssen nicht dem aktuellen Sicherheitsstandards entsprechend. Für Tipps bin ich aber dankbar und passe die Datei dann gerne an.</p><h2 id="traefik-letsencrypt-tlschallenge">Traefik letsencrypt tlsChallenge<a href="#traefik-letsencrypt-tlschallenge" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Mit der tlsChallange ist es wahrscheinlich die einfachste Variante Zertifikate via Let’s encrypt zu beantragen. Hier kann Traefik direkt so konfiguriert, bzw. über die Docker Konfiguration so eingerichtet werden, dass nur Port 443, also HTTPS, veröffentlicht werden muss. Möchte man nur ein paar wenige Zertifikate beantragen ist das meiner Meinung die empfehlenswerte Version.</p><p>Die Konfiguration der tlsChallenge ist ziemlich einfach. Man fügt in der traefik.toml Datei folgende Zeilen am Ende ein:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#7ee787">certificatesResolvers</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">acme</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">email</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"deine@email-adresse.example"</span><span style="color:#6e7681"/><span style="color:#8b949e;font-style:italic">#Email Adresse hier anpassen</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">storage</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"/etc/traefik/ACME/acme.json"</span></span></span></code></pre></div></div><p>Email-Adresse ist für die Benachrichtigung von Let’s encrypt an dich gedacht. Entsprechend empfehle ich hier eine valide Email-Adresse anzugeben. Die Storage Angabe ist der Speicherort der Zertifikate. Entsprechend muss in der Docker Konfiguration auch das beachtet werden.</p><h2 id="traefik-letsencrypt-httpchallenge">Traefik letsencrypt httpChallenge<a href="#traefik-letsencrypt-httpchallenge" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Die httpChallenge ist quasi das gleich wie die tlsChallenge, allerdings via Port 80 anstatt 443. Hier muss als in der Docker Konfiguration auch Port 80 veröffentlicht werden. So ergibt sich daraus folgender Inhalt für die traefik.toml:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#7ee787">certificatesResolvers</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">acme</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">email</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"deine@email-adresse.example"</span><span style="color:#6e7681"/><span style="color:#8b949e;font-style:italic">#Email Adresse hier anpassen</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">storage</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"/etc/traefik/ACME/acme.json"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">httpChallenge</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">entryPoint</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">web</span></span></span></code></pre></div></div><h2 id="traefik-letsencrypt-dnschallenge-am-beispiel-cloudflare">Traefik letsencrypt dnsChallenge (am Beispiel Cloudflare)<a href="#traefik-letsencrypt-dnschallenge-am-beispiel-cloudflare" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Die dnsChallenge ist quasi die Königsdisziplin. Allerdings nur wirklich dann sinnvoll wenn man z. B. Wildcard Zertifikate benötig oder wenn man viele Subdomainzertifikate benötigt. Entsprechend muss man hier auch ein wenig mehr konfigurieren und vor allen Dingen benötigt man einen DNS Provider der von Let’s encrypt unterstützt wird. Ich empfehle hier Cloudflare.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#7ee787">certificatesResolvers</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">acme</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">email</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"mail@teqqy.de"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">storage</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"/etc/traefik/ACME/acme.json"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">dnsChallenge</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">provider</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"cloudflare"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">resolvers</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"1.1.1.1:53"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"1.0.0.1:53"</span></span></span></code></pre></div></div><p>Hinzu kommt, dass wir in der<code>docker-compose.yaml</code> noch den API Token für die Cloudflare API hinzufügen. Dazu einfach noch folgende Zeilen einfügen:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">CF_DNS_API_TOKEN</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">"{STRENGGEHEIMERAPIKEY}"</span></span></span></code></pre></div></div><p><img src="/traefik-letsencrypt-tutorial/images/traefik-letsencrypt-cloudflare-api-key_hu_258edc5025bb9e7.webp" srcset="/traefik-letsencrypt-tutorial/images/traefik-letsencrypt-cloudflare-api-key_hu_8da039c58f354eb1.webp 384w, /traefik-letsencrypt-tutorial/images/traefik-letsencrypt-cloudflare-api-key_hu_258edc5025bb9e7.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Screenshot Cloudflare API Key Übersicht" loading="lazy" fetchpriority="auto" decoding="async" width="768" height="396"/><h2 id="zertifikate-löschen">Zertifikate löschen<a href="#zertifikate-l%c3%b6schen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Zertifikate werden in der<strong>acme.json</strong> Datei gespeichert und könnten dort heraus gelöscht werden. Zu jedem Zertifikat gibt es eine<strong>certificate</strong> und<strong>key</strong> Definition. Man kann also die Datei entsprechend editieren und die Zeichenketten entsprechend heraus löschen.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">json</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="json"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-json" data-lang="json"><span style="display:flex;"><span> {</span></span><span style="display:flex;"><span><span style="color:#7ee787">"domain"</span>: {</span></span><span style="display:flex;"><span><span style="color:#7ee787">"main"</span>:<span style="color:#a5d6ff">"teqqy.de"</span>,</span></span><span style="display:flex;"><span><span style="color:#7ee787">"sans"</span>: [</span></span><span style="display:flex;"><span><span style="color:#a5d6ff">"www.teqqy.de"</span></span></span><span style="display:flex;"><span> ]</span></span><span style="display:flex;"><span> },</span></span><span style="display:flex;"><span><span style="color:#7ee787">"certificate"</span>:<span style="color:#a5d6ff">"&lt;Zeichenkette&gt;"</span>,</span></span><span style="display:flex;"><span><span style="color:#7ee787">"key"</span>:<span style="color:#a5d6ff">"&lt;Zeichenkette&gt;"</span>,</span></span><span style="display:flex;"><span><span style="color:#7ee787">"Store"</span>:<span style="color:#a5d6ff">"default"</span></span></span><span style="display:flex;"><span> }<span style="color:#f85149">,</span></span></span></code></pre></div></div><p>Notwendig ist dies aber nur dann, wenn bei der Erstellung ein Fehler aufgetreten ist oder Let’s Encrypt Zertifikate wg. Fehlern zurückruft. Andernfalls laufen die Zertifikate automatisch nach 90 Tagen ab. Ein manuelles Aufräumen ist nicht notwendig.</p>
]]></content:encoded><category>selfhosted</category><category>traefik</category><category>ssl-tls</category><category>docker</category><category>cloudflare</category></item><item><title>Meine Top 10 Homelab Services 2021</title><link>https://www.teqqy.de/2021-11-meine-top-10-homelab-services/</link><pubDate>Thu, 18 Nov 2021 22:36:14 +0100</pubDate><lastBuildDate>Thu, 18 Nov 2021 22:36:14 +0100</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/2021-11-meine-top-10-homelab-services/</guid><description>Viele Menschen starten ihr Homelab mit ein oder zwei Programmen auf einem kleinen Rechner. Langsam aber sicher wird dieses dann ausgebaut und im Laufe der Zeit erweitert. Geht man weg von einem Raspberry Pi (externer Link) und wechselt zum Beispiel auf einen Intel NUC hat man viel Freiraum für neue Services.</description><content:encoded>&lt;![CDATA[<p>Viele Menschen starten ihr Homelab mit ein oder zwei Programmen auf einem kleinen Rechner. Langsam aber sicher wird dieses dann ausgebaut und im Laufe der Zeit erweitert. Geht man weg von einem<a href="https://www.amazon.de/shop/teqqyde/list/3JR8DIQ92BDIQ?ref_=aip_sf_list_spv_ons_mixed_d" target="_blank" rel="noopener noreferrer">Raspberry Pi<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
und wechselt zum Beispiel auf einen Intel NUC hat man viel Freiraum für neue Services.</p><p>Genau aus diesem Grund möchte ich dir als Anregung meine Top 10 Homelab Services aufzählen. Vielleicht ist ja noch ein wenig Inspiration für dich mit dabei.</p><p>Bevor du dein Homelab startest solltest du dir erst einmal Gedanken machen auf welcher Hardware du deine Dienste installieren möchtest. Am einfachsten startet man mit alter, vorhandener Hardware. Solltest du etwas stromspurenderes benötigten kann man mit einem<a href="https://www.amazon.de/shop/teqqyde/list/3JR8DIQ92BDIQ?ref_=aip_sf_list_spv_ons_mixed_d" target="_blank" rel="noopener noreferrer">Raspberry Pi<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
starten. Auf Amazon gibt es diverse Sets die direkt alles in einem liefern. Das ist zwar etwas teurer, dafür musst du dich nicht um Einzelteile kümmern.</p><p>Eine Alternative die natürlich mehr Power haben, sind Intel NUCs. Diese sehr beliebten Minirechner sind von kleinen stromsparenden CPUs bis hin zu einem potenten Core i7! Wer direkt viel Freiraum haben, langfristig plant und dennoch wenig für Strom ausgaben möchte ist damit wohl am besten bedient.</p><h2 id="meine-top-10-homelab-services">Meine Top 10 Homelab Services<a href="#meine-top-10-homelab-services" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Natürlich sind diese Softwareprodukte in eine Reihenfolge gebracht worden. Allerdings ist es manchmal schwer diese auch dauerhaft so zu verargumentieren. Die Reihenfolge ändert sich natürlich immer ein wenig. Aber die Produkte an sich bleiben doch meist gleich. Also los gehts:</p><h2 id="10--freshrss">10 – FreshRSS<a href="#10--freshrss" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p><a href="https://freshrss.org/" target="_blank" rel="noopener noreferrer">FreshRSS<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
ist wie der Name schon verrät ein RSS Reader. Eigentlich ja nichts Besonderes zumal es ja viele Cloud-Dienste wie z. B. Feedly gibt, die genau das gleiche machen. Wir wären aber nicht im Homelab, wenn wir nicht versuchen würden, möglichst viele Dienste selbst bereitzustellen.</p><p>Mit FreshRSS kannst du über den Browser den RSS Feed deiner Lieblingsblogs und -webseiten lesen. Hoffentlich auch den von teqqy.de 😉</p><p>Ich nutze als mobilen Client unter iOS zudem noch<a href="https://reederapp.com/" target="_blank" rel="noopener noreferrer">Reeder<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
. Diese App hat eine direkte Integration für FreshRSS und macht so das Setup total einfach.</p><p><a href="https://paperless-ng.readthedocs.io/en/latest/" target="_blank" rel="noopener noreferrer">Paperless-NG<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
ist ein DMS (Document Management System) und der Nachfolger des leider nicht mehr weiter entwickelten paperless. Viele Tutorials da draußen funktionieren auch weiterhin mit paperless-ng. Ein DMS hilft dir deinen Papierkram digital zu strukturieren und im Falle des Falles schnell wieder zu finden.</p><p>Im Laufe der Zeit habe ich verschiedene andere DMS Systeme ausprobiert. Das ebenfalls kostenfreie papermerge sowie das kostenpflichtige ecoDMS, um nur zwei der gefühlt unendlich langen Liste zu nennen.</p><h2 id="8--hajimari">8 – Hajimari<a href="#8--hajimari" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Davon wirst du bestimmt noch nichts gehört haben. Macht nichts, dafür bin ich ja da. Hajimari ist ein<a href="/mein-homelab-dashboard-2022/">Dashboard</a>
. Aber im Gegensatz zu Dashboards wie Heimdall ist dies rein auf die Installation in einem Kubernetes Cluster spezialisiert. Hajimari verwendet die Ingress API, um automatisch die Anwendungen im Cluster darzustellen.</p><p><img src="/2021-11-meine-top-10-homelab-services/images/hajimari-dashboard_hu_34549619344423c0.webp" srcset="/2021-11-meine-top-10-homelab-services/images/hajimari-dashboard_hu_7dedb9a1477b8e4c.webp 384w, /2021-11-meine-top-10-homelab-services/images/hajimari-dashboard_hu_34549619344423c0.webp 768w, /2021-11-meine-top-10-homelab-services/images/hajimari-dashboard_hu_23f50bf03cff60c3.webp 1536w" sizes="(max-width: 768px) 100vw, 768px" alt="Meine Top 10 Homelab Services im Dashboard vereint" loading="eager" fetchpriority="high" decoding="async" width="768" height="433">
Zudem kann es noch mit weiteren Links zu Lieblingsseiten erweitert werden. Falls du kein Kubernetes einsetzt, empfehle ich dir Heimdall oder Organizr mal anzugucken. Zu beiden gibt es sogar auch ein Video auf meinem<a href="https://www.youtube.com/channel/UCnBQ7GosWO57aTpm2wR7Q7Q" target="_blank" rel="noopener noreferrer">YouTube<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Kanal.</p><h2 id="7--littlelink">7 – Littlelink<a href="#7--littlelink" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Sicherlich auch ein Service von dem du noch nichts gehört hast.<a href="https://littlelink.io/" target="_blank" rel="noopener noreferrer">Littlelink<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
ist eine Alternative zu Linktree, einer Onlineplattform um Links zu verschiedenen Webseiten zusammen zu fassen. Wenn du viel in sozialen Netzwerken unterwegs bist, hast du das sicherlich schon mal gesehen.</p><p>Littlelink wurde von dem YouTuber TechnoTim (<a href="https://youtube.com/c/TechnoTimLive" target="_blank" rel="noopener noreferrer">Folgeempfehlung<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
) erstellt und kann natürlich auch via Docker installiert werden. Ein Beispiel kannst du dir bei<a href="https://links.teqqy.social" target="_blank" rel="noopener noreferrer">mir<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
anschauen.</p><h2 id="6--grafana">6 – Grafana<a href="#6--grafana" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Im Laufe der Zeit sammeln sich verschiedene Metriken, Performance- und Statistikdaten im Homelab an. Sei es durch das Monitoring, die Heim-Automatisation oder einfach nur weil die intelligenten Steckdosen den Strom sauber messen sollen. Grafana ist hierbei eines der, wenn nicht das beste Tool, um diese Daten zu visualisieren. Einen guten Einsteig in Grafana habe auch als kleine<a href="https://youtube.com/playlist?list=PL5Zq2RTMFBNPGdmPbYHVrOA9l1urFlOrV" target="_blank" rel="noopener noreferrer">Tutorialserie<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
auf YouTube veröffentlicht. Vielleicht ist das ja noch was für dich.</p><h2 id="5--authentik">5 – Authentik<a href="#5--authentik" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Bereits vor kurzem hatte ich einen Blogartikel veröffentlicht, wie man Proxmox an Authentik anbinden kann. Aber was ist Authentik eigentlich? Mit dieser Software kannst du eine zentrale Nutzerverwaltung für deine Homelab Dienste bereitstellen. So musst du nicht in jeder Anwendung einzelne Benutzeraccounts pflegen.</p><p>Das besondere an Authentik ist, dass es die Benutzer auch nicht selbst pflegen muss, sondern z. B. von GitHub, Google oder LDAP heranziehen kann. Dir stehen damit also viele Möglichkeiten offen.</p><p>Ich versuche mittlerweile, jede Software, die eine Schnittstelle zu OpenID, oAuth oder LDAP hat, mit Authentik bekannt zu machen, um mir die Pflege der Nutzeraccounts zu vereinfachen.</p><h2 id="4--proxmox">4 – Proxmox<a href="#4--proxmox" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Proxmox? Ja Proxmox. Eine gute Virtualisierungsplattform zu haben, ist für das Homelab äußerst praktisch. Es lassen sich schnell und einfach neue System hoch ziehen und neue Software und Tools ausprobieren. Die Möglichkeit neue Dinge zu lernen kann somit schier unendlich sein.</p><p>{% youtube Io7oOnmhpZs %}</p><h2 id="3--jellyfin">3 – Jellyfin<a href="#3--jellyfin" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Ich ware viele Jahre Plex Nutzer. Plex ist ein Netzwerkmediaplayer, um Filme, Serien oder Musik im Netzwerk zu streamen. Da die coolen Funktionen in Plex nur mit einem Plex Pass zu haben sind, welcher gebührenpflichtig ist, ist das für viele ein kleines Hindernis.</p><p>Weitere Platzhirsche sind noch Kodi und Emby. Kodi hat für mich persönlich den Nachteil, dass die ganze Intelligenz in Client am TV hängt, heißt der muss entsprechend die Power haben. Bei den anderen wird mögliche Transcodierleistung vom Server erwartet.</p><p>Zu<a href="https://jellyfin.org/" target="_blank" rel="noopener noreferrer">Jellyfin<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
bin ich vor kurzem gewechselt, weil ich etwas neues ausprobieren wollte – und bin dort hängen geblieben. Es ist einfach eine richtig gute Software.</p><h2 id="2--blocky">2 – blocky<a href="#2--blocky" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Von dieser Software hast du sicherlich auch noch nichts gehört. PiHole oder AdGuard Home allerdings schon.<a href="https://github.com/0xERR0R/blocky" target="_blank" rel="noopener noreferrer">Blocky<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
ist eine weitere Alternative dazu. Ich setze eben diese ein, weil sie perfekt für einen Kubernetes Cluster gemacht ist: Leichtgewichtig, komplett via deployment zu konfigurieren und stabil.</p><p>Wer den Werbeblocker nicht in einem Containercluster bereit stellt, dem ist weiterhin aus meiner Sicht eher AdGuard als PiHole zu empfehlen. Ich verfolge zwar die Entwicklung von PiHole nicht mehr aktiv, war aber mit AdGuard einfach immer zufriedener.</p><h2 id="1--home-assistant">1 – Home-Assistant<a href="#1--home-assistant" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Sicherlich eine der wenigen Software in der Liste, die du auf jeden Fall kennst. Home-Assistant ist meine Software, um meine komplette Heimautomatisation zu steuern. Von smarten Glühbirnen über Tür- und Fenstersensoren, Luftbefeuchter bis hin zu Staubsaugern und vielem mehr wird hierüber durch verschiedene Automatisierungen gesteuert. Meine Konfiguration findet du dazu übrigens auch auf<a href="https://github.com/cbirkenbeul/homeassistant-config" target="_blank" rel="noopener noreferrer">GitHub<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
.</p><p>Home-Assistant nutze ich, seit dem ich vor ca. 4 Jahren von FHEM dorthin gewechselt bin. Mit FHEM wurde ich irgendwie nie wirklich warm und openHAB2… nunja… Es ist Java…</p><h2 id="sonstiges">Sonstiges<a href="#sonstiges" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Sicherlich vermisst du Dienste wie Passwortmanager oder Codeverwaltung? Das liegt daran, dass beide Services so wichtig sind, dass ich im Homelab nicht die notwendige Uptime dafür bereitstellen kann und möchte. Zwar gehört auch immer ein gewisses Stück Vertrauen in die Software, allerdings haben mich 1Password als Passwortmanager und GitHub als Codeverwaltung noch nie enttäuscht.</p><p>Zwischenzeitlich hatte ich beide Services sogar mal selbst gehostet, aber auf Grund der eben angesprochenen Problematik dann doch wieder einem Cloud-Service überlassen.</p>
]]></content:encoded><category>selfhosted</category><category>homelab</category><category>docker</category><category>kubernetes</category><category>home-assistant</category></item><item><title>Traefik Troubleshooting Guide</title><link>https://www.teqqy.de/traefik-troubleshooting-guide/</link><pubDate>Wed, 07 Apr 2021 15:29:13 +0200</pubDate><lastBuildDate>Wed, 07 Apr 2021 15:29:13 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/traefik-troubleshooting-guide/</guid><description>In allen meiner Tutorials verwende ich Traefik als Reverse Proxy für Docker Container, so natürlich auch auf meinem YouTube Kanal (externer Link) . Im Laufe der Zeit fragen immer wieder Leser und Zuschauer ob ich ihnen bei ihrem Problem helfen kann. Dies mache ich natürlich gerne. Für ein gewisse Selbsthilfe möchte ich dir allerdings diesen Traefik Troubleshooting Guide an die Hand geben.</description><content:encoded>&lt;![CDATA[<p>In allen meiner Tutorials verwende ich Traefik als<a href="/reverse-proxy-mit-traefik-unter-docker/">Reverse Proxy</a>
für Docker Container, so natürlich auch auf meinem<a href="http://youtube.com/teqqyde" target="_blank" rel="noopener noreferrer">YouTube Kanal<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
. Im Laufe der Zeit fragen immer wieder Leser und Zuschauer ob ich ihnen bei ihrem Problem helfen kann. Dies mache ich natürlich gerne. Für ein gewisse Selbsthilfe möchte ich dir allerdings diesen Traefik Troubleshooting Guide an die Hand geben.</p><h2 id="vorbereitende-maßnahmen">Vorbereitende Maßnahmen<a href="#vorbereitende-ma%c3%9fnahmen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Um mit einem guten Troubeshooting zu beginnen möchte ich zwei Maßnahmen vorweg greifen. Diese helfen dir ein paar Dinge auszuschließen bzw. eventuell schnell selbst auf eine Lösung zu kommen.</p><p><img src="/traefik-troubleshooting-guide/images/traefik-troubleshooting_hu_c55681aa534d7e0e.webp" srcset="/traefik-troubleshooting-guide/images/traefik-troubleshooting_hu_4c9f0ac2d543e280.webp 384w, /traefik-troubleshooting-guide/images/traefik-troubleshooting_hu_c55681aa534d7e0e.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Traefik Troubleshooting" loading="eager" fetchpriority="high" decoding="async" width="768" height="509"/><h2 id="container-richtig-neu-starten">Container richtig neu starten<a href="#container-richtig-neu-starten" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Wenn ihr Änderungen am Container von Traefik oder gar an den Konfigurationsdateien vornimmt, muss Traefik komplett neu gestartet werden. Ein stoppen des jeweiligen ist nicht ausreichend. Bei<a href="https://github.com/cbirkenbeul/docker-homelab" target="_blank" rel="noopener noreferrer">meinen Compose Dateien<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
verwende also bitte nach dem stoppen noch ein</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker-compose rm</span></span></code></pre></div></div><p>um diesen komplett zu löschen. Anschließend kannst du den Container wieder starten und eine neue Konfiguration ist übernommen.</p><h2 id="erhöhen-des-log-levels">Erhöhen des Log Levels<a href="#erh%c3%b6hen-des-log-levels" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Zum Traefik Troubleshooting gehört auf jeden Fall auch das betrachten der Log Dateien. In meiner Vorlage steht das Logging auf einer sehr kleinen Stufe um nicht unnötig Speicherplatz zu benötigen. Wenn du mit Traefik startest empfehle ich dir, dieses auf debug zu stellen.</p><p>Hierzu einfach die traefik.toml Datei anpassen:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">conf</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="conf"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code class="language-conf" data-lang="conf">[log]
level = "DEBUG"</code></pre></div><h2 id="fehlerlösungen">Fehlerlösungen<a href="#fehlerl%c3%b6sungen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><h3 id="die-webseite-wird-als-nicht-sicher-angezeigt">Die Webseite wird als nicht sicher angezeigt<a href="#die-webseite-wird-als-nicht-sicher-angezeigt" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Dieser Fehler entsteht zumeist wenn Traefik kein<a href="https://letsencrypt.org" target="_blank" rel="noopener noreferrer">Let’s Encrypt<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Zertifikat abrufen konnte. Leider kann das mehrere Ursachen haben:</p><h3 id="zu-häufiges-abrufen-von-zertifikaten">Zu häufiges Abrufen von Zertifikaten<a href="#zu-h%c3%a4ufiges-abrufen-von-zertifikaten" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Im Log steht hier meist, dass die Anzahl der Möglichen Erstellversuche von Zertifikaten erreicht ist. LE lässt es nur zu 10 Versuche binnen 24 Stunden auf ein SSL-Zertifikat zu erstellen. Wenn du eine eigene Domain hast, versuche es mit einer anderen Subdomain erneut. Andernfalls hilft nur warten.</p><h3 id="ein-anderer-container-hört-auf-port-80">Ein anderer Container hört auf Port 80<a href="#ein-anderer-container-h%c3%b6rt-auf-port-80" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Let’s Encrypt nutzt bei der ersten Kommunikation zwischen Server und Client auch HTTP (Port 80). Wenn dieser Port also noch durch einen anderen Container geblockt ist kann keine Verbindung aufgebaut werden. Ebenso könnte es sein, dass dein NAT in deinem Router Port 80 noch nicht weiter leitet.</p><h3 id="eine-404-seite-wird-angezeigt">Eine 404-Seite wird angezeigt<a href="#eine-404-seite-wird-angezeigt" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Jetzt wird es spannend. Sobald eine 404-Seite angezeigt wird, gibts nämlich ein Problem mit dem Routing zu den Containern. Folgende Dinge kannst du hier prüfen:</p><ul><li>Wird der korrekte Port weiter geleitet?</li><li>Stimmen alle Middlewere-Configs überein?</li></ul>
]]></content:encoded><category>selfhosted</category><category>traefik</category><category>docker</category><category>ssl-tls</category></item><item><title>WordPress Docker Performance &amp;#8211; Meine 3 Tipps für deinen Erfolg!</title><link>https://www.teqqy.de/wordpress-docker-performance/</link><pubDate>Wed, 30 Sep 2020 13:01:52 +0200</pubDate><lastBuildDate>Wed, 30 Sep 2020 13:01:52 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/wordpress-docker-performance/</guid><description>WordPress ist eine der beliebtesten CMS Systeme. Leider ist die Geschwindigkeit häufig nicht gut. Mit meinen drei Tipps kannst du die WordPress Docker Performance ein gutes Stück verbessern.
Im Internet gibt es nicht wirklich viele Informationen zu dem Problem. Meist wird behauptet, dass es am Hostsystem liegen soll. Da ich das bereits ausschließen konnte wurden viele Beiträge obsolet.
Anfangen sollte man aller erstes aber mit der Messung von harten Zahlen. Eine subjektive Meinung hilft bei der Geschwindigkeit meist wenig. Ob eine Seite schnell oder langsam lädt ist auch ein Rankingfaktor bei Google, also wichtig für das SEO.</description><content:encoded>&lt;![CDATA[<p>WordPress ist eine der beliebtesten CMS Systeme. Leider ist die Geschwindigkeit häufig nicht gut. Mit meinen drei Tipps kannst du die WordPress Docker Performance ein gutes Stück verbessern.</p><p>Im Internet gibt es nicht wirklich viele Informationen zu dem Problem. Meist wird behauptet, dass es am Hostsystem liegen soll. Da ich das bereits ausschließen konnte wurden viele Beiträge obsolet.</p><p>Anfangen sollte man aller erstes aber mit der Messung von harten Zahlen. Eine subjektive Meinung hilft bei der Geschwindigkeit meist wenig. Ob eine Seite schnell oder langsam lädt ist auch ein Rankingfaktor bei Google, also wichtig für das SEO.</p><p>Ich überprüfe die Geschwindigkeit häufig mit<a href="https://pagespeed.web.dev/?hl=DE" target="_blank" rel="noopener noreferrer">Google PageSpeed Insights<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
. Es gibt zwar noch viele weitere Tools um die Ladezeiten einer Webseite zu messen, aber ich habe mich sehr an das Tool gewöhnt. Schlussendlich bleibt es aber dir überlassen, welches du nimmst. Wichtig ist nur, dass du vorher und nachher das die gleiche Software verwendest und damit nicht Äpfel mit Birnen vergleichst.</p><p>In den Tiefen Wurzeln von Google (quasi ab Seite 4) entdeckte ich dann einen Beitrag der darauf hin wies, dass die Verwendung von bind mounts unter<a href="/docker-befehle-fuer-den-alltag/">Docker</a>
häufig zu Performance Problemen führen kann. Gerade bei Webseiten soll, so die Informationen, immer nur eine Datei gleichzeitig geöffnet werden. Das beeinträchtigit die WordPress Docker Performance dann sehr.</p><p>Ich wollte diesen Blog also nicht direkt umstellen, sondern testete erst einmal mit einer neuen Installation und siehe da: Es rannte!</p><p>Entsprechend habe ich in meiner<a href="https://github.com/cbirkenbeul/docker-homelab/tree/master/wordpress" target="_blank" rel="noopener noreferrer">docker-compose.yaml<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Datei ein zweites Volume hinzugefügt und den Stack neu gestartet. Anschließend über die CLI unter Linux die Dateien vom bind mount in das Volume kopiert.</p><p>Docker bietet zwar mit<strong>docker cp</strong> ein eigenen CLI Befehl, allerdings wollte ich das direkt am Linux System machen. Ob das gut ist, wird sich noch raus stellen.</p><p>Mittels</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>cp -R<span style="color:#ff7b72;font-weight:bold">{</span>bind mount pfad<span style="color:#ff7b72;font-weight:bold">}</span>/* /var/lib/docker/volumes/<span style="color:#ff7b72;font-weight:bold">{</span>volume id<span style="color:#ff7b72;font-weight:bold">}</span>/_data/wp-content/chown www-data. -R /var/lib/docker/volumes/<span style="color:#ff7b72;font-weight:bold">{</span>volume id<span style="color:#ff7b72;font-weight:bold">}</span>/_data/</span></span></code></pre></div></div><p>die Daten kopiert und die Rechte angepasst. Nach Neustart des Stacks merke man schon einen deutlichen Performanceboost.</p><h2 id="wordpress-docker-performance-mit-redis-verbessern">WordPress Docker Performance mit Redis verbessern<a href="#wordpress-docker-performance-mit-redis-verbessern" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Anschließend habe ich direkt noch Redis als Cache hinzugefügt. Mit dem<a href="https://de.wordpress.org/plugins/redis-cache/" target="_blank" rel="noopener noreferrer">Plugin Redis Object Cache<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
wird das dann unter WordPress aktiviert. In meiner Compose Datei habe ich natürlich erst noch den Redis Container hinzugefügt:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">wordpress-cache</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">redis:latest</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">teqqyde-cache</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">unless-stopped</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">depends_on</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">wordpress-app</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">default</span></span></span></code></pre></div></div><p>Unter Docker findet das Plugin den Redis Server nicht. Also muss noch die wp-config.php Datei angepasst werden</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>vim /var/lib/docker/volumes/<span style="color:#ff7b72;font-weight:bold">{</span>volume id<span style="color:#ff7b72;font-weight:bold">}</span>/_data/wp-config.php</span></span></code></pre></div></div><p>Dort fügen wir unter den ganzen anderen „define“ Variablen noch die Zeile</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">conf</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="conf"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code class="language-conf" data-lang="conf">define( 'WP_REDIS_HOST', 'wordpress-cache');</code></pre></div><p>hinzu. Nun wieder den Stack komplett neu starten und das Plugin aktivieren. Nach kurzer Zeit gibt es auch bereits die ersten Informationen in den Metriken.</p><p>Sicherlich gibt es noch weitere Punkte um die WordPress Docker Performance zu verbessern, allerdings reicht mir diese erst einmal aus.</p><h2 id="wordpress-docker-performance-messen">WordPress Docker Performance messen<a href="#wordpress-docker-performance-messen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Um nun zu überprüfen ob die Performance gestiegen ist, können wir erneut mit dem Google Page Speed Insights die Webseite messen. In meinem Fall bin ich in fast allen Punkten in kleines Stück besser geworden. Natürlich benötigt man noch weitere Optimierungen, aber für den Anfang ist schon vieles gemacht.</p><p><img src="/wordpress-docker-performance/images/wordpress-docker-performance_hu_e1143e7769fef3c2.webp" srcset="/wordpress-docker-performance/images/wordpress-docker-performance_hu_29245dfbb5cfc7bd.webp 384w, /wordpress-docker-performance/images/wordpress-docker-performance_hu_e1143e7769fef3c2.webp 768w" sizes="(max-width: 768px) 100vw, 768px" alt="Screenshot aus Google Page Speed Insides das die gestiegene WordPress Docker Performance zeigt" loading="eager" fetchpriority="high" decoding="async" width="768" height="372"/>
]]></content:encoded><category>selfhosted</category><category>wordpress</category><category>docker</category></item><item><title>Docker Befehle für den Alltag</title><link>https://www.teqqy.de/docker-befehle-fuer-den-alltag/</link><pubDate>Sun, 20 Sep 2020 13:23:41 +0200</pubDate><lastBuildDate>Sun, 20 Sep 2020 13:23:41 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/docker-befehle-fuer-den-alltag/</guid><description>Um Docker im Alltag zu meisten, ist es ratsam sich ein paar Docker Befehle anzueignen und diese anwenden zu können. Ich möchte dir ein paar meiner alltäglichen Helfer in diesem Beitrag vorstellen.
Docker (externer Link) hat sich in den letzten Jahren immer mehr entwickelt und ist aus vielen Homelabs nicht mehr weg zu denken. Einige recht umfangreiche Infrastrukturen basieren vollständig auf dieser Art der Containerisierung. Im Laufe der Zeit wird man immer mehr zum Profi und kann auch komplexe Probleme schnell löschen. Als Anfänger allerdings steht man häufig vor Problemen.</description><content:encoded>&lt;![CDATA[<p>Um Docker im Alltag zu meisten, ist es ratsam sich ein paar Docker Befehle anzueignen und diese anwenden zu können. Ich möchte dir ein paar meiner alltäglichen Helfer in diesem Beitrag vorstellen.</p><p><a href="https://docker.com" target="_blank" rel="noopener noreferrer">Docker<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
hat sich in den letzten Jahren immer mehr entwickelt und ist aus vielen Homelabs nicht mehr weg zu denken. Einige recht umfangreiche<a href="/proxmox-backup-server/">Infrastrukturen</a>
basieren vollständig auf dieser Art der Containerisierung. Im Laufe der Zeit wird man immer mehr zum Profi und kann auch komplexe Probleme schnell löschen. Als Anfänger allerdings steht man häufig vor Problemen.</p><p><strong>Informationen über Docker Container</strong></p><p>Wir starten mit einem Docker Befehl um die Informationen eines Containers, heißt IP-Adresse, Konfiguration und ähnliche Dinge einsehen zu können.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>docker inspect {container name}</code></pre></div><p><strong>Log des Containers einsehen</strong></p><p>Sollten alle Container immer problemlos laufen, bräuchten wir diesen Beitrag nicht. Aber wir wissen alle, dass das nicht der Fall ist. Um sich die Log Dateien bzw. das STDOUT des Containers anzuschauen gibt es den Befehl</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>docker logs {container name}</code></pre></div><p>Dieser listet alle Loginformationen seit dem letzten Start des Containers auf. Dies kann also schon mal recht lang werden. Einfacher ist es dann den Befehl um ein -f zu erweitern</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>docker logs -f {container name}</code></pre></div><p>Jetzt haben wir die Chance das Logfile dauerhaft anschauen zu können. Sobald der Container also etwas protokolliert, wird dies direkt angezeigt. Mit STRG+C können wir das abbrechen.</p><p><strong>Alle Container stoppen</strong></p><p>Manchmal muss man alle Container auf einmal beenden. Zum Beispiel wenn man Update am Hostsystem einspielen, das Hostsystem kontrolliert herunterfahren oder andere Wartungsarbeiten durchführen möchte.</p><p>Wer mit<a href="/docker-compose-sammlung-fuer-dein-homelab/">Docker Compose</a>
arbeitet und nur eine große Datei hat – davon sei übrigens abzuraten – hat es einfach. Allerdings ist das nur sehr selten der Fall.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>docker stop $(docker ps -a -q)</code></pre></div><p>Der Befehl stoppt alle Container (docker stop) die mit dem Befehl (docker -ps -a -q) gefunden werden. Also alle Container, egal welchen Status diese derzeit haben. Hier werden also Docker Befehle zusammen gefasst um dir das Leben direkt zu erleichtern.</p><p><strong>Alle Container löschen</strong></p><p>Ab und zu ist es auch notwendig alle<a href="/interne-namensaufloesung-bei-docker-mit-traefik/">Docker</a>
Container zu löschen. Zum Beispiel um neue Environment-Variablen einzulesen. Allerdings müssen wir erst alle Container stoppen, z. B. mit dem Befehl weiter oben.</p><p>Anschließend bedienen wir uns einer sehr ähnlichen Technik und löschen alle Container die mit docker ps gefunden werden</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>docker rm $(docker ps -a -q)</code></pre></div><p>Ich hoffe ich konnte dir ein paar nützliche Docker Befehle mit an die Hand geben. Mich würde es noch interessieren, was deine Empfehlung für diese Liste wäre.</p>
]]></content:encoded><category>docker</category><category>homelab</category></item><item><title>Nextcloud Docker Setup - Step by step zum Erfolg</title><link>https://www.teqqy.de/nextcloud-docker-tutorial-step-by-step-zum-erfolg/</link><pubDate>Wed, 15 Apr 2020 10:38:31 +0200</pubDate><lastBuildDate>Wed, 15 Apr 2020 10:38:31 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/nextcloud-docker-tutorial-step-by-step-zum-erfolg/</guid><description>Vor einiger Zeit gab es von mir ein Nextcloud Docker Setup Tutorial bereits auf meinem YouTube Kanal. (externer Link) Dies ist soweit auch weiterhin aktuell. Allerdings bedarf es für eine gute Nextcloud Installation noch weiterer Konfiguration.
Um Nextcloud immer von überall aus erreichen zu können, empfehle ich dir die Installation auf einem virtuellen Server bei einem Hosting Provider. Ich nutze hierfür Netcup, welche ich sehr empfehlen kann.</description><content:encoded>&lt;![CDATA[<p>Vor einiger Zeit gab es von mir ein Nextcloud Docker Setup Tutorial bereits auf meinem<a href="https://youtube.com/teqqyde" target="_blank" rel="noopener noreferrer">YouTube Kanal.<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Dies ist soweit auch weiterhin aktuell. Allerdings bedarf es für eine gute Nextcloud Installation noch weiterer Konfiguration.</p><p>Um Nextcloud immer von überall aus erreichen zu können, empfehle ich dir die Installation auf einem virtuellen Server bei einem Hosting Provider. Ich nutze hierfür Netcup, welche ich sehr empfehlen kann.</p><h2 id="nextcloud-docker-setup-als-video">Nextcloud Docker Setup als Video<a href="#nextcloud-docker-setup-als-video" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Mit diesem Video hast du das Basissetup von Nextcloud. Jetzt werden wir das ganz noch etwas besser einrichten und vor allen Dingen die Warnungen aus dem Administrationsbereich beseitigen.</p><div class="video-embed" data-src="https://www.youtube-nocookie.com/embed/wlZ685wGH34?autoplay=1&rel=0"><button class="video-embed-trigger" type="button" data-umami-event="Video Load" data-umami-event-provider="YouTube" data-umami-event-id="wlZ685wGH34"><svg class="video-embed-play-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true" width="48" height="48"><circle cx="12" cy="12" r="12" fill="rgba(0,0,0,0.6)"/><path d="M9.5 7.5l7 4.5-7 4.5V7.5z" fill="white"/></svg><span class="video-embed-title">YouTube Video</span><span class="video-embed-note">YouTube &middot; Klicken zum Laden</span></button></div><p>Wenn du Nextcloud nicht in deinem Homelab selbst hosten möchtest, empfehle ich dir Netcup als Hostingunternehmen. Meine langjährige Erfahrung mit Netcup hat mit gelehrt das ein zuverlässiger Partner im Bereich Hosting Gold wert ist. Auch wenn das manchmal ein paar Euro im Jahr mehr kostet.</p><h3 id="aktuelle-compose-datei-verwenden">Aktuelle Compose Datei verwenden<a href="#aktuelle-compose-datei-verwenden" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Meine<a href="https://github.com/cbirkenbeul/docker-homelab" target="_blank" rel="noopener noreferrer">Docker Compose Dateien<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
ändern sich zwischendurch. Beachte also bitte, dass du die aktuellen Dateien verwendest. Dieses Tutorial ist für<a href="/traefik-troubleshooting-guide/">Traefik</a>
als reverse proxy ausgelegt. Solltest du etwas anderes nutzen wollen, musst du dir diverse Einstellungen herleiten. Gerade auch die Traefik Konfiguration ändert sich, gerade was die Sicherheitseinstellungen angeht, auch. Bitte updatete daher gegebenenfalls auch diese.</p><h3 id="installation-durchführen">Installation durchführen<a href="#installation-durchf%c3%bchren" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Nun kannst du die Installation, wie im Video beschrieben, durchführen. Ich gehe entsprechend davon aus, dass du jetzt eine funktionsfähige Installation hast.</p><h3 id="reverse-proxy-konfiguration">Reverse Proxy Konfiguration<a href="#reverse-proxy-konfiguration" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Nextcloud möchte, dass wir die notwendigen Einstellungen vornehmen um der Installation die reverse proxy Konfiguration mitzugeben. Als erstes benötigen wir die IP Adresse in<a href="https://de.wikipedia.org/wiki/Classless_Inter-Domain_Routing" target="_blank" rel="noopener noreferrer">CIDR<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Notation unseres Traefik Containers</p><p>~~bash
docker inspect traefik</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>Nun rattern ein paar Zeilen config durchs Bild. Interessant ist für uns eigentlich nur der letzte Abschnitt:</code></pre></div><pre><code> "traefik_proxy": {
"IPAMConfig": null,
"Links": null,
"Aliases": [
"0d9ab883d62e",
"traefik"
],
"NetworkID": "b23ae2baa87df4b02c1cbed4679c8ea3c4ef4d2b8c8d05efb4b0bf0d94ced7f2",
"EndpointID": "44b9f2e00a25177f6084ecfa270df6be9cc75430ed64609ce60897fda8ca67b6",
"Gateway": "172.19.0.1",
"IPAddress": "172.19.0.4",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:13:00:04",
"DriverOpts": null
}</code></pre><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>Diese Informationen sind häufig unterschiedlich. Du solltest also meine Werte nicht einfach blind übernehmen. Aus dem obrigen Teil benötigen wir die Punkte „IPAddress“ und „IPPrefixLen“.
Damit editieren wir nun die config.php Datei unserer Nextcloud Installation und passen diese im Bereich „trused\_proxies“ an. Die Angabe setzt sich also aus IP-Adresse mit anschließender Netzgröße zusammen.</code></pre></div><p>&rsquo;trusted_proxies&rsquo; =&gt; &lsquo;172.19.0.4/16&rsquo;</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>### Datenbank Optimierungen durchführen
Die Übersichtsseite möchte das wir noch ein paar Änderungen in der Datenbank durchführen. Dieses machen wir, indem wir uns mit einem „docker exec“ Befehl kurz in den Container verbinden und den notwendigen Befehl der Nextcloud CLI durchführen. Beide Befehle solltest du nach Möglichkeit vor weiterer Einrichtung und Benutzung von Nextcloud durchführen. Andernfalls können diese Befehle einige Zeit in Anspruch nehmen.
~~~bash
docker exec --user www-data nextcloud-app php occ db:add-missing-indicesdocker exec --user www-data nextcloud-app php occ db:convert-filecache-bigint</code></pre></div><p>Beide Befehle brauchen jeweils einen kurzen Moment. Je nach Leistung deines Servers.</p><h3 id="nextcloud-client-einstellungen-anpassen">Nextcloud Client Einstellungen anpassen<a href="#nextcloud-client-einstellungen-anpassen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Damit wir den Nextcloud Client benutzen können, musste ich noch ein paar weitere Einstellungen an der config.php durchführen. Ändere die Option „overwrite.cli.uri“ ab und füge noch zwei Zeilen hinzu:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code> 'overwrite.cli.url' =&gt; 'https://nextcloud.example.com', 'overwriteprotocol' =&gt; 'https', 'overwritehost' =&gt; 'nextcloud.example.com',</code></pre></div><p>Natürlich musst du die jeweiligen URLs an deine Installation anpassen.</p><h3 id="container-sauber-neu-starten">Container sauber neu starten<a href="#container-sauber-neu-starten" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h3><p>Damit dieses Nextcloud Docker Tutorial auch wirklich funktioniert müssen wir anschließend unsere Container komplett neu starten. Erst einmal beenden wir alles</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker compose stop</span></span></code></pre></div></div><p>und anschließend löschen wir die Container, damit die Konfiguration auch wirklich übernommen wird</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>docker compose rm -f</code></pre></div><p>Jetzt sind wir bereit die Instanz frisch zu starten</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label"/><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang=""><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><pre tabindex="0"><code>docker compose up -d</code></pre></div><p>Unter Einstellungen -&gt; Überblick sollten also keine weiteren Meldungen mehr auftauchen.</p><p>Nun sollte dein Nextcloud Docker Setup hervorragend laufen. Sollte dem nicht so sein, tritt doch meinem<a href="https://s.teqqy.de/discord" target="_blank" rel="noopener noreferrer">Discord Server<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
bei und lass dir von der Community helfen.</p>
]]></content:encoded><category>selfhosted</category><category>nextcloud</category><category>docker</category><category>traefik</category></item><item><title>Interne Namensauflösung bei Docker mit Traefik</title><link>https://www.teqqy.de/interne-namensaufloesung-bei-docker-mit-traefik/</link><pubDate>Thu, 12 Mar 2020 15:01:33 +0100</pubDate><lastBuildDate>Thu, 12 Mar 2020 15:01:33 +0100</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/interne-namensaufloesung-bei-docker-mit-traefik/</guid><description>Traefik nutze ich primär um als reverse proxy von extern auf meine Docker Container zugreifen zu können. Dies natürlich SSL terminiert. Verschiedene Dienste sollen allerdings nicht extern erreichbar sein und benötigen auch – aus meiner Sicht – nicht zwingend eine verschlüsstele Verbindung.
Aus diesem Grund habe ich auf meinem internen Docker Server Traefik als reverse proxy laufen, welcher den verschiedenen Diensten via netzwerkinterner DNS-Auflösung ein DNS Namen verpasst. So kann ich z. B. via http://phpipam.docker.domain.local (externer Link) auf mein PHPIPAM (externer Link) Dienst zugreifen.</description><content:encoded>&lt;![CDATA[<p><a href="/reverse-proxy-mit-traefik-unter-docker/">Traefik</a>
nutze ich primär um als reverse proxy von extern auf meine Docker Container zugreifen zu können. Dies natürlich<a href="/nginx-reverse-proxy-mit-lets-encrypt-und-cloudflare/">SSL</a>
terminiert. Verschiedene Dienste sollen allerdings nicht extern erreichbar sein und benötigen auch – aus meiner Sicht – nicht zwingend eine verschlüsstele Verbindung.</p><p>Aus diesem Grund habe ich auf meinem internen Docker Server<a href="/nginx-reverse-proxy-mit-lets-encrypt-und-cloudflare/">Traefik</a>
als reverse proxy laufen, welcher den verschiedenen Diensten via netzwerkinterner DNS-Auflösung ein DNS Namen verpasst. So kann ich z. B. via<a href="http://phpipam.docker.domain.local" target="_blank" rel="noopener noreferrer">http://phpipam.docker.domain.local<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
auf mein<a href="https://phpipam.net/" target="_blank" rel="noopener noreferrer">PHPIPAM<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Dienst zugreifen.</p><h2 id="voraussetzungen">Voraussetzungen<a href="#voraussetzungen" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><ul><li>Docker Host</li><li>Bereits eingerichtet Services (ich empfehle die Services intern immer erst mal rudimentär zu testen und dann zu erweitern)</li><li>internen DNS Server (ich nutze hier Windows DNS)</li></ul><p>Auf meinem Windows DNS Server lege ich im DNS eine neue primäre Zone mit dem Namen „docker.domain.local“ (entsprechend an deine Bedürfnisse anpassen). Diese erhält dann einen einzigen A-Record der als Wildcard auf den Docker-Host zeigt.</p><h2 id="traefik-einrichten">Traefik einrichten<a href="#traefik-einrichten" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Um Traefik dann nutzen zu können, bediene ich mich zum Teil meiner vorhandenen<a href="https://github.com/cbirkenbeul/docker-homelab" target="_blank" rel="noopener noreferrer">Docker-Compose Sammlung<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
auf<a href="https://www.github.com/cbirkenbeul" target="_blank" rel="noopener noreferrer">Github<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
. Den Traefik Container und die traefik.toml Datei wird dabei ein wenig angepasst.</p><p>traefik.toml:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">toml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="toml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>[log]</span></span><span style="display:flex;"><span>level =<span style="color:#a5d6ff">"DEBUG"</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>[providers]</span></span><span style="display:flex;"><span>[providers.docker]</span></span><span style="display:flex;"><span>exposedByDefault =<span style="color:#79c0ff">false</span></span></span><span style="display:flex;"><span>endpoint =<span style="color:#a5d6ff">"unix:///var/run/docker.sock"</span></span></span><span style="display:flex;"><span>network =<span style="color:#a5d6ff">"traefik_proxy"</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>[entryPoints]</span></span><span style="display:flex;"><span>[entryPoints.web]</span></span><span style="display:flex;"><span>address =<span style="color:#a5d6ff">":80"</span></span></span></code></pre></div></div><p>docker-compose.yaml</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">version</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">'3.3'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">traefik:latest</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">traefik</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">always</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/run/docker.sock:/var/run/docker.sock</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">$PWD/config:/etc/traefik</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/etc/localtime:/etc/localtime</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ports</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"80:80"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">default</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">traefik_proxy</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik_proxy</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">external</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">driver</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">bridge</span></span></span></code></pre></div></div><p>Anschließend lässt sich der Container starten und ist bereit um Container als reverse proxy anzubieten.</p><p>Bei den anzubietenden Services müssen wir dann natürlich auch noch die Compose Datei anpassen. Beispielhaft hier meine zu phpIPAM:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">version</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">'3'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">phpipam-mysql</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">mysql:5.7</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">phpipam-mysql</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">unless-stopped</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">$PWD/mysql:/var/lib/mysql</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">MYSQL_ROOT_PASSWORD=ROOTPASSWORD</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">phpipam-phpipam</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">pierrecdn/phpipam:latest</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">phpipam-phpipam</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">unless-stopped</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">MYSQL_ENV_MYSQL_USER=root</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">MYSQL_ENV_MYSQL_ROOT_PASSWORD=ROOTPASSWORD</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">MYSQL_ENV_MYSQL_HOST=phpipam-mysql</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">labels</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.enable=true"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.phpipam-http.entrypoints=web"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.routers.phpipam-http.rule=Host(`phpipam.docker.domain.local`)"</span><span style="color:#6e7681"/><span style="color:#8b949e;font-style:italic">#Domain anpassen</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.http.services.phpipam.loadbalancer.server.port=80"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">depends_on</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">phpipam-mysql</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">traefik_proxy</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">default</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik_proxy</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">external</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">driver</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">bridge</span></span></span></code></pre></div></div><p>Anschließend auch noch diese Compose Datei starten und nun lässt sich, wenn alles korrekt eingerichtet wurde, der Service als URL öffnen. So ist es wesentlich einfacherer als ich für jeden Service einen neuen Port überlegen zu müssen.</p>
]]></content:encoded><category>selfhosted</category><category>docker</category><category>traefik</category><category>dns</category></item><item><title>Docker Monitoring mit Prometheus und Grafana</title><link>https://www.teqqy.de/docker-monitoring-mit-prometheus-und-grafana/</link><pubDate>Thu, 20 Jun 2019 18:10:53 +0200</pubDate><lastBuildDate>Thu, 20 Jun 2019 18:10:53 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/docker-monitoring-mit-prometheus-und-grafana/</guid><description>Um das Docker Monitoring sollte man sich nicht drücken, denn es ist wichtig zu sehen, welche Auslastung die einzelnen Container verursachen. Zum einen um etwaige Probleme festzustellen und zum anderen um die Leistung des Docker Hosts evtl. anpassen zu können.
In meinem docker-homelab (externer Link) Repository auf Github (externer Link) habe ich vor kurzem ein Docker Compose Stack hinzugefügt, welche genau dies macht. Über die Monitoring Tools Prometheus (externer Link) , Node Exporter (externer Link) und cAdvisor (externer Link) werden die Daten erfasst und mittels Grafana (externer Link) ansprechend dargestellt.</description><content:encoded>&lt;![CDATA[<p>Um das Docker Monitoring sollte man sich nicht drücken, denn es ist wichtig zu sehen, welche Auslastung die einzelnen Container verursachen. Zum einen um etwaige Probleme festzustellen und zum anderen um die Leistung des Docker Hosts evtl. anpassen zu können.</p><p>In meinem<a href="https://github.com/cbirkenbeul/docker-homelab" target="_blank" rel="noopener noreferrer">docker-homelab<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Repository auf<a href="https://www.github.com/cbirkenbeul" target="_blank" rel="noopener noreferrer">Github<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
habe ich vor kurzem ein Docker Compose Stack hinzugefügt, welche genau dies macht. Über die Monitoring Tools<a href="https://prometheus.io" target="_blank" rel="noopener noreferrer">Prometheus<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
,<a href="https://github.com/prometheus/node_exporter" target="_blank" rel="noopener noreferrer">Node Exporter<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
und<a href="https://github.com/google/cadvisor" target="_blank" rel="noopener noreferrer">cAdvisor<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
werden die Daten erfasst und mittels<a href="https://grafana.com" target="_blank" rel="noopener noreferrer">Grafana<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
ansprechend dargestellt.</p><h2 id="docker-monitoring-einrichten">Docker Monitoring einrichten<a href="#docker-monitoring-einrichten" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Um das ganze wie im oben gezeigten Dashboard zu realisieren kann man sich meiner<a href="https://github.com/cbirkenbeul/docker-homelab/blob/master/monitoring/docker-compose.yaml" target="_blank" rel="noopener noreferrer">docker-compose.yaml<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Datei bedienen. Am einfachsten ist es natürlich man verwendet das komplette Repository, weil dort auch alle anderen Dateien für das Docker Monitoring vorhanden sind.</p><p>Grundsätzlich reicht es dann mit einem einfachen</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">bash</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="bash"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker-compose up -d</span></span></code></pre></div></div><p>den kompletten Monitoring Stack zu starten. Solltest du kein<a href="/reverse-proxy-mit-traefik-unter-docker/">Traefik</a>
als Reverse Proxy nutzen kannst du in der docker-compose.yaml Datei auch den Bereich der Labels sowie die Netzwerkdefinition weg lassen.</p><p>Anschließend verbindet man sich über den gewünschten Browser mit dem Grafana Dashboard und loggt sich mit<em><strong>admin/admin</strong></em> dort ein.</p><p>Im ersten Schritt muss man nun die Datenquelle hinzufügen. Im Dashboard bedarf es hier nur ein klick. Als Datenquelle verwenden wir entsprechend Prometheus.</p><p>Es müssen dann nur die Felder Name und URL gefüllt werden. Sollte das vordefinierte Dashboard aus dem Repository verwendet werden, sollte die Datenquelle den Namen „Prometheus“ tragen. Als URL wird<strong>http://mon_prometheus:9090</strong></p><p>eingetragen. Es sollte bei dir dann analog zu diesem Screenshot aussehen:</p><p>Sobald man auf<em><strong>Save &amp; Test</strong></em> geklickt hat, sollte ein grüner Balken erscheinen der die erfolgreiche Verbindung bestätigt.</p><h2 id="grafana-dashboard-importieren">Grafana Dashboard importieren<a href="#grafana-dashboard-importieren" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Nun müssen wir nur noch das Grafana Dashboard importieren um das Docker Monitoring zu vervollständigen.</p><p>Hierfür klickt man links auf<em><strong>Dashboard</strong></em> und anschließend auf<em><strong>manage</strong></em>.</p><p>Über den Button importieren kann man nun die<a href="https://github.com/cbirkenbeul/docker-homelab/blob/master/monitoring/grafana/dashboard.json" target="_blank" rel="noopener noreferrer">dashboard.json<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Datei hinzufügen. Es muss dann nur noch die korrekte Datenquelle angegeben werden und schon sollte das Dashboard entsprechend Werte anzeigen.</p>
]]></content:encoded><category>selfhosted</category><category>docker</category><category>monitoring</category><category>prometheus</category><category>grafana</category></item><item><title>Docker-Compose Sammlung für dein Homelab</title><link>https://www.teqqy.de/docker-compose-sammlung-fuer-dein-homelab/</link><pubDate>Fri, 31 May 2019 14:19:21 +0200</pubDate><lastBuildDate>Fri, 31 May 2019 14:19:21 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/docker-compose-sammlung-fuer-dein-homelab/</guid><description>In meinen Videos verwende ich recht häufig Docker um Anwendungen zu installieren. Daher habe ich eine Docker-Compose Sammlung für Homelabs gestartet. Diese docker-compose.yaml Dateien sind von mir erstellt und/oder vorhandene editiert. Damit kannst du dein Docker Homelab schnell und einfach aufbauen.
Docker kommt beim heimischen Anwender immer mehr an. Zumindest wenn dieser technikinteressiert ist und sich auch die Arbeit damit machen möchte. Wer ein Docker Homelab starten möchte, kommt an Anfang nicht darum herum viel zu lesen. Allerdings möchte ich diesen Einstieg etwas einfacher gestalten.</description><content:encoded>&lt;![CDATA[<p>In meinen Videos verwende ich recht häufig Docker um Anwendungen zu installieren. Daher habe ich eine Docker-Compose Sammlung für Homelabs gestartet. Diese docker-compose.yaml Dateien sind von mir erstellt und/oder vorhandene editiert. Damit kannst du dein Docker Homelab schnell und einfach aufbauen.</p><p>Docker kommt beim heimischen Anwender immer mehr an. Zumindest wenn dieser technikinteressiert ist und sich auch die Arbeit damit machen möchte. Wer ein Docker Homelab starten möchte, kommt an Anfang nicht darum herum viel zu lesen. Allerdings möchte ich diesen Einstieg etwas einfacher gestalten.</p><p>Zwar gibt es immer noch das eine oder andere Problem mit dem reverse proxy (ich setze hierbei auf<a href="/nginx-reverse-proxy-mit-lets-encrypt-und-cloudflare/">Traefik</a>
), dennoch ist es mit ein paar Schritten schnell erledigt seine Lieblingsanwendung schnell und gut Verfügbar zu machen.</p><p>Auf der Plattform<a href="https://github.com" target="_blank" rel="noopener noreferrer">github.com<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
habe ich daher ein<a href="https://github.com/cbirkenbeul/docker-homelab" target="_blank" rel="noopener noreferrer">Repository<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
erstellt das ständig erweitert und aktualisiert wird. Gestartet habe ich jetzt erst mal mit Nextcloud und<a href="/reverse-proxy-mit-traefik-unter-docker/">Taefik</a>
. Hierzu wurde bereits ein Video veröffentlicht in dem ich das en detail zeige wie ihr das einrichten müsst.</p><p>Mit zukünftigen Videos wird auf dieses Repository immer hingewiesen und ich werde immer diese docker-compose.yaml Dateien verwenden. Wer mir also auf<a href="https://www.youtube.com/channel/UCnBQ7GosWO57aTpm2wR7Q7Q" target="_blank" rel="noopener noreferrer">YouTube<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
folgt (das solltest du, wenn du am Thema Homelab interessiert bist), wird die neusten Dateien immer mitbekommen.</p><p>Eines sei dazu aber noch gesagt: Diese Dateien sind sehr vereinfacht. Viele Dinge lassen sich anders und teils mit mehr Aufwand auch erledigen. Ich habe hier allerdings den kleinsten gemeinsamen Nenner gesucht und wohl auch gefunden. Solltet ihr Fehler entdecken, eröffnet ein<a href="https://github.com/cbirkenbeul/docker-homelab/issues" target="_blank" rel="noopener noreferrer">Issue<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
bei<a href="https://www.github.com/cbirkenbeul" target="_blank" rel="noopener noreferrer">Github<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
(wenn ihr einen Account habt) oder postet gerade in den entsprechenden Kommentaren.</p><p>Wenn dir eine bestimmte Software fehlen sollte, die du unbedingt dabei haben möchtest, bin ich natürlich gerne für Vorschläge offen. Natürlich kannst du auch ein Pull Request bei<a href="https://www.github.com/cbirkenbeul" target="_blank" rel="noopener noreferrer">GitHub<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
einreichen. Nach einer kurzen Überprüfung übernehme ich im Regelfall auch die Vorschläge der Community. So kann das Docker Homelab stetig bei allen wachsen.</p>
]]></content:encoded><category>selfhosted</category><category>docker</category><category>homelab</category><category>traefik</category></item><item><title>Reverse Proxy mit Traefik unter Docker</title><link>https://www.teqqy.de/reverse-proxy-mit-traefik-unter-docker/</link><pubDate>Sun, 07 Oct 2018 14:39:07 +0200</pubDate><lastBuildDate>Sun, 07 Oct 2018 14:39:07 +0200</lastBuildDate><guid isPermaLink="true">https://www.teqqy.de/reverse-proxy-mit-traefik-unter-docker/</guid><description>Um mehrere Webseiten unter einer IP und einer Domain zu veröffentlichen, ist es am einfachsten, wenn man sich ein sogenannten reverse proxy einrichtet. Die wohl bekannte Variante dazu ist von NGINX. Hierfür gibt es auch diverse Tutorials im Internet.
Meine ganzen Services, die ich extern verfügbar machen möchte, laufen allerdings als Docker (externer Link) Container. Entsprechend bietet es sich an, auch den reverse proxy Traefik unter Docker als Container laufen zu lassen.</description><content:encoded>&lt;![CDATA[<p>Um mehrere Webseiten unter einer IP und einer Domain zu veröffentlichen, ist es am einfachsten, wenn man sich ein sogenannten reverse proxy einrichtet. Die wohl bekannte Variante dazu ist von NGINX. Hierfür gibt es auch diverse Tutorials im Internet.</p><p>Meine ganzen Services, die ich extern verfügbar machen möchte, laufen allerdings als<a href="https://teqqy.de/tags/docker" target="_blank" rel="noopener noreferrer">Docker<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
Container. Entsprechend bietet es sich an, auch den reverse proxy Traefik unter Docker als Container laufen zu lassen.</p><p>Auch hier gibt es für NGINX – auch in Kombination mit Let’s encrypt Zertifikaten – reichlich Tutorials. Ich hatte mich damals allerdings für einen anderen Weg entscheiden und<a href="https://traefik.io/" target="_blank" rel="noopener noreferrer">Traefik<svg class="link-external-icon" aria-hidden="true" focusable="false" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg><span class="visually-hidden"> (externer Link)</span></a>
als reverse proxy genommen.</p><p>Wichtig ist natürlich, dass ihr in eurer Firewall bzw. Router ein NAT auf euren Docker Host einstellt. Port 80 (HTTP) und 443 (HTTPS) sollten entsprechend reichen.</p><h2 id="docker-container-mittels-compose">Docker Container mittels Compose<a href="#docker-container-mittels-compose" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Ich gehe erst mal davon aus, dass ihr Docker in einer der letzten Versionen installiert habt und eure Services, zumindest intern, vollständig funktionieren. Zudem nutze ich Docker Compose zum Verwalten meiner Container. Eine Adaption zu einem docker run command sollte kein Problem darstellen.</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">version</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">'3'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">traefik:latest</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">traefik</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">restart</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">always</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">ports</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">80</span>:<span style="color:#a5d6ff">80</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">443</span>:<span style="color:#a5d6ff">443</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">8080</span>:<span style="color:#a5d6ff">8080</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/run/docker.sock:/var/run/docker.sock</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">./traefik:/etc/traefik</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">environment</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"TZ=Europe/Berlin"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">traefik_proxy</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">default</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik_proxy</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">external</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">driver</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">bridge</span></span></span></code></pre></div></div><p>Ports 80 und 443 werden benötigt, um die entsprechenden Seiten dann auch weiterzuleiten. Port 8080 verwenden wir für das Webfrontend von Traefik. Ihr müsst also aufpassen, dass keine anderen Container diese Ports verwenden. Den Traefik Webport könnt ihr auch durch einen anderen ersetzen.</p><p>Zudem mounten wir als Volumes den Docker Socket, um Zugriff auf die laufenden Container zu haben. Als zweites Volume nutzen wir für die Konfigurationsdateien für Traefik.</p><p>Netzwerke legen wir an, um Traefik von außen erreichbar zu machen (default Netzwerk) und für das interne Routing zu Containern (traefik_proxy).</p><h2 id="traefik-konfiguration">Traefik Konfiguration<a href="#traefik-konfiguration" class="heading-anchor" aria-label="Diesen Abschnitt verlinken"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg></a></h2><p>Im Verzeichnis traefik legen wir nun noch die Datei traefik.toml an, welche folgenden Inhalt bekommt:</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">toml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="toml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span>logLevel =<span style="color:#a5d6ff">"INFO"</span></span></span><span style="display:flex;"><span>defaultEntryPoints = [<span style="color:#a5d6ff">"http"</span>,<span style="color:#a5d6ff">"https"</span>]</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>[web]</span></span><span style="display:flex;"><span> address =<span style="color:#a5d6ff">":8080"</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>[docker]</span></span><span style="display:flex;"><span> domain =<span style="color:#a5d6ff">"example.com"</span></span></span><span style="display:flex;"><span> watch =<span style="color:#79c0ff">true</span></span></span><span style="display:flex;"><span> exposedbydefault =<span style="color:#79c0ff">false</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># Force HTTPS</span></span></span><span style="display:flex;"><span>[entryPoints]</span></span><span style="display:flex;"><span> [entryPoints.http]</span></span><span style="display:flex;"><span> address =<span style="color:#a5d6ff">":80"</span></span></span><span style="display:flex;"><span> [entryPoints.http.redirect]</span></span><span style="display:flex;"><span> entryPoint =<span style="color:#a5d6ff">"https"</span></span></span><span style="display:flex;"><span> [entryPoints.https]</span></span><span style="display:flex;"><span> address =<span style="color:#a5d6ff">":443"</span></span></span><span style="display:flex;"><span> [entryPoints.https.tls]</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># Let's encrypt configuration</span></span></span><span style="display:flex;"><span>[acme]</span></span><span style="display:flex;"><span> email=<span style="color:#a5d6ff">"youremail.address@example.com"</span></span></span><span style="display:flex;"><span> storage=<span style="color:#a5d6ff">"/etc/traefik/acme/acme.json"</span></span></span><span style="display:flex;"><span> entryPoint=<span style="color:#a5d6ff">"https"</span></span></span><span style="display:flex;"><span> acmeLogging=<span style="color:#79c0ff">true</span></span></span><span style="display:flex;"><span> OnHostRule=<span style="color:#79c0ff">true</span></span></span><span style="display:flex;"><span> [acme.httpChallenge]</span></span><span style="display:flex;"><span> entryPoint =<span style="color:#a5d6ff">"http"</span></span></span></code></pre></div></div><p>Wichtig ist, dass ihr eure Domain unter [docker] und eure Email Adresse unter [acme] richtig anpasst. Die Email Adresse wird für die<a href="/nginx-reverse-proxy-mit-lets-encrypt-und-cloudflare/">Let’s encrypt</a>
Zertifikate benötigt.</p><p>Im Grundsätzlichen war es das schon für das Setup. Um jetzt Docker Container auch dazu zu bringen, auf die entsprechenden Domains zu hören, müssen wir die Konfiguration der einzelnen Container auch anpassen. Hier mal ein Beispiel von „The Lounge“ (einem IRC Frontend)</p><div class="code-block"><div class="code-block-header"><span class="code-lang-label">yaml</span><button class="code-copy-btn" type="button" aria-label="Code kopieren" data-umami-event="Code Copy" data-umami-event-lang="yaml"><svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg><svg class="icon-check" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg></button></div><div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;"><code class="language-yaml" data-lang="yaml"><span style="display:flex;"><span><span style="color:#ff7b72">---</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">version</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">'3'</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">services</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">thelounge</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">image</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">thelounge/lounge:latest</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">container_name</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">thelounge</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">volumes</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">/var/docker/thelounge:/home/lounge/data</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">labels</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.backend=thelounge"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.enable=true"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.frontend.rule=Host:subdomain.example.com"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.port=9000"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">"traefik.docker.network=traefik_proxy"</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/>-<span style="color:#a5d6ff">traefik_proxy</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#7ee787">networks</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">traefik_proxy</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">external</span>:<span style="color:#6e7681"/><span style="color:#79c0ff">true</span><span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">default</span>:<span style="color:#6e7681"/></span></span><span style="display:flex;"><span><span style="color:#6e7681"/><span style="color:#7ee787">driver</span>:<span style="color:#6e7681"/><span style="color:#a5d6ff">bridge</span></span></span></code></pre></div></div><p>Folgende Werte müsst ihr pro Container anpassen:</p><ul><li>traefik.backend (Name des Backends – könnt ihr frei vergeben)</li><li>traefik.frontend.rule (die URL, auf dem der Service hören soll)</li><li>traefik.port (der Port, auf dem eure Anwendung hört)</li></ul><p>Der Rest kann jeweils übernommen werden. Sollte ihr euren Container schon gestartet haben, solltet ihr diesen beenden, evtl. den Container löschen und neu starten. Ein paar Sekunden später ist der Service dann extern verfügbar.</p>
]]></content:encoded><category>selfhosted</category><category>traefik</category><category>docker</category><category>ssl-tls</category></item></channel></rss>