Neun Dienste auf 1 GB RAM: Wann bricht der Mini-Server?
WordPress und fünf kleine Dienste liefen auf 1 GB RAM mit Swap ohne Mühe, Nextcloud mit App-Passwort auch. Mit Kontopasswort kippte Nextcloud den ganzen Server. Paperless-ngx füllte den Swap, mit Jellyfin brach WordPress ein.
Mit KI erstellt – redaktionelle Prüfung ausstehend
Werbung Mit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Wie viele Dienste passen auf einen Server mit 1 GB RAM, bevor er bricht? Diese Anleitung nimmt einen netcup VPS piko G11s mit einer vCPU, richtet ihn so ein, wie es die bisherigen Teile der Reihe empfehlen, und legt Dienst für Dienst nach: WordPress, Uptime Kuma, Vaultwarden, ntfy, AdGuard Home, Forgejo, Nextcloud, Paperless-ngx und Jellyfin. Nach jedem Dienst lief zehn Minuten lang eine gemischte Last auf alle bis dahin gestarteten Dienste.
Dies ist Teil 7 der Reihe „Mini-Server“. Die Grundlage sind die Swapdatei aus Teil 5 und die Speichergrenzen aus Teil 6.
Was Sie brauchen
- Einen Linux-Server mit Docker und 1 GB RAM, hier der Mini-Server aus Teil 1, mit der Swapdatei aus Teil 5.
- WordPress mit Speichergrenzen und 8 Apache-Prozessen wie in Teil 6, die kleinen Dienste wie in Teil 4.
- Für die Messung einen zweiten Rechner mit k6 als Lastgenerator wie in Teil 2. Lasttests nur auf eigenen Systemen.
Schritt 1: Alle Dienste in ein Compose-Projekt
Alle Dienste laufen in einem Compose-Projekt hinter einem Caddy, so wie WordPress in Teil 3. compose.yaml enthält WordPress mit den Speichergrenzen und den 8 Apache-Prozessen aus Teil 6. Jeder weitere Dienst bekommt eine eigene kleine Datei, zum Beispiel s5.yaml für Forgejo:
services:
forgejo:
image: codeberg.org/forgejo/forgejo:17.0.1
restart: unless-stopped
environment:
USER_UID: "1000"
USER_GID: "1000"
FORGEJO__database__DB_TYPE: sqlite3
FORGEJO__server__ROOT_URL: https://mini.example.com:8447/
FORGEJO__server__DISABLE_SSH: "true"
FORGEJO__security__INSTALL_LOCK: "true"
FORGEJO__service__DISABLE_REGISTRATION: "true"
volumes: [./forgejo:/data]Caddy leitet je Port an einen Dienst weiter, WordPress bleibt auf Port 443, die übrigen Dienste bekamen die Ports 8443 bis 8450. Uptime Kuma zog dafür von 443 auf 8446. Caddy muss die Ports veröffentlichen, im Dienst caddy in compose.yaml:
services:
caddy:
ports: ["80:80", "443:443", "8443-8450:8443-8450"]Für Forgejo sieht der Eintrag im Caddyfile so aus:
mini.example.com:8447 {
reverse_proxy forgejo:3000
}Damit Compose alle Dateien kennt, auch bei ps und exec, tragen Sie die Liste in die Datei .env neben compose.yaml ein und starten den neuen Dienst einzeln:
# echo 'COMPOSE_FILE=compose.yaml:s1.yaml:s2.yaml:s3.yaml:s4.yaml:s5.yaml' > .env
# docker compose up -d forgejoForgejo hat danach noch kein Konto, die Registrierung ist abgeschaltet. Das erste Konto legen Sie im Container an:
# docker compose exec -u 1000 forgejo forgejo admin user create --admin --username NAME --email ADRESSE --random-passwordDie neuen Dienste liefen im Test ohne Speichergrenze, weil eine geschätzte Grenze die Messung verfälscht hätte.
Verifizieren: docker compose ps zeigt den neuen Dienst mit Status Up, und er antwortet über seinen Port.
Schritt 2: Nach jedem Dienst den Speicher prüfen
Nach jedem neuen Dienst sehen Sie sich drei Werte an: den verfügbaren Speicher, den belegten Swap und den Speicherdruck.
# free -m
# cat /proc/pressure/memory /proc/pressure/cpuWichtig: docker stats zeigt nur den Teil eines Containers, der im RAM liegt. Was ausgelagert ist, fehlt dort. Den Swap eines Containers lesen Sie im cgroup-Verzeichnis, hier für Paperless-ngx:
# cat /sys/fs/cgroup/system.slice/docker-$(docker compose ps -q paperless).scope/memory.swap.currentVerifizieren: So sah free -m nach der Stufe mit Paperless-ngx aus, der Swap war zu 944 von 1.023 MiB belegt:
total used free shared buff/cache available
Mem: 957 793 81 35 258 164
Swap: 1023 944 79docker stats zeigte für Paperless-ngx zur selben Zeit nur 91 MiB. Ausgelagert waren bei Paperless-ngx in dieser Stufe bis zu 484 MiB.
Schritt 3: Nextcloud mit App-Passwort anbinden
Nextcloud prüft bei jeder Anmeldung mit dem Kontopasswort einen aufwendigen Passwort-Hash. Synchronisations-Programme und WebDAV-Clients sollten deshalb ein App-Passwort bekommen. Sie legen es im Browser unter Persönliche Einstellungen, Sicherheit an oder auf der Kommandozeile:
# docker compose exec -u www-data nextcloud php occ user:auth-tokens:add adminDer Befehl fragt nach dem Anmeldepasswort des Benutzers und gibt danach das App-Passwort einmal aus. Im Test lief er ohne Eingabe durch, das App-Passwort funktionierte für WebDAV. Es ersetzt im Client das Kontopasswort.
Verifizieren: Eine WebDAV-Abfrage des Benutzerordners dauerte auf dem ruhigen Server mit dem Kontopasswort 0,64 bis 0,71 Sekunden, der erste Aufruf 2,5 Sekunden, mit dem App-Passwort 0,15 bis 0,19 Sekunden:
# curl -s -o /dev/null -w '%{http_code} %{time_total}\n' -X PROPFIND -H 'Depth: 1' -u 'admin:APP-PASSWORT' https://mini.example.com:8448/remote.php/dav/files/admin/207 0.181994
207 0.153390
207 0.185901
207 0.192526
207 0.172018So wurde gemessen
Der Server startete für jeden Lauf neu, mit Swapdatei, WordPress, MariaDB und Caddy. Im ersten vollständigen Lauf kam alle 13 Minuten ein Dienst dazu: drei Minuten ohne Last zum Einschwingen, danach zehn Minuten Messung. In den Wiederholungen kamen die Dienste bis zur gemessenen Stufe im Abstand von einer Minute ohne Last dazu. Die Reihenfolge stand vorher fest: Uptime Kuma mit den Monitoren aus Teil 4, Vaultwarden, ntfy, AdGuard Home, Forgejo mit einem Repository, Nextcloud mit eigener Datenbank in der MariaDB von WordPress, Paperless-ngx mit Redis und leerer Ablage, Jellyfin ohne Mediathek.
k6 schickte vom zweiten Server gleichzeitig eine Mischlast auf alle laufenden Dienste: WordPress 2 Aufrufe pro Sekunde, Nextcloud, Forgejo, Paperless-ngx, Jellyfin und Vaultwarden je einen alle zwei Sekunden, Uptime Kuma einen alle fünf Sekunden, ntfy eine Nachricht alle zehn Sekunden. AdGuard Home bekam ab seiner Stufe 20 DNS-Anfragen pro Sekunde. Ein Skript auf dem Server schrieb alle 2 Sekunden Speicher, Swap, Druck und den Speicher jedes Containers mit.
Als Bruch galt vorher festgelegt: ein OOM-Kill, WordPress-Antwortzeit p95 über 2 Sekunden, ein Dienst mit mehr als 5 % Fehlern oder ein Ausfall von SSH. Die Stufen 0 bis 4 liefen einmal, Stufe 5 zweimal, Stufe 6 fünfmal in verschiedenen Varianten (Ergebnis 2), Stufe 7 zweimal und Stufe 8 einmal. Die Wiederholung von Stufe 7 brach nach der Regel, deshalb lief Stufe 8 kein zweites Mal.
Ergebnis 1: Dienst für Dienst

