<?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>Nextcloud – Serverküche</title><link>https://serverkueche.de/tags/nextcloud/</link><description>Nextcloud – Neueste Beiträge von Serverküche</description><generator>Hugo</generator><language>de-DE</language><managingEditor>feedback@serverkueche.de (Serverküche)</managingEditor><webMaster>feedback@serverkueche.de (Serverküche)</webMaster><copyright>2026 Serverküche</copyright><lastBuildDate>Sun, 19 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://serverkueche.de/tags/nextcloud/index.xml" rel="self" type="application/rss+xml"/><item><title>Nextcloud absichern &amp; optimieren: alle Warnungen abarbeiten (Teil 2)</title><link>https://serverkueche.de/tutorials/nextcloud-optimieren-absichern/</link><pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/tutorials/nextcloud-optimieren-absichern/</guid><description>Die Admin-Übersicht deiner Nextcloud grün bekommen: HSTS-Header, E-Mail-Versand, Zwei-Faktor-Pflicht und Brute-Force-Schutz mit echten IPs einrichten.</description><content:encoded><![CDATA[<p>Deine Nextcloud läuft – aber in der Admin-Übersicht leuchten gelbe Warnungen, es gibt
keine funktionierende E-Mail und kein zweiter Faktor schützt deine Konten. In diesem
zweiten Teil machen wir aus „läuft&quot; ein „sauber abgesichert und flott&quot;: Wir arbeiten
jede Warnung ab, bis die Übersicht grün ist.</p>
<h2 id="was-bauen-wir">Was bauen wir?</h2>
<p>Am Ende zeigt die <strong>Sicherheits- &amp; Einrichtungsübersicht</strong> deiner Nextcloud keine
Warnungen mehr. Konkret bauen wir auf der Installation aus
<a href="/tutorials/nextcloud-eigene-cloud/">Teil 1</a> auf und ergänzen: den fehlenden
<strong>HSTS-Sicherheitsheader</strong> über Traefik, ein konfiguriertes <strong>Wartungsfenster</strong>, den
funktionierenden <strong>E-Mail-Versand</strong> (für Passwort-Resets und Benachrichtigungen), eine
<strong>erzwungene Zwei-Faktor-Authentifizierung</strong> und einen <strong>Brute-Force-Schutz, der die
echten Angreifer-IPs sieht</strong> – die Grundlage für Fail2ban.</p>
<p>Getestet ist alles gegen <strong>Nextcloud 34.0.1</strong> hinter <strong>Traefik v3.7</strong> auf Debian 13 mit
PHP 8.5. Das ist Fleißarbeit, aber genau die Fleißarbeit, die in 90 % aller
Nextcloud-Anleitungen fehlt – und die den Unterschied zwischen „irgendwie online&quot; und
„vernünftig betrieben&quot; ausmacht.</p>
<h2 id="voraussetzungen">Voraussetzungen</h2>
<ul>
<li>Eine <strong>laufende Nextcloud</strong> wie in
<a href="/tutorials/nextcloud-eigene-cloud/">Nextcloud selbst hosten (Teil 1)</a> aufgesetzt:
klassisches <code>nextcloud</code>-Image hinter Traefik, mit MariaDB, Redis und Cron-Sidecar.
Die Container-Namen aus Teil 1 (<code>nc-app</code>, <code>nc-db</code>, <code>nc-redis</code>, <code>nc-cron</code>) und der
Compose-Ordner <code>~/nextcloud</code> sind hier die Basis.</li>
<li><strong>SSH-Zugriff</strong> auf den Server und das Kommandozeilen-Werkzeug <strong><code>occ</code></strong> – wir rufen es
wie in Teil 1 im App-Container auf: <code>docker exec -u www-data nc-app php occ &lt;befehl&gt;</code>.</li>
<li>Ein <strong>Traefik-Reverse-Proxy</strong> mit dem <code>proxy</code>-Netz und dem Resolver <code>le</code> wie im
Tutorial <a href="/tutorials/reverse-proxy-traefik/">Reverse Proxy mit Traefik</a> – die
Sicherheits-Header hängen wir als Traefik-Middleware an.</li>
</ul>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>occ im Griff behalten
  </p>
  <div class="prose-kitchen text-sm"><p><code>occ</code> ist Nextclouds Admin-Werkzeug. Weil die Container in Teil 1 feste Namen bekommen
haben (<code>container_name</code>), sprichst du den App-Container direkt an – egal, in welchem
Verzeichnis du bist:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ status</span></span></code></pre></div>
</div>
<p>Du solltest <code>installed: true</code> und deine Version sehen. Diesen Präfix
(<code>docker exec -u www-data nc-app php occ …</code>) kürzen wir im Folgenden nicht ab – so kannst
du jeden Befehl direkt kopieren. Nur die wenigen <code>docker compose …</code>-Befehle (etwa der
Container-Neustart in Schritt 3) führst du weiterhin aus dem Ordner <code>~/nextcloud</code> aus.</p>
</div>
</div>
<h2 id="schritt-für-schritt">Schritt für Schritt</h2>
<h3 id="schritt-1-die-admin-übersicht-als-bestandsaufnahme-lesen">Schritt 1: Die Admin-Übersicht als Bestandsaufnahme lesen</h3>
<p>Melde dich als Administrator an und öffne <strong>Administrationseinstellungen → Übersicht</strong>.
Oben steht der Abschnitt <strong>„Sicherheits- &amp; Einrichtungswarnungen&quot;</strong>. Direkt nach einer
Standardinstallation sieht das so aus:</p>
<p><figure class="my-6"><img src="/tutorials/nextcloud-optimieren-absichern/nc-uebersicht-warnungen_hu_ded0bba1c144426e.webp" srcset="/tutorials/nextcloud-optimieren-absichern/nc-uebersicht-warnungen_hu_a4ebfe3ed3a25ade.webp 480w, /tutorials/nextcloud-optimieren-absichern/nc-uebersicht-warnungen_hu_ded0bba1c144426e.webp 768w, /tutorials/nextcloud-optimieren-absichern/nc-uebersicht-warnungen_hu_bbc66bad38685276.webp 1200w, /tutorials/nextcloud-optimieren-absichern/nc-uebersicht-warnungen_hu_2de722e751877ff1.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/nextcloud-optimieren-absichern/nc-uebersicht-warnungen_hu_9a42eb97ca12bc11.webp"
    alt="Die Nextcloud-Admin-Übersicht listet mehrere gelbe Warnungen zu Wartungsfenster, MIME-Type-Migrationen und HTTP-Headern auf" title="Ausgangslage: drei Warnungen und mehrere Hinweise in der Admin-Übersicht"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Ausgangslage: drei Warnungen und mehrere Hinweise in der Admin-Übersicht</figcaption></figure></p>
<p>Nextcloud unterscheidet drei Stufen: <strong>gelbe Warnungen</strong> (⚠, solltest du beheben),
<strong>blaue Hinweise</strong> (ℹ, meist optional) und stillschweigend bestandene Prüfungen. Bei
unserer frischen Instanz stehen drei Warnungen und ein paar Hinweise an:</p>
<ul>
<li>⚠ <strong>Beginn des Wartungsfensters</strong> ist nicht gesetzt (Schritt 2)</li>
<li>⚠ <strong>MIME-Type-Migrationen verfügbar</strong> (Schritt 2)</li>
<li>⚠ <strong>HTTP-Header</strong> – der <code>Strict-Transport-Security</code>-Header fehlt (Schritt 3)</li>
<li>ℹ <strong>E-Mail-Test</strong> – noch kein Mailserver hinterlegt (Schritt 4)</li>
<li>ℹ <strong>Zwei-Faktor-Konfiguration</strong> – 2FA ist verfügbar, aber nicht verpflichtend (Schritt 5)</li>
</ul>
<p>Denselben Bericht bekommst du auch auf der Kommandozeile – praktisch, um den Fortschritt
zwischendurch zu prüfen, ohne durch die Weboberfläche zu klicken:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ setupchecks</span></span></code></pre></div>
</div>
<p>Der Befehl gibt jede Prüfung mit ✓, ⚠ oder ✗ aus. Genau diese Liste arbeiten wir jetzt
von oben nach unten ab.</p>
<h3 id="schritt-2-die-zwei-schnellen-warnungen-beheben">Schritt 2: Die zwei schnellen Warnungen beheben</h3>
<p>Zwei Warnungen sind mit je einem Befehl erledigt.</p>
<p><strong>Wartungsfenster festlegen.</strong> Nextcloud führt einmal täglich rechenintensive
Aufräumjobs aus (Vorschauen, Aktivitäten, Kalender-Wiederholungen). Ohne definiertes
Zeitfenster laufen die <em>irgendwann</em> – auch mitten am Tag. Leg einen Startzeitpunkt fest,
zu dem kaum jemand arbeitet. Der Wert ist eine <strong>volle Stunde in UTC</strong>; <code>1</code> legt den
Beginn auf 01:00 UTC – der Check meldet danach das Fenster von 1:00 bis 7:00 UTC:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ config:system:set maintenance_window_start --type<span class="o">=</span>integer --value<span class="o">=</span><span class="m">1</span></span></span></code></pre></div>
</div>
<p>Zur Kontrolle bestätigt der Setup-Check danach:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">✓ Maintenance window start: Maintenance window to execute heavy background jobs is between 1:00 UTC and 7:00 UTC</span></span></code></pre></div>
</div>
<p><strong>MIME-Type-Migrationen ausführen.</strong> Gelegentlich lernt Nextcloud neue Dateitypen (etwa
für bessere Icons und Vorschauen). Diese Migration läuft bei Updates <em>nicht</em> automatisch,
weil sie auf großen Instanzen dauern kann. Auf einer frischen Cloud ist sie in Sekunden
durch:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ maintenance:repair --include-expensive</span></span></code></pre></div>
</div>
<p>Du siehst eine Liste abgearbeiteter Reparaturschritte (u. a. <code>Repair mime types</code>).
Danach meldet der Check <code>Mimetype migrations available: None</code>. Zwei Warnungen weniger.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-sky-300 bg-sky-50 dark:border-sky-800 dark:bg-sky-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">ℹ️</span>Und die blauen Hinweise?
  </p>
  <div class="prose-kitchen text-sm">Die Hinweise <strong>„AppAPI-Bereitstellungs-Daemon&quot;</strong> und <strong>„Konfiguration Server-ID&quot;</strong> kannst
