> ## Content Index
> Fetch the complete content index at: https://cubem.de/llms.txt
> Use this file to discover other available public pages before exploring further.

# 02. Debian 13 auf dem VPS sicher einrichten: SSH, Benutzer, Firewall
- URL: https://cubem.de/02-debian-13-auf-dem-vps-sicher-einrichten-ssh-benutzer-firewall/
- Published: 2026-11-12T08:14:17.000Z
- Updated: 2026-11-12T08:14:16.000Z
- Description: Ein frisch gemieteter Server ist noch kein sicherer Server. Eigener Benutzer, Anmeldung per Schlüssel, Firewall und automatische Sicherheitsupdates – das Fundament in einem Durchgang, mit Prüfschritten nach jedem Abschnitt.
- Author: martin
- Tags: VPS Edition, Self-Hosting 2027, Grundlagen, Debian, Sicherheit

\*Stand: November 2026

Ein frisch installierter VPS ist schnell verfügbar. Das heißt aber noch nicht, dass er sinnvoll oder sicher eingerichtet ist. In den ersten Minuten nach der Installation legst du fest, ob dein System später ruhig wartbar bleibt – oder ob du dir mit kleinen Versäumnissen dauerhaft Komplexität einhandelst.

Dieser Beitrag baut bewusst nur das Fundament: Debian 13 installieren, SSH per Schlüssel einrichten und eine saubere Linux-Basis herstellen. Keine Anwendungen, kein Docker, kein Webserver – das kommt in den nächsten Artikeln. Diese Basis soll später möglichst unverändert bleiben.