| Stufe | WordPress p95 | Verfügbar (Median) | Swap belegt | Bruch |
|---|---|---|---|---|
| WordPress | 240 ms | 408 MiB | 0 MiB | nein |
| + Uptime Kuma | 263 ms | 341 MiB | 97 MiB | nein |
| + Vaultwarden | 275 ms | 396 MiB | 156 MiB | nein |
| + ntfy | 288 ms | 379 MiB | 158 MiB | nein |
| + AdGuard Home | 313 ms | 297 MiB | 163 MiB | nein |
| + Forgejo | 360 ms / 378 ms | 228 / 221 MiB | 251 / 264 MiB | nein, zwei Läufe |
| + Nextcloud (App-Passwort) | 625 ms | 161 MiB | 395 MiB | nein |
| + Paperless-ngx | 1.644 ms / Zeitlimit 10 s, 10 % Fehler | 156 / 154 MiB | 941 / 943 MiB | knapp nein / ja |
| + Jellyfin | Zeitlimit 10 s, 27 % Fehler | 139 MiB | 1.023 MiB | ja, ein Lauf |
Bis Forgejo blieb alles entspannt: Der verfügbare Speicher sank von 408 auf rund 230 MiB, der Swap stieg auf rund 250 MiB, und WordPress wurde nur um 120 bis 140 ms langsamer. Die Stufe mit Forgejo lief zweimal mit fast gleichem Ergebnis. Ausgelagert wurde in diesen Stufen vor allem MariaDB, bis zu 96 MiB. Uptime Kuma belegte allein bis zu 206 MiB RAM.
Mit Nextcloud stieg der Swap auf rund 400 MiB, WordPress lag bei 625 ms. Paperless-ngx war der Wendepunkt: Der Container lagerte bis zu 484 MiB aus, der Swap war fast voll, WordPress lag über das ganze Messfenster bei 1,6 Sekunden (p95) und Paperless-ngx selbst bei 1,7 Sekunden. In beiden Läufen kamen die meisten langsamen Antworten in den ersten zwei Minuten nach der ruhigen Phase. In der Wiederholung scheiterten in diesen zwei Minuten fast alle WordPress-Aufrufe, danach lief die Stufe fehlerfrei mit 0,8 bis 1,4 Sekunden. Über das ganze Messfenster waren das 10 % Fehler, nach der vorher festgelegten Regel ein Bruch. Mit Jellyfin war der Swap voll. Damit war Schluss: 27 % der WordPress-Aufrufe scheiterten, die meisten zwischen Minute 5 und 8 der Messung, die CPU war zu 89 % belegt, der Speicherdruck lag bei bis zu 37 %. Die übrigen Dienste antworteten langsam, aber fast fehlerfrei. Ein OOM-Kill gab es nicht.
DNS über AdGuard Home verlor in allen Stufen außer den Zusammenbrüchen in Ergebnis 2 gleichmäßig 4,4 bis 5,2 % der Anfragen, auch ohne Speicherdruck. Dieser Grundwert fließt nicht in die Wertung ein.
Ergebnis 2: Nextcloud und die Anmeldung