du auf einer normalen Ein-Server-Installation ignorieren. Der erste betrifft nur die
Installation externer „Ex-Apps&quot; über einen Docker-Daemon, der zweite nur Setups, die über
mehrere PHP-Server verteilt laufen. Beides brauchst du hier nicht – deshalb bleiben es
Hinweise und keine Warnungen.</div>
</div>
<h3 id="schritt-3-den-hsts-sicherheitsheader-über-traefik-setzen">Schritt 3: Den HSTS-Sicherheitsheader über Traefik setzen</h3>
<p>Die dritte Warnung ist die wichtigste: Der <strong><code>Strict-Transport-Security</code>-Header</strong> (HSTS)
fehlt. Er weist den Browser an, diese Domain <strong>ausschließlich über HTTPS</strong> anzusprechen –
auch dann, wenn jemand <code>http://</code> eintippt oder ein Angreifer die Verbindung umzubiegen
versucht. Ohne HSTS bleibt ein kleines Zeitfenster für Downgrade-Angriffe offen.</p>
<p>Weil unsere Nextcloud hinter Traefik sitzt, setzen wir den Header <strong>im Proxy</strong>, nicht in
Nextcloud – dort gehört er hin, denn Traefik terminiert das TLS. Ergänze in der
<code>compose.yaml</code> deiner Nextcloud (aus Teil 1) die Middleware <code>nc-secure</code> und häng sie an
den Router. Konkret ändern sich zwei Stellen im <code>labels</code>-Block von <code>nc-app</code>.</p>
<p>Erstens die Router-Zeile um <code>nc-secure</code> erweitern:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.nc.middlewares=nc-dav,nc-secure&#34;</span></span></span></code></pre></div>
</div>
<p>Zweitens die Header-Middleware definieren (direkt bei den anderen <code>nc-app</code>-Labels):</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.middlewares.nc-secure.headers.stsSeconds=15552000&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.middlewares.nc-secure.headers.stsIncludeSubdomains=true&#34;</span></span></span></code></pre></div>
</div>
<p><code>stsSeconds=15552000</code> sind 180 Tage – der von Nextcloud geforderte Mindestwert. Übernimm
die Änderung und lade nur den App-Container neu:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose up -d nc-app</span></span></code></pre></div>
</div>
<p>Prüfe nach ein paar Sekunden von deinem eigenen Rechner aus, dass der Header wirklich
ausgeliefert wird:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">curl -sS -I https://cloud.DEINE_DOMAIN/ <span class="p">|</span> grep -i strict-transport</span></span></code></pre></div>
</div>
<p>Du solltest genau das sehen:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">strict-transport-security: max-age=15552000; includeSubDomains</span></span></code></pre></div>
</div>
<p>In der Admin-Übersicht wird die HTTP-Header-Warnung damit grün: <em>„Your server is correctly
configured to send security headers.&quot;</em> Die übrigen Header (<code>X-Content-Type-Options</code>,
<code>X-Frame-Options</code>, <code>Referrer-Policy</code> …) liefert Nextcloud selbst aus – nur HSTS musste vom
Proxy kommen.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-amber-400 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">⚠️</span>preload ist eine Einbahnstraße
  </p>
  <div class="prose-kitchen text-sm"><code>stsIncludeSubdomains=true</code> erweitert den HTTPS-Zwang auf alle Subdomains <strong>von