[ Neu in der Reihe? Hier geht's los ](https://cubem.de/self-hosting/)  
[ Hardware & Setup dieser Serie ](https://cubem.de/mein-setup) 

## Am Ende hast du

- Debian 13 (Trixie) installiert und aktualisiert
- Einen normalen Benutzer eingerichtet (Beispiel: `martin`) mit UID 1000
- SSH-Zugriff ohne Passwort, nur per Schlüssel – unter einem eigenen Schlüsselnamen, der vorhandene Schlüssel nicht überschreibt
- Eine benannte Verbindung: `ssh vps` statt IP und Benutzername
- Die Passphrase deines Schlüssels im Schlüsselbund – eingegeben wird sie einmal, danach nicht mehr
- Verstanden, was beim ersten SSH-Login passiert (Host-Key, Passphrase)
- Basispakete installiert, Zeitzone und Locale gesetzt
- SSH gehärtet, Firewall aktiviert, automatische Sicherheitsupdates konfiguriert

## Voraussetzungen

- VPS mit öffentlicher IPv4
- Zugriff auf das Provider-Panel (Installation, SSH-Key-Hinterlegung)
- macOS, Linux oder Windows mit Terminal / SSH-Client

> **Getestet mit:** Debian 13 (Trixie) · macOS als Rechner
> 
> **Zuletzt durchgespielt:** 05.11.2026 auf einem frisch installierten VPS 500 G12 bei Netcup

## 1\. SSH-Key lokal erstellen (ed25519)

SSH arbeitet mit einem Schlüsselpaar:

- **Private Key:** bleibt auf deinem Rechner. Er ist dein Zugang.
- **Public Key:** wird auf dem Server hinterlegt. Er erlaubt genau deinem Private Key den Login.

Das ist der entscheidende Unterschied zu Passwörtern: Der Server muss kein Passwort akzeptieren, das jemand erraten könnte. Er akzeptiert nur den Nachweis, dass du den passenden Schlüssel besitzt.

### Key erzeugen

Auf deinem lokalen Rechner:

```bash
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519_vps -C "martin@vps"

```

- **Passphrase:** unbedingt setzen

> **Warum ein eigener Dateiname?**
> 
> Ohne `-f` legt `ssh-keygen` immer `~/.ssh/id_ed25519` an. Liegt dort schon ein Schlüssel – für eine NAS, einen anderen Server, einen Git-Dienst –, fragt das Programm, ob es ihn überschreiben soll. Ein Ja an dieser Stelle lässt sich nicht rückgängig machen: Der alte Schlüssel ist weg, und mit ihm der Zugang zu allem, was ihn kannte. Ein sprechender Name pro Ziel kostet nichts und schließt diesen Fehler aus.

> **Warum eine Passphrase wichtig ist**
> 
> Die Datei mit dem Private Key ist der Zugang zu deinem Server – wer sie hat, ist drin. Geht dein Rechner verloren oder wird gestohlen, oder landet der Schlüssel irgendwann unbemerkt woanders, weil `~/.ssh` in einem Cloud-Ordner liegt oder auf einer alten Sicherungsplatte mitgelaufen ist, dann ist die Passphrase das Einzige, was noch dazwischensteht. Sie ist der zweite Schutz hinter dem Schlüssel selbst. Tippen musst du sie nur einmal: In Abschnitt 4.1 landet sie im Schlüsselbund deines Rechners.

Danach existieren:

- `~/.ssh/id_ed25519_vps` (Private Key – **niemals** teilen!)
- `~/.ssh/id_ed25519_vps.pub` (Public Key – dieser kommt auf den Server)

**Check**

```bash
ls -l ~/.ssh/id_ed25519_vps*

```

*Ausgabe:* zwei Dateien – `id_ed25519_vps` und `id_ed25519_vps.pub`.

## 2\. Public Key ≠ Fingerprint

Hier passieren die meisten Anfängerfehler, weil die Begriffe ähnlich wirken.

**Fingerprint (nicht für Login geeignet)**

Beispiel:

```
SHA256:abc123def456...

```

Das ist nur eine Prüfsumme zur Kontrolle. Damit loggst du dich nicht ein.

**Public Key (das, was der Server braucht)**

Den Public Key gibst du ins Provider-Panel oder kopierst ihn auf den Server:

```bash
cat ~/.ssh/id_ed25519_vps.pub

```

Er beginnt typischerweise mit:

```
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5... martin@vps

```

> **Merksatz**
> 
> Ein SSH-Key beginnt mit `ssh-ed25519`. Alles, was mit `SHA256:` beginnt, ist ein Fingerprint, kein Login-Key.

**Check**

Wenn deine Ausgabe mit `ssh-ed25519` beginnt, hast du den richtigen Inhalt zum Hinterlegen.

## 3\. Debian 13 installieren

> **`martin`** steht in dieser Reihe überall für deinen eigenen Benutzernamen. Du legst ihn gleich bei der Installation fest und setzt ihn ab dann überall dort ein, wo `martin` steht – in Befehlen, Dateien und Pfaden wie `/home/martin`.

### Option A: Provider mit SSH-Key-Support (z. B. Netcup, Hetzner)

Benutzer und Public Key werden hier schon während der Installation angelegt. Du kommst also gleich beim ersten Login als dein eigener Benutzer per Schlüssel auf den Server, ohne vorher als `root` etwas einrichten zu müssen.

Das sind zwei getrennte Vorgänge: Den Schlüssel legst du einmalig in deinem Konto ab, bei der Installation wählst du ihn nur noch aus. Bei Netcup im Server Control Panel (SCP) hat er dafür einen **eigenen Menüpunkt ganz oben im Menü**, nicht etwa ein Feld im Installationsdialog.

![](https://cubem.de/content/images/2026/11/01-netcup-scp-servers.webp)

**Schritt 1: Den Schlüssel im Konto ablegen**

Dort legst du einen neuen Schlüssel an und fügst die Ausgabe von `cat ~/.ssh/id_ed25519_vps.pub` aus Abschnitt 2 ein – die **komplette Zeile**, von `ssh-ed25519` bis zum Kommentar am Ende, ohne Zeilenumbruch. Dazu ein Name, unter dem du ihn später wiedererkennst.

Ein versehentlich abgeschnittener Schlüssel wird klaglos angenommen; auffallen wird es dir erst, wenn der erste Login scheitert. Und der Fehler, den Abschnitt 2 verhindern soll: Was mit `SHA256:` beginnt, ist der Fingerprint und gehört hier nicht hinein.

![](https://cubem.de/content/images/2026/11/02-netcup-scp-ssh-schluessel.webp)

![](https://cubem.de/content/images/2026/11/03-netcup-scp-ssh-schluessel-angelegt.webp)

Einmal abgelegt, steht der Schlüssel für jeden Server im Konto zur Verfügung – auch für spätere.

**Schritt 2: Debian installieren**

Im SCP unter **Medien → Images**:

1. **Debian 13 (UEFI)** als Abbild auswählen
2. **Sprache auf Englisch umstellen** – vorbelegt ist Deutsch
3. **Partitionen:** eine große Partition für das Betriebssystem, die den kompletten freien Speicherplatz beinhaltet
4. **Hostname:** `vps`
5. **Zusätzlichen Benutzer erstellen** aktivieren (Benutzername z. B. `martin`, dazu ein Passwort wählen)
6. Den eben abgelegten **SSH-Schlüssel auswählen**
7. Keine Extras, keine Skripte
8. Auf **Installieren** klicken

![](https://cubem.de/content/images/2026/11/04-netcup-scp-server.webp)

![](https://cubem.de/content/images/2026/11/05-netcup-scp-server-images.webp)

![](https://cubem.de/content/images/2026/11/06-netcup-scp-server-debian-installationeinstellungen.webp)

![](https://cubem.de/content/images/2026/11/07-netcup-scp-server-debian-installation.webp)

> **Warum Englisch?**
> 
> Ein englisch aufgesetztes System bringt `en_US.UTF-8` mit, und darauf baut Schritt 2 weiter unten auf. Wichtiger im Alltag: Fehlermeldungen bleiben in der Sprache, in der auch die Antworten stehen. Eine übersetzte Meldung findest du in keiner Suchmaschine wieder. Die Anzeigesprache des Panels bleibt davon unberührt.

**Schritt 3: Bestätigen und warten**

Nach dem Klick fragt das Panel nach, ob das Abbild wirklich installiert werden soll – mit dem Hinweis, dass **alle Daten auf der primären Festplatte dauerhaft gelöscht werden**. Anschließend musst du dich in einem Popup noch einmal ausweisen. Beides ist Absicht: Der Vorgang setzt den Server komplett zurück.

Danach erscheint oben rechts eine kleine Anzeige „Image Installation wird durchgeführt" samt Fortschrittsbalken. Die ist leicht zu übersehen – sie ist aber die einzige Rückmeldung, dass überhaupt etwas läuft.

![](https://cubem.de/content/images/2026/11/08-netcup-scp-server-debian-installationsfortschritt-1.webp)

**Schritt 4: Das Installationsergebnis sichern**

Ist die Installation durch, zeigt das Panel das Ergebnis an: die **IP-Adresse** des Servers und ein **root-Passwort**.

> ⚠️ **Diese Zugangsdaten werden nur einmal angezeigt**
> 
> Das root-Passwort taucht später nirgends wieder auf. Speichere es sofort in deinem Passwortmanager – nicht in einer Textdatei auf dem Schreibtisch.
> 
> Für den Alltag brauchst du es nicht: Du arbeitest gleich als `martin` mit deinem Schlüssel. Gebraucht wird es, wenn SSH einmal nicht mehr geht und nur die Konsole im Panel bleibt – dort zählt kein Schlüssel. Fehlt es dann, setzt du im SCP unter **Zugang** ein neues; aufgehoben erspart es dir diesen Umweg.

Die IP-Adresse brauchst du im nächsten Abschnitt.

![](https://cubem.de/content/images/2026/11/09-netcup-scp-server-debian-installationsergebnis.webp)

### Option B: Provider ohne SSH-Key-Support

1. **Debian 13 (Trixie)** installieren
2. Per Root-Passwort einloggen (wird vom Provider generiert)
3. Manuell User anlegen und SSH-Key kopieren (siehe unten)

### Nach Installation: User anlegen (falls nicht vom Provider gemacht)

Falls dein Provider keinen User angelegt hat, auf dem Server als root:

```bash
# Als root einloggen
ssh root@<SERVER-IP>

# User erstellen (UID 1000 wird automatisch vergeben, wenn erster User)
adduser martin

# Sudo-Rechte geben
usermod -aG sudo martin

# SSH-Verzeichnis anlegen
mkdir -p /home/martin/.ssh
chmod 700 /home/martin/.ssh

```

Public Key kopieren – diesen Befehl führst du auf deinem **lokalen Rechner** aus:

```bash
cat ~/.ssh/id_ed25519_vps.pub | ssh root@<SERVER-IP> "cat >> /home/martin/.ssh/authorized_keys"

```

Anschließend wieder als root auf dem Server – Rechte korrekt setzen:

```bash
chmod 600 /home/martin/.ssh/authorized_keys
chown -R martin:martin /home/martin/.ssh

```

Test – ausloggen und als `martin` einloggen. Weil der Schlüssel nicht am Standardpfad liegt, gibst du ihn hier noch mit `-i` an; Abschnitt 4.1 macht das gleich überflüssig:

```bash
exit
ssh -i ~/.ssh/id_ed25519_vps martin@<SERVER-IP>

```

## 4\. Erster SSH-Login – Meldungen verstehen

### 4.1 Die Verbindung benennen

Dein Schlüssel heißt nicht mehr `id_ed25519`, also findet SSH ihn nicht mehr von allein. Statt ihn bei jedem Aufruf mit `-i` mitzugeben, trägst du die Verbindung einmal in deine persönliche SSH-Konfiguration ein.

Auf deinem lokalen Rechner:

```bash
nano ~/.ssh/config

```

Die Datei gibt es standardmäßig noch nicht – `nano` legt sie an. Inhalt:

```
Host vps
    HostName <SERVER-IP>
    User martin
    IdentityFile ~/.ssh/id_ed25519_vps
    AddKeysToAgent yes
    UseKeychain yes

```

**Für `<SERVER-IP>` trägst du die echte IP-Adresse deines Servers ein** – spitze Klammern weg, nur die Zahlen. Die Adresse hat dir das Panel nach der Installation angezeigt; sie steht außerdem in der Server-Übersicht deines Anbieters. Der Rest der Datei bleibt so stehen: `vps` ist der Name, den du dir selbst gibst, `martin` dein Benutzer vom Server.

Die letzten beiden Zeilen nehmen dir die Passphrase ab. `AddKeysToAgent yes` übergibt den entschlüsselten Schlüssel nach der ersten Eingabe an den SSH-Agenten deines Rechners, `UseKeychain yes` legt die Passphrase zusätzlich in den Schlüsselbund. Du tippst sie also einmal und danach nicht wieder – auch nicht nach einem Neustart und auch nicht, wenn in Artikel 07 ein Editor die Verbindung aufbaut.

> **Nicht auf einem Mac?** `UseKeychain` gibt es nur dort; unter Linux und Windows lässt du die Zeile weg. `AddKeysToAgent yes` genügt, dann hält der Rechner die Passphrase für die Dauer der Sitzung. Unter Windows muss der Dienst „OpenSSH Authentication Agent" dafür laufen – ab Werk ist er nicht gestartet.

Speichern (**Ctrl+X**, dann **Y**), anschließend die Rechte setzen:

```bash
chmod 600 ~/.ssh/config

```

Ab jetzt genügt `ssh vps`. Kein Benutzername, keine IP, kein `-i`.

> **Der Name bleibt, die Adresse wandert**
> 
> In Artikel 05 wird der Zugang auf ein VPN umgestellt und der SSH-Port nach außen geschlossen. Dann änderst du in dieser Datei nur die Zeile `HostName` auf die VPN-Adresse. Der Befehl `ssh vps` bleibt derselbe – und VS Codium in Artikel 07 greift auf genau diesen Eintrag zurück.

### 4.2 Host-Key-Abfrage

Jetzt der erste Login:

```bash
ssh vps

```

Statt einer Eingabeaufforderung erscheint zunächst das hier:

```
The authenticity of host '...' can't be established.
ED25519 key fingerprint is SHA256:...
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

```

**Was passiert hier?**

SSH kennt diesen Server noch nicht. Der Server präsentiert seinen Host-Key. Dein Client fragt dich, ob du diesem Schlüssel vertraust. Das schützt vor Man-in-the-Middle-Angriffen.

Wenn du den Server gerade selbst installiert hast, bestätige mit `yes`.

Danach steht oft:

```
Warning: Permanently added '...' to the list of known hosts.

```

Der Host-Key wird lokal gespeichert: `~/.ssh/known_hosts`.

> **Wenn du den Server noch einmal neu installierst**
> 
> Dann bekommt er neue Host-Keys, dein Rechner kennt aber noch die alten – und meldet sich mit einer Warnung in Rahmen und Großbuchstaben:
> 
> ```
> WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
> ...
> Host key verification failed.
> 
> ```
> 
> Das ist keine Fehlfunktion, sondern genau der Schutz aus dem Absatz oben: SSH sieht einen anderen Schlüssel als beim letzten Mal und verweigert die Verbindung. Nach einer Neuinstallation ist der Grund bekannt, also entfernst du den alten Eintrag:
> 
> ```bash
> ssh-keygen -R <SERVER-IP>
> 
> ```
> 
> Danach `ssh vps` erneut aufrufen und mit `yes` bestätigen wie beim ersten Mal.
> 
> **Nur wenn du weißt, warum sich der Schlüssel geändert hat.** Erscheint die Warnung, ohne dass du am Server etwas verändert hast, ist sie ernst zu nehmen – dann ist das Löschen des Eintrags genau der falsche Schritt.

### 4.3 Passphrase-Abfrage

Wenn du eine Passphrase gesetzt hast:

```
Enter passphrase for key '.../id_ed25519_vps':

```

Was bedeutet das?

- Du nutzt Schlüssel-Login
- Dein Private Key ist zusätzlich geschützt
- Du gibst keinen Server-Login per Passwort frei

**Check**

Melde dich mit `exit` ab und verbinde dich erneut:

```bash
ssh vps

```

*Ausgabe:* Diesmal weder Host-Key- noch Passphrase-Abfrage, sondern direkt die Eingabeaufforderung des Servers. Der Host-Key steht jetzt in `known_hosts`, die Passphrase im Schlüsselbund – beides aus Abschnitt 4.1 und 4.2.

Fragt er weiterhin nach der Passphrase, fehlen die beiden Zeilen aus Abschnitt 4.1 oder stehen im falschen `Host`\-Block.

> **Nebeneffekt, der verwirren kann:** Sobald der Schlüssel im Agenten liegt, funktioniert auch der lange Aufruf `ssh martin@<SERVER-IP>` ohne Eingabe. SSH bietet dem Gegenüber alle Schlüssel an, die es zur Hand hat – nicht nur den aus dem passenden `Host`\-Eintrag. Der Eintrag spart dir also vor allem Tipparbeit und sorgt dafür, dass es beim ersten Mal überhaupt klappt.

## 5\. Benutzer und UID 1000

Nachdem der erste Login funktioniert, prüfen wir die Benutzer- und Rechtebasis.

Best Practice: Der primäre Admin-User (im Beispiel `martin`) sollte die Standard-UID/GID **1000:1000** haben.

> **Warum das wichtig ist**
> 
> Viele Container- und NAS-Workflows arbeiten mit `PUID`/`PGID`. Wenn dein Standardbenutzer konsistent 1000:1000 ist, werden Dateirechte bei Volumes, Backups und Migrationen deutlich einfacher.

**Check**

```bash
whoami
id martin

```

*Ausgabe:*

```
martin
uid=1000(martin) gid=1000(martin) groups=1000(martin)

```

Entscheidend ist die zweite Zeile: UID und GID stehen beide auf 1000.

> **Hinweis zur sudo-Gruppe**
> 
> Ob `27(sudo)` zusätzlich in der Ausgabe erscheint, hängt vom Provider ab: Manche Installer legen den User direkt mit Sudo-Rechten an (z. B. Netcup), andere nicht. Falls die Gruppe fehlt, holen wir das in Sektion 7 nach – wichtig ist hier nur, dass UID und GID stimmen.

## 6\. Die fünf Basisschritte

### Schritt 1: System aktualisieren & Basispakete installieren

Zuerst Updates:

```bash
sudo apt update && sudo apt upgrade -y

```

**Basispakete**

Ein frisch installiertes Debian ist sehr minimal gehalten. Das ist gut für Sicherheit, aber im Alltag fehlen ein paar Werkzeuge, die wir für Administration, Fehlersuche und spätere Installationen ständig brauchen.

```bash
sudo apt install -y curl ca-certificates gnupg nano htop git unzip rsync bash-completion needrestart qemu-guest-agent

```

| Paket            | Zweck                                                                                               |
| ---------------- | --------------------------------------------------------------------------------------------------- |
| curl             | HTTP(S)-Requests, Downloads, API-Checks                                                             |
| ca-certificates  | Vertrauenswürdige Zertifikate für HTTPS/TLS                                                         |
| gnupg            | Signaturen prüfen (z. B. bei externen Quellen)                                                      |
| nano             | Konfigurationsdateien bearbeiten                                                                    |
| htop             | Prozesse und Ressourcen übersichtlich prüfen                                                        |
| git              | Versionierung für Doku und Configs                                                                  |
| unzip            | ZIP-Archive entpacken                                                                               |
| rsync            | Effiziente Backups und Syncs                                                                        |
| bash-completion  | Weniger Tippfehler, bessere CLI-Erfahrung                                                           |
| needrestart      | Zeigt nach Updates an, welche Dienste neu gestartet werden müssen – wichtig für unattended-upgrades |
| qemu-guest-agent | Verbindung zwischen Server und Virtualisierungs-Host – siehe Kasten                                 |

> **Wofür der Guest Agent gut ist**
> 
> Wenn dein Panel meldet, der QEMU Guest Agent laufe nicht, ist das kein Fehler: Das minimale Abbild bringt ihn nicht mit. Er ist ein kleiner Dienst *im* Server, über den der Virtualisierungs-Host mit dem laufenden System sprechen kann. Ohne ihn sieht der Host nur eine Blackbox.
> 
> Zwei Dinge hängen daran. Erstens das Herunterfahren aus dem Panel: Mit Agent wird das System gebeten, sich ordentlich zu beenden – ohne ihn kommt der Knopf im Zweifel dem Ziehen des Stromsteckers näher. Zweitens, und wichtiger, die **Snapshots des Anbieters**: Der Agent hält vor einem Snapshot kurz das Dateisystem an und sorgt dafür, dass noch offene Schreibvorgänge auf der Platte landen. Ohne ihn entspricht ein Snapshot dem Zustand nach einem Stromausfall. Meistens übersteht ein System das – aber „meistens" ist bei Sicherungen das falsche Wort.
> 
> Aktivieren musst du ihn nicht. Das Paket bringt eine udev-Regel mit, die den Dienst startet, sobald die passende Schnittstelle da ist. Ein `systemctl enable` lehnt systemd deshalb mit einem langen Hinweis ab („The unit files have no installation config") – das ist kein Fehler, sondern der Normalfall auf Debian.
> 
> **Check**
> 
> ```bash
> systemctl is-active qemu-guest-agent
> 
> ```
> 
> *Ausgabe:* `active`. Steht dort `inactive`, fehlt dem Server die virtio-Schnittstelle – daran lässt sich im System selbst nichts ändern.

### Schritt 2: Zeitzone und Locale prüfen

Beides hast du bei der Installation festgelegt. Zwei Befehle bestätigen, dass es auch so angekommen ist:

```bash
timedatectl
locale

```

*Ausgabe:* bei `Time zone` steht `Europe/Berlin`, bei `locale` steht `LANG=en_US.UTF-8`.

Eine falsche Zeitzone fällt erst Wochen später auf, wenn ein Log-Zeitstempel nicht zu dem passt, was du erlebt hast – und dann kostet sie eine Stunde Fehlersuche. Deshalb der Blick jetzt.

> **Falls etwas anderes dasteht**
> 
> Das kommt vor, wenn die Vorbelegung im Installationsdialog stehen geblieben ist oder dein Anbieter diese Felder gar nicht anbietet. Nachträglich:
> 
> ```bash
> sudo timedatectl set-timezone Europe/Berlin
> sudo update-locale LANG=en_US.UTF-8
> 
> ```
> 
> Die Locale-Änderung greift erst bei der nächsten Anmeldung – also einmal abmelden und `ssh vps` neu aufrufen.

Das Tastaturlayout bleibt von alldem unberührt: Deine Eingaben kommen über SSH von deinem eigenen Rechner.

### Schritt 3: SSH weiter absichern

Konfiguration öffnen:

```bash
sudo nano /etc/ssh/sshd_config

```

Diese Datei steuert, wie sich der SSH-Server verhält. Die folgenden Einstellungen sorgen dafür, dass nur das Nötigste erlaubt ist.

**Empfohlene Kerneinstellungen**

```
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers martin

```

| Einstellung               | Bedeutung                                                                                                                                    |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| PermitRootLogin no        | Niemand kann sich direkt als Root anmelden. Selbst wenn jemand einen Root-Schlüssel hätte, wäre der Login blockiert.                         |
| PasswordAuthentication no | Der Server akzeptiert keine Passwörter mehr. Damit fallen die meisten automatisierten Angriffe weg.                                          |
| PubkeyAuthentication yes  | Anmeldung ist nur noch mit SSH-Schlüsseln erlaubt – also mit deinem Key.                                                                     |
| AllowUsers martin         | Nur der Benutzer martin darf sich per SSH anmelden. Selbst wenn später weitere Nutzer existieren, kommen sie nicht automatisch per SSH rein. |

> **Nicht einfach ans Ende schreiben**
> 
> In dieser Datei **gewinnt der erste Treffer, nicht der letzte**. Steht ein Schlüsselwort weiter oben schon aktiv drin, wird deine Zeile am Dateiende stillschweigend ignoriert – ohne Fehler, ohne Warnung.
> 
> Such deshalb mit **Ctrl+W** in nano nach jedem der vier Begriffe. Findest du eine aktive Zeile, änderst du sie dort. Nur was gar nicht vorkommt, schreibst du neu dazu.
> 
> Zeilen mit `#` davor zählen nicht mit – das ist nur Dokumentation des Standardwerts. Bei manchen Anbietern stehen am Dateiende allerdings schon fertige Zeilen, etwa `PasswordAuthentication no` und `PermitRootLogin yes`. Die sind aktiv und wollen angepasst werden.

Nach der Änderung nano mit **Ctrl+X** beenden und mit **Y** speichern bestätigen.

**Vor dem Reload: Syntax prüfen**

Bevor du den Dienst neu lädst, prüfst du die Konfiguration auf Tippfehler:

```bash
sudo sshd -t

```

Wenn der Befehl ohne Ausgabe zurückkehrt, ist die Syntax in Ordnung. Bei Fehlern wirst du auf die Zeile hingewiesen – korrigieren, bevor du weitermachst.

Aktivieren:

```bash
sudo systemctl reload ssh

```

**Check**

`sshd -t` prüft nur die Rechtschreibung. Ob deine Einstellungen auch wirklich greifen, zeigt erst dieser Befehl:

```bash
sudo sshd -T | grep -Ei 'permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers'

```

*Ausgabe:*

```
permitrootlogin no
pubkeyauthentication yes
passwordauthentication no
allowusers martin

```

`-T` gibt die tatsächlich wirksame Konfiguration aus – die Schlüsselwörter erscheinen dabei kleingeschrieben. Steht dort etwas anderes als erwartet, gewinnt an anderer Stelle eine konkurrierende Zeile.

> **Wenn die Ausgabe nicht passt**
> 
> Ganz oben in der Datei steht `Include /etc/ssh/sshd_config.d/*.conf`. Alles aus diesem Verzeichnis wird **an dieser Stelle** eingelesen, also vor deinen Zeilen weiter unten – und gewinnt damit. Manche Anbieter legen dort eine Datei ab. Was drinliegt, zeigt:
> 
> ```bash
> ls /etc/ssh/sshd_config.d/
> 
> ```
> 
> Findet sich dort eine konkurrierende Einstellung, änderst du sie in dieser Datei statt in `sshd_config`.

**Warum das wichtig ist:**

- Root-Login über SSH ist ein unnötiges Risiko
- Passwort-Login ist die häufigste Angriffsfläche bei VPS-Systemen
- Weniger SSH-Features bedeutet weniger Überraschungen

> ⚠️ **Wichtiger Check – aussperren vermeiden**
> 
> Öffne ein **zweites Terminal** und teste den Login erneut, *bevor* du die alte Session schließt:
> 
> ```bash
> ssh vps
> 
> ```
> 
> Der Login klappt. Ein Login mit `ssh root@<SERVER-IP>` wird dagegen sofort verweigert. Erst danach die alte Session schließen.

### Schritt 4: Firewall aktivieren (UFW, minimal offen)

UFW installieren und Default-Policy setzen:

```bash
sudo apt install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing

```

**IPv6 kurz prüfen**

Fast jeder VPS hat heute neben der IPv4- auch eine IPv6-Adresse. Filtert UFW nur IPv4, wäre der Server über IPv6 ungeschützt erreichbar. Ein Blick genügt:

```bash
grep IPV6 /etc/default/ufw

```

*Ausgabe:* `IPV6=yes`. Das ist auf Debian 13 der Vorgabewert, du musst also nichts ändern. UFW legt damit zu jeder Regel automatisch eine IPv6-Variante an – zu sehen gleich im Check unten an den Zeilen mit `(v6)`.

> **Falls dort `no` steht**
> 
> Dann die Datei öffnen, den Wert auf `yes` setzen und speichern (**Ctrl+X**, dann **Y**):
> 
> ```bash
> sudo nano /etc/default/ufw
> 
> ```
> 
> Solange UFW noch nicht aktiv ist, genügt das. Änderst du den Wert später einmal an einer laufenden Firewall, reicht `sudo ufw reload` dafür **nicht** – dann brauchst du `sudo ufw disable` und anschließend `sudo ufw enable`.

SSH erlauben:

```bash
sudo ufw allow OpenSSH

```

Firewall aktivieren:

```bash
sudo ufw enable

```

UFW warnt, dass bestehende SSH-Verbindungen betroffen sein könnten. Da wir SSH oben explizit erlaubt haben, kannst du mit `y` bestätigen:

```
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

```

> **Warum `OpenSSH` und nicht `22/tcp`?**
> 
> UFW kennt für viele Dienste vordefinierte „Application Profiles". `OpenSSH` ist eines davon. Funktional ist es bei SSH dasselbe wie `22/tcp`, aber die Schreibweise ist klarer und konsistent mit Profilen wie `Nginx Full`, die später für Web-Dienste sinnvoll werden.

> **Warum Firewall überhaupt?**
> 
> Prinzip: Alles ist gesperrt – nur explizit erlaubte Ports sind offen. So behältst du die Kontrolle, auch wenn später Dienste installiert werden.

> ⚠️ **Die zweite Firewall, die du nicht siehst**
> 
> UFW läuft auf dem Server. Manche Anbieter betreiben zusätzlich eine eigene Firewall im Netzwerk davor – bei Netcup gehört sie seit Server-Generation 12 zum Lieferumfang und ist bei neu bestellten Servern von Anfang an aktiv. Ein Paket muss beide Ebenen passieren; was die vorgelagerte Firewall verwirft, erreicht dein Debian nie und taucht in keinem Log auf.
> 
> **Eingehend lässt sie zunächst alles durch** – die Regeln, die hier zählen, sind also deine UFW-Regeln. Ausgehend bringt sie zwei fertige Regelsätze mit: einen, der Ping erlaubt, und `netcup Mail block`, der die Mail-Ports 25, 465 und 587 sperrt. Der zweite wird in Artikel 08 zum Thema, wenn der Mail-Versand zum ersten Mal daran scheitert.
> 
> **Ansonsten lass sie in diesem Artikel unangetastet.** Sobald du dort eine eigene Regel anlegst, wechselt die Grundeinstellung für diese Richtung automatisch von „erlauben" auf „verwerfen" – wer dabei SSH vergisst, kommt nicht mehr auf den Server. Dazu behandelt sie UDP zustandslos: Dienste wie DNS und Zeitabgleich brauchen dann Regeln in beide Richtungen, sonst klemmt plötzlich die Namensauflösung.

**Warum UFW und nicht nftables direkt?**

UFW nutzt unter der Haube nftables (auf Debian 13), bietet aber eine deutlich einfachere Syntax für Homelab-Szenarien. Für komplexe Enterprise-Setups wäre nftables direkt besser – für Self-Hosting ist UFW perfekt.

**Check**

```bash
sudo ufw status verbose

```

*Ausgabe:*

```
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp (OpenSSH)           ALLOW IN    Anywhere
22/tcp (OpenSSH (v6))      ALLOW IN    Anywhere (v6)

```

### Schritt 5: Automatische Sicherheitsupdates aktivieren

Debian sollte automatisch Sicherheits-Patches installieren:

```bash
sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure unattended-upgrades

```

Der Dialog fragt, ob du es aktivieren willst – bestätige mit „Yes".

**Was passiert?**

- Täglich werden Sicherheitsupdates automatisch heruntergeladen und installiert
- Nur aus dem `Debian-Security`\-Repository (keine Breaking Changes)
- Logs liegen unter `/var/log/unattended-upgrades/`

**Automatischen Reboot konfigurieren**

Manche Updates – Kernel, Glibc, systemd – werden erst nach einem Reboot wirksam. Ohne automatischen Reboot bleibt dein Server bis zum manuellen Neustart mit der alten, möglicherweise verwundbaren Version laufen.

Die Standard-Datei `/etc/apt/apt.conf.d/50unattended-upgrades` ist lang, komplett auf Englisch und alle relevanten Zeilen sind auskommentiert. Statt darin die richtigen Stellen zu suchen und zu entkommentieren, legen wir eine **eigene kleine Datei** an, die nur unsere Einstellungen enthält:

```bash
sudo nano /etc/apt/apt.conf.d/52unattended-upgrades-local

```

Folgenden Inhalt einfügen:

```
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

```

Speichern mit **Ctrl+X**, dann **Y**.

> **Warum eine eigene Datei?**
> 
> Die höhere Nummer (`52`) gewinnt gegen die Defaults in der `50`\-Datei – APT liest die Dateien in `/etc/apt/apt.conf.d/` der Reihe nach, spätere überschreiben frühere. Du musst nichts suchen, nichts entkommentieren. Und bei einem Paket-Update der `50`\-Datei bleibt deine Einstellung erhalten, weil sie in einer separaten Datei steht.

> **Wann lieber `false` setzen?**
> 
> Wenn du echte Mission-Critical-Dienste betreibst, bei denen ungeplante Reboots problematisch wären. Für klassische Self-Hosting-Setups (Vaultwarden, Immich, Blog) ist `true` mit nächtlichem Zeitfenster die ehrlichere Wahl: Sicherheitslücken werden zeitnah geschlossen, Downtime fällt mitten in die Nacht. `needrestart` (haben wir oben mit installiert) zeigt dir auf jedem Login an, ob ein Reboot nötig ist – Überraschungen ausgeschlossen.

**Check**

Zuerst prüfen, ob der Service läuft und beim Boot startet:

```bash
sudo systemctl status unattended-upgrades
sudo systemctl is-enabled unattended-upgrades

```

*Ausgabe:* `active (running)` und `enabled`.

> **Hinweis:** Der Service heißt vollständig „Unattended Upgrades **Shutdown**" – das ist normal und hat nichts mit Herunterfahren zu tun. Es ist ein Wächter-Prozess, der im Hintergrund läuft und beim Systemstart-/Shutdown noch ausstehende Updates sauber abschließt. Die täglichen Updates selbst laufen über einen separaten Timer.

Dann prüfen, ob deine Reboot-Einstellungen wirklich greifen:

```bash
apt-config dump | grep -i "Unattended-Upgrade::Automatic-Reboot"

```

*Ausgabe:*

```
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";

```

Tauchen beide Zeilen auf, wird deine `52unattended-upgrades-local` korrekt eingelesen und überschreibt die Defaults.

> **Warum das wichtig ist**
> 
> Sicherheitsupdates manuell zu machen heißt: vergessen. Automatisierung ist 2026 Standard für VPS-Betrieb.

## 7\. sudo statt Root: das Least-Privilege-Prinzip

In den Schritten oben hast du schon mehrmals `sudo` benutzt. Hier nochmal kurz, *warum* das so läuft – und wie du sicherstellst, dass es bei dir auch wirklich funktioniert.

**Warum nicht einfach als root arbeiten?**

Der Root-Benutzer hat uneingeschränkte Systemrechte. Ein Tippfehler – etwa ein `rm -rf` an der falschen Stelle – kann das ganze System unbrauchbar machen. Deshalb gilt im Server-Alltag das Prinzip *Least Privilege*: Du arbeitest standardmäßig als normaler Benutzer und holst dir Administratorrechte nur dann, wenn du sie wirklich brauchst – über `sudo`.

Das ist nicht nur Sicherheits-Hygiene, sondern auch ein Konzept, das später überall wieder auftaucht: Container laufen mit eingeschränkten Rechten, Apps haben eigene Service-User, Backups schreiben mit minimalen Berechtigungen. Wer das Prinzip einmal verinnerlicht hat, versteht später vieles automatisch mit.

**Prüfen, ob dein Benutzer in der sudo-Gruppe ist**

```bash
groups martin

```

Erscheint `sudo` in der Ausgabe, ist alles korrekt.

**Falls `sudo` fehlt** (einmalig als Root oder über die Provider-Konsole):

```bash
sudo usermod -aG sudo martin

```

Danach **einmal neu einloggen** – Gruppenrechte werden erst beim Login geladen.

> **Hinweis**
> 
> Auf manchen Providern (z. B. Netcup) wird der erste User direkt mit Sudo-Rechten angelegt – dann ist hier nichts zu tun. Auf anderen musst du nachhelfen. Der Check oben zeigt dir, was zutrifft.

## Wenn es nicht klappt

| Was du siehst                                                   | Ursache                                                                                                                                                                                                                               | Weiter                         |
| --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
| Permission denied (publickey) beim ersten Login                 | Im Installationsdialog war **Zusätzlichen Benutzer erstellen** nicht angehakt – sshd meldet ein fehlendes Konto genauso wie einen fehlenden Schlüssel. Seltener: abgeschnittener Schlüssel oder der Fingerprint statt des Public Keys | → Abschnitt 3, Schritt 1 und 2 |
| WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!                | Server neu installiert, dein Rechner kennt noch die alten Host-Keys                                                                                                                                                                   | → Abschnitt 4.2, Kasten        |
| Jede Verbindung fragt erneut nach der Passphrase                | AddKeysToAgent/UseKeychain fehlen oder stehen im falschen Host\-Block                                                                                                                                                                 | → Abschnitt 4.1                |
| sshd -T zeigt andere Werte, als du eingetragen hast             | Eine Datei in /etc/ssh/sshd\_config.d/ wird vorher eingelesen und gewinnt                                                                                                                                                             | → Abschnitt 6, Schritt 3       |
| The unit files have no installation config bei qemu-guest-agent | Kein Fehler – der Dienst startet auf Debian über eine udev-Regel, nicht über enable                                                                                                                                                   | → Abschnitt 6, Schritt 1       |

## Und jetzt?

Du hast jetzt eine saubere, gehärtete Linux-Basis: SSH per Schlüssel, Firewall aktiv, automatische Sicherheitsupdates, klare Benutzerrechte. Diese Basis bleibt von hier an möglichst unverändert – alles, was du an Diensten brauchst, läuft ab dem nächsten Artikel in Containern darüber. Docker und Docker Compose sind das nächste Fundament-Stück.

> **Was mit Port 22 noch passiert**
> 
> In Schritt 4 hast du Port 22 in der Firewall bewusst offen gelassen – ohne ihn kämst du nicht mehr auf den Server. Durch die Schlüssel-Anmeldung sind Anmeldeversuche von außen chancenlos, sichtbar ist der Port aber trotzdem. Das ist ein Zwischenstand, kein Endzustand: In Artikel 05 kommt ein VPN dazu, danach ist SSH nur noch darüber erreichbar und Port 22 verschwindet vollständig aus dem öffentlichen Netz.

👉 **Nächster Artikel:** [03\. Docker auf dem VPS: Engine, Compose und zwei Netzwerke](#)