Im ersten Durchgang schickte jede WebDAV-Abfrage das Kontopasswort mit. Ab der zweiten Minute unter Last scheiterten fast alle Aufrufe an allen Diensten, nicht nur an Nextcloud. Der Nextcloud-Container wuchs auf über 700 MiB RAM und über 600 MiB Swap, der Swap des Servers lief voll, und der Kernel beendete im Messfenster drei und vier Prozesse, darunter Uptime Kuma und im zweiten Lauf MariaDB. Im ersten Lauf fing sich der Server erst gut 20 Minuten nach dem Ende der Last von selbst, insgesamt hatte der Kernel bis dahin 12 Prozesse beendet. Im zweiten Lauf wurde er kurz nach der Messung neu gestartet.
Zwei Gegenproben, je einmal gelaufen, zeigen die Ursache. Ohne Last auf Nextcloud lief dieselbe Stufe ohne einen Fehler. Mit App-Passwort statt Kontopasswort lief sie ohne Bruch: WordPress ohne Fehler bei 625 ms, Nextcloud 508 ms mit 0,7 % Fehlern in der ersten Minute, kein OOM-Kill. Gekippt hat den Server in diesen Läufen also nicht Nextcloud selbst, sondern die Last mit Kontopasswort. Auf dem ruhigen Server dauerte jede Abfrage damit rund eine halbe Sekunde länger als mit App-Passwort. Im Zusammenbruch stieg die Zahl der Apache-Prozesse auf bis zu 81, die meisten davon im Nextcloud-Container, dessen Image ohne Anpassung bis zu 150 zulässt, wie das WordPress-Image vor Teil 6.
Nextcloud mit Speichergrenze von 384 MiB und 8 Apache-Prozessen wie WordPress in Teil 6 hielt den Server bei Kontopasswort zwar am Leben: kein OOM-Kill, SSH erreichbar, die kleinen Dienste ohne Fehler. WordPress scheiterte über das Messfenster zu 9,5 %, alle Fehler fielen aber in die ersten zwei Minuten nach der ruhigen Phase, danach antwortete WordPress fehlerfrei mit 0,9 bis 1,8 Sekunden. Dieser Lauf fand einmal statt.
Ergebnis 3: Was jeder Dienst belegt
| Dienst | RAM in seiner Stufe | RAM plus Swap mit allen Diensten |
|---|---|---|
| Paperless-ngx | 356 MiB | 585 MiB |
| Jellyfin | 96 MiB | 181 MiB |
| Forgejo | 215 MiB | 174 MiB |
| Nextcloud (App-Passwort) | 133 MiB | 160 MiB |
| Uptime Kuma | 206 MiB | 146 MiB |
| WordPress | 153 MiB | 121 MiB |
| MariaDB | 142 MiB | 121 MiB |
| AdGuard Home | 91 MiB | 87 MiB |
| Caddy | 58 MiB | 39 MiB |
| Vaultwarden | 49 MiB | 32 MiB |
| ntfy | 51 MiB | 28 MiB |
| Redis (für Paperless-ngx) | 5 MiB | 8 MiB |
Die erste Spalte zeigt den höchsten RAM-Wert in der Stufe, in der der Dienst dazukam, also bevor spätere Dienste ihn verdrängten. Die zweite zeigt RAM und Swap zusammen, zur gleichen Zeit gemessen, in der Stufe mit allen Diensten. Paperless-ngx ist mit Abstand der größte Posten, obwohl die Ablage leer war. Uptime Kuma, Forgejo, Nextcloud und Jellyfin lagen bei 150 bis 180 MiB, Vaultwarden und ntfy unter 35 MiB.
Was das für Ihren Server heißt
Auf 1 GB RAM mit Swapdatei passen WordPress und eine Handvoll kleiner Dienste wie Uptime Kuma, Vaultwarden, ntfy, AdGuard Home und Forgejo bequem. Nextcloud passt noch, wenn alle Clients App-Passwörter verwenden. Mit Paperless-ngx ist die Grenze erreicht, Jellyfin dazu ist zu viel: Der Swap läuft voll, und der Server wird langsam, ohne dass der OOM-Killer eingreift.
Behalten Sie den Swap im Auge. Solange er unter rund 400 MiB blieb, antwortete WordPress unter 700 ms. Ab 900 MiB wurde es eng. Der Speicherdruck in /proc/pressure/memory zeigt es ebenfalls: In den ruhigen Stufen blieb some avg10 stets unter 15 %, ab Paperless-ngx erreichte er Spitzen von 26 bis 40 %. Rechnen Sie außerdem damit, dass ein Server mit vollem Swap nach einer ruhigen Phase ein bis zwei Minuten braucht, bis er wieder flüssig antwortet.
Typische Fehler
- Nach dem Start von Nextcloud antworten alle Dienste nicht mehr
Prüfen Sie, ob Clients sich mit dem Kontopasswort anmelden. Legen Sie für jeden Client ein App-Passwort an wie in Schritt 3. Begrenzen Sie außerdem die Apache-Prozesse von Nextcloud wie bei WordPress in Teil 6.
docker statszeigt wenig Speicher, trotzdem ist der Server volldocker statszählt den Swap nicht mit. Lesen Siememory.swap.currentwie in Schritt 2 und den Swap infree -m.- ntfy antwortet mit HTTP 429
ntfy erlaubt je Absender standardmäßig 60 Anfragen auf einmal und danach eine alle 5 Sekunden. Im Test lehnte es bei einer Nachricht pro Sekunde von derselben Adresse rund 70 % ab. Das ist kein Speicherproblem. Schicken Sie seltener oder nehmen Sie eigene Absender mit
visitor-request-limit-exempt-hostsin derserver.ymlaus.
Häufige Fragen
Warum hatten die neuen Dienste keine Grenzen?
Weil eine geschätzte Grenze die Messung verfälscht hätte. Für eigene Grenzen nehmen Sie RAM plus Swap aus der Tabelle in Ergebnis 3 als Untergrenze.
Zählt die leere Ablage bei Paperless-ngx?
Ja, die Werte gelten für eine leere Ablage ohne Dokumente in Verarbeitung.
Fazit
Ein Mini-Server mit 1 GB RAM, Swapdatei und Grenzen für WordPress trägt mehr, als man denkt: WordPress und fünf kleine Dienste liefen ohne Mühe, Nextcloud mit App-Passwörtern ebenfalls. Die Grenze kam mit Paperless-ngx und Jellyfin, und sie kam als volle Swapdatei und langsame Antworten, nicht als Absturz. Gefährlicher war ein einzelner Fehler in der Einrichtung: Nextcloud mit Kontopasswort brachte den Server schon in Stufe 6 komplett zum Stehen. Im letzten Teil der Reihe folgt die Bilanz: was auf 1 GB sinnvoll passt und was nicht.
Weiterführende Anleitungen und Quellen
- Mini-Server Teil 1: Was bleibt von 1 GB RAM übrig?
- Mini-Server Teil 2: Wie viele Aufrufe schafft ein Kern?
- Mini-Server Teil 3: WordPress auf 1 GB RAM
- Mini-Server Teil 4: Vier kleine Dienste auf 1 GB RAM
- Mini-Server Teil 5: Swap, zram oder nichts?
- Mini-Server Teil 6: Speichergrenzen für Docker-Container
- Nextcloud: occ-Befehle
- Paperless-ngx: Konfiguration
- Forgejo mit Docker
- Jellyfin im Container
- Linux-Kernel: Pressure Stall Information