<code>cloud.DEINE_DOMAIN</code></strong> (nicht auf Geschwister wie <code>www.DEINE_DOMAIN</code> – der Header gilt
immer nur für den Host, der ihn ausliefert). Bewusst <strong>nicht</strong> gesetzt ist
<code>stsPreload=true</code>: Damit würdest du signalisieren, dass du die Domain in die
<a href="https://hstspreload.org/">HSTS-Preload-Liste</a> der Browser eintragen lassen willst – und
so ein Eintrag ist nur mit wochenlangem Vorlauf wieder rückgängig zu machen. Falls du
das eines Tages bewusst willst: Die Preload-Liste akzeptiert nur <code>max-age</code> ≥ 31536000
(1 Jahr) – mit den 15552000 oben wäre das Flag ohnehin wirkungslos. Setze <code>preload</code>
nur, wenn wirklich <em>jeder</em> Dienst unter der Domain dauerhaft HTTPS spricht; der Header
ist auch ohne vollwertig.</div>
</div>
<h3 id="schritt-4-e-mail-versand-einrichten">Schritt 4: E-Mail-Versand einrichten</h3>
<p>Ohne funktionierenden Mailversand kann Nextcloud keine <strong>Passwort-Resets</strong> verschicken,
keine <strong>Freigabe-Benachrichtigungen</strong> und keine <strong>Sicherheitswarnungen</strong> – und der
Hinweis „E-Mail-Test&quot; bleibt stehen. Das holen wir nach.</p>
<p>Öffne <strong>Administrationseinstellungen → Grundeinstellungen</strong> und scroll zum Abschnitt
<strong>„E-Mail-Server&quot;</strong>. Trag die Zugangsdaten deines Mail-Anbieters ein:</p>
<ul>
<li><strong>Sendemodus:</strong> <code>SMTP</code></li>
<li><strong>Verschlüsselung:</strong> <code>SSL/TLS</code> (Port <strong>465</strong>) oder <code>STARTTLS</code> (Port <strong>587</strong>) – nie
unverschlüsselt</li>
<li><strong>Absenderadresse:</strong> z. B. <code>cloud</code> @ <code>DEINE_DOMAIN</code></li>
<li><strong>Serveradresse:</strong> Host und Port deines Anbieters</li>
<li><strong>Authentifizierung:</strong> einschalten und Benutzername/Passwort hinterlegen</li>
</ul>
<p>Trag oben unter <strong>Persönliche Informationen</strong> eine E-Mail-Adresse für dein Admin-Konto
ein (dorthin geht die Testmail). Dann klick auf <strong>„Test-E-Mail senden&quot;</strong>. Kommt die Mail
an, bestätigt Nextcloud das mit einer grünen Meldung:</p>
<p><figure class="my-6"><img src="/tutorials/nextcloud-optimieren-absichern/nc-email-test_hu_f1a5ed435fa3db91.webp" srcset="/tutorials/nextcloud-optimieren-absichern/nc-email-test_hu_5adf7017629a931a.webp 480w, /tutorials/nextcloud-optimieren-absichern/nc-email-test_hu_f1a5ed435fa3db91.webp 768w, /tutorials/nextcloud-optimieren-absichern/nc-email-test_hu_5646fac37d8678c9.webp 1200w, /tutorials/nextcloud-optimieren-absichern/nc-email-test_hu_4e4b07dca9cf3d75.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/nextcloud-optimieren-absichern/nc-email-test_hu_39bdda64e2c97535.webp"
    alt="Der E-Mail-Server ist mit SMTP konfiguriert, ein Test-Versand wird oben rechts mit „E-Mail wurde versandt&quot; bestätigt" title="Erfolgreicher Test-Versand – die Werte im Bild stammen aus einem internen Test-Mailserver und sind NICHT für echte Postfächer zu übernehmen; dort gehören Host, Port 587/465 mit STARTTLS/SSL und die Zugangsdaten deines Anbieters hin"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Erfolgreicher Test-Versand – die Werte im Bild stammen aus einem internen Test-Mailserver und sind NICHT für echte Postfächer zu übernehmen; dort gehören Host, Port 587/465 mit STARTTLS/SSL und die Zugangsdaten deines Anbieters hin</figcaption></figure></p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>App-Passwort statt Kontopasswort
  </p>
  <div class="prose-kitchen text-sm">Nutzt dein Mail-Anbieter selbst Zwei-Faktor-Authentifizierung (Gmail, Mailbox.org, viele
andere), funktioniert dein normales Login-Passwort hier <strong>nicht</strong>. Leg im Konto deines
Anbieters ein dediziertes <strong>App-Passwort</strong> an und trag das ein. Das lässt sich zudem
gezielt widerrufen, ohne dein Haupt-Passwort zu ändern.</div>
</div>
<h3 id="schritt-5-zwei-faktor-authentifizierung-erzwingen">Schritt 5: Zwei-Faktor-Authentifizierung erzwingen</h3>
<p>Ein gestohlenes Passwort ist der häufigste Weg, wie Konten übernommen werden. Ein
<strong>zweiter Faktor</strong> (ein zeitbasierter Code aus einer Authenticator-App, TOTP) macht das
Passwort allein wertlos. Nextcloud bringt den passenden Anbieter schon mit – wir müssen
ihn nur aktivieren und zur Pflicht machen.</p>
<p>Aktiviere zunächst die TOTP-App (sie ist im Lieferumfang enthalten):</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ app:enable twofactor_totp</span></span></code></pre></div>
</div>
<p>Jeder Nutzer richtet seinen zweiten Faktor danach selbst ein – unter <strong>Persönliche
Einstellungen → Sicherheit → „TOTP (Authenticator-App)&quot;</strong>. Beim Aktivieren zeigt
Nextcloud einen QR-Code, den man mit einer App wie Aegis, andOTP oder Google Authenticator
scannt. Zusätzlich empfiehlt sich die App <strong>„Zwei-Faktor-Backup-Codes&quot;</strong> – die einmaligen
Codes retten dich, wenn das Handy verloren geht.</p>
<p>Damit niemand die Absicherung „vergisst&quot;, erzwingst du 2FA für die Administratoren. Im Web
findest du das unter <strong>Administrationseinstellungen → Sicherheit → „Zwei-Faktor-
Authentifizierung erzwingen&quot;</strong>, per Kommandozeile geht es so:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ twofactorauth:enforce --on --group<span class="o">=</span>admin</span></span></code></pre></div>
</div>
<p><figure class="my-6"><img src="/tutorials/nextcloud-optimieren-absichern/nc-zweifaktor_hu_a132ce2453d02b15.webp" srcset="/tutorials/nextcloud-optimieren-absichern/nc-zweifaktor_hu_94f90414c751c23b.webp 480w, /tutorials/nextcloud-optimieren-absichern/nc-zweifaktor_hu_a132ce2453d02b15.webp 768w, /tutorials/nextcloud-optimieren-absichern/nc-zweifaktor_hu_34a2ce03c7d7cb52.webp 1200w, /tutorials/nextcloud-optimieren-absichern/nc-zweifaktor_hu_6beccff3d885822a.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/nextcloud-optimieren-absichern/nc-zweifaktor_hu_21452c4f02d2cd91.webp"
    alt="Die Sicherheits-Einstellungen zeigen die erzwungene Zwei-Faktor-Authentifizierung für die Gruppe „admin“ sowie den Brute-Force-Status mit korrekt erkannter Client-IP" title="Zwei-Faktor-Pflicht für die Gruppe „admin“ – und darüber der Beleg, dass Nextcloud die echte Client-IP erkennt"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Zwei-Faktor-Pflicht für die Gruppe „admin“ – und darüber der Beleg, dass Nextcloud die echte Client-IP erkennt</figcaption></figure></p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-paprika-400 bg-paprika-50 dark:border-paprika-700 dark:bg-paprika-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🔥</span>Sperr dich nicht selbst aus
  </p>
  <div class="prose-kitchen text-sm">Sobald die Erzwingung aktiv ist, <strong>muss</strong> jedes Mitglied der Gruppe beim nächsten Login
einen zweiten Faktor einrichten. Richte deshalb <strong>zuerst deinen eigenen</strong> zweiten Faktor
ein und bewahre die Backup-Codes sicher auf, bevor du die Pflicht scharf schaltest. Falls
doch etwas schiefgeht, hebst du die Erzwingung über die Kommandozeile wieder auf:
<code>docker exec -u www-data nc-app php occ twofactorauth:enforce --off</code>. Einen
einzelnen festgefahrenen Faktor entfernst du mit
<code>… php occ twofactorauth:disable BENUTZER totp</code>.</div>
</div>
<h3 id="schritt-6-brute-force-schutz-mit-echten-ips--basis-für-fail2ban">Schritt 6: Brute-Force-Schutz mit echten IPs – Basis für Fail2ban</h3>
<p>Nextcloud drosselt fehlgeschlagene Logins von Haus aus: Nach mehreren Fehlversuchen
verzögert es weitere Anfragen <strong>derselben IP</strong>. Dieser Schutz steht und fällt aber damit,
dass Nextcloud die <strong>echte Client-IP</strong> sieht – und nicht die interne IP von Traefik. Genau
das leistet die <code>TRUSTED_PROXIES</code>-Einstellung aus Teil 1.</p>
<p>Ob es funktioniert, siehst du unter <strong>Administrationseinstellungen → Sicherheit</strong> im
Kasten „Brute-Force-Zulassungsliste&quot; (im Screenshot oben). Dort steht deine aktuelle,
korrekt erkannte öffentliche IP:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Ihre aktuelle IP-Adresse wird als &#34;DEINE_IP&#34; erkannt. Diese Adresse wird derzeit nicht gedrosselt.</span></span></code></pre></div>
</div>
<p>Steht da stattdessen eine <code>172.x.x.x</code>-Adresse aus dem Docker-Netz, greift <code>TRUSTED_PROXIES</code>
nicht – dann würde der Brute-Force-Schutz alle Nutzer über einen Kamm scheren und im
Zweifel Traefik selbst sperren. In dem Fall zurück zu Teil 1, Schritt 2/3.</p>
<p><strong>Harte Sperren mit Fail2ban.</strong> Die eingebaute Drosselung verzögert nur; wer Angreifer
richtig aussperren will, kombiniert Nextcloud mit
<a href="/tutorials/fail2ban-einrichten/">Fail2ban</a>. Nextcloud protokolliert jeden Fehlversuch im
JSON-Log – und dank <code>TRUSTED_PROXIES</code> mit der echten IP:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">{&#34;level&#34;:2,&#34;time&#34;:&#34;2026-07-18T08:14:05+00:00&#34;,&#34;remoteAddr&#34;:&#34;203.0.113.47&#34;,&#34;user&#34;:&#34;--&#34;,&#34;app&#34;:&#34;no app in context&#34;,&#34;method&#34;:&#34;POST&#34;,&#34;url&#34;:&#34;/login&#34;,&#34;message&#34;:&#34;Login failed: BENUTZER (Remote IP: 203.0.113.47)&#34;}</span></span></code></pre></div>
</div>
<p>Dieses Log liegt im Nextcloud-Volume. Den Pfad auf dem Host findest du so:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker inspect -f <span class="s1">&#39;{{ range .Mounts }}{{ if eq .Destination &#34;/var/www/html&#34; }}{{ .Source }}{{ end }}{{ end }}&#39;</span> nc-app</span></span></code></pre></div>
</div>
<p>Darunter liegt die Datei <code>data/nextcloud.log</code>. Auf die zeigst du einen Fail2ban-Filter,
der auf <code>remoteAddr</code> matcht, plus ein Jail nach dem Muster aus dem
<a href="/tutorials/fail2ban-einrichten/">Fail2ban-Tutorial</a>. So wandert nach ein paar
Fehlversuchen die Angreifer-IP direkt in die Firewall – bevor die Anfrage Nextcloud
überhaupt erreicht.</p>
<h3 id="schritt-7-caching--php-prüfen--das-performance-fundament">Schritt 7: Caching &amp; PHP prüfen – das Performance-Fundament</h3>
<p>Zum Schluss vergewissern wir uns, dass die Performance-Basis steht. Vieles davon hat Teil 1
über die <code>REDIS_HOST</code>-Variable schon automatisch eingerichtet – prüfen schadet trotzdem
nicht, denn genau hier wird eine Nextcloud zäh oder flott.</p>
<p>Nextcloud nutzt <strong>drei</strong> Cache-Rollen. Kontrolliere alle drei:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ config:system:get memcache.local
</span></span><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ config:system:get memcache.distributed
</span></span><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ config:system:get memcache.locking</span></span></code></pre></div>
</div>
<p>Erwartet:</p>
<div class="sk-code">
  <span class="sk-code-head">Ausgabe</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">\OC\Memcache\APCu
