Mini-VPS optimiert mit Claude Code
Als mein kleiner VPS heute Morgen einfach einfror und ich ihn neu starten musste, beschloss ich, das Problem endlich richtig anzugehen — gemeinsam mit Claude Code direkt im Terminal.
Der Patient
Ein kleiner VPS mit 1 CPU, 896 MB RAM, 10 GB Disk. Drauf läuft ein nginx Reverse-Proxy, der ein knappes Dutzend Dienste nach außen exponiert: Blogs, ein Mastodon-Server, ein paar Kollaborationstools. Leichte Kost — eigentlich.
Die Diagnose
Claude hat sofort den Finger in die Wunde gelegt:
- Kein Swap — beim ersten RAM-Engpass friert das System ein, statt langsam zu werden
- RAM: 71 MB frei bei 896 MB gesamt
- Hauptverbraucher: Node.js (90 MB), diverse Systemdienste,
und snapd — das auf einem Server schlicht nichts verloren hat
Was wir gemeinsam erledigt haben
1. Swap einrichten
2 GB Swap-Datei angelegt, in /etc/fstab eingetragen. Der Server überlebt jetzt RAM-Spitzen, statt einzufrieren. Sofortiger Effekt.
2. snapd aufräumen
Erst geprüft, ob snapd wirklich genutzt wird — tatsächlich war hugo als Snap installiert. Nach Installation via apt konnte snapd sauber entfernt werden. Ergebnis: ~140 MB RAM wieder frei.
3. Nginx Security-Headers verifiziert
Alle 17 vhosts geprüft: X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security, Referrer-Policy — überall gesetzt, teils via zentralem Snippet, teils direkt. Kein vhost ohne Headers.
4. fail2ban von 1 auf 4 Jails erweitert
Vorher: nur SSH, mit schwachen Defaults (10 Minuten Ban nach 5 Versuchen).
Jetzt:
- sshd — maxretry 3, Ban 24 Stunden
- nginx-http-auth — Brute-Force auf Login-Seiten
- nginx-botsearch — Scanner die nach
/wp-admin,/.envetc. suchen - nginx-bad-request — Garbage-Requests und fehlerhafte HTTP-Anfragen
Dazu Increment-Banning: Wer wiederkommt, wird progressiv länger gesperrt — 1h → 2h → 4h → bis zu einer Woche.
Kleines Detail das uns fast entgangen wäre: die nginx-Jails lasen gar keine Logs, weil backend = systemd gesetzt war — nginx schreibt aber in Dateien, nicht ins Journal. Nach dem Fix auf backend = auto wurden sofort 6 Log-Dateien überwacht und erste Treffer gezählt.
5. Disk von 87 % auf 78 % befreit
Das systemd-Journal hatte ohne Limit 885 MB angesammelt. Nach journalctl --vacuum-size=200M und einem dauerhaften Limit in journald.conf.d/size.conf waren ~700 MB auf einen Schlag weg.
Das Ergebnis
| Vorher | Nachher |
|---|---|
| Kein Swap → System friert ein | 2 GB Swap, persistent |
| 71 MB RAM frei | ~220 MB frei |
| 1 fail2ban-Jail, schwache Defaults | 4 Jails, Increment-Banning |
| Disk 87 % voll | Disk 78 %, Journal limitiert |
| snapd läuft ungenutzt | sauber entfernt |
Was mich begeistert hat
Claude hat nicht einfach Befehle rausgefeuert. Es wurde immer erst geprüft — läuft hugo wirklich über snap? Liest der Jail wirklich die richtigen Log-Dateien? Warum zeigt nginx-bad-request keine Treffer?
Jeder Schritt wurde erklärt, jede Änderung begründet. Das Ergebnis ist kein Cargo-Cult-Serversetup, sondern eines das ich verstehe und selbst weiterentwickeln kann.
Ein kleiner VPS, ein Vormittag, ein deutlich besserer Server.
Ich bin wirklich begeistert.