</span></span><span class="line"><span class="cl">\OC\Memcache\Redis
</span></span><span class="line"><span class="cl">\OC\Memcache\Redis</span></span></code></pre></div>
</div>
<ul>
<li><strong>Lokaler Cache (APCu):</strong> hält häufig genutzte Daten im RAM des PHP-Prozesses – der
spürbarste Beschleuniger im Alltag.</li>
<li><strong>Verteilter Cache (Redis):</strong> teilt Cache-Daten über Prozesse hinweg, wichtig sobald
App- und Cron-Container zusammenspielen.</li>
<li><strong>File-Locking (Redis):</strong> verhindert, dass zwei Zugriffe dieselbe Datei gleichzeitig
verändern und sie beschädigen. Der Grund, warum wir in Teil 1 überhaupt Redis eingebaut
haben.</li>
</ul>
<p>Passt das Zusammenspiel, meldet <code>docker exec -u www-data nc-app php occ setupchecks</code> die
Zeile <code>✓ Memcache: Configured</code>. (Bestandene Prüfungen zeigt die Web-Übersicht nicht an –
dort tauchen nur Warnungen und Hinweise auf, deshalb kontrollierst du das hier per CLI.)</p>
<p><strong>OPcache</strong> – der Bytecode-Cache von PHP – ist im offiziellen <code>nextcloud</code>-Image bereits
sinnvoll vorkonfiguriert (u. a. <code>opcache.interned_strings_buffer=32</code>). Du musst hier also
nichts nachziehen; die früher berüchtigte OPcache-Warnung taucht mit aktuellen Images gar
nicht mehr auf. Nachschauen kannst du bei Bedarf so:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php -i <span class="p">|</span> grep opcache.interned_strings_buffer</span></span></code></pre></div>
</div>
<p>Damit ist die Übersicht warnungsfrei:</p>
<p><figure class="my-6"><img src="/tutorials/nextcloud-optimieren-absichern/nc-uebersicht-gruen_hu_e398290706625ab9.webp" srcset="/tutorials/nextcloud-optimieren-absichern/nc-uebersicht-gruen_hu_e354f69e1443ecd8.webp 480w, /tutorials/nextcloud-optimieren-absichern/nc-uebersicht-gruen_hu_e398290706625ab9.webp 768w, /tutorials/nextcloud-optimieren-absichern/nc-uebersicht-gruen_hu_d2ede7a8e25e526d.webp 1200w, /tutorials/nextcloud-optimieren-absichern/nc-uebersicht-gruen_hu_77659c13bfe90ad3.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/nextcloud-optimieren-absichern/nc-uebersicht-gruen_hu_c26ff36bf5d6b604.webp"
    alt="Die Nextcloud-Admin-Übersicht zeigt keine gelben Warnungen mehr, nur noch zwei optionale Hinweise, und meldet die aktuelle Version" title="Ergebnis: keine Warnungen mehr, Version aktuell – nur die zwei optionalen Hinweise bleiben"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Ergebnis: keine Warnungen mehr, Version aktuell – nur die zwei optionalen Hinweise bleiben</figcaption></figure></p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Vorschaubilder gezielt erzeugen
  </p>
  <div class="prose-kitchen text-sm">Wenn deine Nutzer viele Fotos ablegen, lohnt sich die App <strong>„Preview Generator&quot;</strong>: Ein
<code>occ</code>-Cronjob erzeugt Vorschaubilder im Voraus, statt sie beim ersten Öffnen langsam on
the fly zu berechnen. Ergänzt du sie, begrenze über
<code>occ config:system:set preview_max_x --value=2048</code> (und <code>preview_max_y</code>) die maximale
Vorschaugröße, sonst wächst der Speicherbedarf schnell.</div>
</div>
<h2 id="wenn-es-nicht-funktioniert">Wenn es nicht funktioniert</h2>
<p><strong>Symptom:</strong> Nach dem Traefik-Neustart erscheint der HSTS-Header nicht in der <code>curl</code>-Ausgabe.</p>
<p><strong>Ursache &amp; Lösung:</strong> Meist ist die Middleware nicht am Router. Prüfe, dass die Zeile
<code>traefik.http.routers.nc.middlewares</code> <strong>beide</strong> Middlewares nennt (<code>nc-dav,nc-secure</code>) und
dass die drei <code>nc-secure</code>-Header-Labels im <code>nc-app</code>-Block stehen. Danach
<code>docker compose up -d nc-app</code>. Traefik übernimmt geänderte Labels erst beim Neu-Erstellen
des Containers.</p>
<p><strong>Symptom:</strong> Der E-Mail-Test schlägt fehl („Es gab ein Problem beim Senden der E-Mail&quot;).</p>
<p><strong>Ursache &amp; Lösung:</strong> Fast immer Port/Verschlüsselung oder Authentifizierung. Kombiniere
<code>SSL/TLS</code> mit Port <strong>465</strong> oder <code>STARTTLS</code> mit Port <strong>587</strong> – nicht kreuzweise. Nutzt dein
Anbieter 2FA, brauchst du ein <strong>App-Passwort</strong> (siehe Schritt 4). Details stehen im
Nextcloud-Log: <code>docker exec -u www-data nc-app php occ log:tail 20</code>.</p>
<p><strong>Symptom:</strong> Du kommst nach dem Erzwingen von 2FA selbst nicht mehr rein.</p>
<p><strong>Ursache &amp; Lösung:</strong> Du hattest noch keinen zweiten Faktor eingerichtet. Hebe die Pflicht
per Kommandozeile auf, richte deinen Faktor in Ruhe ein und schalte sie danach wieder
scharf: <code>docker exec -u www-data nc-app php occ twofactorauth:enforce --off</code>.</p>
<p><strong>Symptom:</strong> Im Brute-Force-Kasten steht eine <code>172.x.x.x</code>-Adresse statt deiner echten IP.</p>
<p><strong>Ursache &amp; Lösung:</strong> <code>TRUSTED_PROXIES</code> passt nicht zum tatsächlichen <code>proxy</code>-Subnetz.
Ermittle es mit <code>docker network inspect proxy -f '{{(index .IPAM.Config 0).Subnet}}'</code> und
trag den Wert in der <code>nc-app</code>-Umgebung ein (Teil 1, Schritt 2). Sonst sperrt der
Brute-Force-Schutz im Ernstfall den Proxy und damit alle Nutzer.</p>
<p><strong>Symptom:</strong> Nach einem Reboot meldet Nextcloud „Redis went away&quot; oder wird sehr langsam.</p>
<p><strong>Ursache &amp; Lösung:</strong> Der App-Container ist vor Redis gestartet. Stelle sicher, dass
<code>nc-redis</code> in <code>depends_on</code> steht (Teil 1) und mit <code>restart: unless-stopped</code> läuft – dann
fängt Docker den Startreihenfolge-Fall selbst ab.</p>
<h2 id="wartung--backups">Wartung &amp; Backups</h2>
<ul>
<li><strong>Übersicht nach jedem Update prüfen.</strong> Neue Nextcloud-Versionen bringen neue Checks
mit. Wirf nach jedem Upgrade einen Blick auf <strong>Administrationseinstellungen → Übersicht</strong>
oder lass <code>occ setupchecks</code> laufen – so fängst du neue Warnungen früh ab.</li>
<li><strong>Regelmäßig den offiziellen Security-Scan nutzen.</strong> Der
<a href="https://scan.nextcloud.com/">Nextcloud Security Scan</a> prüft deine Domain von außen und
vergibt eine Note. Mit HSTS und aktuellen Versionen ist <strong>A/A+</strong> das realistische Ziel;
fällt die Note, ist meist ein Update überfällig.</li>
<li><strong>Zweite Faktoren im Blick behalten.</strong> Bewahre die Backup-Codes getrennt vom Handy auf.
Verliert ein Nutzer sein Gerät, entfernst du seinen Faktor mit
<code>occ twofactorauth:disable BENUTZER totp</code>, danach richtet er ihn neu ein.</li>
<li><strong>App-Passwörter aufräumen.</strong> Jeder verbundene Client (Desktop, Handy) bekommt ein
eigenes App-Passwort. Unter <strong>Persönliche Einstellungen → Sicherheit</strong> siehst du alle
Geräte und kannst einzelne bei Verlust gezielt widerrufen.</li>
<li><strong>Die Absicherung ersetzt kein Backup.</strong> All das schützt vor fremdem Zugriff, nicht vor
Datenverlust. Die konsistente Sicherung aus Datenbank-Dump und Datenverzeichnis bleibt
Pflicht – siehe den Wartungsabschnitt in <a href="/tutorials/nextcloud-eigene-cloud/">Teil 1</a> und
<a href="/tutorials/backups-mit-restic/">Backups mit Restic</a>. Ehrlich zum Aufwand: Plane den
monatlichen Update-Durchgang mit einem kurzen Blick auf die Übersicht fest ein – dann
bleibt deine Cloud dauerhaft grün.</li>
</ul>
]]></content:encoded></item><item><title>Nextcloud selbst hosten: deine eigene Cloud hinter Traefik</title><link>https://serverkueche.de/tutorials/nextcloud-eigene-cloud/</link><pubDate>Sun, 19 Jul 2026 00:00:00 +0000</pubDate><author>feedback@serverkueche.de (Serverküche)</author><guid>https://serverkueche.de/tutorials/nextcloud-eigene-cloud/</guid><description>Nextcloud mit Docker hinter Traefik aufsetzen: eigene Cloud für Dateien, Kalender und Kontakte – mit MariaDB, Redis und automatischem HTTPS.</description><content:encoded><![CDATA[<p>Deine Dateien, dein Kalender, deine Kontakte – aber auf deinem Server statt bei einem
Cloud-Konzern. <strong>Nextcloud</strong> ist das Flaggschiff des Selfhostings: eine vollwertige
Cloud, die du selbst betreibst. In diesem Rezept setzen wir sie sauber hinter Traefik
auf, mit eigener Datenbank, Caching und automatischem HTTPS.</p>
<h2 id="was-bauen-wir">Was bauen wir?</h2>
<p>Am Ende läuft <strong>Nextcloud 34</strong> hinter deinem Traefik-Proxy, erreichbar unter
<code>https://cloud.DEINE_DOMAIN</code> mit gültigem Let&rsquo;s-Encrypt-Zertifikat. Nextcloud ist deine
private Cloud: Dateien synchronisieren (wie bei Dropbox), Kalender und Kontakte über
alle Geräte, Fotos, Notizen, Office-Dokumente. Du verbindest den offiziellen
<strong>Desktop-Sync-Client</strong> und die <strong>Handy-Apps</strong> mit deinem Server – die Daten liegen
dabei ausschließlich bei dir.</p>
<p>Wir setzen bewusst auf das <strong>klassische <code>nextcloud</code>-Image</strong> (nicht auf „Nextcloud
All-in-One&quot;) plus <strong>MariaDB</strong> als Datenbank und <strong>Redis</strong> fürs Caching und File-Locking.
Diese Kombination ist stabil, gut dokumentiert und passt exakt in das Traefik-Muster aus
der Serverküche.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-sky-300 bg-sky-50 dark:border-sky-800 dark:bg-sky-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">ℹ️</span>Warum nicht Nextcloud AIO?
  </p>
  <div class="prose-kitchen text-sm">Nextcloud bietet auch ein „All-in-One&quot;-Paket (AIO) an. Das bringt aber sein <strong>eigenes
TLS und eigene Ports</strong> mit und will den Reverse-Proxy-Teil selbst übernehmen – das
beißt sich mit einem bestehenden Traefik. Für unser Setup ist das klassische Image die
richtige, kontrollierbare Wahl.</div>
</div>
<h2 id="voraussetzungen">Voraussetzungen</h2>
<ul>
<li>Ein laufender <strong>Traefik-Reverse-Proxy</strong> mit dem gemeinsamen <code>proxy</code>-Netzwerk und dem
Let&rsquo;s-Encrypt-Resolver <code>le</code> – wie im Tutorial
<a href="/tutorials/reverse-proxy-traefik/">Reverse Proxy mit Traefik</a> aufgebaut.</li>
<li>Eine Subdomain <code>cloud.DEINE_DOMAIN</code>, deren DNS-Record (A/AAAA) auf deine Server-IP
zeigt – siehe <a href="/tutorials/domain-mit-server-verbinden/">Domain mit Server verbinden</a>.</li>
<li>Ein funktionierendes <strong>Backup</strong>. Eine Cloud ist der Ort, an dem Datenverlust am
meisten wehtut – richte zuerst <a href="/tutorials/backups-mit-restic/">Backups mit Restic</a>
ein.</li>
</ul>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>Wie groß muss der Server sein?
  </p>
  <div class="prose-kitchen text-sm">Nextcloud ist genügsamer als sein Ruf: Für den privaten Gebrauch oder eine kleine
Familie (1–5 Nutzer) reichen <strong>2 vCPU und 4 GB RAM</strong> gut aus – der getestete VPS 1000
passt. Der Flaschenhals ist der Arbeitsspeicher: Bei zu wenig RAM fängt der Server an zu
swappen und wird zäh. Redis (bauen wir gleich ein) entlastet spürbar. Für Nextcloud
Office/Collabora oder viele parallele Nutzer solltest du eher 8 GB einplanen.</div>
</div>
<p>Wie groß dein Server für deine Nutzerzahl sein sollte, schätzt dir der
<a href="/serverempfehlung/">Server-Rechner</a> in ein paar Klicks.</p>
<div class="not-prose my-6 overflow-hidden rounded-xl border border-paprika-200 bg-paprika-50 dark:border-paprika-800 dark:bg-paprika-900/20">
  <div class="flex items-center justify-between border-b border-paprika-200 bg-paprika-100 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-paprika-700 dark:border-paprika-800 dark:bg-paprika-900/40 dark:text-paprika-300">
    <span>🍳 Empfehlung</span>
    <span title="Mit * markierte Links sind Affiliate-Links.">Anzeige</span>
  </div>
  <div class="flex flex-col gap-4 p-4 sm:flex-row sm:items-center sm:justify-between">
    <div>
      <p class="text-lg font-bold text-slate-900 dark:text-white">VPS 1000 G12</p>
      <p class="mt-1 text-sm text-slate-600 dark:text-slate-300">4 vCore · 8 GB RAM · 256 GB NVMe</p>
      <p class="mt-1 text-sm font-semibold text-paprika-700 dark:text-paprika-400">ab 10,36 €/Monat</p>
      <p class="mt-2 text-sm text-slate-600 dark:text-slate-400">Für eine private Nextcloud mit ein paar Nutzern reicht der VPS 1000 gut aus.</p>
    </div>
    <a href="https://www.netcup.com/de/server/vps/vps-1000-g12-12m?ref=44083" rel="sponsored noopener" target="_blank"
   class="inline-flex shrink-0 items-center justify-center rounded-lg bg-paprika-600 px-5 py-2.5 font-semibold text-white transition-colors hover:bg-paprika-700">
  Zu netcup →
</a>

  </div><div class="px-4 pb-4"><p class="not-prose my-3 flex flex-wrap items-center gap-x-2 gap-y-1 rounded-lg border border-herb-500/40 bg-herb-50 px-3 py-2 text-sm text-slate-700 dark:bg-herb-900/20 dark:text-slate-200">
  <span>💶 <strong>5 € Gutschein</strong> für netcup-Neukunden:</span>
  <code class="rounded bg-white px-2 py-0.5 font-mono text-sm font-semibold text-herb-800 dark:bg-slate-800 dark:text-herb-400">36nc17844976032</code>
  <span class="text-xs text-slate-500 dark:text-slate-400">(nur Neukunden, keine Domains)</span>
</p></div>
</div>

<h2 id="schritt-für-schritt">Schritt für Schritt</h2>
<h3 id="schritt-1-dns-record-anlegen">Schritt 1: DNS-Record anlegen</h3>
<p>Lege bei deinem DNS-Anbieter einen Eintrag <code>cloud.DEINE_DOMAIN</code> an, der auf deine
Server-IP zeigt (A-Record für IPv4, AAAA für IPv6). Prüfe, dass er aufgelöst wird:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">dig +short cloud.DEINE_DOMAIN</span></span></code></pre></div>
</div>
<p>Du solltest deine Server-IP sehen. Erst wenn der Record steht, kann Traefik später das
HTTPS-Zertifikat holen.</p>
<h3 id="schritt-2-das-proxy-subnetz-ermitteln">Schritt 2: Das proxy-Subnetz ermitteln</h3>
<p>Nextcloud sitzt hinter Traefik. Damit Nextclouds Brute-Force-Schutz die <strong>echte</strong>
Besucher-IP erkennt (und nicht die interne Traefik-IP sperrt), müssen wir Traefik als
„vertrauenswürdigen Proxy&quot; eintragen. Dazu brauchst du das Subnetz deines
<code>proxy</code>-Netzwerks:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker network inspect proxy -f <span class="s1">&#39;{{(index .IPAM.Config 0).Subnet}}&#39;</span></span></span></code></pre></div>
</div>
<p>Du bekommst etwas wie <code>172.18.0.0/16</code>. <strong>Merke dir diesen Wert</strong> – er kommt gleich als
<code>TRUSTED_PROXIES</code> in die Konfiguration.</p>
<h3 id="schritt-3-die-composeyaml-anlegen">Schritt 3: Die compose.yaml anlegen</h3>
<p>Leg einen Ordner an und wechsle hinein:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">mkdir -p ~/nextcloud <span class="o">&amp;&amp;</span> <span class="nb">cd</span> ~/nextcloud</span></span></code></pre></div>
</div>
<p>Erstelle die <code>compose.yaml</code>. Ersetze <code>cloud.DEINE_DOMAIN</code>, alle Passwörter und das
<code>TRUSTED_PROXIES</code>-Subnetz aus Schritt 2:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nc-db</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">mariadb:11.4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">nc-db</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span>--<span class="l">transaction-isolation=READ-COMMITTED --log-bin=binlog --binlog-format=ROW</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MARIADB_ROOT_PASSWORD</span><span class="p">:</span><span class="w"> </span><span class="l">EIN_STARKES_ROOT_PASSWORT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MARIADB_DATABASE</span><span class="p">:</span><span class="w"> </span><span class="l">nextcloud</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MARIADB_USER</span><span class="p">:</span><span class="w"> </span><span class="l">nextcloud</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MARIADB_PASSWORD</span><span class="p">:</span><span class="w"> </span><span class="l">EIN_STARKES_DB_PASSWORT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">nc_db:/var/lib/mysql</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">healthcheck</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">test</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;CMD&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;healthcheck.sh&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;--connect&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;--innodb_initialized&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">interval</span><span class="p">:</span><span class="w"> </span><span class="l">10s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">timeout</span><span class="p">:</span><span class="w"> </span><span class="l">5s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">retries</span><span class="p">:</span><span class="w"> </span><span class="m">6</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">networks</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">default]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nc-redis</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">redis:8-alpine</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">nc-redis</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="l">redis-server --requirepass EIN_STARKES_REDIS_PASSWORT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">networks</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">default]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nc-app</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">nextcloud:34-apache</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">nc-app</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">depends_on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">nc-db</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">condition</span><span class="p">:</span><span class="w"> </span><span class="l">service_healthy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">nc-redis</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">condition</span><span class="p">:</span><span class="w"> </span><span class="l">service_started</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">environment</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MYSQL_HOST</span><span class="p">:</span><span class="w"> </span><span class="l">nc-db</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MYSQL_DATABASE</span><span class="p">:</span><span class="w"> </span><span class="l">nextcloud</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MYSQL_USER</span><span class="p">:</span><span class="w"> </span><span class="l">nextcloud</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">MYSQL_PASSWORD</span><span class="p">:</span><span class="w"> </span><span class="l">EIN_STARKES_DB_PASSWORT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">REDIS_HOST</span><span class="p">:</span><span class="w"> </span><span class="l">nc-redis</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">REDIS_HOST_PASSWORD</span><span class="p">:</span><span class="w"> </span><span class="l">EIN_STARKES_REDIS_PASSWORT</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">NEXTCLOUD_TRUSTED_DOMAINS</span><span class="p">:</span><span class="w"> </span><span class="l">cloud.DEINE_DOMAIN</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">OVERWRITEPROTOCOL</span><span class="p">:</span><span class="w"> </span><span class="l">https</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">OVERWRITECLIURL</span><span class="p">:</span><span class="w"> </span><span class="l">https://cloud.DEINE_DOMAIN</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">TRUSTED_PROXIES</span><span class="p">:</span><span class="w"> </span><span class="m">172.18.0.0</span><span class="l">/16</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">PHP_MEMORY_LIMIT</span><span class="p">:</span><span class="w"> </span><span class="l">1024M</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">PHP_UPLOAD_LIMIT</span><span class="p">:</span><span class="w"> </span><span class="l">10G</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">nc_html:/var/www/html</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">labels</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.enable=true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.nc.rule=Host(`cloud.DEINE_DOMAIN`)&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.nc.entrypoints=websecure&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.nc.tls.certresolver=le&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.routers.nc.middlewares=nc-dav&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.services.nc.loadbalancer.server.port=80&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="c"># .well-known-Redirect für CalDAV/CardDAV (siehe unten)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.middlewares.nc-dav.redirectregex.regex=https://(.*)/.well-known/(?:card|cal)dav&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.middlewares.nc-dav.redirectregex.replacement=https://cloud.DEINE_DOMAIN/remote.php/dav/&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;traefik.http.middlewares.nc-dav.redirectregex.permanent=true&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">networks</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">default, proxy]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nc_html</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nc_db</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">networks</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">default</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">proxy</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">external</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span></span></span></code></pre></div>
</div>
<p>Was hier wichtig ist:</p>
<ul>
<li><strong>Drei Container:</strong> <code>nc-app</code> (Nextcloud), <code>nc-db</code> (MariaDB), <code>nc-redis</code>. Nur <code>nc-app</code>
hängt im <strong><code>proxy</code>-Netz</strong> (für Traefik) <em>und</em> im internen <code>default</code>-Netz. Datenbank und
Redis bleiben ausschließlich intern – sie haben <strong>kein <code>ports:</code></strong> und sind von außen
nicht erreichbar.</li>
<li><strong>Zwei Named Volumes:</strong> <code>nc_html</code> (Programmcode, <code>config.php</code>, Nutzerdaten) und
<code>nc_db</code> (die MariaDB-Daten). Das <code>nc_db</code>-Volume ist Pflicht: Ohne den Eintrag landet
die Datenbank in einem <strong>anonymen</strong> Volume, und ein <code>docker compose down</code> gefolgt
von <code>up</code> würde sie <strong>unwiederbringlich verlieren</strong>.</li>
<li><strong><code>healthcheck</code> + <code>depends_on: service_healthy</code>:</strong> Nextcloud startet schneller als die
Datenbank initialisiert ist. Ohne diesen Healthcheck scheitert die Erstinstallation an
einem „Connection refused&quot;. So wartet der App-Container, bis MariaDB wirklich bereit ist.</li>
<li><strong><code>NEXTCLOUD_TRUSTED_DOMAINS</code>:</strong> ohne die eigene Domain hier begrüßt dich Nextcloud mit
„Zugriff über eine nicht vertrauenswürdige Domäne&quot;.</li>
<li><strong><code>OVERWRITEPROTOCOL: https</code></strong> sagt Nextcloud, dass es hinter HTTPS läuft – sonst baut
es interne Links als <code>http://</code> und Logins/Redirects brechen.</li>
<li><strong><code>TRUSTED_PROXIES</code>:</strong> das Subnetz aus Schritt 2. Damit erkennt Nextcloud die echte
Client-IP; sonst sperrt der Brute-Force-Schutz die Traefik-IP.</li>
<li><strong><code>PHP_MEMORY_LIMIT</code> / <code>PHP_UPLOAD_LIMIT</code>:</strong> die Defaults (512 MB) sind für große
Uploads zu klein. Hier großzügig gesetzt.</li>
<li><strong><code>loadbalancer.server.port=80</code>:</strong> das Apache-Image lauscht im Container auf Port 80.</li>
<li><strong>Die <code>nc-dav</code>-Middleware</strong> löst ein klassisches Nextcloud-Problem – dazu gleich mehr.</li>
</ul>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-amber-400 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">⚠️</span>CalDAV/CardDAV: der .well-known-Redirect
  </p>
  <div class="prose-kitchen text-sm">Nextcloud möchte Kalender-/Kontakt-Clients über <code>/.well-known/caldav</code> und
<code>/.well-known/carddav</code> zu <code>/remote.php/dav/</code> schicken. Hinter einem Reverse Proxy
funktioniert Nextclouds eigener Redirect nicht zuverlässig – das führt später zu einer
Warnung im Sicherheits-Check und zu Problemen bei der Kalender-Einrichtung. Die
<code>nc-dav</code>-Middleware oben erledigt den Redirect direkt in Traefik. Wichtig: Das Muster
muss die <strong>volle <code>https://…</code>-URL</strong> matchen – <code>redirectregex</code> prüft immer die komplette
URL, nicht nur den Pfad. Ein reines Pfad-Muster wie <code>^/.well-known/…</code> greift deshalb
nie.</div>
</div>
<h3 id="schritt-4-starten-und-den-erst-setup-durchlaufen">Schritt 4: Starten und den Erst-Setup durchlaufen</h3>
<p>Starte den Stack:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose up -d</span></span></code></pre></div>
</div>
<p>Beim ersten Start initialisiert MariaDB die Datenbank und Nextcloud entpackt sich –
das dauert ein bis zwei Minuten. Verfolge es im Log:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose logs -f nc-app</span></span></code></pre></div>
</div>
<p>Beim ersten Lauf entpackt das Image Nextcloud ins Volume; du siehst Zeilen wie
<code>Initializing nextcloud 34.0.1.2 ...</code> und schließlich <code>Initializing finished</code>, gefolgt
vom Apache-Start. Erscheint stattdessen wiederholt <code>restarting</code>, wirf einen Blick in den
Abschnitt „Wenn es nicht funktioniert&quot;. Mit <code>Strg+C</code> verlässt du die Log-Ansicht wieder
(der Container läuft weiter).</p>
<p>Ruf dann <code>https://cloud.DEINE_DOMAIN</code> auf. Traefik holt beim ersten Zugriff das
Zertifikat (kann ein paar Sekunden dauern). Weil wir Datenbank und Redis schon per
Umgebungsvariablen konfiguriert haben, erkennt Nextcloud das automatisch und fragt nur
noch nach einem <strong>Administrationskonto</strong>:</p>
<p><figure class="my-6"><img src="/tutorials/nextcloud-eigene-cloud/nextcloud-setup_hu_bd390b1b06152f06.webp" srcset="/tutorials/nextcloud-eigene-cloud/nextcloud-setup_hu_54205e140ab4df51.webp 480w, /tutorials/nextcloud-eigene-cloud/nextcloud-setup_hu_bd390b1b06152f06.webp 768w, /tutorials/nextcloud-eigene-cloud/nextcloud-setup_hu_6aed3ce169effeae.webp 1200w, /tutorials/nextcloud-eigene-cloud/nextcloud-setup_hu_2dd5324525c2b322.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/nextcloud-eigene-cloud/nextcloud-setup_hu_b8b96096d363578.webp"
    alt="Der Nextcloud-Erst-Setup erkennt die Autoconfig und fragt nur noch nach Name und Passwort des Administrationskontos" title="Erst-Setup: Datenbank ist vorkonfiguriert, du legst nur das Admin-Konto an"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Erst-Setup: Datenbank ist vorkonfiguriert, du legst nur das Admin-Konto an</figcaption></figure></p>
<p>Vergib einen Admin-Namen und ein starkes Passwort und klick auf <strong>Installieren</strong>.
Nextcloud richtet die Instanz ein – danach landest du auf der Anmeldeseite:</p>
<p><figure class="my-6"><img src="/tutorials/nextcloud-eigene-cloud/nextcloud-login_hu_80e3fea49ed0fa5d.webp" srcset="/tutorials/nextcloud-eigene-cloud/nextcloud-login_hu_7b6cf30b4bed90d8.webp 480w, /tutorials/nextcloud-eigene-cloud/nextcloud-login_hu_80e3fea49ed0fa5d.webp 768w, /tutorials/nextcloud-eigene-cloud/nextcloud-login_hu_31fcd7effc10218d.webp 1200w, /tutorials/nextcloud-eigene-cloud/nextcloud-login_hu_f9021634b2859d48.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/nextcloud-eigene-cloud/nextcloud-login_hu_76d7c24abc8fef7e.webp"
    alt="Die Nextcloud-Anmeldeseite unter der eigenen HTTPS-Domain" title="Die Anmeldeseite unter cloud.DEINE_DOMAIN – mit gültigem HTTPS von Traefik"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Die Anmeldeseite unter cloud.DEINE_DOMAIN – mit gültigem HTTPS von Traefik</figcaption></figure></p>
<p>Nach dem Login begrüßt dich das <strong>Dashboard</strong>, und unter <strong>Dateien</strong> findest du deine
Cloud mit ein paar Beispieldateien:</p>
<p><figure class="my-6"><img src="/tutorials/nextcloud-eigene-cloud/nextcloud-dashboard_hu_c73d63376be11028.webp" srcset="/tutorials/nextcloud-eigene-cloud/nextcloud-dashboard_hu_8b8b0eae69ca9f5.webp 480w, /tutorials/nextcloud-eigene-cloud/nextcloud-dashboard_hu_c73d63376be11028.webp 768w, /tutorials/nextcloud-eigene-cloud/nextcloud-dashboard_hu_234eec6f42d11461.webp 1200w, /tutorials/nextcloud-eigene-cloud/nextcloud-dashboard_hu_74337e3e851cbd62.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/nextcloud-eigene-cloud/nextcloud-dashboard_hu_bb8653ade3e6bf20.webp"
    alt="Das Nextcloud-Dashboard mit dem Widget „Empfohlene Dateien&quot;" title="Das Dashboard nach dem ersten Login"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Das Dashboard nach dem ersten Login</figcaption></figure></p>
<p><figure class="my-6"><img src="/tutorials/nextcloud-eigene-cloud/nextcloud-dateien_hu_8c55170c4ab25cd1.webp" srcset="/tutorials/nextcloud-eigene-cloud/nextcloud-dateien_hu_b1b801f2689f8212.webp 480w, /tutorials/nextcloud-eigene-cloud/nextcloud-dateien_hu_8c55170c4ab25cd1.webp 768w, /tutorials/nextcloud-eigene-cloud/nextcloud-dateien_hu_2b1999b825fcf10.webp 1200w, /tutorials/nextcloud-eigene-cloud/nextcloud-dateien_hu_b18f6036e55a9058.webp 1920w" sizes="(min-width: 768px) 768px, 100vw"
    width="768" height="432"
    data-full="/tutorials/nextcloud-eigene-cloud/nextcloud-dateien_hu_eb10dcee28315b64.webp"
    alt="Die Dateien-Oberfläche von Nextcloud mit Ordnern und Beispieldateien" title="Die Dateien-App – das Herzstück deiner eigenen Cloud"
    loading="lazy" decoding="async" class="rounded-lg"><figcaption class="mt-2 text-sm text-center text-slate-500 italic">Die Dateien-App – das Herzstück deiner eigenen Cloud</figcaption></figure></p>
<h3 id="schritt-5-hintergrund-jobs-cron-einrichten">Schritt 5: Hintergrund-Jobs (Cron) einrichten</h3>
<p>Nextcloud muss regelmäßig Aufgaben erledigen (Aufräumen, Benachrichtigungen,
Vorschaubilder). Standardmäßig passiert das per „AJAX&quot; bei jedem Seitenaufruf – das ist
unzuverlässig. Der empfohlene Weg ist ein <strong>Cron-Sidecar</strong>: ein zweiter Container mit
demselben Image, der nur <code>cron.php</code> ausführt. Ergänze in der <code>compose.yaml</code> einen
Service:</p>
<div class="sk-code">
  <span class="sk-code-head">YAML</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="w">  </span><span class="nt">nc-cron</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">nextcloud:34-apache</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">nc-cron</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">entrypoint</span><span class="p">:</span><span class="w"> </span><span class="l">/cron.sh</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">depends_on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">nc-db</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">condition</span><span class="p">:</span><span class="w"> </span><span class="l">service_healthy</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">nc_html:/var/www/html</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">networks</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="l">default]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">unless-stopped</span></span></span></code></pre></div>
</div>
<p>Der Sidecar teilt sich das <code>nc_html</code>-Volume mit der App und führt die Jobs alle fünf
Minuten aus. Übernimm die Änderung und stell den Modus in Nextcloud auf „Cron&quot;:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker compose up -d
</span></span><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ background:cron</span></span></code></pre></div>
</div>
<p>Unter <strong>Verwaltung → Grundeinstellungen</strong> sollte jetzt „Cron&quot; aktiv sein.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-herb-400 bg-herb-50 dark:border-herb-700 dark:bg-herb-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">🧑‍🍳</span>occ – das Kommandozeilen-Werkzeug
  </p>
  <div class="prose-kitchen text-sm"><p><code>occ</code> ist Nextclouds Admin-Werkzeug. Du rufst es immer als Nutzer <code>www-data</code> im
App-Container auf: <code>docker exec -u www-data nc-app php occ &lt;befehl&gt;</code>. Zwei nützliche
Aufräum-Befehle direkt nach der Installation:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ db:add-missing-indices
</span></span><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ config:system:set default_phone_region --value<span class="o">=</span>DE</span></span></code></pre></div>
</div></div>
</div>
<h3 id="schritt-6-die-clients-verbinden">Schritt 6: Die Clients verbinden</h3>
<p>Jetzt der eigentliche Nutzen. Es gibt drei Wege, deine Cloud zu benutzen:</p>
<ol>
<li><strong>Desktop-Sync-Client</strong> (Windows/macOS/Linux): Installiere den „Nextcloud Desktop&quot;-
Client, gib als Server-Adresse <code>https://cloud.DEINE_DOMAIN</code> ein, melde dich an und
wähle einen lokalen Ordner. Dateien werden wie bei Dropbox synchronisiert.
Mit den <strong>virtuellen Dateien</strong> (Windows/macOS) belegen sie erst dann Platz auf der
Platte, wenn du sie öffnest – praktisch, wenn deine Cloud größer ist als die lokale
Festplatte.</li>
<li><strong>Handy-App</strong> (Android/iOS): die offizielle Nextcloud-App, gleiche Server-Adresse.
Ideal für den automatischen <strong>Foto-Upload</strong> vom Smartphone.</li>
<li><strong>Kalender &amp; Kontakte:</strong> In den Systemeinstellungen deines Geräts ein CalDAV-/
CardDAV-Konto mit der Adresse <code>https://cloud.DEINE_DOMAIN</code> anlegen – dank der
<code>.well-known</code>-Middleware aus Schritt 3 funktioniert die automatische Erkennung.</li>
</ol>
<p>Funktionen wie Kalender, Kontakte oder Mail sind eigene <strong>Apps</strong>, die du unter
<strong>Verwaltung → Apps</strong> mit einem Klick nachinstallierst – Nextcloud ist also erweiterbar,
ohne dass du am Server etwas anfassen musst.</p>
<div class="not-prose my-6 rounded-lg border-l-4 p-4 border-amber-400 bg-amber-50 dark:border-amber-700 dark:bg-amber-900/20">
  <p class="mb-1 flex items-center gap-2 font-semibold text-slate-900 dark:text-white">
    <span aria-hidden="true">⚠️</span>Nicht mit dem Admin-Konto arbeiten
  </p>
  <div class="prose-kitchen text-sm">Das Administrationskonto aus Schritt 4 ist für die <strong>Verwaltung</strong> gedacht, nicht für den
Alltag. Leg dir unter <strong>Verwaltung → Konten</strong> ein normales Nutzerkonto an und synchronisiere
deine Dateien darüber. So ist dein mächtiges Admin-Konto nicht ständig auf allen Geräten
angemeldet – ein einfacher, aber wirksamer Sicherheitsgewinn. Für Familie oder Team legst
du hier weitere Konten an; jedes bekommt seinen eigenen, verschlüsselten Bereich.</div>
</div>
<h2 id="wenn-es-nicht-funktioniert">Wenn es nicht funktioniert</h2>
<p><strong>Symptom:</strong> „<strong>Zugriff über eine nicht vertrauenswürdige Domäne</strong>&quot; statt der Login-Seite.</p>
<p><strong>Ursache &amp; Lösung:</strong> Deine Domain steht nicht in <code>trusted_domains</code>. Prüfe
<code>NEXTCLOUD_TRUSTED_DOMAINS</code> in der Compose-Datei. Nachträglich setzen geht per occ:
<code>docker exec -u www-data nc-app php occ config:system:set trusted_domains 1 --value=cloud.DEINE_DOMAIN</code>.</p>
<p><strong>Symptom:</strong> Der Sicherheits-Check meldet „<strong>Your web server is not set up properly to
resolve .well-known/caldav</strong>&quot;.</p>
<p><strong>Ursache &amp; Lösung:</strong> Der CalDAV/CardDAV-Redirect greift nicht. Kontrolliere die
<code>nc-dav</code>-Middleware-Labels (Schritt 3) und dass der Router sie über
<code>...routers.nc.middlewares=nc-dav</code> einbindet. Das Regex muss die volle
<code>https://…</code>-URL matchen – <code>redirectregex</code> prüft die komplette URL, nicht nur den Pfad.</p>
<p><strong>Symptom:</strong> Warnung „<strong>The &lsquo;Strict-Transport-Security&rsquo; HTTP header is not set</strong>&quot;.</p>
<p><strong>Ursache &amp; Lösung:</strong> Der HSTS-Header fehlt. Setz ihn als Traefik-Middleware und häng sie
an den Router:
<code>traefik.http.middlewares.nc-secure.headers.stsSeconds=15552000</code>. Häng sie zusätzlich zur
<code>nc-dav</code>-Middleware an den Router (<code>...routers.nc.middlewares=nc-dav,nc-secure</code>). Der Header
muss vom Proxy kommen, nicht von Nextcloud. In
<a href="/tutorials/nextcloud-optimieren-absichern/">Teil 2</a> richten wir genau diese
<code>nc-secure</code>-Middleware vollständig ein (inklusive <code>includeSubdomains</code>).</p>
<p><strong>Symptom:</strong> Große Uploads brechen ab oder enden mit einem Timeout / „413&quot;.</p>
<p><strong>Ursache &amp; Lösung:</strong> Das PHP-Limit ist zu klein. Erhöhe <code>PHP_UPLOAD_LIMIT</code> und
<code>PHP_MEMORY_LIMIT</code> (Schritt 3) und starte den Container neu. In seltenen Fällen greifen
diese Variablen nicht – dann ein eigenes <code>php.ini</code>-Snippet ins Image mounten.</p>
<p><strong>Symptom:</strong> Beim ersten Start bricht die Installation mit „<strong>MySQL server has gone
away</strong>&quot; oder „Connection refused&quot; ab.</p>
<p><strong>Ursache &amp; Lösung:</strong> Der App-Container war schneller als die Datenbank. Genau dagegen
ist der <code>healthcheck</code> mit <code>depends_on: condition: service_healthy</code> da – prüfe, dass beide
in deiner Compose-Datei vorhanden sind, und starte mit <code>docker compose up -d</code> neu.</p>
<h2 id="wartung--backups">Wartung &amp; Backups</h2>
<ul>
<li>
<p><strong>Backups sind bei einer Cloud Pflicht.</strong> Ein konsistentes Backup braucht <strong>drei
Dinge</strong>: die <strong>Datenbank</strong> (MariaDB-Dump), das <strong>Datenverzeichnis</strong> (deine Dateien) und
die <strong>Konfiguration</strong> (<code>config.php</code>). Versetze Nextcloud vor dem Backup kurz in den
Wartungsmodus, damit Datenbank und Dateien zueinander passen:</p>
<div class="sk-code">
  <span class="sk-code-head">Terminal</span>
  <div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ maintenance:mode --on
</span></span><span class="line"><span class="cl">docker <span class="nb">exec</span> nc-db mariadb-dump -u root -pEIN_STARKES_ROOT_PASSWORT nextcloud &gt; nextcloud-db.sql
</span></span><span class="line"><span class="cl">docker <span class="nb">exec</span> -u www-data nc-app php occ maintenance:mode --off</span></span></code></pre></div>
</div>
<p>Sichere den Dump zusammen mit dem <code>nc_html</code>-Volume <strong>verschlüsselt und off-site</strong> mit
<a href="/tutorials/backups-mit-restic/">Restic</a> – das rohe <code>nc_db</code>-Volume musst du dank des
Dumps nicht zusätzlich sichern. Im <code>nc_html</code>-Volume stecken sowohl der
Programmcode und die <code>config.php</code> als auch – unter <code>data/</code> – <strong>deine eigentlichen
Nutzerdateien</strong>. Wächst deine Cloud stark, kannst du dieses <code>data/</code>-Verzeichnis später
auf ein eigenes, größeres Volume auslagern; fürs erste reicht ein Volume für alles.</p>
</li>
<li>
<p><strong>Updates: immer nur eine Hauptversion pro Schritt.</strong> Von 34 auf 35, nie direkt auf 36.
Setz den Image-Tag hoch (<code>nextcloud:35-apache</code>), dann <code>docker compose pull</code> und
<code>docker compose up -d</code>. Der Container führt das nötige <code>occ upgrade</code> beim Start
<strong>automatisch</strong> aus. <strong>Vorher immer ein Backup</strong> anlegen. Den Cron-Sidecar auf dieselbe
Version heben.</p>
</li>
<li>
<p><strong>Sicherheit prüfen.</strong> Lass nach dem Aufsetzen den offiziellen
<a href="https://scan.nextcloud.com/">Nextcloud Security Scan</a> gegen deine Domain laufen (Ziel:
Note A) und arbeite die Warnungen aus der Admin-Übersicht ab. Die Übersicht unter
<strong>Verwaltung → Übersicht</strong> führt automatische Prüfungen durch und zeigt genau, was noch
fehlt. Halte Nextcloud aktuell – Sicherheitslücken werden zeitnah geschlossen, aber nur,
wenn du updatest.</p>
</li>
<li>
<p><strong>Ehrlich zum Aufwand:</strong> Eine selbst gehostete Cloud will gepflegt werden. Rechne mit
einem Update-Durchgang etwa monatlich und einem regelmäßigen Blick in die
Admin-Übersicht. Dafür gehören die Daten dann wirklich dir.</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>