Linux Admin
Kompendium
Fortschritt
0 %
Kompendium · Selbststudium · Praxis

Linux Server
Administration

Von der ersten SSH-Verbindung bis zur Produktionsumgebung. Praxisnah, in klarer Sprache, mit Schritt-für-Schritt-Aufgaben.

25 Module 76 Unterrichtseinheiten Debian / Ubuntu Praxisaufgaben KI-Hinweise Glossar
🧭 So arbeitest du mit diesem Kompendium

Arbeite die Module der Reihe nach durch – jedes baut auf dem vorherigen auf. Unbekannte Begriffe erklärt das Glossar. Die orangefarbenen Praxisaufgaben am Ende jedes Moduls sind der wichtigste Teil – ohne Übung bleibt kaum etwas hängen. Die violetten KI-Hinweise zeigen, wann es sich lohnt, Claude oder ChatGPT zu fragen.

Grundlagen Module 01–06
MODUL 01 · 4 UE
Grundlagen der Netzwerktechnik
IP · DNS · Ports · Routing
MODUL 02 · 3 UE
SSH – Sicherer Fernzugriff
Schlüssel · Tunnel · Config
MODUL 03 · 5 UE
Bash & Editor vim
Terminal · Befehle · vim
MODUL 04 · 1 UE
Dokumentation mit man
man · --help · tldr
MODUL 05 · 3 UE
Netzwerk-Konfiguration
ip · Netplan · nmcli
MODUL 06 · 2 UE
APT – Paketverwaltung
apt · Repos · Updates
System Module 07–11
MODUL 07 · 2 UE
Grafischer Remote Desktop
RDP · VNC · xrdp
MODUL 08 · 2 UE
Nutzer & Gruppenverwaltung
useradd · sudo · Gruppen
MODUL 09 · 3 UE
Aufbau von Linux
Boot · Partitionen · FHS
MODUL 10 · 3 UE
mount & /etc/fstab
Partitionen · SAMBA · SSHFS
MODUL 11 · 2 UE
Datei-Berechtigungen
chmod · chown · ACL · SUID
Netzlaufwerke & Web Module 12–15
MODUL 12 · 3 UE
SFTP, SSHFS & SAMBA
Netzlaufwerke · smb.conf
MODUL 13 · 4 UE
Webserver & Reverse Proxy
Caddy · SSL · Let's Encrypt
MODUL 14 · 3 UE
Firewall-Administration
ufw · iptables · Fail2ban
MODUL 15 · 2 UE
DNS-Server (dnsmasq)
Lokales DNS · DHCP · Cache
Dienste & Stack Module 16–20
MODUL 16 · 5 UE
Datenbank-Administration
MySQL · MariaDB · phpMyAdmin
MODUL 17 · 4 UE
LAMP-Stack & PHP-FPM
Apache · PHP · WordPress
MODUL 18 · 3 UE
Git – Versionskontrolle
Commits · Branches · GitHub
MODUL 19 · 5 UE
Docker & Docker Compose
Container · Images · Stacks
MODUL 20 · 4 UE
Virtualisierung
Proxmox · VirtualBox · KVM
Automatisierung & Sicherheit Module 21–25
MODUL 21 · 4 UE
Bash-Scripting
Variablen · Schleifen · Logik
MODUL 22 · 3 UE
Linux-Services & Cron
systemd · Timer · Crontab
MODUL 23 · 3 UE
Backups
rsync · Borg · 3-2-1-Regel
MODUL 24 · 4 UE
Sicherheitshärtung
Härtung · Lynis · AppArmor
MODUL 25 · 3 UE
Systemrettung & Wiederherst.
chroot · GRUB · fsck
Nachschlagewerk

Glossar

Alle wichtigen Abkürzungen und Fachbegriffe erklärt. Im Kompendium sind Begriffe mit gestrichelter Unterlinie direkt erklärbar – einfach mit der Maus drüberfahren.

Modul 014 Unterrichtseinheiten

Grundlagen der Netzwerktechnik

Bevor du einen Server verwaltest, musst du verstehen, wie Netzwerke funktionieren. Dieses Modul erklärt die wichtigsten Grundbausteine: IP-Adressen, Ports, DNS und Routing – die Sprache, in der Computer weltweit miteinander reden.

Keine Voraussetzungen IP-Adressen · Ports · DNS · Routing Werkzeuge: ping · dig · ss · ip
IP-Adressen – die Postanschrift im Netzwerk

Jedes Gerät in einem Netzwerk – ob Laptop, Server oder Smartphone – braucht eine eindeutige Adresse, damit Datenpakete ankommen. Diese Adresse heißt IP-Adresse. Es gibt zwei Versionen:

  • IPv4 – vier Zahlen von 0 bis 255, getrennt durch Punkte. Beispiel: 192.168.1.100
  • IPv6 – acht Blöcke aus Hexadezimalziffern. Beispiel: 2001:0db8:85a3::8a2e:0370:7334

IPv4 ist noch immer am weitesten verbreitet. IPv6 wurde eingeführt, weil es von IPv4 nur rund 4 Milliarden Adressen gibt – viel zu wenig für die Milliarden vernetzter Geräte heute.

Private vs. öffentliche IP-Adressen

Nicht jede IP-Adresse ist im Internet erreichbar. Einige Bereiche sind für private Netzwerke reserviert – etwa dein Heimnetz oder das Firmennetzwerk:

BereichBeispielTypischer Einsatz
10.0.0.0/810.0.0.1Große Firmen- und Rechenzentrumsnetze
172.16.0.0/12172.16.0.1Mittlere Netze, VMs, Docker
192.168.0.0/16192.168.1.1Heimnetzwerke, Router, kleine Büros

Alles außerhalb dieser Bereiche ist eine öffentliche IP-Adresse – über sie ist ein Server direkt aus dem Internet erreichbar.

💡 Merkhilfe: Was ist meine IP?

Im Terminal: ip addr show zeigt alle IP-Adressen deines Rechners. Deine öffentliche IP findest du z.B. mit curl ifconfig.me.

Subnetting und CIDR-Schreibweise

Die Zahl hinter dem Schrägstrich (z.B. /24) gibt an, wie viele Bits die Netzwerkmaske umfasst – also wie groß das Netzwerk ist. Je größer die Zahl, desto kleiner das Netz:

CIDRNetzmaskeNutzbare AdressenTypischer Einsatz
/8255.0.0.016.777.214Sehr große Netze
/16255.255.0.065.534Mittelgroße Firmen
/24255.255.255.0254Heimnetz, kleines Büro
/30255.255.255.2522Punkt-zu-Punkt-Links
/32255.255.255.2551 (nur diese IP)Firewall-Regeln
🧠 Eselsbrücke

Stell dir das Netzwerk wie eine Straße vor: /24 ist eine Straße mit 254 Häusern. /25 teilt diese Straße in zwei gleiche Hälften. /32 ist genau ein einzelnes Haus.

Ports – die Türnummern eines Servers

Ein Server hat eine IP-Adresse, aber gleichzeitig laufen darauf viele verschiedene Dienste: Webserver, SSH, Datenbank, Mail. Ports trennen diese Dienste voneinander.

Stell dir vor: Die IP-Adresse ist das Gebäude, der Port ist die Büronummer. Wenn du 192.168.1.50:22 aufrufst, erreichst du genau den SSH-Dienst auf diesem Server.

PortProtokollDienstWofür
22TCPSSHSichere Fernverwaltung
80TCPHTTPUnverschlüsselte Webseiten
443TCPHTTPSVerschlüsselte Webseiten
21TCPFTPDateiübertragung (veraltet)
25TCPSMTPE-Mails senden
53TCP/UDPDNSNamensauflösung
3306TCPMySQL/MariaDBDatenbank-Verbindungen
5432TCPPostgreSQLDatenbank-Verbindungen
8080TCPHTTP (alternativ)Webserver, Dev-Server
⚠️ Ports unter 1024 brauchen Root-Rechte

Ports von 1 bis 1023 heißen Well-Known Ports. Ein normaler Benutzer darf sie nicht öffnen – dafür braucht es Root-Rechte. Ports von 1024 bis 65535 kann jeder Nutzer frei verwenden.

DNS – das Telefonbuch des Internets

Kein Mensch merkt sich IP-Adressen. DNS (Domain Name System) übersetzt lesbare Namen wie google.com in IP-Adressen wie 142.250.185.78 – vollautomatisch, im Hintergrund, bei jeder Anfrage.

Wie DNS-Auflösung funktioniert

  1. Du tippst google.com in den Browser
  2. Dein Rechner fragt seinen konfigurierten DNS-Resolver (meistens der Router oder ein externer wie 1.1.1.1)
  3. Der Resolver fragt ggf. weiter: Root-Nameserver → TLD-Nameserver (.com) → Google-Nameserver
  4. Die IP-Adresse kommt zurück und wird kurzzeitig im Cache gespeichert (TTL)

Die wichtigsten DNS-Eintragstypen

TypBedeutungBeispiel
ADomain → IPv4-Adresseexample.com → 1.2.3.4
AAAADomain → IPv6-Adresseexample.com → 2001:db8::1
CNAMEAlias → andere Domainwww → example.com
MXMail-Server für diese Domainmail.example.com
PTRIP → Domain (Reverse DNS)1.2.3.4 → example.com
TXTFreitext (SPF, DKIM, Verifikation)v=spf1 include:…
NSZuständige Nameserverns1.example.com
💡 TTL – Time to Live

Jeder DNS-Eintrag hat eine TTL (Sekunden). Solange er im Cache liegt, wird nicht erneut gefragt. Ein niedriger TTL (z.B. 60) ist praktisch beim DNS-Wechsel, ein hoher TTL (z.B. 86400 = 1 Tag) reduziert Last. Nach einem DNS-Wechsel kann es bis zur vollen TTL dauern, bis alle ihn sehen.

Routing – Pakete durch das Netz lenken

Wenn dein Computer ein Paket sendet, muss er wissen, wohin. Das erledigt die Routing-Tabelle. Der wichtigste Eintrag ist das Standard-Gateway – der Router, an den alles weitergeleitet wird, was nicht im lokalen Netz liegt.

Routing-Tabelle anzeigen
ip route show

# Typische Ausgabe:
default via 192.168.1.1 dev eth0        # → Standard-Gateway (alles unbekannte geht hier hin)
192.168.1.0/24 dev eth0 proto kernel    # → lokales Netz direkt erreichbar

Pakete an 192.168.1.x gehen direkt ans Ziel. Alles andere (z.B. 8.8.8.8) geht zum Gateway (192.168.1.1), der es dann weiterschickt.

Netzwerk-Diagnose-Werkzeuge

Diese Werkzeuge brauchst du täglich. Lerne sie auswendig – sie helfen dir, Probleme schnell einzugrenzen.

Erreichbarkeit und Verbindung testen

ping – ist ein Host erreichbar?
ping 8.8.8.8              # Pakete senden, Antwortzeit messen (Ctrl+C zum Stoppen)
ping -c 4 google.com      # nur 4 Pakete senden (dann automatisch stoppen)
ping -i 0.2 192.168.1.1   # schneller pingen (alle 0,2 Sekunden)
traceroute / mtr – welchen Weg nehmen Pakete?
traceroute google.com     # alle Zwischenstationen (Hops) anzeigen
mtr google.com            # interaktive Kombination aus ping + traceroute
                           # (installieren: sudo apt install mtr)

DNS abfragen

dig – detaillierte DNS-Abfragen
dig google.com            # A-Eintrag abfragen (vollständige Ausgabe)
dig +short google.com     # nur die IP-Adresse ausgeben
dig google.com MX         # Mail-Server-Einträge abfragen
dig google.com ANY        # alle Eintragstypen abfragen
dig -x 8.8.8.8             # Reverse-Lookup: IP → Domain
dig @1.1.1.1 heise.de      # bestimmten DNS-Server direkt befragen

nslookup google.com       # einfachere Alternative zu dig

IP-Adressen und Interfaces

ip – Netzwerkkonfiguration anzeigen
ip addr show              # alle Interfaces mit IP-Adressen
ip addr show eth0          # nur das Interface eth0
ip route show             # Routing-Tabelle
ip link show              # Status aller Interfaces (UP / DOWN)

Offene Ports und aktive Verbindungen

ss – welche Ports lauschen auf diesem Server?
ss -tulpn                  # alle lauschenden Ports anzeigen (wichtigster Befehl!)
                           # -t = TCP, -u = UDP, -l = lauschend, -p = Prozess, -n = Nummern
ss -tulpn | grep :22      # nur SSH-Port filtern
ss -tulpn | grep :80      # nur HTTP-Port filtern

netstat -tulpn             # ältere Alternative zu ss (evtl. nachinstallieren)
Beispiel-Ausgabe von ss -tulpn
Netid  State   Recv-Q  Send-Q  Local Address:Port   Process
tcp    LISTEN  0       128     0.0.0.0:22          sshd
tcp    LISTEN  0       511     0.0.0.0:80          nginx
tcp    LISTEN  0       511     0.0.0.0:443         nginx
tcp    LISTEN  0       128     127.0.0.1:3306      mysqld

Diese Ausgabe liest sich so: SSH (:22) und nginx (:80, :443) sind von überall erreichbar (0.0.0.0). MySQL (:3306) lauscht nur auf 127.0.0.1 – also nur lokal, nicht von außen. Genau so soll es sein!

✅ Sicherheits-Daumenregel

Prüfe mit ss -tulpn regelmäßig, welche Ports offen sind. Alles was nicht gebraucht wird, sollte nicht lauschen. Ein Port, der auf 0.0.0.0 lauscht, ist aus dem Internet erreichbar (sofern keine Firewall dahinter ist).

🤖
KI-Tipp: Ausgaben erklären lassen

Wenn du eine Ausgabe von ss -tulpn, ip route show oder dig nicht verstehst, kopiere sie einfach in Claude oder ChatGPT und schreib dazu: „Erkläre mir diese Ausgabe Zeile für Zeile auf Deutsch." Das spart viel Recherche-Zeit und du lernst dabei mehr als aus trockener Dokumentation.

Praxisaufgaben
AUFGABE 1.1 Dein eigenes Netzwerk erkunden

In dieser Aufgabe schaust du dir an, wie dein System gerade ins Netzwerk eingebunden ist. Öffne ein Terminal auf deiner Linux-VM oder deinem Server.

1
Zeige alle IP-Adressen deines Systems an: ip addr show. Welche IP-Adresse hat dein Haupt-Interface (z.B. eth0 oder enp3s0)? Notiere sie.
2
Zeige die Routing-Tabelle an: ip route show. Welche IP-Adresse steht nach default via? Das ist dein Standard-Gateway.
3
Pinge das Gateway: ping -c 4 <gateway-ip>. Wie groß ist die durchschnittliche Antwortzeit (RTT)? Unter 1 ms ist normal bei lokalem Netz.
4
Teste die Internetverbindung: ping -c 4 8.8.8.8. Funktioniert es? Falls nicht, liegt das Problem zwischen deinem Rechner und dem Internet.
5
Zeige alle lauschenden Ports an: ss -tulpn. Welche Dienste laufen auf deinem System? Erkennst du SSH (:22)?
Lösungshinweise anzeigen

Bei ip addr suchst du nach Zeilen wie inet 192.168.1.50/24 – das ist deine IP mit Subnetzmaske. Die Zeile beginnt mit inet (nicht inet6).

Bei ip route ist die Zeile default via X.X.X.X dein Gateway. Bei einem typischen Heimnetz endet die IP auf .1, z.B. 192.168.1.1.

Die RTT beim lokalen Ping sollte unter 1 ms liegen. Zu 8.8.8.8 (Google) sind 10–30 ms in Deutschland normal.

AUFGABE 1.2 DNS-Einträge untersuchen

Lerne, wie DNS-Einträge aufgebaut sind, indem du sie für echte Domains abfragst.

1
Frage die IP-Adresse von heise.de ab: dig +short heise.de. Du bekommst eine oder mehrere IP-Adressen zurück.
2
Frage die Mail-Server von gmail.com ab: dig gmail.com MX. Siehst du die MX-Einträge in der ANSWER SECTION? Die Zahlen davor sind Prioritäten (kleinere = bevorzugter).
3
Mache einen Reverse-Lookup: dig -x 8.8.8.8. Welchen Namen hat Googles DNS-Server? (Tipp: Der Eintrag steht im PTR-Record)
4
Frage explizit einen anderen DNS-Server: dig @1.1.1.1 heise.de. Vergleiche das Ergebnis mit dem ohne @1.1.1.1. Unterscheiden sich die IPs?
5
Schau dir die vollständige dig-Ausgabe an (ohne +short): dig heise.de. Finde den TTL-Wert in der ANSWER SECTION. In wie vielen Sekunden verfällt dieser Cache-Eintrag?
Lösungshinweise anzeigen

Der Reverse-Lookup von 8.8.8.8 ergibt dns.google – so heißt Googles öffentlicher DNS-Server offiziell.

Der TTL-Wert steht in der ANSWER SECTION als Zahl in der zweiten Spalte, z.B. heise.de. 3600 IN A 193.99.144.80 – hier ist der TTL 3600 Sekunden (= 1 Stunde).

AUFGABE 1.3 Verbindungsweg nachverfolgen

In dieser Aufgabe siehst du, welchen Weg deine Datenpakete durchs Internet nehmen.

1
Installiere mtr falls noch nicht vorhanden: sudo apt install mtr
2
Starte eine Route-Analyse: mtr google.com. Du siehst jeden Router auf dem Weg. Drücke q zum Beenden.
3
Beobachte: Bei welchem Hop springt die Latenz plötzlich stark an? Dieser Sprung markiert meist den Übergang vom regionalen Netz ins Internet-Backbone.
4
Starte nun mtr 1.1.1.1 (Cloudflare-DNS). Wie viele Hops sind es? Wo unterscheidet sich der Weg von mtr google.com?
Lösungshinweise anzeigen

Typisch sind 10–15 Hops bis zu einem großen Ziel. Die ersten 3–4 Hops sind meist in deinem lokalen Netz und sehr schnell (<5 ms). Danach kommen Provider-Router, dann Internet-Austauschpunkte (IXPs).

Wenn ein Hop ??? oder 100% Paketverlust zeigt, bedeutet das nicht zwingend ein Problem – viele Router antworten aus Sicherheitsgründen nicht auf ICMP-Anfragen, leiten aber regulären Traffic durch.

🤖
KI-Tipp: Subnetting üben

Subnetting (die Berechnung von IP-Bereichen aus CIDR-Notationen) ist zunächst verwirrend. Frag eine KI: „Erkläre mir Schritt für Schritt, was das Netz 10.0.5.0/26 bedeutet: Wie viele Hosts passen rein? Was ist die erste und letzte nutzbare IP? Was ist die Broadcast-Adresse?" – Lass dir dann eigene Beispiele zum Üben geben.

Modul 023 Unterrichtseinheiten

SSH -- Sicherer Fernzugriff

Server stehen selten neben dir auf dem Schreibtisch. Du verwaltest sie aus der Ferne -- per SSH. In diesem Modul lernst du, wie du dich sicher verbindest, Schlüsselpaare einrichtest und den SSH-Dienst absicherst.

Voraussetzung: Modul 01 SSH-Verbindung · Schlüsselpaare · Config · Tunnel
Bevor wir starten: Zwei Kontexte

Bei SSH arbeitest du immer an zwei Orten gleichzeitig: deinem eigenen Rechner und dem Server. Stell dir vor, du rufst einen Kollegen an und gibst ihm Anweisungen -- du sitzt an deinem Schreibtisch, er sitzt am anderen Ende der Leitung. Was du tippst, führt er aus. Ab jetzt markieren wir in diesem Modul immer klar, wo du dich befindest:

💻 Dein Rechner

Befehle, die du in deinem eigenen Terminal eingibst -- auf deinem Laptop oder PC.

🖥️ Server

Befehle, die auf dem entfernten Server laufen -- erst nach dem SSH-Login erreichbar.

Was ist SSH?

SSH (Secure Shell) ist ein Protokoll, mit dem du dich verschlüsselt auf einem entfernten Server anmelden und ihn bedienen kannst -- als wärst du direkt davor. Alles, was du tippst, und alles, was der Server antwortet, ist verschlüsselt. Niemand kann mitlesen.

Aus Modul 01 weißt du bereits: SSH läuft standardmäßig auf Port 22 (TCP). Der Server wartet dort auf Verbindungen, und du verbindest dich von deinem Rechner aus mit einem SSH-Client.

💡 SSH-Client ist schon installiert

Auf Linux und macOS ist der SSH-Client bereits vorinstalliert. Unter Windows 10/11 ebenfalls (PowerShell oder Windows Terminal). Du brauchst nichts zu installieren.

Die erste SSH-Verbindung

Die einfachste Verbindung sieht so aus -- du tippst das auf deinem eigenen Rechner:

💻 Auf deinem Rechner

Ersetze benutzername und 192.168.1.50 durch die echten Daten deines Servers.

Verbindung per Passwort
ssh benutzername@192.168.1.50
# Beim ersten Mal kommt eine Fingerprint-Warnung -- mit "yes" bestätigen
# Danach dein Passwort eingeben (Zeichen werden NICHT angezeigt)

Du kannst statt der IP-Adresse auch einen Hostnamen verwenden, wenn DNS funktioniert:

ssh admin@mein-server.local
💻 Auf deinem Rechner

Manchmal läuft SSH nicht auf dem Standard-Port 22. Dann gibst du den Port mit -p an:

ssh -p 2222 admin@192.168.1.50
⚠️ Fingerprint-Warnung beim ersten Verbinden

Beim allerersten Verbinden fragt SSH: "Are you sure you want to continue connecting?". Das ist normal -- SSH kennt den Server noch nicht. Bestätige mit yes. Der Fingerprint wird dann in ~/.ssh/known_hosts auf deinem Rechner gespeichert. Kommt die Warnung später nochmal, könnte jemand den Server fälschen -- dann Vorsicht!

SSH-Schlüsselpaare -- Anmelden ohne Passwort

Passwörter sind umständlich und unsicher. Die bessere Methode ist ein SSH-Schlüsselpaar. Du hast zwei Dateien:

  • Privater Schlüssel (id_ed25519) -- bleibt auf deinem Rechner. Niemals weitergeben!
  • Öffentlicher Schlüssel (id_ed25519.pub) -- wird auf den Server kopiert. Kann bedenkenlos geteilt werden.

Stell dir das wie ein Schloss mit Schlüssel vor: Den öffentlichen Schlüssel (das Schloss) hängst du an den Server. Den privaten Schlüssel (der echte Schlüssel) behältst du bei dir.

Schlüsselpaar erstellen

💻 Auf deinem Rechner

Dieser Befehl erstellt dein Schlüsselpaar. Er läuft auf deinem eigenen Computer -- nicht auf dem Server.

Schlüsselpaar generieren
ssh-keygen -t ed25519 -C "mein-laptop"
# -t ed25519 = moderner, sicherer Algorithmus
# -C = Kommentar (hilft beim Zuordnen)

# Du wirst gefragt:
# 1. Speicherort (Enter = Standard: ~/.ssh/id_ed25519)
# 2. Passphrase (optional, aber empfohlen -- schützt den Schlüssel)

Nach dem Erstellen findest du zwei Dateien auf deinem Rechner:

DateiTypBedeutung
~/.ssh/id_ed25519PrivatDein geheimer Schlüssel -- nie teilen!
~/.ssh/id_ed25519.pubÖffentlichWird auf den Server kopiert
🚨 Privaten Schlüssel NIEMALS weitergeben

Der private Schlüssel (id_ed25519 ohne .pub) ist wie dein Haustürschlüssel. Wer ihn hat, kommt auf alle Server, für die er eingerichtet ist. Teile ihn nicht per E-Mail, Chat oder Cloud. Setze eine starke Passphrase.

Öffentlichen Schlüssel auf den Server kopieren

💻 Auf deinem Rechner

ssh-copy-id läuft auf deinem Rechner und verbindet sich einmalig mit dem Server, um den Schlüssel zu übertragen. Du brauchst dafür noch einmal dein Passwort.

Schlüssel übertragen
ssh-copy-id admin@192.168.1.50
# Fragt einmalig das Passwort ab
# Kopiert deinen öffentlichen Schlüssel auf den Server
💻 Auf deinem Rechner

Ab jetzt kannst du dich ohne Passwort anmelden:

ssh admin@192.168.1.50
# Keine Passwort-Abfrage mehr! (nur ggf. die Passphrase des Schlüssels)
🧠 Was passiert im Hintergrund?

ssh-copy-id fügt deinen öffentlichen Schlüssel in die Datei ~/.ssh/authorized_keys auf dem Server ein. Das ~ steht hier für das Home-Verzeichnis des Benutzers auf dem Server -- nicht auf deinem Rechner. Du könntest das auch manuell tun: nach dem SSH-Login den Inhalt von id_ed25519.pub in die Datei auf dem Server einfügen. ssh-copy-id macht es nur bequemer.

Überprüfen: Schlüssel auf dem Server angekommen?

🖥️ Auf dem Server -- erst per SSH einloggen, dann diesen Befehl eingeben

Verbinde dich zuerst mit ssh admin@192.168.1.50 auf den Server. Sobald du eingeloggt bist, prüfe den Inhalt der authorized_keys-Datei:

cat ~/.ssh/authorized_keys
# Du solltest eine Zeile sehen, die mit "ssh-ed25519" beginnt
# und mit deinem Kommentar "mein-laptop" endet

Anschließend Verbindung beenden:

exit
Die SSH-Config -- Abkürzungen für Verbindungen
📝 Dateien bearbeiten mit nano

Um eine Textdatei anzulegen oder zu bearbeiten, nutzen wir hier nano -- einen einfachen Editor, der direkt im Terminal läuft. Du brauchst für nano kein Vorwissen:

  • nano DATEINAME -- Datei öffnen (wird neu erstellt, falls sie noch nicht existiert)
  • Text eingeben und bearbeiten wie in einem normalen Texteditor
  • Ctrl+O dann Enter -- Datei speichern
  • Ctrl+X -- nano schließen

In Modul 03 lernst du ausführlich, wie du mit Texteditoren im Terminal arbeitest.

💻 Auf deinem Rechner

Wenn du dich täglich auf mehrere Server verbindest, wird das Tippen von Benutzernamen, IP-Adressen und Ports schnell lästig. Die SSH-Config-Datei auf deinem Rechner ist deine Abkürzung.

Öffne die Datei mit nano (sie wird neu angelegt, falls sie noch nicht existiert):

nano ~/.ssh/config

Füge folgenden Inhalt ein -- passe IP-Adresse und Benutzername an deinen Server an:

~/.ssh/config -- Inhalt der Datei
# Datei: ~/.ssh/config -- liegt auf DEINEM Rechner

Host webserver
    HostName 192.168.1.50
    User admin
    Port 22

Host backup
    HostName 10.0.0.200
    User root
    Port 2222
    IdentityFile ~/.ssh/id_backup

Danach verbindest du dich einfach mit dem Kurznamen:

ssh webserver     # statt: ssh admin@192.168.1.50
ssh backup        # statt: ssh -p 2222 root@10.0.0.200
OptionBedeutung
HostDein frei wählbarer Kurzname
HostNameIP-Adresse oder Domain des Servers
UserBenutzername auf dem Server
PortSSH-Port (Standard: 22)
IdentityFilePfad zu einem bestimmten privaten Schlüssel
Dateien per SCP übertragen
💻 Auf deinem Rechner

SSH kann nicht nur Befehle ausführen, sondern auch Dateien kopieren. Das Werkzeug heißt SCP (Secure Copy). Alle SCP-Befehle gibst du auf deinem Rechner ein -- SCP kümmert sich selbst um die Verbindung zum Server.

Dateien kopieren
# Datei von deinem Rechner → Server
scp datei.txt admin@192.168.1.50:/home/admin/

# Datei vom Server → deinen Rechner
scp admin@192.168.1.50:/var/log/syslog ./syslog-kopie.txt

# Ganzen Ordner kopieren (rekursiv)
scp -r mein-ordner/ admin@192.168.1.50:/tmp/

Wenn du die SSH-Config eingerichtet hast, funktionieren auch die Kurznamen:

scp datei.txt webserver:/home/admin/
SSH-Tunnel -- Dienste sicher durchschleusen

Manchmal läuft ein Dienst auf einem Server, der nur lokal erreichbar ist -- z.B. eine Datenbank auf 127.0.0.1:3306. Mit einem SSH-Tunnel leitest du diesen Port verschlüsselt auf deinen Rechner um.

💻 Auf deinem Rechner

Dieser Befehl baut den Tunnel auf -- du tippst ihn auf deinem Rechner. SSH verbindet sich mit dem Server und leitet den dortigen Port zu dir durch.

Lokalen Tunnel aufbauen
ssh -L 3306:127.0.0.1:3306 admin@192.168.1.50
# -L = Local Tunnel
# 3306 (links) = Port auf DEINEM Rechner
# 127.0.0.1:3306 (rechts) = Ziel auf dem SERVER

Jetzt kannst du auf deinem Rechner localhost:3306 aufrufen und erreichst die Datenbank auf dem Server -- verschlüsselt durch den SSH-Tunnel.

💡 Wann brauchst du Tunnel?

Immer wenn ein Dienst nur auf 127.0.0.1 lauscht (sichtbar in ss -tulpn aus Modul 01) und du ihn von deinem Rechner aus nutzen willst. Typisch: Datenbanken, Admin-Panels, interne Webseiten.

SSH-Server absichern (sshd_config)
🖥️ Auf dem Server -- per SSH eingeloggt

Der SSH-Server hat eine Konfigurationsdatei: /etc/ssh/sshd_config. Sie liegt auf dem Server -- öffne sie nach dem SSH-Login mit nano:

sudo nano /etc/ssh/sshd_config
# sudo ist nötig, weil die Datei root gehört
# Speichern: Ctrl+O → Enter · Schließen: Ctrl+X

Suche in der Datei die folgenden Einstellungen und passe sie an (oder füge sie hinzu, falls sie fehlen):

/etc/ssh/sshd_config -- wichtige Einstellungen
# Root-Login verbieten (immer als normaler User anmelden, dann sudo)
PermitRootLogin no

# Passwort-Anmeldung deaktivieren (nur noch Schlüssel erlauben)
PasswordAuthentication no

# Nur bestimmte Benutzer erlauben
AllowUsers admin deploy

# Port ändern (optional, reduziert automatisierte Angriffe)
Port 2222

# Leere Passwörter verbieten
PermitEmptyPasswords no

Nach Änderungen musst du den SSH-Dienst neu laden. Das reload statt restart ist wichtig -- bestehende Verbindungen bleiben so erhalten:

sudo systemctl reload sshd
🚨 Sperre dich nicht aus!

Bevor du PasswordAuthentication no setzt, stelle sicher, dass dein SSH-Schlüssel funktioniert! Teste die Schlüssel-Anmeldung in einer zweiten, parallelen SSH-Sitzung (zweites Terminalfenster öffnen, neu verbinden), bevor du die Passwort-Anmeldung deaktivierst. Sonst kommst du nicht mehr auf den Server.

⚠️ Reihenfolge beachten

1. Schlüsselpaar erstellen. 2. Öffentlichen Schlüssel auf den Server kopieren. 3. Schlüssel-Login testen (zweites Terminal!). 4. Erst dann Passwort-Login deaktivieren. Niemals Schritt 4 vor Schritt 3!

🤖
KI-Tipp: sshd_config verstehen

Die Datei /etc/ssh/sshd_config hat viele Optionen. Wenn du dir unsicher bist, was eine Einstellung bewirkt, kopiere die relevanten Zeilen und frag: "Erkläre mir diese sshd_config-Zeilen auf Deutsch. Was bewirkt jede Einstellung und ist sie sicher?"

Nützliche SSH-Tricks

Befehl direkt auf dem Server ausführen

💻 Auf deinem Rechner

Du kannst einen einzelnen Befehl auf dem Server ausführen, ohne eine interaktive SSH-Sitzung zu öffnen. Der Befehl wird in Anführungszeichen nach der Server-Adresse angegeben:

ssh webserver "df -h"           # Festplattenplatz anzeigen
ssh webserver "cat /etc/hostname" # Hostnamen abfragen

SSH-Verbindung am Leben halten

💻 Auf deinem Rechner

Wenn die Verbindung nach Inaktivität abbricht, füge in deine ~/.ssh/config auf deinem Rechner ein:

Host *
    ServerAliveInterval 60
    ServerAliveCountMax 3

SSH sendet dann alle 60 Sekunden ein Keep-Alive-Signal.

Mehrere Schlüssel verwalten

💻 Auf deinem Rechner

Für verschiedene Server kannst du verschiedene Schlüssel erstellen und in der SSH-Config zuweisen:

ssh-keygen -t ed25519 -f ~/.ssh/id_arbeit -C "arbeit-server"
ssh-keygen -t ed25519 -f ~/.ssh/id_privat -C "privat-server"

In der SSH-Config weist du dann jedem Host den passenden Schlüssel zu (mit IdentityFile).

Praxisaufgaben
AUFGABE 2.1 Erste SSH-Verbindung herstellen

Du verbindest dich zum ersten Mal per SSH mit einem Server oder einer virtuellen Maschine in deinem Netzwerk. Dafür brauchst du die IP-Adresse des Servers und einen Benutzernamen.

1
Finde die IP-Adresse deines Servers heraus: Entweder über die Router-Oberfläche (meist 192.168.x.x) oder -- falls du direkten Zugang zum Server hast -- durch Ablesen vom Bildschirm des Servers.
2
Öffne ein Terminal auf deinem Rechner und verbinde dich: ssh benutzername@IP-ADRESSE. Bestätige den Fingerprint mit yes und gib dein Passwort ein.
🖥️ Du bist jetzt auf dem Server angemeldet -- alle folgenden Schritte laufen dort
3
Prüfe, wo du gelandet bist: Gib whoami ein (zeigt deinen Benutzernamen auf dem Server) und dann hostname (zeigt den Namen des Servers). Beide Ausgaben sollten sich von deinem lokalen Rechner unterscheiden.
💻 Zurück auf deinem Rechner -- tippe exit, um die Verbindung zu trennen, oder öffne ein zweites Terminal
4
Schau dir den gespeicherten Fingerprint an: cat ~/.ssh/known_hosts. Diese Datei liegt auf deinem Rechner und enthält einen Eintrag pro bekanntem Server.
5
Verbinde dich ein zweites Mal: ssh benutzername@IP-ADRESSE. Diesmal kommt keine Fingerprint-Warnung mehr -- SSH erkennt den Server wieder.
Lösungshinweise anzeigen

whoami zeigt den Benutzernamen, mit dem du auf dem Server angemeldet bist. hostname zeigt den Servernamen. Beides sollte sich von deinem lokalen Rechner unterscheiden -- das bestätigt, dass du wirklich auf dem Server bist.

In ~/.ssh/known_hosts auf deinem Rechner steht eine lange Zeile pro bekanntem Server mit IP-Adresse und Fingerprint.

AUFGABE 2.2 SSH-Schlüsselpaar einrichten

Du richtest eine schlüsselbasierte Anmeldung ein -- die sicherste und bequemste Methode. Alle Schritte bis auf Schritt 5 laufen auf deinem eigenen Rechner.

1
Erstelle auf deinem Rechner ein Schlüsselpaar: ssh-keygen -t ed25519 -C "mein-rechner". Wähle eine Passphrase (mindestens 8 Zeichen).
2
Prüfe auf deinem Rechner, dass beide Dateien existieren: ls -la ~/.ssh/id_ed25519*. Du solltest zwei Dateien sehen: die ohne Endung (privat) und die mit .pub (öffentlich).
3
Kopiere den öffentlichen Schlüssel auf den Server: ssh-copy-id benutzername@IP-ADRESSE. Dieser Befehl läuft auf deinem Rechner und fragt einmalig dein Passwort ab.
4
Teste auf deinem Rechner die schlüsselbasierte Anmeldung: ssh benutzername@IP-ADRESSE. Du solltest kein Server-Passwort mehr eingeben müssen -- nur ggf. die Passphrase deines Schlüssels.
🖥️ Für Schritt 5: Verbinde dich per SSH auf den Server
5
Prüfe auf dem Server den Inhalt von ~/.ssh/authorized_keys: cat ~/.ssh/authorized_keys. Findest du deinen Kommentar "mein-rechner" am Ende der Zeile?
💻 Schritt abgeschlossen -- tippe exit um den Server zu verlassen
Lösungshinweise anzeigen

Nach ssh-keygen siehst du auf deinem Rechner zwei Dateien: id_ed25519 (privat, Rechte 600) und id_ed25519.pub (öffentlich).

Die Datei ~/.ssh/authorized_keys auf dem Server enthält genau den Inhalt deiner .pub-Datei -- eine Zeile beginnend mit ssh-ed25519 und endend mit mein-rechner.

AUFGABE 2.3 SSH-Config und SCP nutzen

Du richtest eine SSH-Config ein und überträgst Dateien per SCP. Alle Schritte laufen auf deinem Rechner -- SCP und SSH kümmern sich selbst um die Verbindung zum Server.

💻 Alle folgenden Schritte auf deinem Rechner
1
Öffne die SSH-Config auf deinem Rechner mit: nano ~/.ssh/config. Füge folgenden Block ein (IP und Benutzername anpassen) und speichere mit Ctrl+O → Enter, schließe mit Ctrl+X:

Host mein-server
    HostName 192.168.1.50
    User admin
    Port 22
2
Teste den Kurznamen in deinem Terminal: ssh dein-kurzname. Du solltest direkt verbunden werden -- ohne IP-Adresse einzutippen. Tippe exit um die Verbindung wieder zu trennen.
3
Erstelle eine Testdatei auf deinem Rechner: echo "Hallo vom Laptop" > test.txt. Der Befehl echo gibt Text aus, das > leitet die Ausgabe in eine Datei um -- sie wird neu erstellt. Du solltest keine Ausgabe sehen; die Datei entsteht still im Hintergrund.
4
Kopiere die Datei auf den Server: scp test.txt dein-kurzname:/tmp/. SCP läuft auf deinem Rechner und überträgt die Datei automatisch.
5
Prüfe, ob die Datei angekommen ist -- ohne dich einzuloggen: ssh dein-kurzname "cat /tmp/test.txt". Dieser Befehl wird auf deinem Rechner eingegeben, führt aber cat auf dem Server aus und zeigt dir das Ergebnis.
Lösungshinweise anzeigen

Die SSH-Config muss Rechte 600 oder 644 haben. Falls der Kurzname nicht funktioniert, prüfe Einrückung (4 Leerzeichen) und Schreibweise in der Datei -- Groß-/Kleinschreibung bei Host, HostName usw. beachten.

Schritt 5 zeigt, wie SSH als "Fernsteuerung" funktioniert: du tippst lokal, der Server führt aus und schickt die Ausgabe zurück zu dir.

🤖
KI-Tipp: SSH-Fehler diagnostizieren

SSH-Verbindungen schlagen oft mit kryptischen Meldungen fehl: "Permission denied (publickey)", "Connection refused" oder "Host key verification failed". Kopiere die Fehlermeldung und frag: "Ich bekomme diesen SSH-Fehler. Was bedeutet er und wie behebe ich ihn? Mein Setup: Ubuntu 24.04, Schlüssel-Authentifizierung."

Modul 035 Unterrichtseinheiten

Bash & Editor vim

Das Terminal ist dein wichtigstes Werkzeug auf dem Server. In diesem Modul lernst du, wie du dich im Linux-Dateisystem bewegst, Dateien und Texte verwaltest und mit dem Editor vim Konfigurationsdateien bearbeitest -- alles direkt auf der Kommandozeile.

Voraussetzung: Modul 01 Voraussetzung: Modul 02 (SSH) Navigation · grep · find · Pipes · vim
Bevor wir starten: Alles passiert auf dem Server

In Modul 02 hast du gelernt, wie du dich per SSH mit dem Server verbindest. Ab dem Moment, wo du eingeloggt bist, läuft alles in diesem Modul auf dem Server. Du schreibst in deinem Terminal -- dein Rechner zeigt dir die Ausgabe an --, aber die Befehle werden auf dem Server ausgeführt.

💡 Alle Befehle in diesem Modul gibst du auf dem Server ein

Melde dich zuerst per SSH auf deinem Server an: ssh benutzername@IP-ADRESSE. Sobald du den Prompt siehst (z.B. admin@server01:~$), bist du bereit. Alle folgenden Befehle führst du in dieser Sitzung aus.

Die Shell -- dein Cockpit auf dem Server

Nach dem SSH-Login landest du in der Shell. Die Shell ist ein Programm, das deine Eingaben entgegennimmt, ausführt und dir das Ergebnis zurückgibt. Auf Debian/Ubuntu heißt sie Bash (Bourne Again Shell). Stell dir die Shell wie das Armaturenbrett in einem Auto vor: erst fremd, aber sobald du die wichtigsten Elemente kennst, willst du nicht mehr zurück.

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt

Der Prompt zeigt dir immer, wer du bist und wo du dich befindest:

Aufbau des Prompts
admin@server01:~$
# admin    = dein Benutzername
# server01 = Hostname des Servers
# ~        = aktuelles Verzeichnis (~ ist Abkürzung für dein Home-Verzeichnis)
# $        = normaler Benutzer (# bedeutet: du bist root)
Navigation im Dateisystem

Linux hat keine Laufwerksbuchstaben wie Windows (C:, D:). Alles hängt an einem einzigen Stammverzeichnis: /. Stell es dir wie einen Baum vor -- der Stamm ist /, alle Äste (Ordner) wachsen davon ab.

🖥️ Auf dem Server
Grundlegende Navigationsbefehle
pwd                     # Aktuelles Verzeichnis anzeigen (Print Working Directory)
ls                      # Inhalt des aktuellen Verzeichnisses auflisten
ls -la                  # Detailliert inkl. versteckter Dateien (beginnen mit .)
ls -lh                  # Mit lesbaren Dateigrößen (KB, MB, GB)
cd /var/log             # In ein anderes Verzeichnis wechseln
cd ..                   # Ein Verzeichnis nach oben gehen
cd                      # Immer zurück ins Home-Verzeichnis (~)
cd -                    # Ins zuletzt besuchte Verzeichnis wechseln

Wichtige Verzeichnisse kennen

PfadWas ist dort
/Stammverzeichnis -- der Anfang von allem
/home/adminDein persönliches Home-Verzeichnis (Abkürzung: ~)
/etcKonfigurationsdateien des Systems und der Dienste
/var/logLog-Dateien -- hier steht, was auf dem System passiert
/tmpTemporäre Dateien -- werden beim Neustart gelöscht
/usr/binInstallierte Programme und Befehle
/rootHome-Verzeichnis des root-Benutzers
🧠 Tab-Vervollständigung: deine wichtigste Abkürzung

Drücke nach den ersten Buchstaben eines Befehls oder Pfades die Tab-Taste. Die Shell vervollständigt automatisch. Zweimal Tab zeigt alle Möglichkeiten. Das spart enorm viel Tipparbeit und verhindert Tippfehler.

Dateien und Ordner verwalten
🖥️ Auf dem Server
Dateien lesen
cat datei.txt            # Gesamten Inhalt anzeigen
less /var/log/syslog     # Große Datei seitenweise lesen (q = beenden)
head -20 datei.txt       # Erste 20 Zeilen anzeigen
tail -20 datei.txt       # Letzte 20 Zeilen anzeigen
tail -f /var/log/syslog  # Live: neue Zeilen in Echtzeit (Ctrl+C = beenden)
Ordner und Dateien erstellen
mkdir projekte            # Neuen Ordner erstellen
mkdir -p a/b/c           # Verschachtelte Ordner auf einmal erstellen
touch datei.txt          # Leere Datei erstellen
echo "Hallo" > datei.txt  # Text in Datei schreiben (überschreibt!)
echo "Mehr" >> datei.txt  # Text an Datei anhängen
Kopieren, Verschieben, Umbenennen
cp datei.txt kopie.txt    # Datei kopieren
cp -r ordner/ backup/    # Ganzen Ordner rekursiv kopieren
mv datei.txt neu.txt      # Datei umbenennen
mv datei.txt /tmp/       # Datei in anderes Verzeichnis verschieben
🚨 rm -- Löschen ohne Papierkorb

Linux hat keinen Papierkorb. Was du mit rm löschst, ist sofort und unwiderruflich weg. Sei besonders vorsichtig:

rm datei.txt              # Einzelne Datei löschen -- keine Rückfrage!
rm -r ordner/             # Ordner mit allem Inhalt löschen
rm -i datei.txt           # Sicher: fragt vor dem Löschen nach

rm -rf / löscht das gesamte System -- führe diesen Befehl niemals aus. Tippe immer genau hin, was du löschen willst.

Textsuche mit grep und find

grep durchsucht Dateien nach Textmustern -- wie eine Suchfunktion, nur für das Terminal. find sucht nach Dateien und Ordnern im Dateisystem selbst.

🖥️ Auf dem Server
grep -- in Dateien suchen
grep "error" /var/log/syslog          # Zeilen mit "error" finden
grep -i "error" /var/log/syslog       # Groß-/Kleinschreibung ignorieren
grep -r "Port 22" /etc/              # Rekursiv in allen Dateien unter /etc/
grep -n "root" /etc/passwd           # Mit Zeilennummer
grep -v "#" /etc/ssh/sshd_config      # Zeilen OHNE Kommentare anzeigen
find -- Dateien aufspüren
find /etc -name "*.conf"              # Alle .conf-Dateien unter /etc
find /var/log -name "*.log" -mtime -1   # Log-Dateien, geändert in den letzten 24h
find /home -size +100M               # Dateien größer als 100 MB
find /tmp -type f -empty             # Leere Dateien finden
🧠 grep -v zeigt das Wesentliche

Konfigurationsdateien wie sshd_config enthalten oft mehr Kommentare als echte Einstellungen. Mit grep -v "^#" /etc/ssh/sshd_config | grep -v "^$" siehst du nur die aktiven Zeilen -- ohne Kommentare und Leerzeilen.

Pipes -- Befehle clever verketten

Die wirkliche Stärke der Shell zeigt sich, wenn du Befehle miteinander kombinierst. Mit dem Pipe-Zeichen | leitest du die Ausgabe eines Befehls direkt als Eingabe in den nächsten. Stell dir eine Fließbandproduktion vor: jeder Befehl macht einen Arbeitsschritt, dann gibt er das Ergebnis weiter.

🖥️ Auf dem Server
Pipes in der Praxis
# Lauschende Ports finden und nach SSH filtern
ss -tulpn | grep ":22"

# Wie viele Benutzer gibt es auf dem System?
cat /etc/passwd | wc -l

# Die 5 größten Dateien unter /var/log finden
du -ah /var/log | sort -rh | head -5

# Aktive Einstellungen aus sshd_config (ohne Kommentare und Leerzeilen)
grep -v "^#" /etc/ssh/sshd_config | grep -v "^$"
Ausgabe in Dateien umleiten
ls /var/log > logdateien.txt         # Ausgabe in Datei speichern (überschreibt)
echo "Neue Zeile" >> logdateien.txt   # An bestehende Datei anhängen
find /etc -name "*.conf" 2>/dev/null  # Fehlermeldungen verwerfen
💡 Die drei Kanäle: stdin, stdout, stderr

Jedes Programm hat drei Kanäle: stdin (Eingabe), stdout (normale Ausgabe) und stderr (Fehlermeldungen). Mit > leitest du stdout um, mit 2> stderr. Mit 2>/dev/null verwirfst du Fehlermeldungen -- sehr nützlich bei find.

Bash-Tricks: schneller arbeiten

Diese kleinen Tricks machen den Unterschied zwischen mühsamer Tipparbeit und flüssigem Arbeiten.

🖥️ Auf dem Server
Befehlshistorie und Abkürzungen
# Befehlshistorie
history                   # Letzte Befehle anzeigen
history | grep "ssh"    # Nur SSH-Befehle aus der Historie

# In der Historie navigieren:
# Pfeiltaste hoch/runter = vorherige/nächste Befehle
# Ctrl+R = interaktive Rückwärtssuche in der Historie
# !! = letzten Befehl wiederholen
# !ssh = letzten Befehl, der mit "ssh" anfing, wiederholen
Aliase -- eigene Abkürzungen definieren
# Temporärer Alias (gilt nur in dieser Sitzung)
alias ll="ls -lah"
alias frei="df -h"

# Permanente Aliase: in ~/.bashrc eintragen
echo 'alias ll="ls -lah"' >> ~/.bashrc
source ~/.bashrc          # Änderungen sofort aktiv machen
TastenkürzelAktion
TabBefehl oder Pfad vervollständigen
Tab TabAlle Möglichkeiten zur Vervollständigung anzeigen
Pfeiltaste oben/untenDurch frühere Befehle blättern
Ctrl+RIn der Befehlshistorie rückwärts suchen
Ctrl+CLaufenden Befehl abbrechen
Ctrl+LTerminal leeren (wie clear)
Ctrl+ACursor an den Anfang der Zeile
Ctrl+ECursor ans Ende der Zeile
🤖
KI-Tipp: Befehle erklären und zusammenbauen lassen

Wenn du eine bestimmte Information brauchst oder einen Befehl nicht verstehst, beschreibe dein Ziel: "Erkläre mir diesen Bash-Befehl Schritt für Schritt: du -ah /var/log | sort -rh | head -5. Was macht jeder Teil?" -- oder: "Wie finde ich unter Linux alle Dateien im Ordner /var/log, die größer als 50 MB sind und in den letzten 7 Tagen geändert wurden?"

Der Editor vim

Auf Servern gibt es keine Maus und keine grafischen Programme. Um eine Konfigurationsdatei zu bearbeiten, brauchst du einen Editor, der direkt im Terminal läuft. vim ist auf praktisch jedem Linux-System vorinstalliert -- auch auf minimalen Server-Installationen ohne Extras.

vim hat einen Ruf, kompliziert zu sein. Der Grund: Es gibt Modi. Du kannst nicht einfach lostippen. Aber sobald du die drei wichtigsten Modi verstehst, wirst du feststellen, dass vim extrem effizient ist -- wie ein Spezialwerkzeug, das sich zunächst fremd anfühlt, aber nach kurzer Übung nicht mehr wegzudenken ist.

Die drei Modi von vim

ModusWozuWie aktivieren
Normal-ModusNavigieren, Löschen, Kopieren -- der Standard-Modus beim ÖffnenEsc
Einfüge-ModusText eingeben und bearbeiteni
BefehlsmodusSpeichern, Beenden, Suchen, Ersetzen: (Doppelpunkt)
🖥️ Auf dem Server
vim -- die wichtigsten Befehle
vim datei.txt             # Datei öffnen (oder neu erstellen)

# Du startest im Normal-Modus
i                          # → Einfüge-Modus: jetzt kannst du tippen
Esc                        # → zurück zum Normal-Modus (immer dein Sicherheitsnetz)

# Speichern und Beenden (aus dem Normal-Modus, dann : drücken)
:w                         # Speichern (write)
:q                         # Beenden (quit) -- nur wenn keine ungespeicherten Änderungen
:wq                        # Speichern und beenden
:q!                        # Beenden OHNE Speichern (Änderungen verwerfen)
🧠 vim-Überlebensstrategie für Einsteiger

Du musst vim nicht meistern -- du musst es bedienen können. Merke dir diese eine Sequenz: i zum Tippen → Esc:wq zum Speichern und Raus. Das reicht für 90 % der Fälle. Wenn du dich verirrt hast: Esc drücken, dann :q! -- raus ohne Speichern, kein Schaden angerichtet.

Nützliche vim-Befehle im Normal-Modus

TasteAktion
iEinfüge-Modus (vor dem Cursor)
aEinfüge-Modus (nach dem Cursor)
oNeue Zeile darunter + Einfüge-Modus
ddGanze Zeile löschen
yyGanze Zeile kopieren
pEinfügen (nach dem Cursor)
uRückgängig machen (Undo)
ggZum Anfang der Datei springen
GZum Ende der Datei springen
/suchbegriffSuchen -- n = nächster Treffer
:set numberZeilennummern einblenden
:%s/alt/neu/gAlle "alt" durch "neu" ersetzen

Alternative: nano

Wenn vim im Moment zu viel ist, gibt es auch nano -- einen einfacheren Editor, der die Tastenkürzel am unteren Rand anzeigt. Ctrl+O speichert, Ctrl+X beendet. Trotzdem: Lerne vim. Manche Systembefehle wie visudo oder crontab -e öffnen automatisch vim -- dann musst du wissen, wie du rauskommst.

🤖
KI-Tipp: vim-Befehle nachschlagen lassen

vim hat hunderte Befehle. Du musst sie nicht auswendig lernen. Wenn du etwas Bestimmtes tun willst: "Wie ersetze ich in vim in der gesamten Datei alle Vorkommen von 'localhost' durch '192.168.1.50'? Zeige mir den Befehl und erkläre die Syntax."

Praxisaufgaben
AUFGABE 3.1 Im Dateisystem navigieren und Dateien verwalten

Du lernst die grundlegenden Navigationsbefehle, indem du dich durch das Dateisystem bewegst und einen Arbeitsordner für spätere Module anlegst.

🖥️ Melde dich per SSH auf deinem Server an -- alle Schritte laufen dort
1
Zeige dein aktuelles Verzeichnis an: pwd. Du solltest /home/deinname sehen. Schaue dir dann den Inhalt an: ls -la.
2
Wechsle nach /var/log und liste den Inhalt sortiert nach Größe auf: cd /var/log && ls -lhS. Welche Log-Datei ist am größten?
3
Zeige die letzten 15 Zeilen des Syslogs an: tail -15 syslog. Du bist bereits in /var/log, daher reicht der Dateiname ohne vollen Pfad.
4
Gehe zurück ins Home-Verzeichnis: cd. Erstelle dort einen Übungsordner: mkdir ~/uebung. Wechsle hinein und erstelle drei leere Dateien: touch a.txt b.txt c.txt.
5
Kopiere a.txt nach a-kopie.txt: cp a.txt a-kopie.txt. Benenne b.txt um: mv b.txt notizen.txt. Prüfe das Ergebnis: ls -la.
Lösungshinweise anzeigen

Nach dem SSH-Login zeigt pwd typischerweise /home/admin (dein Home-Verzeichnis). In /var/log ist syslog oft die größte Datei.

Im Ordner ~/uebung solltest du nach Schritt 5 vier Dateien sehen: a.txt, a-kopie.txt, notizen.txt und c.txt. Alle haben 0 Bytes, da touch leere Dateien erstellt.

AUFGABE 3.2 grep und Pipes -- Informationen aus dem System holen

Du kombinierst grep, find und Pipes, um gezielt Informationen aus dem System zu extrahieren -- genau das, was du im Server-Alltag regelmäßig brauchst.

🖥️ Auf dem Server -- du bist bereits eingeloggt
1
Zeige alle Benutzer, die eine Login-Shell haben: grep "/bin/bash" /etc/passwd. Wie viele sind es?
2
Zähle alle Einträge in /etc/passwd: cat /etc/passwd | wc -l. Die meisten sind Systembenutzer ohne echte Login-Shell.
3
Finde alle .conf-Dateien unter /etc und zähle sie: find /etc -name "*.conf" 2>/dev/null | wc -l. Das 2>/dev/null unterdrückt Fehlermeldungen für Ordner, auf die du keinen Zugriff hast.
4
Zeige die aktiven (nicht auskommentierten) Einstellungen der SSH-Konfiguration: grep -v "^#" /etc/ssh/sshd_config | grep -v "^$".
5
Finde die fünf größten Dateien unter /var: sudo du -ah /var 2>/dev/null | sort -rh | head -5. Welche Datei belegt am meisten Platz?
Lösungshinweise anzeigen

Auf einem frischen Ubuntu-Server haben typischerweise nur ein oder zwei Benutzer /bin/bash als Shell. Die meisten Einträge in /etc/passwd sind Systembenutzer mit /usr/sbin/nologin -- das ist normal und kein Problem.

Die aktiven SSH-Einstellungen sollten zehn bis zwanzig Zeilen ergeben -- deutlich weniger als die gesamte Datei, die meist über hundert Zeilen mit Kommentaren enthält.

AUFGABE 3.3 vim -- eine Konfigurationsdatei bearbeiten

Du übst vim, indem du eine Datei erstellst, Text eingibst, speicherst und wieder bearbeitest. Das ist genau der Ablauf, den du später bei echten Konfigurationsdateien brauchst.

🖥️ Auf dem Server -- du bist bereits eingeloggt
1
Öffne eine neue Datei: vim ~/uebung/notizen.txt. Du startest im Normal-Modus -- du kannst noch nicht direkt tippen.
2
Drücke i für den Einfüge-Modus. Unten siehst du -- INSERT --. Tippe drei Zeilen Text ein, z.B. deinen Servernamen, die IP-Adresse und ein kurzes Memo.
3
Drücke Esc, um in den Normal-Modus zurückzukehren. Tippe dann :wq und bestätige mit Enter. Die Datei wird gespeichert und vim beendet sich.
4
Prüfe den Inhalt: cat ~/uebung/notizen.txt. Stehen deine drei Zeilen drin?
5
Öffne die Datei erneut: vim ~/uebung/notizen.txt. Navigiere mit den Pfeiltasten zur zweiten Zeile. Drücke dd im Normal-Modus, um die Zeile zu löschen. Speichere mit :wq.
6
Prüfe mit cat ~/uebung/notizen.txt: Ist die zweite Zeile wirklich weg? Wenn ja, hast du vim erfolgreich benutzt.
Lösungshinweise anzeigen

Wenn du nach dem Öffnen von vim einfach lostippst und wirre Buchstaben oder Befehle erscheinen, bist du noch im Normal-Modus. Drücke Esc, dann :q! zum Beenden ohne Speichern -- und fang neu an.

Das -- INSERT -- am unteren Rand zeigt dir: du bist im Einfüge-Modus und kannst tippen. Wenn es fehlt, bist du im Normal-Modus.

Falls du dich mit :wq verspeichert hast (z.B. ein Tippfehler in der Datei): Öffne sie erneut mit vim, navigiere zur falschen Zeile und benutze u (Undo) oder dd (Zeile löschen).

Modul 041 Unterrichtseinheit

Dokumentation mit man

Du musst keine Optionen auswendig lernen. Linux bringt sein Handbuch direkt ins Terminal -- man zeigt dir zu jedem Befehl alles, was du brauchst. In diesem Modul lernst du, das Handbuch zu lesen, schnell darin zu suchen und mit tldr noch schneller ans Ziel zu kommen.

Voraussetzung: Modul 03 man · --help · tldr · apropos
🖥️ Server-Kontext

Alle Befehle in diesem Modul gibst du auf dem Server ein -- du bist bereits per SSH eingeloggt. man und die anderen Werkzeuge laufen direkt in deiner Terminal-Sitzung auf dem Server.

man-Pages -- das Handbuch im Terminal

Stell dir vor, du kaufst ein neues Werkzeug und es liegt ein vollständiges Reparaturhandbuch bei -- auf Knopfdruck abrufbar. Genau das ist man (kurz für manual). Jeder installierte Befehl bringt seine eigene Dokumentation mit, die du jederzeit aufrufen kannst.

🖥️ Auf dem Server

Rufe die man-Page eines Befehls auf, indem du man gefolgt vom Befehlsnamen eingibst:

man-Pages aufrufen
man ls           # Handbuch für den Befehl ls
man grep         # Handbuch für grep
man ssh          # Handbuch für SSH

Die man-Page öffnet sich im Pager less -- den du bereits aus Modul 03 kennst. Navigiere so:

TasteAktion
Leertaste / Page DownEine Seite vorblättern
b / Page UpEine Seite zurückblättern
/suchbegriffVorwärts suchen (z. B. /-i für die Option -i)
nNächsten Treffer anspringen
NVorherigen Treffer anspringen
qBeenden und zurück zum Terminal
🧠 Direkt zur gesuchten Option springen

Man-Pages sind oft lang. Statt alles durchzulesen: Drücke / und tippe den Namen der Option, nach der du suchst -- z. B. /-r in man grep. Mit n springst du von Treffer zu Treffer.

Aufbau einer man-Page

Alle man-Pages folgen einem einheitlichen Schema. Sobald du das kennst, findest du dich in jeder man-Page sofort zurecht -- egal ob man ssh oder man tar:

AbschnittInhalt
NAMEBefehlsname und eine kurze Beschreibung, was er tut
SYNOPSISSyntax-Übersicht: welche Optionen und Argumente gibt es?
DESCRIPTIONAusführliche Beschreibung des Befehls
OPTIONSAlle verfügbaren Flags erklärt (-l, --help, ...)
EXAMPLESPraxisbeispiele -- nicht in jeder man-Page vorhanden
FILESKonfigurationsdateien, die der Befehl verwendet
SEE ALSOVerwandte Befehle und Handbücher
💡 SYNOPSIS lesen -- ohne Angst

Die SYNOPSIS sieht oft einschüchternd aus. Eckige Klammern [...] bedeuten: optional. Alles ohne Klammern ist Pflicht. ... bedeutet: kann mehrfach angegeben werden. Beispiel: ls [OPTION]... [DATEI]... -- alle Optionen und Dateinamen sind optional.

man-Sektionen -- was steht wo

Das Linux-Handbuch ist in Sektionen aufgeteilt -- ähnlich wie Kapitel in einem Ordner. Manche Namen tauchen in mehreren Sektionen auf. passwd zum Beispiel gibt es als Befehl (Sektion 1) und als Konfigurationsdatei (Sektion 5):

SektionInhaltTypisches Beispiel
1Benutzerbefehle (täglich genutzt)man 1 grep
2Systemaufrufe (Kernel-Schnittstellen)man 2 open
3Bibliotheksfunktionen (Programmierung)man 3 printf
4Gerätedateien (/dev/...)man 4 tty
5Dateiformate und Konfigurationsdateienman 5 passwd
6Spiele und Bildschirmschonerman 6 fortune
7Übersichten und Konventionenman 7 ip
8Systembefehle (oft Root erforderlich)man 8 iptables
9Kernel-Routinen (nur für Entwickler)man 9 kmalloc
🖥️ Auf dem Server

Ohne Sektionsnummer öffnet man immer die niedrigste passende Sektion. Mit einer Zahl davor wählst du gezielt:

Sektionen gezielt aufrufen
man passwd          # Öffnet Sektion 1 -- der Befehl zum Passwort ändern
man 5 passwd        # Öffnet Sektion 5 -- Format der Datei /etc/passwd
man 5 sshd_config   # Alle Optionen der SSH-Server-Konfiguration
man 5 fstab         # Aufbau und Syntax von /etc/fstab
🧠 Sektion 5 ist Gold wert

Wenn du verstehen willst, welche Einstellungen eine Konfigurationsdatei hat, schau in Sektion 5 nach. man 5 sshd_config erklärt jede einzelne Option des SSH-Servers -- genauer als jeder Blog-Artikel.

Suchen mit apropos und man -k

Du weißt, was du tun willst -- aber nicht, wie der Befehl heißt? Kein Problem. apropos durchsucht alle man-Page-Beschreibungen nach deinem Stichwort. Das ist wie eine Volltextsuche im Handbuch.

🖥️ Auf dem Server
Stichwortsuche in allen man-Pages
apropos password    # Alle Befehle, die mit Passwörtern zu tun haben
apropos network     # Alle Befehle zum Thema Netzwerk
apropos disk        # Alle Befehle rund um Festplatten

# man -k ist identisch mit apropos
man -k password     # Gleiches Ergebnis wie apropos password

# whatis: nur eine kurze Einzeiler-Beschreibung
whatis grep         # → grep (1) - print lines that match patterns
whatis passwd        # Zeigt alle Sektionen, in denen passwd vorkommt
💡 apropos liefert zu viel? Filtern mit grep

apropos disk zeigt oft Dutzende Treffer. Kombiniere es mit grep aus Modul 03: apropos disk | grep -i format filtert die Ausgabe weiter. So findest du schnell, was du suchst.

--help, -h und tldr -- schneller ans Ziel

Manchmal brauchst du keine vollständige man-Page. Für eine schnelle Optionsübersicht reicht --help oder das moderne Werkzeug tldr.

🖥️ Auf dem Server

Fast jeder Befehl kennt --help oder -h -- das gibt eine kurze Übersicht aller Optionen aus, ohne den Pager zu öffnen:

Schnelle Hilfe mit --help
ls --help
grep --help
tar --help        # Kürzer als die man-Page, aber vollständig

tldr geht noch einen Schritt weiter: Es zeigt nur die häufigsten Anwendungsfälle mit kopierbaren Beispielen. Erst installieren, dann nutzen:

tldr installieren und nutzen
sudo apt install tldr
tldr --update         # Datenbank beim ersten Mal aktualisieren (braucht Internet)

tldr tar              # Die häufigsten tar-Befehle auf einen Blick
tldr find             # find-Beispiele -- deutlich übersichtlicher als man find
tldr ssh-keygen       # Bekannt aus Modul 02 -- sieh dir die Kurzfassung an
WerkzeugWann benutzenAusgabe
man befehlVollständige Dokumentation, alle OptionenViel Text, im Pager
befehl --helpSchnelle OptionsübersichtDirekt ins Terminal
tldr befehlHäufigste Anwendungsfälle mit BeispielenKompakt, farbig
whatis befehlEine-Zeile-BeschreibungEinzeiler
apropos stichwortBefehl suchen, Name unbekanntListe passender Befehle
🤖
KI-Tipp: man-Pages auf Deutsch erklärt bekommen

Man-Pages sind fast immer auf Englisch. Wenn du eine Option nicht verstehst, kopiere den entsprechenden Abschnitt und frag: "Übersetze und erkläre mir diesen Abschnitt der man-Page von sshd_config auf Deutsch. Was bedeuten die Optionen im Alltag eines Server-Administrators?"

Praxisaufgaben
AUFGABE 4.1 man-Pages lesen und navigieren

Du lernst, man-Pages effizient zu nutzen -- ohne jeden Browser zu öffnen. Alle Schritte laufen auf dem Server.

1
Öffne man grep. Drücke / und suche nach -i. Welche Funktion hat die Option -i laut Beschreibung?
2
Öffne man 5 sshd_config. Suche nach /PermitRootLogin. Welche Werte sind laut Handbuch erlaubt?
3
Vergleiche man passwd und man 5 passwd -- öffne beide nacheinander. Was beschreibt jeweils die DESCRIPTION-Sektion?
4
Nutze apropos disk. Welche Befehle findest du? Erkennst du einen, der aus Modul 03 bekannt ist?
5
Prüfe mit whatis ls und whatis passwd, was dir die Einzeiler-Beschreibung sagt. Siehst du bei passwd mehrere Sektionen?
Lösungshinweise anzeigen

Die Option -i bei grep steht für "ignore case" -- Groß- und Kleinschreibung werden beim Suchen ignoriert.

PermitRootLogin in der sshd_config akzeptiert: yes, no, prohibit-password und forced-commands-only. Empfehlung: no.

man passwd (Sektion 1) beschreibt den Befehl zum Ändern des Passworts. man 5 passwd beschreibt das Dateiformat von /etc/passwd -- die Liste aller Benutzer auf dem System.

whatis passwd zeigt dir beide Einträge: passwd (1) und passwd (5) in einer Ausgabe.

AUFGABE 4.2 tldr installieren und mit man vergleichen

Du installierst tldr und lernst, wann du welches Werkzeug einsetzt. Alle Schritte laufen auf dem Server.

1
Installiere tldr: sudo apt install tldr. Danach einmal die Datenbank aktualisieren: tldr --update. Das braucht eine Internetverbindung.
2
Öffne man tar und dann tldr tar. Wie viele Zeilen hat jeweils die Ausgabe? Welche Variante ist für den schnellen Alltag besser?
3
Rufe tldr find auf. Findest du direkt einen Befehl, den du sofort für eine Dateisuche kopieren könntest?
4
Teste tldr ssh-keygen -- den Befehl kennst du aus Modul 02. Stimmt die Kurzfassung mit dem überein, was du damals gemacht hast?
Lösungshinweise anzeigen

man tar hat mehrere hundert Zeilen mit allen Optionen. tldr tar zeigt in etwa 20 Zeilen die häufigsten Anwendungsfälle mit kopierbaren Beispielen. Für den Alltag ist tldr deutlich schneller.

Falls tldr --update fehlschlägt, prüfe die Internetverbindung des Servers. Die Datenbank wird von GitHub heruntergeladen.

Die Kurzfassung von tldr ssh-keygen zeigt genau den Befehl ssh-keygen -t ed25519, den du in Modul 02 verwendet hast.

AUFGABE 4.3 Unbekannten Befehl per apropos finden

Ein typischer Alltag: Du weißt, was du tun willst, aber nicht den genauen Befehl. Mit apropos findest du ihn in Sekunden.

1
Du willst den freien Festplattenplatz prüfen, weißt aber nicht den Befehl: apropos disk | grep free. Welche Ergebnisse bekommst du?
2
Öffne die man-Page eines vielversprechenden Befehls aus Schritt 1. Lies die DESCRIPTION und prüfe, ob er das tut, was du gesucht hast.
3
Suche nach Befehlen zum Thema Komprimierung: apropos compress. Welche Befehle kennst du schon, welche sind neu?
4
Rufe für einen neuen Befehl aus Schritt 3 sowohl man befehl als auch -- falls vorhanden -- tldr befehl auf. Nutze /EXAMPLES in der man-Page, um direkt zum Beispiel-Abschnitt zu springen.
Lösungshinweise anzeigen

apropos disk | grep free liefert in der Regel df (1) -- "disk free". df -h zeigt den freien Platz in lesbaren Einheiten (KB, MB, GB).

apropos compress zeigt Werkzeuge wie gzip, bzip2, xz und zip. In Modul 03 hast du bereits tar kennengelernt, das oft mit gzip kombiniert wird.

In der man-Page direkt zum EXAMPLES-Abschnitt springen: /EXAMPLES eingeben und Enter drücken.

Modul 053 Unterrichtseinheiten

Netzwerk-Konfiguration

Ein Server ohne feste IP-Adresse ist wie ein Handwerksbetrieb ohne Straßenadresse -- niemand findet ihn zuverlässig. In diesem Modul lernst du, wie du den Netzwerkstatus prüfst, eine statische IP einrichtest und DNS konfigurierst.

Voraussetzung: Modul 01 Voraussetzung: Modul 03 ip · Netplan · DNS · /etc/hosts · nmcli
🖥️ Server-Kontext

Alle Befehle und Konfigurationsdateien in diesem Modul befinden sich auf dem Server. Du bist bereits per SSH eingeloggt (aus Modul 02). Es gibt hier keinen Wechsel zwischen deinem Rechner und dem Server -- alles läuft dort.

Netzwerk-Interfaces verstehen

Aus Modul 01 weißt du, was IP-Adressen und Netzwerkinterfaces sind. Jetzt lernst du, wie du sie auf deinem Server anzeigst und liest. Ein Netzwerk-Interface ist der Netzwerkanschluss des Servers -- vergleichbar mit der Netzwerkdose an der Wand. Jedes Interface bekommt eine IP-Adresse zugewiesen.

🖥️ Auf dem Server

Zeige alle vorhandenen Netzwerk-Interfaces an:

Interfaces auflisten
ip link show
# Typische Ausgabe:
# 1: lo: <LOOPBACK,UP>       -- Loopback (127.0.0.1, nur intern)
# 2: eth0: <BROADCAST,UP>    -- Ethernet-Anschluss (Kabel)
# 3: ens18: <BROADCAST,UP>   -- Ethernet in VMs (z.B. Proxmox)

Mit UP in der Ausgabe ist das Interface aktiv. Zeige dann IP-Adressen und Routing-Tabelle:

IP-Adressen und Routen anzeigen
ip addr show                  # Alle Interfaces mit IP-Adressen
ip addr show eth0             # Nur ein bestimmtes Interface
ip -4 addr show               # Nur IPv4-Adressen (übersichtlicher)
ip route show                 # Routing-Tabelle -- Gateway finden

Das Gateway steht in der Routing-Tabelle nach default via -- das ist die IP-Adresse deines Routers.

Interface-NameBedeutung
loLoopback -- internes Interface (127.0.0.1), niemals umbenennen
eth0Klassischer Ethernet-Name (ältere Systeme)
enp3s0Neuerer Ethernet-Name (Predictable Network Interface Names)
ens18Ethernet in virtuellen Maschinen (z.B. Proxmox, VMware)
wlan0 / wlp2s0WLAN-Interface (auf Servern selten)
DHCP vs. statische IP -- warum Server immer eine feste IP brauchen

Standardmäßig beziehen die meisten Systeme ihre IP-Adresse per DHCP automatisch vom Router. Das ist für Laptops praktisch -- für Server ein Problem. Stell dir vor, du hast in deiner Werkstatt eine Telefonnummer, die sich jeden Morgen ändert: Kein Kunde erreicht dich zuverlässig.

Bei Servern ist es genauso: SSH-Verbindungen, Dienste und andere Geräte im Netzwerk verlassen sich auf eine gleichbleibende IP-Adresse. Deshalb gilt für Server: immer statische IP einrichten.

💡 DHCP-Reservierung als Alternative

Viele Router bieten DHCP-Reservierung an: Der Router vergibt immer dieselbe IP an eine bestimmte MAC-Adresse des Servers. Das ist einfacher einzurichten, aber du bist vom Router abhängig. Fällt der Router aus oder wird zurückgesetzt, verliert der Server seine feste IP. Für Produktionsserver ist die statische IP direkt auf dem Server die sicherere Wahl.

Netplan -- Netzwerk-Konfiguration unter Ubuntu

Auf Ubuntu-Servern wird das Netzwerk mit Netplan konfiguriert. Netplan ist wie ein Konfigurationszettel: Du trägst ein, welche IP der Server haben soll, wo das Gateway ist und welche DNS-Server er nutzen soll -- und Netplan sorgt dafür, dass das System sich daran hält.

Die Konfigurationsdateien liegen unter /etc/netplan/ und sind im YAML-Format geschrieben.

Aktuelle Konfiguration lesen

🖥️ Auf dem Server

Zeige, welche Netplan-Dateien vorhanden sind und lies ihren Inhalt:

Netplan-Dateien anzeigen
ls /etc/netplan/           # Welche Dateien gibt es?
cat /etc/netplan/*.yaml    # Inhalt der Konfiguration anzeigen

DHCP-Konfiguration (Standard-Ausgangslage)

🖥️ Auf dem Server

So sieht eine typische DHCP-Konfiguration aus -- der Server bezieht seine IP automatisch vom Router:

/etc/netplan/01-netcfg.yaml -- DHCP
network:
  version: 2
  ethernets:
    eth0:          # Interface-Name -- bei dir vielleicht ens18 oder enp3s0
      dhcp4: true

Statische IP einrichten

🖥️ Auf dem Server

Bearbeite die Netplan-Datei mit vim (aus Modul 03). Ersetze den DHCP-Block durch eine statische Konfiguration:

/etc/netplan/01-netcfg.yaml -- statische IP
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: false
      addresses:
        - 192.168.1.50/24     # Deine gewünschte IP + Subnetzmaske
      routes:
        - to: default
          via: 192.168.1.1    # IP-Adresse deines Routers (Gateway)
      nameservers:
        addresses:
          - 1.1.1.1           # Cloudflare DNS
          - 9.9.9.9           # Quad9 DNS (Backup)

Nach dem Bearbeiten die Konfiguration testen und anwenden:

Netplan testen und anwenden
# Syntax prüfen (zeigt Fehler, ändert noch nichts)
sudo netplan generate

# Änderungen testen -- 120 Sekunden Zeit zum Bestätigen
sudo netplan try
# Bei Verbindung OK: Enter drücken
# Bei Problemen: einfach 120 Sek. warten, automatischer Rollback

# Direkt anwenden (nur wenn du dir sicher bist)
sudo netplan apply
🚨 Immer netplan try -- nicht netplan apply!

Nutze beim ersten Testen immer sudo netplan try, niemals direkt sudo netplan apply. Bei try hast du 120 Sekunden, um die Verbindung zu bestätigen. Wenn du dich durch einen Tippfehler (falsche IP, falsches Gateway) aussperrst, werden die Änderungen automatisch zurückgesetzt und du kannst dich wieder per SSH verbinden. Bei apply ohne Absicherung brauchst du im Fehlerfall physischen Zugang zum Server.

⚠️ YAML -- Leerzeichen statt Tabs

YAML (das Format der Netplan-Dateien) verwendet Einrückung zur Struktur. Dabei müssen es immer Leerzeichen sein -- keine Tabs. Viele Editoren fügen beim Drücken der Tab-Taste automatisch einen Tab ein, nicht Leerzeichen. Prüfe in vim mit :set list, ob du Tabs siehst (dann als ^I dargestellt). Falsche Einrückung führt zu Syntaxfehlern, die schwer zu finden sind.

Nutze immer sudo netplan try -- damit siehst du Syntaxfehler sofort, bevor sie Schaden anrichten.

Netplan-FeldBedeutungBeispiel
dhcp4: falseDHCP für IPv4 deaktivieren--
addressesStatische IP mit Subnetzmaske (CIDR)192.168.1.50/24
routes - to: default via:Standard-Gateway (dein Router)192.168.1.1
nameservers.addressesDNS-Server-Liste1.1.1.1, 9.9.9.9
🤖
KI-Tipp: Netplan-YAML erstellen lassen

Netplan-YAML ist fehleranfällig -- ein falsch gesetztes Leerzeichen reicht für einen Syntaxfehler. Beschreib dein Setup und lass dir die fertige Datei generieren: "Erstelle mir eine Netplan-Konfiguration für Ubuntu 24.04: Interface ens18, statische IP 10.0.1.100/24, Gateway 10.0.1.1, DNS 1.1.1.1 und 8.8.8.8. Zeige die komplette Datei." Kopiere das Ergebnis direkt in den Editor.

DNS-Konfiguration prüfen

DNS ist das Telefonbuch des Internets: Es übersetzt Hostnamen wie google.com in IP-Adressen. Wenn DNS nicht funktioniert, können keine Pakete installiert werden, keine Webseiten aufgerufen werden und keine Verbindungen zu externen Diensten aufgebaut werden -- obwohl die Netzwerkverbindung selbst funktioniert.

🖥️ Auf dem Server

Prüfe, welchen DNS-Server dein System aktuell verwendet, und teste die DNS-Auflösung:

DNS-Status und Test
# Aktuell verwendete DNS-Server anzeigen (systemd-resolved)
resolvectl status

# Klassische Datei (auf Ubuntu oft ein Symlink, nicht direkt bearbeiten)
cat /etc/resolv.conf

# DNS-Auflösung testen
dig +short google.com     # Zeigt nur die IP-Adresse
ping -c 2 google.com       # Testet Verbindung + DNS gleichzeitig
⚠️ /etc/resolv.conf nicht direkt bearbeiten

Auf modernen Ubuntu-Systemen ist /etc/resolv.conf ein Symlink, der von systemd-resolved automatisch verwaltet wird. Manuelle Änderungen werden beim nächsten Neustart überschrieben. Konfiguriere DNS-Server stattdessen in der Netplan-Datei unter nameservers.addresses -- dann bleibt die Einstellung dauerhaft erhalten.

Hostname und /etc/hosts

Der Hostname ist der Name deines Servers -- wie das Firmenschild über der Tür. Er erscheint im Terminal-Prompt und wird bei der Kommunikation im Netzwerk verwendet. Setze einen sinnvollen Hostnamen, damit du bei mehreren Servern den Überblick behältst.

🖥️ Auf dem Server

Hostname anzeigen und dauerhaft ändern:

Hostname verwalten
# Aktuellen Hostnamen anzeigen
hostname
hostnamectl            # Ausführlichere Informationen (Betriebssystem, Kernel)

# Hostnamen dauerhaft ändern
sudo hostnamectl set-hostname webserver01
# Wirkt sofort, im Prompt erst nach neuer SSH-Sitzung sichtbar

/etc/hosts -- lokale Namensauflösung

Die Datei /etc/hosts ist das lokale Telefonbuch des Servers: Sie ordnet IP-Adressen Hostnamen zu, ohne einen DNS-Server zu befragen. Einträge hier haben Vorrang vor DNS. Das ist nützlich für Server im lokalen Netzwerk, die du unter einem Namen statt einer IP-Adresse ansprechen willst.

🖥️ Auf dem Server

Bearbeite /etc/hosts mit vim (aus Modul 03):

/etc/hosts bearbeiten
sudo vim /etc/hosts

# Standardinhalt (nicht löschen):
127.0.0.1       localhost
127.0.1.1       webserver01     # Eigener Hostname -- hier anpassen

# Eigene Einträge für Geräte im Netzwerk hinzufügen:
192.168.1.1     router
192.168.1.50    webserver01
192.168.1.51    dbserver01
192.168.1.52    backupserver

Danach kannst du statt IP-Adressen die Namen verwenden:

ping -c 2 dbserver01         # statt: ping 192.168.1.51
ssh admin@dbserver01          # statt: ssh admin@192.168.1.51
NetworkManager und nmcli (kurz)

Auf Desktop-Installationen und manchen Server-Varianten ist statt Netplan der NetworkManager aktiv. Du erkennst das an: ls /etc/netplan/ gibt nichts aus, aber systemctl status NetworkManager zeigt einen laufenden Dienst.

🖥️ Auf dem Server

Die wichtigsten nmcli-Befehle zum Prüfen und Konfigurieren:

nmcli -- Netzwerkverbindungen verwalten
# Alle Verbindungen anzeigen
nmcli connection show

# Details einer Verbindung anzeigen
nmcli connection show "Wired connection 1"

# Statische IP setzen
sudo nmcli connection modify "Wired connection 1" \
  ipv4.method manual \
  ipv4.addresses 192.168.1.50/24 \
  ipv4.gateway 192.168.1.1 \
  ipv4.dns "1.1.1.1,9.9.9.9"

# Verbindung neu starten (Änderungen aktivieren)
sudo nmcli connection down "Wired connection 1"
sudo nmcli connection up "Wired connection 1"

# Zurück auf DHCP
sudo nmcli connection modify "Wired connection 1" ipv4.method auto
💡 Netplan oder NetworkManager?

Ubuntu Server 20.04+ verwendet standardmäßig Netplan. Ubuntu Desktop und manche Cloud-Images nutzen den NetworkManager. Prüfe mit ls /etc/netplan/ und systemctl status NetworkManager, welches System aktiv ist. In diesem Kurs arbeiten wir vorwiegend mit Netplan.

Netzwerkprobleme systematisch diagnostizieren

Wenn das Netzwerk nicht funktioniert, gehe diese Schritte der Reihe nach durch -- von unten nach oben im Netzwerk-Stack. Stell dir vor, du prüfst eine Wasserleitung: erst den Haupthahn, dann die Rohre, dann den Wasserdruck am Auslass.

🖥️ Auf dem Server

Netzwerk-Diagnose von der untersten Ebene aufwärts:

Schritt-für-Schritt-Diagnose
# Schritt 1: Ist das Interface überhaupt aktiv?
ip link show
# "UP" muss in der Ausgabe stehen

# Schritt 2: Hat das Interface eine IP-Adresse?
ip addr show
# Nach "inet" suchen -- z.B. "inet 192.168.1.50/24"

# Schritt 3: Ist das Gateway (der Router) erreichbar?
ping -c 3 192.168.1.1
# IP deines Routers hier eintragen

# Schritt 4: Funktioniert die Internet-Verbindung (ohne DNS)?
ping -c 3 8.8.8.8

# Schritt 5: Funktioniert DNS-Auflösung?
ping -c 3 google.com
SchrittBefehlWas du prüfstFehler zeigt auf
1ip link showInterface aktiv?Kabel, Hardware, Treiber
2ip addr showIP-Adresse vorhanden?DHCP oder statische Konfig
3ping 192.168.1.1Gateway erreichbar?IP-Konfig, Subnetz, Gateway
4ping 8.8.8.8Internet erreichbar?Router, ISP, Firewall
5ping google.comDNS funktioniert?DNS-Server-Eintrag

Schritt 4 funktioniert, aber Schritt 5 nicht? DNS ist das Problem -- prüfe die nameservers-Einträge in Netplan. Schritt 3 funktioniert nicht? Die IP-Adresse oder das Gateway ist falsch konfiguriert.

💡 Firewall nicht vergessen

Wenn dein Netzwerk korrekt konfiguriert ist, aber bestimmte Dienste trotzdem nicht erreichbar sind, kann die Firewall des Servers der Grund sein. Ports müssen in der Firewall explizit freigegeben werden. Das lernst du in Modul 14 (Firewall-Administration).

🤖
KI-Tipp: Netzwerkprobleme analysieren

Wenn die Diagnose einen Fehler aufzeigt, aber du nicht weiterkommst, zeig der KI die Ausgabe der Befehle: "Mein Ubuntu-Server hat nach der Netplan-Änderung kein Internet mehr. Schritt 4 (ping 8.8.8.8) funktioniert, aber Schritt 5 (ping google.com) nicht. Hier ist meine Netplan-Datei und die Ausgabe von resolvectl status: [einfügen]. Was ist falsch?"

Praxisaufgaben
AUFGABE 5.1 Netzwerkkonfiguration untersuchen

Du liest die aktuelle Netzwerkkonfiguration deines Servers und verstehst, wie er ans Netzwerk angebunden ist. Das ist der erste Schritt, bevor du irgendetwas änderst.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Zeige alle Netzwerk-Interfaces an: ip link show. Notiere den Namen deines Haupt-Interfaces (das erste, das nicht lo ist).
2
Zeige die IP-Adresse dieses Interfaces: ip addr show INTERFACE-NAME. Welche IP steht nach inet? Ist es eine private Adresse (192.168.x.x oder 10.x.x.x)?
3
Prüfe die Routing-Tabelle: ip route show. Welche IP steht nach default via? Das ist dein Gateway (Router).
4
Prüfe, ob Netplan aktiv ist: ls /etc/netplan/. Gibt es eine YAML-Datei? Zeige den Inhalt: cat /etc/netplan/*.yaml.
5
Prüfe den DNS-Server: resolvectl status. Suche die Zeile "DNS Servers" -- welche IP steht dort?
Lösungshinweise anzeigen

Das Haupt-Interface heißt je nach System eth0, enp3s0 oder ens18 (in VMs häufig). Die IP-Adresse erscheint in ip addr show nach inet mit der Subnetzmaske, z.B. inet 192.168.1.100/24.

Falls /etc/netplan/ leer ist oder nicht existiert, nutzt dein System möglicherweise den NetworkManager. Prüfe mit systemctl status NetworkManager.

AUFGABE 5.2 Statische IP mit Netplan einrichten

Du richtest eine feste IP-Adresse auf deinem Server ein. Danach ist er immer unter derselben Adresse erreichbar -- egal wie oft du ihn neu startest.

🖥️ Alle Schritte auf dem Server
1
Erstelle ein Backup der aktuellen Konfiguration, bevor du etwas änderst: sudo cp /etc/netplan/*.yaml /tmp/netplan-backup.yaml. Bei Problemen kannst du darauf zurückgreifen.
2
Öffne die Netplan-Datei mit vim: sudo vim /etc/netplan/01-netcfg.yaml. Setze dhcp4: false und trage eine statische IP (aus deinem Heimnetz, z.B. 192.168.1.50/24), das Gateway (dein Router) und DNS-Server (1.1.1.1) ein. Orientiere dich am Beispiel aus dem Abschnitt "Statische IP einrichten".
3
Teste die Konfiguration immer zuerst mit: sudo netplan try. Du hast 120 Sekunden, um die SSH-Verbindung zu testen und mit Enter zu bestätigen. Klappt die Verbindung noch? Dann bestätigen.
4
Prüfe die neue IP: ip addr show. Stimmt die Adresse mit dem überein, was du in die Netplan-Datei eingetragen hast?
5
Teste die Internetverbindung und DNS: ping -c 4 google.com. Kommen Antworten zurück?
Lösungshinweise anzeigen

Achte auf korrekte YAML-Einrückung: Immer 2 Leerzeichen pro Ebene, keine Tabs. Die IP-Adresse muss im selben Subnetz wie dein Gateway liegen -- bei Gateway 192.168.1.1 also eine Adresse aus dem Bereich 192.168.1.2 bis 192.168.1.254 mit der Maske /24.

Falls du dich aussperrst: Bei netplan try werden Änderungen nach 120 Sekunden automatisch zurückgesetzt. Du kannst dich dann neu verbinden und die Konfiguration korrigieren.

AUFGABE 5.3 Hostname und /etc/hosts einrichten

Du gibst deinem Server einen sinnvollen Namen und trägst andere Geräte im Netzwerk in die lokale Hostnamen-Datei ein, damit du sie beim Namen statt per IP-Adresse ansprechen kannst.

🖥️ Alle Schritte auf dem Server
1
Zeige den aktuellen Hostnamen mit allen Details: hostnamectl. Wie heißt dein Server gerade?
2
Setze einen neuen, sinnvollen Hostnamen: sudo hostnamectl set-hostname webserver01. Wähle einen Namen ohne Leerzeichen und Sonderzeichen.
3
Öffne /etc/hosts mit vim: sudo vim /etc/hosts. Ändere den alten Hostnamen in der Zeile mit 127.0.1.1 auf den neuen Namen.
4
Füge einen Eintrag für dein Gateway hinzu: 192.168.1.1 router (passe die IP an deinen Router an). Speichere und schließe vim.
5
Teste die Namensauflösung: ping -c 2 router. Wird der Name aufgelöst und kommt eine Antwort?
Lösungshinweise anzeigen

Der neue Hostname ist sofort aktiv, erscheint aber erst im Terminal-Prompt, wenn du eine neue SSH-Sitzung öffnest (alte Sitzung beenden, neu anmelden).

Einträge in /etc/hosts haben Vorrang vor DNS. Du könntest dort auch andere Server im Netzwerk eintragen -- dann sparst du dir das Tippen von IP-Adressen bei SSH-Verbindungen oder Ping-Tests.

AUFGABE 5.4 Netzwerk-Diagnose durchführen

Du lernst, Netzwerkprobleme systematisch einzugrenzen. Auch wenn gerade alles funktioniert, ist es wichtig, die Diagnose-Schritte zu kennen -- sie helfen dir, wenn später mal etwas nicht läuft.

🖥️ Alle Schritte auf dem Server
1
Prüfe den Interface-Status: ip link show. Steht bei deinem Haupt-Interface UP? Was bedeutet der Status DOWN?
2
Prüfe die IP-Konfiguration: ip addr show. Welche IP hat das Interface? Passt sie zum konfigurierten Subnetz?
3
Prüfe das Gateway: ip route show. Ping dann das Gateway: ping -c 3 GATEWAY-IP. Kommen Antworten zurück?
4
Prüfe DNS: Führe erst ping -c 2 8.8.8.8 aus (nur IP, kein DNS), dann ping -c 2 google.com (braucht DNS). Was unterscheidet die Ausgaben?
5
Prüfe den aktuellen DNS-Server: resolvectl status. Suche den Abschnitt deines Interfaces und den Eintrag "DNS Servers".
Lösungshinweise anzeigen

Wenn ping 8.8.8.8 funktioniert, aber ping google.com nicht: DNS ist das Problem. Entweder kein DNS-Server konfiguriert, oder der konfigurierte DNS-Server ist nicht erreichbar.

Wenn ping GATEWAY-IP nicht funktioniert: IP-Adresse oder Subnetz ist falsch. Prüfe, ob deine statische IP und das Gateway im selben Subnetz liegen.

Modul 062 Unterrichtseinheiten

APT -- Paketverwaltung

Unter Linux installierst du Software nicht per Download aus dem Internet, sondern über den Paketmanager. APT ist dein Ersatzteilkatalog: Du sagst, was du brauchst, und APT holt es aus dem richtigen Lager -- geprüft, aktuell, mit allem Zubehör.

Voraussetzung: Modul 03 apt · dpkg · Repositories · Updates
🖥️ Server-Kontext

Alle Befehle in diesem Modul gibst du auf dem Server ein -- du bist bereits per SSH eingeloggt. Es gibt keinen Wechsel zwischen lokalem Rechner und Server.

Was ist ein Paketmanager?

Stell dir vor, du bestellst Ersatzteile für eine Werkstatt. Du rufst beim Lieferanten an, sagst „Ich brauche eine Zündkerze für einen Golf 7", und der Lieferant schickt dir das passende Teil -- inklusive der Dichtung, die dazugehört. Genau so funktioniert APT.

APT (Advanced Package Tool) ist der Paketmanager für Debian und Ubuntu. Er:

  • Holt Software aus geprüften Repositories (Paketquellen -- wie ein Teile-Lager im Internet)
  • Löst Abhängigkeiten automatisch auf -- Programm A braucht Bibliothek B, APT installiert beides
  • Aktualisiert alles mit einem einzigen Befehl
  • Entfernt Software sauber und vollständig
🧠 Warum nicht einfach runterladen?

Unter Windows lädst du .exe-Dateien von beliebigen Webseiten herunter -- mit dem Risiko, Schadsoftware zu erwischen. APT holt Software aus offiziellen, kryptografisch signierten Quellen. Das ist sicherer und bequemer.

Paketlisten aktualisieren und Updates einspielen

Bevor du etwas installierst, musst du APT sagen: „Schau nach, was es Neues gibt." Das ist der Unterschied zwischen update und upgrade -- ein häufiger Stolperstein am Anfang.

🖥️ Auf dem Server

apt update lädt die aktuellen Paketlisten herunter -- es wird noch nichts installiert. Erst apt upgrade installiert die neueren Versionen.

Paketlisten aktualisieren
sudo apt update
# APT schaut nach, was es Neues gibt -- noch nichts wird installiert
# Am Ende steht: "X packages can be upgraded."
Updates installieren
sudo apt upgrade
# Alle veralteten Pakete auf die neueste Version bringen
# APT fragt nach Bestätigung -- mit "j" oder "Enter" bestätigen

# Oder beides in einem Zug (typische Kombination):
sudo apt update && sudo apt upgrade
⚠️ update vs. upgrade -- nicht verwechseln!

apt update schaut nur in den Katalog -- wie ein Blick in die Preisliste. apt upgrade bestellt tatsächlich -- wie das Abschicken der Bestellung. Immer erst update, dann upgrade. Und auf einem Produktions-Server: teste Updates vorher in einer Testumgebung.

Software installieren, suchen und entfernen

Die drei Kernaufgaben eines Paketmanagers: installieren, finden, loswerden.

🖥️ Auf dem Server
Software installieren
# Ein Paket installieren
sudo apt install htop

# Mehrere Pakete auf einmal
sudo apt install htop curl wget tree

# Ohne Rückfrage (praktisch in Skripten)
sudo apt install -y htop
Pakete suchen und Informationen anzeigen
# Nach einem Paket suchen (Stichwortsuche)
apt search webserver

# Details zu einem Paket anzeigen (Version, Größe, Beschreibung)
apt show nginx

# Alle installierten Pakete auflisten
apt list --installed

# Prüfen ob ein bestimmtes Paket installiert ist
apt list --installed | grep nginx
Software entfernen
# Paket entfernen -- Konfigurationsdateien bleiben erhalten
sudo apt remove htop

# Paket vollständig entfernen -- auch Konfiguration weg
sudo apt purge htop

# Nicht mehr benötigte Abhängigkeiten aufräumen
sudo apt autoremove
💡 remove vs. purge

apt remove ist wie Demontage: Die Teile weg, aber die Schrauben noch da. apt purge ist die komplette Entsorgung -- inklusive aller Einstellungen. Wenn du ein Paket mit neuer Konfiguration neu installieren willst, nimm immer zuerst purge.

Die wichtigsten APT-Befehle auf einen Blick

Hier sind alle Befehle, die du in diesem Modul kennengelernt hast -- als schnelle Referenz zum Nachschlagen.

BefehlWas er tut
sudo apt updatePaketlisten aktualisieren (kein Download von Software)
sudo apt upgradeAlle installierten Pakete auf den neuesten Stand bringen
sudo apt install PAKETEin Paket installieren
sudo apt remove PAKETPaket entfernen, Konfiguration bleibt
sudo apt purge PAKETPaket vollständig entfernen inkl. Konfiguration
sudo apt autoremoveVerwaiste Abhängigkeiten aufräumen
apt search STICHWORTIn der Paketliste suchen
apt show PAKETDetails zu einem Paket anzeigen
apt list --installedAlle installierten Pakete auflisten
🤖
KI-Tipp: APT-Fehler lösen

APT-Fehlermeldungen sind oft kryptisch: „unmet dependencies", „dpkg was interrupted", „unable to acquire the dpkg frontend lock". Kopiere die komplette Fehlermeldung und frag: „Ich bekomme diesen Fehler bei 'sudo apt install nginx' auf Ubuntu 24.04: [Fehlermeldung einfügen]. Was ist das Problem und wie behebe ich es Schritt für Schritt?"

Paketquellen (sources.list)

APT weiß, wo es Software holen soll, durch die Paketquellen. Die offizielle Liste liegt in /etc/apt/sources.list und im Ordner /etc/apt/sources.list.d/. Für die meisten Pakete reichen die Standard-Quellen von Ubuntu.

🖥️ Auf dem Server

Aktuelle Paketquellen anzeigen:

# Klassische Paketquellen-Datei anzeigen
cat /etc/apt/sources.list

# Zusätzlich eingebundene Quellen anzeigen
ls /etc/apt/sources.list.d/

Manchmal brauchst du Software, die nicht in den offiziellen Quellen ist -- zum Beispiel Docker oder eine aktuelle Node.js-Version. Dann fügst du ein externes Repository hinzu. Das geht immer nach dem gleichen Muster:

  1. GPG-Schlüssel herunterladen (zur Verifizierung -- damit du sicher weißt, wer das Paket gebaut hat)
  2. Repository-Adresse in sources.list.d/ eintragen
  3. sudo apt update ausführen
  4. Software installieren
⚠️ Nur vertrauenswürdige Repositories hinzufügen

Fremde Repositories können manipulierte Pakete enthalten -- du gibst damit jemandem das Recht, Software auf deinem Server zu installieren. Nutze nur Repositories von bekannten Herstellern (Docker, Microsoft, PostgreSQL, NodeSource). Verwende immer den GPG-Schlüssel zur Verifizierung. Zufällige Anleitungen aus dem Internet ohne GPG-Schlüssel: Finger weg.

🤖
KI-Tipp: Externes Repository sicher einbinden

Jeder Hersteller hat seinen eigenen Weg, ein Repository einzubinden. Lass dir den aktuellen, korrekten Befehl generieren: „Wie binde ich das offizielle Docker-Repository auf Ubuntu 24.04 ein? Zeig mir die aktuellen Befehle mit GPG-Schlüssel." -- Das ist besser als eine veraltete Anleitung zu kopieren.

Automatische Sicherheitsupdates

Sicherheitslücken werden regelmäßig entdeckt. Ein Server, der wochenlang ohne Patches läuft, ist ein offenes Scheunentor. Mit unattended-upgrades werden Sicherheitsupdates automatisch eingespielt -- ohne dass du daran denken musst.

🖥️ Auf dem Server
Automatische Updates einrichten
# Paket installieren
sudo apt install unattended-upgrades

# Aktivieren -- wähle "Ja" in der Dialogbox
sudo dpkg-reconfigure -plow unattended-upgrades

# Status prüfen: Läuft der Dienst?
systemctl status unattended-upgrades

Die Konfiguration findest du in /etc/apt/apt.conf.d/50unattended-upgrades. Standardmäßig werden nur Sicherheitsupdates automatisch installiert -- keine neuen Features, die etwas kaputt machen könnten.

🧠 Automatische Updates = Pflicht auf jedem Server

Richte unattended-upgrades auf jedem neu aufgesetzten Server als erste Maßnahme ein. Bekannte Sicherheitslücken werden dadurch automatisch geschlossen -- selbst wenn du wochenlang nicht einloggst.

dpkg -- das Werkzeug unter der Haube

APT ist das komfortable Oberwerkzeug. Darunter arbeitet dpkg (Debian Package) -- das eigentliche Installationsprogramm. Du brauchst dpkg direkt nur in zwei Fällen: wenn du eine .deb-Datei manuell installieren willst, oder wenn du Informationen über installierte Pakete abfragst.

🖥️ Auf dem Server
dpkg-Befehle
# Lokale .deb-Datei installieren
sudo dpkg -i paket.deb

# Falls Abhängigkeiten fehlen, danach ausführen:
sudo apt install -f

# Prüfen ob und welche Version eines Pakets installiert ist
dpkg -s nginx

# Alle Dateien anzeigen, die ein Paket installiert hat
dpkg -L nginx

# Welches Paket stellt eine bestimmte Datei bereit?
dpkg -S /usr/bin/vim
💡 apt vs. dpkg -- wann was nutzen?

Nutze apt für alles, was mit dem Internet zu tun hat: installieren, aktualisieren, suchen. Nutze dpkg nur für lokale .deb-Dateien oder zum Abfragen von Informationen über installierte Pakete.

Praxisaufgaben
AUFGABE 6.1 Pakete installieren und verwalten

Du lernst die grundlegenden APT-Befehle, die du auf jedem Linux-Server täglich brauchst. Alle Schritte laufen auf dem Server.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Aktualisiere die Paketlisten: sudo apt update. Wie viele Pakete können aktualisiert werden? Die Zahl steht am Ende der Ausgabe.
2
Installiere das Paket tree: sudo apt install tree. Bestätige mit "j". Teste es danach mit: tree /etc/apt
3
Zeige Details zum Paket htop an, bevor du es installierst: apt show htop. Wie groß ist es? Den Wert findest du bei "Installed-Size".
4
Installiere htop: sudo apt install htop. Starte es mit htop und schau dir CPU und RAM-Auslastung an. Beende es mit q.
5
Entferne tree vollständig: sudo apt purge tree. Räume danach auf: sudo apt autoremove.
6
Prüfe, ob htop noch installiert ist: apt list --installed | grep htop. Du solltest eine Zeile mit Version und Architektur sehen.
Lösungshinweise anzeigen

tree /etc/apt zeigt die Verzeichnisstruktur von /etc/apt als Baumdiagramm -- sehr praktisch, um sich schnell einen Überblick zu verschaffen.

htop ist ein interaktiver Prozess-Monitor. Oben siehst du CPU-Balken für jeden Kern und den RAM-Verbrauch. Mit den Pfeiltasten kannst du durch die Prozessliste scrollen, mit F9 einen Prozess beenden.

apt list --installed | grep htop gibt eine Zeile aus, wenn htop installiert ist, z.B.: htop/noble,now 3.3.0-4 amd64 [installiert]

AUFGABE 6.2 System aktualisieren und automatische Updates einrichten

Du bringst das System auf den neuesten Stand und richtest automatische Sicherheitsupdates ein -- eine Pflichtmaßnahme auf jedem produktiven Server.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Aktualisiere Paketlisten und installiere alle Updates: sudo apt update && sudo apt upgrade. Bestätige mit "j". Warte, bis der Vorgang abgeschlossen ist.
2
Installiere das Paket für automatische Updates: sudo apt install unattended-upgrades.
3
Aktiviere automatische Updates: sudo dpkg-reconfigure -plow unattended-upgrades. In der Dialogbox "Ja" auswählen und Enter drücken.
4
Prüfe ob der Dienst läuft: systemctl status unattended-upgrades. Du solltest "active (running)" oder "active (waiting)" sehen.
5
Sieh dir an, was automatisch aktualisiert wird: grep -v "//" /etc/apt/apt.conf.d/50unattended-upgrades | grep -v "^$" | head -20. Welche Update-Quellen sind aktiviert?
Lösungshinweise anzeigen

Nach dem Upgrade sollte APT melden: „0 upgraded, 0 newly installed" -- alle Pakete sind jetzt auf dem neuesten Stand.

Der Dienst unattended-upgrades zeigt "active (waiting)" wenn er auf den nächsten geplanten Ausführungszeitpunkt wartet -- das ist normal und korrekt.

In der Konfigurationsdatei sind standardmäßig nur Sicherheitsupdates aktiviert (${distro_id}:${distro_codename}-security). Das ist die sichere Wahl: Kritische Lücken werden geschlossen, aber keine neuen Features installiert, die etwas kaputt machen könnten.

AUFGABE 6.3 Pakete suchen und dpkg erkunden

Du übst die Suche nach Paketen und lernst, wie du mit dpkg Informationen über installierte Software abrufst.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Suche nach Paketen zum Thema "monitor": apt search monitor. Die Liste ist lang -- du kannst die Ausgabe einschränken: apt search monitor | grep -i "system monitor"
2
Zeige alle Informationen zum Paket curl an: apt show curl. Notiere dir Version und die Installationsgröße (Zeile "Installed-Size").
3
Prüfe mit dpkg, ob curl installiert ist: dpkg -s curl. Was steht unter "Status"?
4
Lass dir alle Dateien anzeigen, die curl installiert hat: dpkg -L curl. Wo liegt die eigentliche Programmdatei?
5
Finde heraus, welches Paket die Datei /usr/bin/curl bereitstellt: dpkg -S /usr/bin/curl.
Lösungshinweise anzeigen

dpkg -s curl zeigt "Status: install ok installed" -- das bedeutet, das Paket ist korrekt installiert.

dpkg -L curl listet alle installierten Dateien: die Programmdatei liegt unter /usr/bin/curl, die Handbuchseite unter /usr/share/man/man1/curl.1.gz.

dpkg -S /usr/bin/curl gibt zurück: curl: /usr/bin/curl -- das Paket heißt also curl.

Modul 072 Unterrichtseinheiten

Grafischer Remote Desktop

Manchmal reicht die Kommandozeile nicht aus. In diesem Modul installierst du eine Desktop-Umgebung auf deinem Server und verbindest dich grafisch per RDP -- als wärst du direkt davor.

Voraussetzung: Modul 02 (SSH) Voraussetzung: Modul 06 (APT) RDP · xrdp · XFCE · Remmina
Bevor wir starten: Zwei Kontexte

In diesem Modul arbeitest du an zwei Orten: Auf dem Server installierst und konfigurierst du alles. Von deinem eigenen Rechner aus verbindest du dich dann grafisch per RDP-Client. Wir markieren das durch diese Zonen:

💻 Dein Rechner

RDP-Client starten, Verbindung herstellen -- auf deinem Laptop oder PC.

🖥️ Server

Desktop-Umgebung und xrdp installieren -- per SSH eingeloggt.

Wann brauchst du eine grafische Oberfläche?

Die meisten Linux-Server laufen ohne Desktop -- und das ist gut so. Ein schlanker Server ohne GUI verbraucht weniger Arbeitsspeicher und hat eine kleinere Angriffsfläche. Trotzdem gibt es Situationen, in denen eine grafische Oberfläche sinnvoll ist:

  • Grafische Verwaltungs-Tools -- manche Software bietet eine GUI, die deutlich komfortabler ist als die Kommandozeile
  • Webbrowser auf dem Server -- um interne Dienste zu testen, die nur auf localhost erreichbar sind
  • Entwicklung und Tests -- IDEs, grafische Editoren oder Test-Anwendungen auf einem dedizierten Server
  • Linux-Einstieg -- für Anfänger kann ein Desktop das Eingewöhnen erleichtern
⚠️ Desktop gehört nicht auf Produktionsserver

Auf einem Server, der Webseiten, Datenbanken oder andere Live-Dienste betreibt, solltest du keine Desktop-Umgebung installieren. Sie frisst RAM und CPU und vergrößert die Angriffsfläche. Nutze Desktop-Umgebungen auf Test- und Entwicklungsservern oder in virtuellen Maschinen.

RDP und VNC -- was ist der Unterschied?

Es gibt zwei gängige Protokolle für grafischen Remote-Zugriff. Stell dir RDP wie ein Telefongespräch vor -- jeder hat seinen eigenen Hörer. VNC hingegen ist wie ein Blick über die Schulter -- du siehst denselben Bildschirm wie der Nutzer am Server.

EigenschaftRDP (xrdp)VNC (TigerVNC)
Port33895901 (erste Sitzung)
VerschlüsselungEingebaut (TLS)Keine -- SSH-Tunnel nötig!
Windows-ClientBereits eingebaut (mstsc)Separater Client nötig
Mehrere NutzerJa -- jeder bekommt eigene SitzungMeist eine Sitzung gleichzeitig
EinsatzbereichNormale Desktop-NutzungFernwartung, bestehende Sitzung zeigen
🧠 Empfehlung: xrdp für den Alltag

xrdp ist die bessere Wahl für den Einstieg: einfacher einzurichten, Windows-Client bereits installiert, Verschlüsselung eingebaut. VNC brauchst du nur, wenn du die laufende Desktop-Sitzung eines anderen Nutzers sehen willst.

Desktop-Umgebung installieren (XFCE)

Für Server empfiehlt sich XFCE -- leichtgewichtig, schnell und trotzdem komfortabel. Es braucht nur rund 300 MB RAM und läuft flüssig auch auf schwächerer Hardware.

🖥️ Auf dem Server -- du bist per SSH eingeloggt

Paketliste aktualisieren und XFCE installieren -- du kennst dieses Prinzip bereits aus Modul 06:

XFCE installieren
sudo apt update
sudo apt install xfce4 xfce4-goodies
# xfce4         = Basis-Desktop
# xfce4-goodies = nützliche Extras: Terminal, Dateimanager, Screenshot-Tool

Die Installation lädt 200--400 MB herunter und dauert einige Minuten. Danach ist XFCE auf dem Server bereit -- du kannst es aber noch nicht sehen, weil du per SSH ohne Bildschirm verbunden bist. Dafür brauchen wir xrdp.

xrdp installieren und einrichten

xrdp ist ein Open-Source-RDP-Server. Er nimmt Verbindungen auf Port 3389 entgegen und startet für jeden Nutzer eine eigene XFCE-Sitzung.

🖥️ Auf dem Server -- per SSH eingeloggt
xrdp installieren und starten
sudo apt install xrdp

# Dienst starten und beim Boot automatisch starten:
sudo systemctl enable --now xrdp

# Status prüfen -- sollte "active (running)" zeigen:
sudo systemctl status xrdp

Jetzt teile xrdp mit, welchen Desktop es starten soll. Dafür schreibst du eine kurze Steuerdatei in dein Home-Verzeichnis:

XFCE als Desktop festlegen
echo "startxfce4" > ~/.xsession
# Prüfen, ob es geschrieben wurde:
cat ~/.xsession
# Ausgabe sollte sein: startxfce4

Prüfe, ob xrdp auf Port 3389 lauscht -- das kennst du schon aus Modul 01:

Port prüfen
ss -tulpn | grep 3389
# Erwartete Ausgabe: tcp  LISTEN  ...  0.0.0.0:3389  ...  xrdp
Verbinden: Windows und Linux

Jetzt wechselst du auf deinen eigenen Rechner. Der Server wartet auf Port 3389 -- du rufst ihn mit einem RDP-Client an.

Windows: Remotedesktopverbindung

💻 Auf deinem Rechner (Windows)

Windows hat den RDP-Client bereits eingebaut -- du brauchst nichts zu installieren:

  1. Drücke Win + R, tippe mstsc und drücke Enter
  2. Gib die IP-Adresse deines Servers ein (z.B. 192.168.1.50) und klicke Verbinden
  3. Bestätige die Zertifikatswarnung beim ersten Mal mit Ja
  4. Melde dich mit deinem Linux-Benutzernamen und Passwort an
  5. Der XFCE-Desktop erscheint im Fenster

Linux: Remmina

💻 Auf deinem Rechner (Linux)

Unter Linux nimmst du Remmina -- einen vielseitigen Remote-Desktop-Client, der RDP, VNC und mehr unterstützt:

Remmina installieren
sudo apt install remmina remmina-plugin-rdp

Starte Remmina aus dem Anwendungsmenü oder mit remmina im Terminal. Wähle dort Neues Verbindungsprofil, setze das Protokoll auf RDP, trage die Server-IP ein und verbinde dich.

💡 IP-Adresse des Servers herausfinden

Du kennst die IP-Adresse deines Servers bereits aus Modul 02. Alternativ findest du sie in der Router-Oberfläche (meist 192.168.x.x) oder -- falls du direkten Zugang zum Server hast -- mit ip addr show direkt am Server-Terminal.

Firewall -- Port 3389 absichern

Ein offener Remote-Desktop-Port ist ein beliebtes Angriffsziel. Schränke den Zugriff deshalb auf dein lokales Netz ein. Details zur Firewall-Verwaltung lernst du in Modul 14 -- hier die wichtigste Regel schon vorab:

🖥️ Auf dem Server -- per SSH eingeloggt
RDP nur aus dem lokalen Netz erlauben (ufw)
# Aktuellen Firewall-Status prüfen:
sudo ufw status

# RDP nur aus dem lokalen Netz (192.168.1.0/24) erlauben:
sudo ufw allow from 192.168.1.0/24 to any port 3389

# Ergebnis prüfen:
sudo ufw status numbered

Passe den IP-Bereich (192.168.1.0/24) an dein Netz an. Bei Unsicherheit: ip addr show zeigt deine Server-IP -- der Netzbereich ist die IP ohne die letzte Zahl plus /24.

🚨 Port 3389 nicht ins Internet öffnen

Öffne Port 3389 niemals für das gesamte Internet. RDP-Ports sind ein Hauptziel für automatisierte Brute-Force-Angriffe. Wenn du von außen auf deinen Desktop zugreifen musst, nutze einen SSH-Tunnel (aus Modul 02): ssh -L 3389:localhost:3389 user@server-ip -- dann bleibt der Port geschlossen und du verbindest dich zu localhost:3389.

VNC als Alternative

VNC ist nützlich, wenn du die laufende Desktop-Sitzung eines anderen Nutzers sehen willst -- zum Beispiel für Fernwartung oder Support. Anders als RDP zeigt VNC immer denselben Bildschirm, egal wer sich verbindet.

🖥️ Auf dem Server -- per SSH eingeloggt
TigerVNC installieren und starten
sudo apt install tigervnc-standalone-server

# VNC-Passwort setzen (wird beim Verbinden abgefragt):
vncpasswd

# VNC-Server starten (Display :1 = Port 5901):
vncserver :1

# Laufende Sitzungen prüfen:
vncserver -list
🚨 VNC ist unverschlüsselt -- immer SSH-Tunnel nutzen!

VNC überträgt standardmäßig keine verschlüsselten Daten. Nutze VNC niemals direkt über das Netzwerk ohne Schutz. Leite die Verbindung immer durch einen SSH-Tunnel -- der Aufbau funktioniert genauso wie in Modul 02 für Datenbankdienste beschrieben.

💻 Auf deinem Rechner -- SSH-Tunnel für VNC aufbauen
ssh -L 5901:localhost:5901 user@server-ip
# Dann VNC-Client mit localhost:5901 verbinden -- NICHT mit der Server-IP
Typische Probleme

Diese Fehler begegnen dir häufig bei der Einrichtung:

ProblemUrsacheLösung
Schwarzer Bildschirm nach Login~/.xsession fehlt oder falschecho "startxfce4" > ~/.xsession, dann neu verbinden
Login-Schleife (immer wieder Login-Bildschirm)Fehlerhafter Desktop-Start oder falsches PasswortLogs prüfen: journalctl -u xrdp -n 30
Verbindung wird abgelehntxrdp läuft nicht oder Firewall blockiertsudo systemctl status xrdp und sudo ufw status prüfen
Desktop extrem langsamDesktop-Umgebung zu schwerGNOME durch XFCE ersetzen
Tastaturlayout falschLocale-Einstellungen im DesktopIn XFCE: Einstellungen → Tastatur → Layout
🤖
KI-Tipp: Schwarzer Bildschirm und Log-Analyse

Wenn nach dem xrdp-Login nur ein schwarzer Bildschirm erscheint, steckt die Ursache fast immer in den Logs. Führe auf dem Server journalctl -u xrdp --no-pager -n 30 aus, kopiere die Ausgabe und frag eine KI: „Nach dem xrdp-Login sehe ich nur einen schwarzen Bildschirm. Hier sind meine Logs -- was ist das Problem und wie behebe ich es?"

Praxisaufgaben
AUFGABE 7.1 XFCE und xrdp installieren und verbinden

Du installierst eine grafische Desktop-Umgebung auf deinem Server und verbindest dich zum ersten Mal per RDP. Am Ende siehst du einen echten XFCE-Desktop im Fenster.

🖥️ Schritte 1--5 auf dem Server -- per SSH eingeloggt
1
Aktualisiere die Paketliste und installiere XFCE und xrdp in einem Schritt: sudo apt update && sudo apt install xfce4 xfce4-goodies xrdp. Das dauert ein paar Minuten.
2
Starte xrdp und aktiviere es beim Boot: sudo systemctl enable --now xrdp. Prüfe den Status: sudo systemctl status xrdp -- du solltest active (running) sehen.
3
Lege XFCE als Desktop fest: echo "startxfce4" > ~/.xsession. Prüfe: cat ~/.xsession -- die Ausgabe muss startxfce4 sein.
4
Prüfe, ob Port 3389 lauscht: ss -tulpn | grep 3389. Du solltest eine Zeile mit :3389 und xrdp sehen.
5
Schränke den RDP-Zugriff auf dein lokales Netz ein: sudo ufw allow from 192.168.1.0/24 to any port 3389 (IP-Bereich anpassen).
💻 Schritt 6 auf deinem Rechner -- öffne den RDP-Client
6
Verbinde dich von deinem Arbeitsrechner: Windows-Nutzer drücken Win + R, tippen mstsc und geben die Server-IP ein. Linux-Nutzer starten Remmina und wählen RDP als Protokoll. Melde dich mit deinem Linux-Benutzernamen und Passwort an.
Lösungshinweise anzeigen

systemctl status xrdp muss active (running) zeigen. Bei ss -tulpn | grep 3389 muss eine Zeile mit 0.0.0.0:3389 und dem Prozess xrdp erscheinen.

Wenn nach dem Login ein schwarzer Bildschirm erscheint: Prüfe mit cat ~/.xsession ob die Datei startxfce4 enthält. Falls nicht, den Befehl aus Schritt 3 wiederholen und die RDP-Sitzung neu starten.

AUFGABE 7.2 VNC über SSH-Tunnel einrichten

Du richtest TigerVNC ein und verbindest dich sicher über einen SSH-Tunnel. Damit übst du die Tunnel-Technik aus Modul 02 in einem neuen Kontext.

🖥️ Schritte 1--4 auf dem Server -- per SSH eingeloggt
1
Installiere TigerVNC: sudo apt install tigervnc-standalone-server
2
Setze ein VNC-Passwort: vncpasswd. Das Passwort wird beim Verbinden abgefragt. Das View-only-Passwort kannst du verneinen.
3
Starte den VNC-Server: vncserver :1. Prüfe mit vncserver -list, ob er läuft.
4
Prüfe, ob Port 5901 lauscht: ss -tulpn | grep 5901. Du solltest eine Zeile sehen, die 127.0.0.1:5901 enthält.
💻 Schritte 5--6 auf deinem Rechner
5
Baue einen SSH-Tunnel auf: ssh -L 5901:localhost:5901 user@server-ip. Das Terminal bleibt geöffnet -- der Tunnel läuft so lange wie diese Verbindung.
6
Verbinde dich mit einem VNC-Client (z.B. Remmina mit VNC-Protokoll) zu localhost:5901 -- nicht zur Server-IP. Gib das VNC-Passwort ein.
Lösungshinweise anzeigen

Der SSH-Tunnel leitet Port 5901 deines lokalen Rechners verschlüsselt an Port 5901 des Servers weiter. Im VNC-Client verbindest du dich daher mit localhost:5901 -- der Tunnel kümmert sich um den Rest.

VNC-Server stoppen geht mit vncserver -kill :1 auf dem Server. Mit vncserver -list siehst du alle laufenden Sitzungen.

AUFGABE 7.3 xrdp über SSH-Tunnel -- Port bleibt geschlossen

Statt Port 3389 in der Firewall zu öffnen, leitest du xrdp durch einen SSH-Tunnel. So bleibt der Port von außen unsichtbar -- eine Profi-Methode für maximale Sicherheit.

🖥️ Schritt 1 auf dem Server -- per SSH eingeloggt
1
Stelle sicher, dass xrdp läuft: sudo systemctl status xrdp. Notiere die Server-IP für den nächsten Schritt.
💻 Schritte 2--5 auf deinem Rechner
2
Baue einen SSH-Tunnel für Port 3389 auf: ssh -L 3389:localhost:3389 user@server-ip. Das Terminal bleibt geöffnet -- schließe es nicht.
3
Starte deinen RDP-Client (Windows: mstsc, Linux: Remmina) und verbinde dich mit localhost als Zieladresse -- nicht mit der Server-IP.
4
Melde dich mit deinem Linux-Benutzernamen und Passwort an. Du solltest den XFCE-Desktop sehen -- obwohl Port 3389 in der Firewall geschlossen sein könnte.
5
Schließe die RDP-Sitzung und das SSH-Tunnel-Terminal. Überlege: Wenn du die ufw-Regel für Port 3389 jetzt entfernen würdest, könntest du trotzdem per Tunnel arbeiten -- der Port wäre für das Netz unsichtbar.
Lösungshinweise anzeigen

Der SSH-Tunnel leitet localhost:3389 auf deinem Rechner an localhost:3389 auf dem Server weiter -- vollständig verschlüsselt. Der RDP-Client weiß nicht, dass er gerade durch einen SSH-Tunnel schaut.

Mit dieser Methode kannst du die ufw-Regel für Port 3389 komplett entfernen und trotzdem per RDP arbeiten. Das ist deutlich sicherer als ein offener Port im Netz.

🤖
KI-Tipp: Desktop-Konfiguration automatisieren

XFCE speichert viele Einstellungen in Konfigurationsdateien unter ~/.config/xfce4/. Wenn du XFCE auf mehreren Servern gleich einrichten willst oder Einstellungen per Skript setzen möchtest, frag eine KI: „Ich möchte XFCE auf Ubuntu so konfigurieren, dass das Panel oben ist und das Tastaturlayout auf Deutsch gestellt ist -- welche Konfigurationsdateien muss ich ändern und wie?"

Modul 082 Unterrichtseinheiten

Nutzer & Gruppenverwaltung

Linux ist ein Mehrbenutzersystem – jeder Nutzer hat eigene Rechte, eigene Dateien und eigene Grenzen. In diesem Modul lernst du, wie du Benutzer anlegst, Gruppen verwaltest und mit sudo sicher Root-Rechte vergibst.

Voraussetzung: Modul 03 useradd · sudo · Gruppen · passwd Dateien: /etc/passwd · /etc/shadow · /etc/group
🖥️ Server-Kontext

Alle Befehle in diesem Modul gibst du auf dem Server ein – du bist bereits per SSH eingeloggt (siehe Modul 02).

Warum Benutzerverwaltung wichtig ist

Stell dir einen Server vor wie ein Bürogebäude: Jeder Mitarbeiter hat einen eigenen Schlüssel, einen eigenen Schreibtisch und Zugang zu bestimmten Räumen. Du würdest nicht jedem den Generalschlüssel geben – und genauso solltest du auf einem Server nicht jedem Root-Rechte einräumen.

Linux unterscheidet drei Arten von Benutzern:

TypUID-BereichBeispielZweck
Root0rootAllmächtiger Systemadministrator
Systembenutzer1–999www-data, sshdDienste isoliert betreiben
Normale Benutzer1000+max, annaEchte Menschen, die sich anmelden
🚨 Niemals dauerhaft als Root arbeiten!

Der Benutzer root darf alles – auch das System unwiderruflich zerstören. Arbeite immer als normaler Benutzer und nutze sudo nur für einzelne Befehle, die Root-Rechte brauchen. Ein versehentliches rm -rf / als Root löscht das gesamte System ohne Rückfrage.

Die wichtigen Konfigurationsdateien

Linux speichert Benutzer-Informationen in drei Textdateien. Du kannst sie lesen (und bei Bedarf bearbeiten), aber für die meisten Aufgaben nutzt du die passenden Befehle.

/etc/passwd – Benutzerliste

Jeder Benutzer hat hier eine Zeile. Trotz des Namens stehen hier keine Passwörter (die sind in /etc/shadow).

🖥️ Auf dem Server – du bist bereits per SSH eingeloggt
Benutzerliste anzeigen
cat /etc/passwd
# Beispielzeile:
# max:x:1001:1001:Max Mustermann:/home/max:/bin/bash

Aufbau einer Zeile in /etc/passwd – alle sieben Felder sind durch Doppelpunkt getrennt:

FeldBeispielwertBedeutung
1maxBenutzername
2xPasswort-Platzhalter (x = in /etc/shadow)
31001User-ID (UID)
41001Primäre Gruppen-ID (GID)
5Max MustermannKommentar (voller Name)
6/home/maxHome-Verzeichnis
7/bin/bashLogin-Shell

/etc/shadow – Passwörter (verschlüsselt)

Diese Datei ist nur für Root lesbar. Sie enthält die verschlüsselten (gehashten) Passwörter. Das $6$ am Anfang des Hashes bedeutet SHA-512 – ein modernes, sicheres Verfahren.

💡 Gesperrte Konten erkennen

Wenn in /etc/shadow statt einem Hash ein ! oder * steht, ist das Konto gesperrt – der Benutzer kann sich nicht mit Passwort anmelden. Systembenutzer wie www-data haben bewusst kein Passwort.

/etc/group – Gruppenliste

Jede Gruppe hat eine Zeile. Die Mitglieder stehen am Ende, durch Komma getrennt:

FeldBeispielwertBedeutung
1entwicklerGruppenname
2xPasswort-Platzhalter (selten genutzt)
31005Gruppen-ID (GID)
4max,annaMitglieder (Komma-getrennt)
Benutzer anlegen und verwalten

Neuen Benutzer erstellen

Auf Debian/Ubuntu gibt es zwei Werkzeuge – adduser und useradd. Der Unterschied ist wichtig:

🧠 adduser vs. useradd

adduser ist ein benutzerfreundliches Wrapper-Skript: Es fragt interaktiv nach Passwort und Namen, legt automatisch das Home-Verzeichnis an und setzt sinnvolle Standardwerte. useradd ist das eigentliche Low-Level-Tool – es macht nur genau das, was du als Optionen mitgibst. Für den Alltag: nimm adduser.

🖥️ Auf dem Server
Benutzer anlegen
# Empfohlener Weg: adduser (interaktiv, erstellt Home-Verzeichnis)
sudo adduser max
# → Fragt nach Passwort, vollem Namen usw.

# Alternativer Weg: useradd (low-level, mehr Kontrolle)
sudo useradd -m -s /bin/bash -c "Max Mustermann" max
# -m  → Home-Verzeichnis erstellen (/home/max)
# -s  → Login-Shell festlegen
# -c  → Kommentar (voller Name)

# Passwort setzen (bei useradd manuell nötig):
sudo passwd max

Benutzer anzeigen und prüfen

🖥️ Auf dem Server
Benutzer-Informationen abfragen
# Aktuellen Benutzer anzeigen:
whoami

# Alle Informationen über einen Benutzer:
id max
# Ausgabe: uid=1001(max) gid=1001(max) groups=1001(max),27(sudo)

# Alle normalen Benutzer auflisten (UID ab 1000):
awk -F: '$3 >= 1000 && $3 < 65534 {print $1}' /etc/passwd

# Wer ist gerade eingeloggt?
who
w     # ausführlicher: zeigt auch, was jeder Nutzer gerade tut

Benutzer ändern

🖥️ Auf dem Server
Benutzer mit usermod modifizieren
# Shell ändern:
sudo usermod -s /bin/zsh max

# Kommentar (voller Name) ändern:
sudo usermod -c "Max M. (Admin)" max

# Konto sperren (Login verhindern):
sudo usermod -L max

# Konto entsperren:
sudo usermod -U max

Benutzer löschen

🚨 userdel -r löscht das Home-Verzeichnis unwiderruflich!

sudo userdel -r max löscht das komplette Home-Verzeichnis des Benutzers – inklusive aller Dateien und E-Mails. Es gibt kein Zurück. Prüfe vorher, ob wichtige Daten vorhanden sind: ls -la /home/max/. Erstelle im Zweifel vorher eine Sicherungskopie.

🖥️ Auf dem Server
Benutzer entfernen
# Benutzer löschen (Home-Verzeichnis bleibt erhalten):
sudo userdel max

# Benutzer löschen MIT Home-Verzeichnis (Achtung: unwiderruflich!):
sudo userdel -r max

# Auf Debian/Ubuntu: benutzerfreundliche Alternative
sudo deluser --remove-home max
Gruppen verwalten

Gruppen bündeln Rechte. Statt jedem Benutzer einzeln Zugriff auf einen Ordner zu geben, fügst du alle relevanten Benutzer einer Gruppe hinzu und gibst der Gruppe den Zugriff. Das ist wie ein Generalschlüssel für eine bestimmte Abteilung – alle Mitglieder kommen rein, der Rest nicht.

Primäre vs. sekundäre Gruppen

Jeder Benutzer hat genau eine primäre Gruppe (die Gruppe, der neue Dateien gehören) und kann beliebig viele sekundäre Gruppen haben (für zusätzliche Rechte).

🖥️ Auf dem Server
Gruppen erstellen und verwalten
# Neue Gruppe erstellen:
sudo groupadd entwickler

# Benutzer einer sekundären Gruppe hinzufügen:
sudo usermod -aG entwickler max
# -a → append (wichtig! Ohne -a werden alle anderen Gruppen entfernt!)
# -G → sekundäre Gruppen

# Mehrere Gruppen auf einmal hinzufügen:
sudo usermod -aG entwickler,docker,www-data max

# Gruppen eines Benutzers anzeigen:
groups max
# Ausgabe: max : max entwickler docker

# Alle Mitglieder einer Gruppe anzeigen:
getent group entwickler

# Gruppe löschen:
sudo groupdel entwickler
🚨 Vergiss niemals -a bei usermod -G!

sudo usermod -G entwickler max (ohne -a) setzt die Gruppenmitgliedschaft auf nur entwickler – alle anderen sekundären Gruppen (z.B. sudo!) werden entfernt. Max könnte sich danach nicht mehr als Admin einloggen. Immer -aG verwenden!

sudo – kontrollierte Root-Rechte

sudo (Superuser Do) erlaubt normalen Benutzern, einzelne Befehle mit Root-Rechten auszuführen – ohne das Root-Passwort zu kennen. Wer sudo nutzen darf, wird über die Datei /etc/sudoers und die Gruppe sudo gesteuert.

su vs. sudo – der Unterschied

BefehlWas er tutWann nutzen
sudo befehlFührt einen Befehl als Root aus, dann zurück zum normalen BenutzerNormalfall – immer bevorzugen
sudo -iÖffnet eine vollständige Root-Shell (bleibt Root bis exit)Nur wenn viele Root-Befehle nötig sind
su - benutzerWechselt komplett zu einem anderen Benutzer (braucht dessen Passwort)Zum Testen anderer Konten

sudo-Zugang einrichten

🖥️ Auf dem Server
Benutzer zum sudo-Nutzer machen
# Einfachster Weg: Benutzer zur Gruppe 'sudo' hinzufügen
sudo usermod -aG sudo max

# Prüfen ob es geklappt hat:
groups max
# Ausgabe: max : max sudo

# Hinweis: Benutzer muss sich ab- und wieder anmelden,
# damit die neue Gruppenmitgliedschaft wirkt.

/etc/sudoers sicher bearbeiten

Die Datei /etc/sudoers steuert, wer was mit sudo darf. Bearbeite sie niemals direkt mit einem Texteditor – nutze immer visudo, das die Syntax vor dem Speichern prüft:

🖥️ Auf dem Server
sudoers bearbeiten
sudo visudo

# Wichtige Zeilen in der Datei:
# root    ALL=(ALL:ALL) ALL    → Root darf alles
# %sudo   ALL=(ALL:ALL) ALL    → Gruppe 'sudo' darf alles

# Einzelnen Benutzer einschränken (nur apt erlauben):
# max     ALL=(ALL) /usr/bin/apt

# sudo ohne Passwort (NUR für Automatisierung, nicht für normale Nutzer!):
# deploy  ALL=(ALL) NOPASSWD: ALL
⚠️ Immer visudo verwenden!

Wenn du /etc/sudoers mit einem normalen Editor bearbeitest und einen Syntaxfehler einbaust, kann sich niemand mehr per sudo anmelden – auch du nicht. visudo prüft die Syntax vor dem Speichern und verhindert dieses Problem.

🤖
KI-Tipp: Benutzer-Skripte erstellen

Wenn du regelmäßig neue Benutzer anlegen musst (z.B. für neue Mitarbeiter), frag eine KI: „Schreibe mir ein Bash-Skript, das einen neuen Benutzer anlegt, ihn zur Gruppe 'entwickler' hinzufügt, ein temporäres Passwort setzt und erzwingt, dass er es beim ersten Login ändert."

Passwort-Richtlinien mit chage

Sichere Passwörter sind die erste Verteidigungslinie. Mit chage (change age) kannst du einstellen, wie oft Benutzer ihr Passwort ändern müssen und wann Konten ablaufen:

🖥️ Auf dem Server
Passwort-Ablauf konfigurieren
# Passwort-Infos eines Benutzers anzeigen:
sudo chage -l max

# Passwort muss alle 90 Tage geändert werden:
sudo chage -M 90 max

# Mindestens 7 Tage zwischen Passwortänderungen:
sudo chage -m 7 max

# Benutzer muss beim nächsten Login das Passwort ändern:
sudo chage -d 0 max
Befehlsübersicht
BefehlFunktion
adduser NAMENeuen Benutzer interaktiv anlegen (Debian/Ubuntu)
useradd -m -s /bin/bash NAMEBenutzer low-level anlegen
passwd NAMEPasswort setzen oder ändern
usermod -aG GRUPPE NAMEBenutzer zu Gruppe hinzufügen
usermod -L NAMEKonto sperren
userdel NAMEBenutzer löschen (Home bleibt)
userdel -r NAMEBenutzer + Home-Verzeichnis löschen
groupadd GRUPPENeue Gruppe anlegen
groupdel GRUPPEGruppe löschen
groups NAMEGruppen eines Benutzers anzeigen
id NAMEUID, GID und alle Gruppen anzeigen
getent group GRUPPEAlle Mitglieder einer Gruppe anzeigen
chage -l NAMEPasswort-Ablauf-Infos anzeigen
visudo/etc/sudoers sicher bearbeiten
Praxisaufgaben
AUFGABE 8.1 Benutzer und Gruppen anlegen

Erstelle eine Projektstruktur mit Benutzern und Gruppen – wie in einem echten Team mit Zugangsbeschränkungen.

🖥️ Alle Schritte auf dem Server – du bist bereits per SSH eingeloggt
1
Erstelle eine neue Gruppe: sudo groupadd projekt
2
Lege zwei Benutzer an: sudo adduser alice und danach sudo adduser bob. Vergib jeweils ein Passwort.
3
Füge beide der Gruppe hinzu: sudo usermod -aG projekt alice und sudo usermod -aG projekt bob
4
Prüfe die Gruppenmitgliedschaft: groups alice und getent group projekt
5
Zeige die Details beider Benutzer an: id alice und id bob
Lösungshinweise anzeigen

Bei groups alice sollte projekt in der Liste erscheinen. Bei getent group projekt siehst du eine Zeile wie projekt:x:XXXX:alice,bob.

id alice zeigt UID, primäre GID und alle sekundären Gruppen. Achte darauf, dass projekt unter den Gruppen aufgeführt ist.

AUFGABE 8.2 sudo-Rechte vergeben und testen

Gib einem Benutzer sudo-Rechte und überprüfe durch einen Vergleich mit einem Benutzer ohne sudo-Rechte, was den Unterschied macht.

🖥️ Alle Schritte auf dem Server
1
Füge Alice zur sudo-Gruppe hinzu: sudo usermod -aG sudo alice
2
Wechsle zum Benutzer Alice: su - alice (Alices Passwort eingeben)
3
Teste sudo als Alice: sudo whoami – die Ausgabe sollte root sein
4
Wechsle zurück: exit
5
Wechsle zu Bob (der kein sudo hat): su - bob. Teste sudo whoami – was passiert?
Lösungshinweise anzeigen

Alice kann sudo nutzen, weil sie in der Gruppe sudo ist. Bob bekommt die Meldung: bob is not in the sudoers file. This incident will be reported.

Die „This incident will be reported"-Meldung ist kein Scherz: Fehlgeschlagene sudo-Versuche werden in /var/log/auth.log protokolliert. Du kannst das prüfen mit: sudo grep sudo /var/log/auth.log | tail -5

AUFGABE 8.3 Konfigurationsdateien untersuchen

Lerne die Konfigurationsdateien kennen, die hinter der Benutzerverwaltung stecken – und beobachte, wer was lesen darf.

🖥️ Alle Schritte auf dem Server
1
Zeige die passwd-Zeile von Alice an: grep alice /etc/passwd. Identifiziere UID, GID, Home-Verzeichnis und Shell.
2
Versuche als normaler Benutzer, die shadow-Datei zu lesen: cat /etc/shadow. Was passiert? Dann mit Root-Rechten: sudo cat /etc/shadow | grep alice
3
Zeige die Passwort-Ablauf-Informationen: sudo chage -l alice
4
Erzwinge eine Passwortänderung beim nächsten Login: sudo chage -d 0 alice
5
Wechsle zu Alice: su - alice – du wirst sofort zur Passwortänderung aufgefordert.
Lösungshinweise anzeigen

In /etc/passwd siehst du eine Zeile wie alice:x:1002:1002:Alice:/home/alice:/bin/bash. Das x bedeutet, dass das Passwort in /etc/shadow steht.

cat /etc/shadow ohne sudo gibt Permission denied – nur Root darf diese Datei lesen. Das ist ein wichtiger Sicherheitsmechanismus, der verhindert, dass normale Benutzer die Passwort-Hashes anderer Nutzer lesen können.

🤖
KI-Tipp: Berechtigungsprobleme debuggen

Wenn ein Benutzer „Permission denied" bekommt oder sich nicht einloggen kann, prüfe seine Konfiguration und frag eine KI: „Der Benutzer 'max' kann sich nicht per SSH einloggen. Hier ist seine Zeile aus /etc/passwd und die Ausgabe von 'id max' und 'sudo chage -l max'. Was könnte das Problem sein?"

Modul 093 Unterrichtseinheiten

Aufbau von Linux

Linux ist kein Geheimnis – es folgt einem klaren Bauplan. In diesem Modul lernst du, wie das System aufgebaut ist: vom Einschalten bis zum Login, vom Kernel bis zur letzten Konfigurationsdatei. Dieses Wissen brauchst du für alle weiteren Module.

Voraussetzung: Modul 03 Kernel · FHS · systemd · Prozesse · Umgebungsvariablen
Alles läuft auf dem Server

In diesem Modul arbeitest du ausschließlich auf dem Server – du bist per SSH eingeloggt (wie in Modul 02 gelernt). Alle Befehle führst du im Server-Terminal aus:

🖥️ Server

Alle Befehle in diesem Modul laufen auf dem Server – du bist bereits per SSH eingeloggt.

Kernel, Shell und Distribution – das Zusammenspiel

Linux besteht aus mehreren Schichten, die zusammenarbeiten. Eine gute Analogie: Stell dir ein Auto vor.

  • Der Kernel ist der Motor – du siehst ihn nicht direkt, aber alles hängt von ihm ab. Er verwaltet Hardware, Arbeitsspeicher und Prozesse.
  • Die Shell (z.B. Bash) ist das Armaturenbrett und das Lenkrad – die Schnittstelle, über die du das System bedienst. Du gibst Befehle ein, die Shell gibt sie an den Kernel weiter.
  • Die Distribution (z.B. Ubuntu oder Debian) ist die Automarke – sie kombiniert Kernel, Shell, Paketmanager und vorinstallierte Software zu einem fertigen Paket.
SchichtBeispielAufgabe
KernelLinux 6.1Hardware steuern, Ressourcen verwalten
ShellBash, Zsh, FishBefehle entgegennehmen und ausführen
Paketmanagerapt (Debian/Ubuntu)Software installieren und aktualisieren
DistributionUbuntu 24.04, Debian 12Alles zusammenpacken und pflegen
🖥️ Auf dem Server – Kernel und Shell abfragen

Mit diesen Befehlen siehst du, welchen Kernel und welche Distribution dein Server nutzt:

System identifizieren
# Kernel-Version anzeigen:
uname -r
# Ausgabe z.B.: 6.1.0-18-amd64

# Welche Shell nutzt du gerade?
echo $SHELL
# Ausgabe z.B.: /bin/bash

# Welche Distribution und Version?
cat /etc/os-release
lsb_release -a
🧠 Kernel-Module = Treiber

Der Linux-Kernel lädt nur die Treiber (Module), die er braucht – wie ein Werkzeugkasten, aus dem du nur das herausnimmst, was du gerade brauchst. Mit lsmod siehst du alle geladenen Module. Das sind typischerweise 60–100 Einträge: Dateisystem-Treiber, Netzwerkkarte, USB-Controller und mehr.

Der Boot-Prozess – vom Einschalten bis zum Login

Wenn du deinen Server einschaltest, läuft in wenigen Sekunden eine feste Kette von Ereignissen ab. Stell dir das wie den Motorstart eines Autos vor: Zündschlüssel dreht → Anlasser springt an → Motor läuft → Bordelektronik wird aktiv. Beim Linux-Server sieht die Kette so aus:

PhaseWas passiertCa. Dauer
1. BIOS / UEFIHardware-Selbsttest (POST), Bootmedium suchen1–5 Sek.
2. GRUB (Bootloader)Kernel-Datei laden, Boot-Menü anzeigen1–3 Sek.
3. KernelHardware erkennen, Treiber laden, Root-Dateisystem einhängen2–5 Sek.
4. initramfsTemporäres Mini-System für frühe Treiber und Entschlüsselung1–2 Sek.
5. systemd (PID 1)Alle Dienste starten, Netzwerk hochfahren, Login bereitstellen3–15 Sek.

BIOS vs. UEFI: Ältere Rechner nutzen das BIOS, modernere das UEFI. Der praktische Unterschied: UEFI unterstützt Festplatten über 2 TB und GPT-Partitionstabellen. Für neue Server immer UEFI verwenden.

🖥️ Auf dem Server – Boot-Informationen abfragen
Boot-Analyse
# BIOS oder UEFI? (Verzeichnis vorhanden = UEFI)
ls /sys/firmware/efi/ && echo "UEFI" || echo "BIOS"

# Gesamte Bootzeit anzeigen:
systemd-analyze
# Ausgabe z.B.: Startup finished in 2.5s (kernel) + 8.3s (userspace) = 10.8s

# Die langsamsten Dienste beim Boot:
systemd-analyze blame | head -10

# Boot-Logs des aktuellen Starts:
journalctl -b --no-pager | tail -30
Die Verzeichnisstruktur (FHS)

Auf Linux gibt es keine Laufwerksbuchstaben wie C: oder D:. Stattdessen hängt alles an einem einzigen Wurzelverzeichnis: /. Diese Struktur heißt FHS (Filesystem Hierarchy Standard) und ist auf allen Linux-Distributionen gleich aufgebaut.

Stell dir das vor wie einen großen Aktenschrank: Jede Schublade hat ein festes Thema – und alle wissen, wo was zu finden ist.

VerzeichnisInhaltAnalogie
/Wurzelverzeichnis – Ausgangspunkt für allesDer gesamte Aktenschrank
/homeBenutzerverzeichnisse (/home/anna, /home/bob)Persönliche Schubladen der Mitarbeiter
/etcKonfigurationsdateien aller ProgrammeOrdner mit Einstellungen und Regeln
/varVariable Daten: Logs, Datenbanken, Mail-WarteschlangenPosteingang und Logbücher
/tmpTemporäre Dateien – werden beim Neustart gelöschtSchmierpapier auf dem Schreibtisch
/usrProgramme, Bibliotheken, DokumentationDer Werkzeugkasten
/bin, /sbinGrundlegende Systembefehle (heute oft Symlinks auf /usr/bin)Werkzeuge, die immer griffbereit sein müssen
/bootKernel und Bootloader-DateienDer Zündschlüssel
/devGerätedateien: Festplatten (/dev/sda), USB, etc.Anschlüsse an der Rückwand
/proc, /sysVirtuelle Dateisysteme mit Live-Infos über Kernel und HardwareDashboard mit Live-Anzeigen
/mnt, /mediaEinhängepunkte für externe Datenträger und NetzlaufwerkeParkplätze für USB-Sticks
/optSoftware, die nicht vom Paketmanager kommt (z.B. kommerzielle Tools)Sonder-Werkzeuge außerhalb des Standards
🖥️ Auf dem Server – Verzeichnisstruktur erkunden
FHS erkunden
# Die erste Verzeichnisebene anzeigen:
ls /

# Was liegt in /etc?
ls /etc/ | head -20

# Wie viel Platz verbraucht jedes Verzeichnis?
sudo du -sh /* 2>/dev/null | sort -hr | head

# Hostnamen lesen:
cat /etc/hostname
🧠 Eselsbrücke: /etc und /var

/etc enthält statische Konfiguration – Dateien, die du als Admin bearbeitest (sshd_config, fstab, hosts). /var enthält laufend wachsende Daten – Logs unter /var/log/, Datenbanken unter /var/lib/. Diese Unterscheidung hilft dir beim Backup: /etc regelmäßig sichern, /var/log rotiert sich selbst.

Prozesse – was auf dem System läuft

Jedes Programm, das auf dem Server läuft, ist ein Prozess. Jeder Prozess bekommt eine eindeutige Nummer: die PID (Process ID). systemd ist immer PID 1 – der erste Prozess nach dem Kernel. Alles andere ist ein Kind- oder Enkelprozess davon.

🖥️ Auf dem Server – Prozesse anzeigen
Prozesse beobachten
# Alle laufenden Prozesse anzeigen:
ps aux
# USER   PID  %CPU %MEM  COMMAND
# root     1   0.0  0.5  /sbin/init  (= systemd)
# www-da 812   0.2  1.3  nginx: master process

# Nach CPU-Auslastung sortiert, Top 10:
ps aux --sort=-%cpu | head -10

# Interaktive Prozessübersicht (beenden mit 'q'):
top
# Noch besser – falls installiert:
htop

# PID eines bestimmten Programms finden:
pgrep nginx
pidof sshd

Prozesse beenden – Signale

Du kannst einem Prozess ein Signal schicken – ähnlich wie ein Handzeichen an einen Kollegen. Das häufigste Signal ist SIGTERM: „Bitte beende dich geordnet." Wenn das nicht hilft, kommt SIGKILL: „Sofort aufhören, egal was gerade passiert."

SignalNummerBedeutungBefehl
SIGTERM15Geordnet beenden (Standard)kill PID
SIGKILL9Sofort abwürgen (kein Aufräumen möglich)kill -9 PID
SIGHUP1Konfiguration neu ladenkill -1 PID
SIGSTOP19Prozess anhalten (pausieren)kill -19 PID
🖥️ Auf dem Server – Prozesse beenden
Signale senden
# Prozess geordnet beenden (SIGTERM, Standard):
kill 1234
# Ersetze 1234 durch die echte PID aus ps aux

# Prozess sofort abwürgen (SIGKILL, letzter Ausweg):
kill -9 1234

# Alle Prozesse eines Namens beenden:
pkill firefox
killall python3
⚠️ kill -9 als letzter Ausweg

SIGKILL (kill -9) gibt dem Prozess keine Chance, offene Dateien zu schließen oder Daten zu speichern. Das kann zu korrupten Dateien führen. Versuche immer zuerst kill PID (SIGTERM) und warte einige Sekunden. Erst wenn der Prozess danach noch läuft, kommt SIGKILL.

systemd – Dienste verwalten

systemd ist der erste Prozess, der nach dem Kernel startet (PID 1). Er verwaltet alle Dienste (Daemons) auf deinem Server – von SSH bis Nginx. Die Grundeinheit von systemd ist die Unit. Die wichtigste Unit-Art ist der Service (z.B. sshd.service, nginx.service).

🖥️ Auf dem Server – Dienste mit systemctl verwalten
systemctl – die wichtigsten Befehle
# Status eines Dienstes anzeigen:
systemctl status ssh
# Zeigt: läuft/gestoppt, letzte Logs, PID

# Dienst starten / stoppen / neustarten:
sudo systemctl start nginx
sudo systemctl stop nginx
sudo systemctl restart nginx

# Nur Konfiguration neu laden (ohne Neustart):
sudo systemctl reload nginx

# Dienst beim Boot automatisch starten:
sudo systemctl enable nginx

# Autostart wieder deaktivieren:
sudo systemctl disable nginx

# Alle laufenden Dienste auflisten:
systemctl list-units --type=service --state=running

Runlevels vs. systemd-Targets

Frühere Linux-Systeme nutzten Runlevels (Zahlen 0–6). systemd ersetzt sie durch Targets – aussagekräftigere Namen für denselben Zweck. Für dich als Server-Admin ist multi-user.target der Normalzustand:

systemd-TargetBeschreibungAltes Runlevel
poweroff.targetSystem herunterfahren0
rescue.targetEinzelbenutzer-Wartungsmodus1
multi-user.targetMehrbenutzerbetrieb ohne GUI – Standard für Server3
graphical.targetDesktop mit grafischer Anmeldung5
reboot.targetSystem neu starten6
🖥️ Auf dem Server – Targets abfragen
# Aktuelles Standard-Target anzeigen:
systemctl get-default
# Auf Servern typisch: multi-user.target

# Standard-Target setzen (nur wenn nötig):
sudo systemctl set-default multi-user.target

Logs mit journalctl lesen

🖥️ Auf dem Server – Logs lesen
journalctl – System-Log
# Alle Logs (neueste zuerst, 'q' zum Beenden):
journalctl -e

# Nur Logs des aktuellen Boots:
journalctl -b

# Nur Fehlermeldungen:
journalctl -b -p err

# Logs eines bestimmten Dienstes:
journalctl -u ssh
journalctl -u nginx -f
# -f = live mitlesen (wie tail -f), beenden mit Strg+C

# Logs der letzten Stunde:
journalctl --since "1 hour ago"
🤖
KI-Tipp: systemd-Fehler verstehen

Wenn ein Dienst nicht startet, zeigt systemctl status dienstname oft kryptische Fehlermeldungen. Kopiere die vollständige Ausgabe und frag: „Mein nginx startet nicht. Hier ist die systemctl-status-Ausgabe. Was bedeutet der Fehler und wie behebe ich ihn auf Ubuntu 24.04?"

Umgebungsvariablen

Umgebungsvariablen sind benannte Werte, die für alle Programme sichtbar sind, die in deiner Shell-Sitzung laufen. Die wichtigste ist PATH – sie sagt der Shell, in welchen Verzeichnissen sie nach Programmen suchen soll.

Stell dir das vor wie eine Liste von Schubladen, in denen die Shell nach Werkzeugen sucht. Gibst du ls ein, schaut die Shell die PATH-Verzeichnisse der Reihe nach durch, bis sie das Programm findet.

🖥️ Auf dem Server – Umgebungsvariablen
Umgebungsvariablen lesen und setzen
# Alle Umgebungsvariablen anzeigen:
env
printenv

# Eine bestimmte Variable lesen:
echo $PATH
echo $HOME
echo $USER

# Variable für die aktuelle Sitzung setzen:
export MEINE_VAR="hallo"
echo $MEINE_VAR
# Gilt nur in dieser Shell-Sitzung – nach logout weg

# Variable dauerhaft für alle Benutzer setzen:
sudo nano /etc/environment
# Dort eintragen: MEINE_VAR="hallo"
# Gilt nach dem nächsten Login systemweit
VariableBedeutungBeispielwert
PATHSuchpfade für Programme/usr/bin:/usr/sbin:/bin
HOMEHome-Verzeichnis des Benutzers/home/admin
USERAktueller Benutzernameadmin
SHELLAktive Shell/bin/bash
LANGSprache und Zeichensatzde_DE.UTF-8
EDITORStandard-Texteditorvim oder nano
💡 Wo werden Variablen dauerhaft gesetzt?

Es gibt drei Stellen: /etc/environment (systemweit, für alle Benutzer), ~/.bashrc oder ~/.profile (nur für einen Benutzer, bei jedem Login) und export VAR=wert im Terminal (nur für die aktuelle Sitzung). Für Server-weite Einstellungen nimm /etc/environment.

🤖
KI-Tipp: Prozesse und Systemauslastung verstehen

Wenn dein Server langsam wird oder unerwartet viel CPU oder RAM verbraucht, führe ps aux --sort=-%cpu | head -15 aus, kopiere die Ausgabe und frag: „Welcher Prozess verursacht die hohe CPU-Auslastung auf meinem Ubuntu-Server? Ist das normal und was kann ich dagegen tun?"

Praxisaufgaben
AUFGABE 9.1 Dein System kennenlernen

Du verschaffst dir einen vollständigen Überblick über deinen Server – Distribution, Kernel, Partitionen und Ressourcen. Das ist die Basis für alle weiteren Module.

🖥️ Alle Schritte auf dem Server – du bist per SSH eingeloggt
1
Finde heraus, welche Distribution und Kernel-Version du nutzt: cat /etc/os-release und uname -r. Notiere die Ergebnisse.
2
Prüfe, ob dein Server BIOS oder UEFI nutzt: ls /sys/firmware/efi/ 2>/dev/null && echo "UEFI" || echo "BIOS"
3
Zeige alle Partitionen an: lsblk. Wie heißt deine Root-Partition (Mountpoint /)? Wie groß ist sie?
4
Prüfe den Festplatten-Füllstand: df -h. Wie viel Prozent sind auf der Root-Partition belegt?
5
Zeige RAM- und CPU-Infos: free -h und lscpu | head -10. Wie viele CPU-Kerne hat dein Server?
Lösungshinweise anzeigen

Bei lsblk erkennst du die Root-Partition am Mountpoint /. Auf VMs heißt sie oft /dev/vda1, auf physischen Servern /dev/sda2.

Bei df -h zeigt die Spalte „Use%" den Füllstand. Unter 80 % ist in der Regel unbedenklich. Über 90 % wird es eng – dann Logs prüfen und aufräumen.

free -h: Schau auf die Zeile „Mem:" – „total" ist dein RAM, „available" ist noch frei nutzbar.

AUFGABE 9.2 Dienste und Prozesse beobachten

Du lernst, welche Dienste auf deinem Server laufen, wie du ihren Status prüfst und wie du Prozesse beobachtest. Das brauchst du täglich in der Server-Administration.

🖥️ Alle Schritte auf dem Server
1
Zeige alle laufenden Dienste: systemctl list-units --type=service --state=running. Zähle, wie viele Dienste aktiv sind.
2
Prüfe den SSH-Dienst: systemctl status ssh. Ist er aktiv? Seit wann läuft er?
3
Zeige die zehn prozessorhungrigsten Prozesse: ps aux --sort=-%cpu | head -10. Welcher Prozess verbraucht am meisten CPU?
4
Schau in die SSH-Logs: journalctl -u ssh -n 20. Siehst du deine eigenen Login-Versuche mit Zeitstempel und IP?
5
Prüfe das Standard-Boot-Target: systemctl get-default. Auf einem Server sollte multi-user.target stehen.
Lösungshinweise anzeigen

Bei systemctl status ssh siehst du in der grünen Zeile „active (running)" wenn der Dienst läuft. Die Zeile „Active:" zeigt, seit wann er läuft.

In den SSH-Logs erscheinen alle Logins mit Benutzername, IP-Adresse und Zeitstempel. So erkennst du auch unerlaubte Login-Versuche fremder IPs.

Ein frischer Debian/Ubuntu-Server hat typischerweise 20–35 laufende Dienste.

AUFGABE 9.3 Verzeichnisstruktur und Umgebungsvariablen

Du erkundest die FHS-Verzeichnisstruktur und lernst, wie Umgebungsvariablen funktionieren. Beides ist Grundlage für Konfigurationsarbeit in allen späteren Modulen.

🖥️ Alle Schritte auf dem Server
1
Zeige die oberste Verzeichnisebene: ls /. Erkennst du die Verzeichnisse aus der Tabelle oben?
2
Finde heraus, welche Verzeichnisse am meisten Platz belegen: sudo du -sh /* 2>/dev/null | sort -hr | head -10. Was steht an erster Stelle?
3
Zeige deinen aktuellen PATH: echo $PATH. Wie viele Verzeichnisse sind durch Doppelpunkt getrennt aufgelistet?
4
Setze eine eigene Variable: export TESTVAR="Linux-Kurs" und zeige sie an: echo $TESTVAR. Logge dich aus und wieder ein – ist die Variable noch da?
5
Schau in die letzten Logs: journalctl -n 20 --no-pager. Kannst du erkennen, was in den letzten Minuten auf dem Server passiert ist?
Lösungshinweise anzeigen

Die größten Verzeichnisse sind typischerweise /usr (2–5 GB – alle Programme) und /var (wächst mit der Zeit durch Logs und Datenbanken).

Ein typischer PATH enthält 5–8 Einträge: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin. Wenn du ein eigenes Programm systemweit verfügbar machen willst, legst du es in /usr/local/bin/ ab.

Nach dem Ausloggen ist $TESTVAR weg – export gilt nur für die aktuelle Shell-Sitzung. Für dauerhafte Variablen trägst du sie in ~/.bashrc oder /etc/environment ein.

Modul 103 Unterrichtseinheiten

mount & /etc/fstab

Eine Festplatte anschließen reicht unter Linux nicht -- du musst sie erst einhängen (mounten), bevor du darauf zugreifen kannst. In diesem Modul lernst du, wie du Partitionen und USB-Sticks einbindest, dauerhaft in der fstab einträgst und typische Fehler vermeidest.

Voraussetzung: Modul 05 Voraussetzung: Modul 09 mount · umount · fstab · UUID · lsblk · blkid
🖥️ Kontext: Alles läuft auf dem Server

In diesem Modul arbeitest du ausschließlich auf dem Server. Alle Befehle werden dort ausgeführt -- du bist per SSH eingeloggt (aus Modul 02). Es gibt keinen Wechsel zum lokalen Rechner.

Was bedeutet Mounten?

Unter Windows steckst du einen USB-Stick ein und er taucht automatisch als Laufwerk D: auf. Unter Linux passiert das nicht von allein. Du musst das Gerät erst an einen Ordner im Verzeichnisbaum einhängen -- das nennt sich mounten.

Stell dir den Verzeichnisbaum wie einen Kleiderschrank vor. Der Schrank hat Fächer (/home, /var, /mnt). Wenn du eine neue Festplatte einhängst, schiebst du ein zusätzliches Fach in den Schrank -- zum Beispiel bei /mnt/daten. Ab diesem Moment sind alle Dateien dieser Festplatte über diesen Ordner erreichbar.

💡 Mountpoint = normaler Ordner

Der Einhängepunkt (Mountpoint) ist einfach ein leerer Ordner, den du vorher mit mkdir erstellst. Nach dem Mounten zeigt dieser Ordner auf die Festplatte -- nicht auf den internen Speicher des Servers.

Geräte und Partitionen anzeigen

Bevor du etwas mountest, musst du wissen, wie das Gerät heißt und welche Partitionen es hat. Dafür gibt es zwei Werkzeuge:

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt

lsblk zeigt dir alle Blockgeräte (Festplatten, Partitionen, USB-Sticks) in einer Baumstruktur:

Alle Blockgeräte anzeigen
lsblk
# Ausgabe-Beispiel:
# NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
# sda      8:0    0   20G  0 disk
# ├─sda1   8:1    0   19G  0 part /
# └─sda2   8:2    0    1G  0 part [SWAP]
# sdb      8:16   0  500G  0 disk
# └─sdb1   8:17   0  500G  0 part

# Mit Dateisystem und UUID anzeigen:
lsblk -f

blkid zeigt dir die UUID und den Dateisystemtyp jeder Partition -- das brauchst du für die fstab:

UUIDs aller Partitionen anzeigen
sudo blkid
# Ausgabe-Beispiel:
# /dev/sda1: UUID="550e8400-e29b-41d4-a716-446655440000" TYPE="ext4"
# /dev/sdb1: UUID="a1b2c3d4-5678-90ab-cdef-1234567890ab" TYPE="ext4"

# Nur eine bestimmte Partition abfragen:
sudo blkid /dev/sdb1
BefehlZeigtWann verwenden
lsblkGeräte und Partitionen als BaumÜberblick verschaffen, Gerätename finden
lsblk -fWie oben + Dateisystem + UUIDAlle Infos auf einen Blick
sudo blkidUUID und Dateisystemtyp aller PartitionenUUID für fstab-Eintrag kopieren
df -hTBelegung aller gemounteten PartitionenFüllstand und freien Platz prüfen
findmntAlle Mounts als BaumstrukturWas ist gerade wo eingehängt?
Partitionen manuell mounten und umounten

Ein manueller Mount gilt nur bis zum nächsten Neustart. Er ist ideal zum Testen oder für USB-Sticks, die du nur gelegentlich anschließt.

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt

Schritt 1: Erstelle einen Ordner als Einhängepunkt. Schritt 2: Hänge die Partition ein. Schritt 3: Prüfe das Ergebnis.

Partition manuell einhängen
# Einhängepunkt erstellen (falls noch nicht vorhanden):
sudo mkdir -p /mnt/daten

# Partition einhängen:
sudo mount /dev/sdb1 /mnt/daten

# Prüfen ob es geklappt hat:
df -h /mnt/daten
ls /mnt/daten/

Zum Aushängen nimmst du umount. Das ist kein Tippfehler -- der Befehl heißt wirklich umount, nicht unmount:

Partition aushängen
# Partition aushängen:
sudo umount /mnt/daten

# Falls "target is busy" kommt -- wer nutzt die Partition noch?
sudo lsof /mnt/daten
# Zeigt alle Prozesse, die Dateien auf der Partition offen haben
⚠️ Niemals einfach den Stecker ziehen!

Ein Speichergerät ohne umount zu entfernen kann zu Datenverlust führen. Das Dateisystem puffert Schreibvorgänge -- beim Aushängen werden diese Puffer erst auf die Platte geschrieben (Flush). Immer erst sudo umount, dann abstecken.

Mount-Optionen

Beim Mounten kannst du mit -o Optionen angeben, die das Verhalten steuern. Mehrere Optionen werden durch Komma getrennt -- ohne Leerzeichen:

🖥️ Auf dem Server
Mount mit Optionen
# Nur-Lesen mounten (Partition kann nicht verändert werden):
sudo mount -o ro /dev/sdb1 /mnt/backup

# Mehrere Optionen kombinieren:
sudo mount -o rw,noexec,noatime /dev/sdb1 /mnt/daten

# ISO-Datei mounten (als Loop-Device):
sudo mount -o loop /tmp/debian.iso /mnt/iso
OptionBedeutungWann sinnvoll
defaultsStandardpaket: rw, suid, dev, exec, autoNormaler Datenträger
roNur-Lesen (read-only)Backup-Medien, ISO-Dateien
rwLesen und SchreibenStandard für Datenpartitionen
noexecKeine Programme ausführenSicherheit: /tmp, Upload-Ordner
noatimeKeine Zugriffszeiten schreibenPerformance bei SSDs
nofailBoot nicht abbrechen wenn Mount fehlschlägtExterne Platten, Netzlaufwerke
_netdevWarten bis Netzwerk bereit istNFS, CIFS, SSHFS
/etc/fstab -- Partitionen dauerhaft einbinden

Ein manueller mount-Befehl ist nach dem Neustart vergessen. Wenn eine Partition automatisch beim Booten eingehängt werden soll, trägst du sie in /etc/fstab ein. Diese Datei liest Linux beim Start und hängt alle eingetragenen Partitionen automatisch ein.

Die sechs Felder der fstab

🖥️ Auf dem Server

So sieht eine typische fstab aus:

/etc/fstab -- Beispiel
# Feld 1: Gerät        Feld 2: Mountpoint  Feld 3: FS   Feld 4: Optionen          Feld 5  Feld 6
UUID=550e8400-e29b-41d4-a716-446655440000  /             ext4   errors=remount-ro  0  1
UUID=a1b2c3d4-5678-90ab-cdef-1234567890ab  /home         ext4   defaults           0  2
/dev/sdb1                                  /mnt/daten    ext4   defaults,nofail    0  2
# Swap-Partition:
UUID=dead1234-beef-5678-abcd-ef0123456789  none          swap   sw                 0  0
FeldBedeutungBeispiel
1 -- GerätWelche Partition (UUID empfohlen!)UUID=550e8400-...
2 -- MountpointWo im Verzeichnisbaum einhängen/mnt/daten
3 -- DateisystemTyp des Dateisystemsext4, vfat, swap
4 -- OptionenMount-Optionen, Komma-getrenntdefaults,nofail
5 -- DumpBackup-Flag -- fast immer 00
6 -- Passfsck-Reihenfolge beim Booten: 1=Root, 2=andere, 0=überspringen2
🚨 fstab-Fehler können den Server unbootbar machen!

Eine einzige falsche Zeile in /etc/fstab kann dazu führen, dass dein Server beim nächsten Neustart hängen bleibt und nicht mehr startet. Deshalb gilt: Immer zuerst mit sudo mount -a testen, bevor du neustartest. Nutze außerdem nofail bei externen Platten -- dann bootet das System auch, wenn das Gerät mal nicht angeschlossen ist.

UUID vs. Gerätename -- warum UUID sicherer ist

Gerätenamen wie /dev/sdb1 sind nicht fix. Wenn du eine zweite Festplatte einbaust oder den Server umbaust, kann aus sdb plötzlich sdc werden -- und dein fstab-Eintrag zeigt auf die falsche Partition.

Die UUID (Universally Unique Identifier) hingegen ist eine einmalige Kennung, die beim Formatieren vergeben wird und sich nie ändert -- egal in welchem SATA-Port die Platte steckt.

🧠 Eselsbrücke: UUID ist wie die Fahrzeugidentifikationsnummer

Der Gerätename /dev/sdb1 ist wie der Parkplatz in einer Tiefgarage -- morgen steht da vielleicht ein anderes Auto. Die UUID ist wie die FIN (Fahrzeugidentifikationsnummer) -- die bleibt immer gleich, egal wo das Fahrzeug steht.

Neue Partition in die fstab eintragen

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt

Das Vorgehen Schritt für Schritt:

fstab-Eintrag erstellen
# 1. UUID der Partition herausfinden:
sudo blkid /dev/sdb1
# Ausgabe: /dev/sdb1: UUID="a1b2c3d4-..." TYPE="ext4"

# 2. Einhängepunkt erstellen:
sudo mkdir -p /mnt/daten

# 3. fstab mit einem Editor öffnen und Zeile hinzufügen:
sudo nano /etc/fstab
# Neue Zeile einfügen (UUID durch echten Wert aus blkid ersetzen):
# UUID=a1b2c3d4-5678-90ab-cdef-1234567890ab  /mnt/daten  ext4  defaults,nofail  0  2

# 4. Testen ohne Neustart -- mountet alle fstab-Einträge:
sudo mount -a
# Kein Fehler = alles korrekt eingetragen

# 5. Ergebnis prüfen:
df -h /mnt/daten
🤖
KI-Tipp: fstab-Eintrag generieren lassen

Die fstab-Syntax ist fehleranfällig -- ein falscher Eintrag und der Server startet nicht mehr. Gib einer KI die Ausgabe von sudo blkid und beschreibe dein Ziel: „Erstelle mir einen fstab-Eintrag für die Partition mit UUID a1b2c3d4-5678-90ab-cdef-1234567890ab, die ich als ext4 unter /mnt/daten dauerhaft einbinden will. Das System soll trotzdem booten, wenn die Platte mal nicht angeschlossen ist."

Swap-Speicher einrichten

Wenn der Arbeitsspeicher (RAM) voll ist, lagert Linux selten genutzte Daten auf die Swap-Partition aus. Das ist langsamer als echter RAM, verhindert aber, dass Programme abstürzen oder der Server nicht mehr reagiert.

Statt einer eigenen Swap-Partition kannst du auch eine Swap-Datei anlegen -- das ist flexibler und auf modernen Systemen genauso schnell:

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt
Swap anzeigen und Swap-Datei erstellen
# Aktuellen Swap-Status anzeigen:
swapon --show
free -h

# Swap-Datei erstellen (2 GB):
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Dauerhaft in fstab eintragen (nach der letzten Zeile einfügen):
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

# Prüfen ob Swap aktiv ist:
swapon --show
💡 Wie viel Swap braucht ein Server?

Faustregel: So viel Swap wie RAM, maximal 4--8 GB. Bei Servern mit 32 GB+ RAM reichen oft 2--4 GB Swap. Zu viel Swap kann schaden -- das System wird dann extrem langsam, statt den Speicherengpass klar anzuzeigen.

Netzlaufwerke einbinden (Ausblick)

Du kannst in der fstab auch Netzlaufwerke dauerhaft einbinden. Das Prinzip ist dasselbe: Mountpoint erstellen, Eintrag in fstab, mount -a testen. Wichtig: Immer _netdev als Option angeben, damit Linux wartet bis das Netzwerk bereit ist.

🖥️ Auf dem Server
Beispiel: NFS-Share in der fstab (Ausblick)
# NFS-Share einbinden (Modul 12 behandelt das ausführlich):
# 192.168.1.10:/export/daten  /mnt/nfs  nfs  defaults,_netdev,nofail  0  0

# Aktuell gemountete Netzlaufwerke anzeigen:
findmnt -t nfs,cifs
💡 Mehr dazu in Modul 12

SFTP, SSHFS und SAMBA-Freigaben werden in Modul 12 ausführlich behandelt. Dort lernst du auch, wie du Windows-Netzlaufwerke (CIFS/SAMBA) unter Linux einbindest.

Typische Fehler und wie du sie findest
🖥️ Auf dem Server

Diese Befehle helfen dir, Mount-Probleme zu diagnostizieren:

Diagnose-Befehle
# Alle aktuell gemounteten Dateisysteme als Baum:
findmnt

# fstab auf Syntaxfehler prüfen (vor dem Neustart!):
findmnt --verify

# Alle fstab-Einträge neu mounten (Test ohne Neustart):
sudo mount -a

# Kernel-Meldungen zu Festplatten anzeigen:
dmesg | grep -i 'sd\|error\|fail' | tail -20
FehlermeldungMögliche UrsacheLösung
wrong fs typeFalsches Dateisystem angegebensudo blkid prüfen, richtigen Typ eintragen
UUID not foundUUID in fstab stimmt nichtUUID mit sudo blkid neu kopieren
target is busyProzess nutzt die Partition nochsudo lsof /mnt/pfad und Prozess beenden
permission deniedFehlende sudo-RechteBefehl mit sudo wiederholen
🤖
KI-Tipp: Mount-Fehler diagnostizieren

Wenn eine Partition sich nicht mounten lässt oder die Fehlermeldung kryptisch ist, kopiere die Ausgabe von sudo mount /dev/sdb1 /mnt/daten und dmesg | tail -20 und frag: „Ich bekomme beim Mounten von /dev/sdb1 die Fehlermeldung 'wrong fs type, bad option, bad superblock'. Hier ist die Ausgabe von sudo blkid /dev/sdb1 und dmesg tail. Was muss ich tun?"

Praxisaufgaben
AUFGABE 10.1 Partitionen und Mounts erkunden

Verschaffe dir einen vollständigen Überblick über alle Partitionen und eingehängten Dateisysteme deines Servers.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Zeige alle Blockgeräte als Baum an: lsblk. Wie viele Festplatten hat dein Server? Welche Partitionen gibt es?
2
Zeige Dateisystem und UUID für alle Partitionen an: lsblk -f. Notiere den Dateisystemtyp deiner Root-Partition (/).
3
Zeige die UUIDs aller Partitionen detailliert: sudo blkid. Notiere die UUID deiner Root-Partition.
4
Lies deine aktuelle fstab: cat /etc/fstab. Findest du die UUID aus Schritt 3 in der fstab wieder?
5
Prüfe die fstab auf Syntaxfehler: findmnt --verify. Wenn keine Ausgabe kommt, ist alles in Ordnung.
Lösungshinweise anzeigen

Bei lsblk siehst du die Geräte (sda, sdb...) und ihre Partitionen (sda1, sda2...). Die Root-Partition hat in der Spalte MOUNTPOINT den Wert /.

In /etc/fstab steht die Root-Partition mit pass=1 (letzte Spalte) -- das bedeutet, sie wird beim Booten als erste auf Fehler geprüft. Alle anderen Partitionen haben pass=2 oder pass=0.

AUFGABE 10.2 Partition manuell mounten und umounten

Du übst das manuelle Einhängen und Aushängen mit einem sicheren Test-Dateisystem. Kein Risiko für deine echten Daten.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Erstelle eine 100-MB-Testdatei, die als Partition simuliert wird: dd if=/dev/zero of=/tmp/testdisk bs=1M count=100. Das dauert einige Sekunden.
2
Formatiere die Testdatei als ext4-Dateisystem: sudo mkfs.ext4 /tmp/testdisk. Bestätige mit y wenn gefragt.
3
Erstelle einen Mountpoint und hänge die Testdatei ein: sudo mkdir -p /mnt/test && sudo mount -o loop /tmp/testdisk /mnt/test.
4
Prüfe ob der Mount funktioniert hat: df -h /mnt/test. Schreibe eine Testdatei: echo "Hallo Welt" | sudo tee /mnt/test/test.txt.
5
Hänge die Partition sauber aus und räume auf: sudo umount /mnt/test && sudo rmdir /mnt/test && rm /tmp/testdisk.
Lösungshinweise anzeigen

dd erstellt eine leere Datei fixer Größe. mkfs.ext4 schreibt ein Dateisystem hinein -- danach verhält sie sich genau wie eine echte Partition. mount -o loop hängt sie als Loop-Device ein.

Nach dem umount ist die Testdatei nicht mehr eingehängt -- die Datei selbst existiert noch unter /tmp/testdisk, bis du sie mit rm löschst.

AUFGABE 10.3 fstab-Eintrag erstellen und sicher testen

Du trägst eine Partition dauerhaft in die fstab ein und testest den Eintrag sicher -- ohne den Server neustarten zu müssen.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Erstelle eine Sicherheitskopie der fstab, bevor du sie änderst: sudo cp /etc/fstab /etc/fstab.bak. Diese Kopie rettet dich falls etwas schiefgeht.
2
Finde die UUID einer Partition, die du eintragen willst: sudo blkid. Wähle eine Partition, die noch nicht in der fstab steht. Falls keine vorhanden: Erstelle eine Testdatei mit dd if=/dev/zero of=/tmp/testdisk bs=1M count=100 && sudo mkfs.ext4 /tmp/testdisk.
3
Erstelle den Mountpoint: sudo mkdir -p /mnt/testdaten. Öffne die fstab im Editor: sudo nano /etc/fstab. Füge am Ende eine neue Zeile hinzu mit UUID, Mountpoint, Dateisystemtyp und den Optionen defaults,nofail.
4
Teste den neuen Eintrag ohne Neustart: sudo mount -a. Kein Fehler bedeutet: Eintrag ist korrekt. Prüfe mit df -h /mnt/testdaten.
5
Prüfe die fstab auf Syntaxfehler: findmnt --verify. Bei Problemen kannst du die Sicherheitskopie wiederherstellen: sudo cp /etc/fstab.bak /etc/fstab.
Lösungshinweise anzeigen

Eine korrekte fstab-Zeile sieht so aus (sechs Felder, durch Leerzeichen oder Tabs getrennt):
UUID=a1b2c3d4-... /mnt/testdaten ext4 defaults,nofail 0 2

Wenn mount -a eine Fehlermeldung ausgibt: Prüfe ob die UUID korrekt kopiert wurde und ob der Mountpoint-Ordner existiert. Die Sicherheitskopie unter /etc/fstab.bak kannst du jederzeit wiederherstellen.

Modul 112 Unterrichtseinheiten

Datei-Berechtigungen

Wer darf lesen, wer darf schreiben, wer darf ausführen? Datei-Berechtigungen sind das Fundament der Linux-Sicherheit. Du lernst, was drwxr-xr-x bedeutet, wie du Berechtigungen mit chmod setzt und warum chmod 777 fast immer ein Fehler ist.

Voraussetzung: Modul 03 Voraussetzung: Modul 08 chmod · chown · umask · SUID · Sticky Bit
Alles passiert auf dem Server

Berechtigungen verwaltest du direkt auf dem Server – nach dem SSH-Login aus Modul 02. Alle Befehle in diesem Modul gibst du im Server-Terminal ein.

🖥️ Server

Alle Befehle in diesem Modul laufen auf dem Server – du bist bereits per SSH eingeloggt.

Das Berechtigungssystem verstehen

Stell dir jede Datei wie einen Werkzeugschrank vor: Es gibt einen Besitzer (der Schlosser, dem er gehört), eine Gruppe (das Team mit einem Schlüssel) und alle anderen (die ohne Schlüssel). Für jede dieser drei Gruppen legst du fest, was erlaubt ist.

Linux kennt drei Grundrechte:

RechtBuchstabeOktalwertBedeutung für DateienBedeutung für Verzeichnisse
Lesenr4Inhalt lesenInhalt auflisten (ls)
Schreibenw2Inhalt ändernDateien erstellen / löschen
Ausführenx1Als Programm startenIn Verzeichnis wechseln (cd)

ls -la lesen – was bedeuten die Zeichen?

🖥️ Auf dem Server – du bist bereits per SSH eingeloggt

Mit ls -la siehst du alle Dateien inklusive ihrer Berechtigungen:

Berechtigungen anzeigen
ls -la
# Beispiel-Ausgabe:
drwxr-xr-x  2 max  entwickler  4096 Jan 15 10:30 projekt/
-rw-r--r--  1 max  entwickler  2048 Jan 15 10:28 readme.txt
-rwxr-x---  1 root root        8192 Jan 14 09:00 backup.sh

So liest du die erste Zeile drwxr-xr-x:

PositionZeichenBedeutung
1dTyp: d = Verzeichnis, - = Datei, l = Symlink
2–4rwxBesitzer darf: lesen + schreiben + ausführen
5–7r-xGruppe darf: lesen + ausführen (kein Schreiben)
8–10r-xAndere dürfen: lesen + ausführen (kein Schreiben)
🧠 Eselsbrücke: Dreiergruppen lesen

Teile die 9 Buchstaben nach dem Typ-Zeichen immer in Dreiergruppen: rwx | r-x | r-x = Besitzer | Gruppe | Andere. Ein - an einer Stelle bedeutet: dieses Recht fehlt.

chmod – Berechtigungen ändern

chmod (change mode) ändert die Berechtigungen einer Datei oder eines Verzeichnisses. Es gibt zwei Schreibweisen: symbolisch (mit Buchstaben) und oktal (mit Zahlen).

Symbolische Schreibweise

🖥️ Auf dem Server

Buchstaben-Syntax: u = Besitzer (user), g = Gruppe, o = Andere (others), a = Alle. Operator: + hinzufügen, - entfernen, = genau setzen.

chmod symbolisch
# Besitzer darf ausführen:
chmod u+x script.sh

# Gruppe darf schreiben:
chmod g+w datei.txt

# Anderen alle Rechte entziehen:
chmod o-rwx geheim.txt

# Allen Lese-Recht geben:
chmod a+r public.html

# Besitzer: rwx, Gruppe: rx, Andere: nichts:
chmod u=rwx,g=rx,o= backup.sh

Oktale Schreibweise – die Zahlen-Methode

Die Oktalschreibweise fasst die Rechte jeder Gruppe in eine Zahl zusammen. Das Prinzip ist wie beim Schlosserzählwerk: Jedes Recht hat einen festen Wert – du addierst, was du brauchst.

RechtWertMerkhilfe
r – Lesen44 = der größte Einzelwert
w – Schreiben22 = halb so viel
x – Ausführen11 = der kleinste

Drei Stellen, drei Gruppen: 755 = Besitzer | Gruppe | Andere. Jede Stelle ist die Summe der erlaubten Rechte:

OktalzahlRechte (rwx)Formel
7rwx4+2+1 = lesen + schreiben + ausführen
6rw-4+2 = lesen + schreiben
5r-x4+1 = lesen + ausführen
4r--4 = nur lesen
0---0 = kein Zugriff
🖥️ Auf dem Server

Die häufigsten Oktalwerte in der Praxis:

chmod mit Oktalzahlen
# 755 = rwxr-xr-x (Standard für Verzeichnisse und Skripte)
chmod 755 script.sh

# 644 = rw-r--r-- (Standard für normale Dateien)
chmod 644 config.txt

# 600 = rw------- (nur Besitzer darf lesen/schreiben – z.B. SSH-Schlüssel)
chmod 600 ~/.ssh/id_ed25519

# 700 = rwx------ (nur Besitzer, voller Zugriff)
chmod 700 ~/privat/

# Rekursiv für ein ganzes Verzeichnis und alle Inhalte:
chmod -R 755 /var/www/html/
💡 Die wichtigsten Oktalwerte im Überblick

755 – Standard für Verzeichnisse und Programme: jeder kann lesen und ausführen, nur Besitzer schreibt.
644 – Standard für normale Dateien: jeder kann lesen, nur Besitzer schreibt.
600 – Geheime Dateien: nur Besitzer liest und schreibt (SSH-Schlüssel, Passwort-Dateien).
640 – Konfigurationsdateien: Besitzer liest/schreibt, Gruppe liest, Andere: nichts.

🚨 chmod 777 ist fast immer falsch

chmod 777 gibt jedem Benutzer auf dem System volle Lese-, Schreib- und Ausführungsrechte – auch fremden Prozessen und Angreifern. Das ist ein häufiger Anfängerfehler. Wenn du „Permission denied" bekommst, ist chmod 777 keine Lösung. Finde stattdessen heraus, welcher Benutzer und welche Gruppe die richtige Berechtigung braucht – und setze nur die.

chown und chgrp – Besitzer und Gruppe ändern

chown (change owner) ändert, wem eine Datei gehört. Das brauchst du z.B. wenn du Webserver-Dateien für den Benutzer www-data freigeben willst.

🖥️ Auf dem Server
Besitzer und Gruppe ändern
# Besitzer ändern (braucht sudo):
sudo chown max datei.txt

# Besitzer und Gruppe in einem Schritt ändern:
sudo chown max:entwickler datei.txt

# Nur die Gruppe ändern:
sudo chgrp entwickler datei.txt

# Rekursiv für ein ganzes Verzeichnis:
sudo chown -R www-data:www-data /var/www/html/

# Aktuellen Besitzer prüfen:
ls -la datei.txt
# -rw-r--r-- 1 max entwickler 2048 Jan 15 datei.txt
#                ^ Besitzer   ^ Gruppe
umask – Standard-Berechtigungen festlegen

Die umask ist wie ein Filter: Sie bestimmt, welche Rechte bei neu erstellten Dateien und Verzeichnissen automatisch weggelassen werden. Der Standard-Wert ist 022.

umaskNeue DateienNeue VerzeichnisseWirkung
022644 (rw-r--r--)755 (rwxr-xr-x)Standard – Gruppe und Andere dürfen lesen
027640 (rw-r-----)750 (rwxr-x---)Restriktiver – Andere haben keinen Zugriff
077600 (rw-------)700 (rwx------)Streng – nur Besitzer hat Zugriff
🖥️ Auf dem Server
umask abfragen und setzen
# Aktuelle umask anzeigen:
umask
# Ausgabe: 0022

# umask für die aktuelle Sitzung ändern:
umask 027

# Dauerhaft ändern – in ~/.bashrc eintragen:
echo "umask 027" >> ~/.bashrc
Spezielle Bits: SUID, SGID und Sticky Bit

Neben den normalen rwx-Rechten gibt es drei Spezialrechte. Du wirst ihnen im Alltag begegnen – hier ist, was sie bedeuten:

BitOktalWirkung auf DateienWirkung auf Verzeichnisse
SUID4000Programm läuft mit Rechten des Besitzers (z.B. als root)
SGID2000Programm läuft mit Rechten der GruppeNeue Dateien erben die Gruppe des Verzeichnisses
Sticky Bit1000Nur der Besitzer darf seine eigenen Dateien löschen
🖥️ Auf dem Server

Beispiele: SUID beim Programm passwd, SGID für Teamverzeichnisse, Sticky Bit beim Ordner /tmp:

Spezielle Bits erkennen und setzen
# SUID-Beispiel: passwd läuft als root, auch wenn ein normaler User es startet:
ls -la /usr/bin/passwd
# -rwsr-xr-x 1 root root ... /usr/bin/passwd
#    ^ das 's' statt 'x' zeigt SUID an

# SGID auf Verzeichnis setzen (neue Dateien erben die Gruppe):
sudo chmod g+s /shared/projekt/
# oder mit Oktal: sudo chmod 2775 /shared/projekt/

# Sticky Bit anschauen – /tmp hat es standardmäßig:
ls -ld /tmp
# drwxrwxrwt  ← das 't' am Ende zeigt das Sticky Bit

# Sticky Bit manuell setzen:
sudo chmod +t /shared/uploads/
🧠 SGID für Teamverzeichnisse

SGID auf einem Teamverzeichnis ist sehr praktisch: Wenn das Verzeichnis der Gruppe entwickler gehört und SGID gesetzt ist, erben alle neuen Dateien automatisch diese Gruppe – egal wer sie erstellt. So können alle Teammitglieder zusammenarbeiten, ohne ständig chgrp aufzurufen.

Praktische Empfehlungen

Hier sind die richtigen Berechtigungen für die häufigsten Szenarien – als schnelle Referenz:

SzenarioEmpfohlene BerechtigungenWarum
Webserver-Dateien (/var/www/html/)sudo chown -R www-data:www-data + 755 / 644Webserver-Prozess braucht Lesezugriff
SSH-Schlüssel (~/.ssh/id_ed25519)chmod 600SSH verweigert Verbindung, wenn der Schlüssel zu offen ist
Gemeinsamer Projektordnerchmod 2775 (SGID)Neue Dateien erben automatisch die Gruppe
Bash-Skriptchmod 755 oder chmod u+xAusführbar für Besitzer, lesbar für alle
Konfigurationsdatei mit Passwortchmod 600 oder 640Passwörter gehören nicht in die Hände Anderer
Upload-Verzeichnischmod 1777 (Sticky Bit)Jeder darf schreiben, aber nur eigene Dateien löschen
🤖
KI-Tipp: Berechtigungsprobleme lösen

„Permission denied" ist eine der häufigsten Fehlermeldungen unter Linux. Wenn du nicht weiterkommst, zeige der KI die Ausgabe von ls -la und id und frag: „Ich bekomme 'Permission denied' wenn ich /var/www/html/index.html bearbeiten will. Hier sind die Berechtigungen und mein aktueller Benutzer – was muss ich ändern und warum?"

Praxisaufgaben
AUFGABE 11.1 Berechtigungen lesen und setzen

Du übst das Lesen und Ändern von Dateiberechtigungen – das Handwerkszeug für die sichere Serververwaltung.

🖥️ Alle Schritte auf dem Server – du bist per SSH eingeloggt
1
Erstelle eine Testdatei und zeige ihre Berechtigungen: touch ~/testdatei.txt && ls -la ~/testdatei.txt. Welche Berechtigungen hat die Datei direkt nach dem Anlegen?
2
Setze die Berechtigungen auf 640: chmod 640 ~/testdatei.txt. Zeige sie erneut mit ls -la ~/testdatei.txt. Was hat sich geändert?
3
Mache die Datei für den Besitzer ausführbar: chmod u+x ~/testdatei.txt. Wie lautet die Berechtigungskette jetzt?
4
Entziehe allen Anderen sämtliche Rechte: chmod o= ~/testdatei.txt. Zeige die Berechtigungen erneut.
5
Setze zurück auf den Standard 644 und räume auf: chmod 644 ~/testdatei.txt && rm ~/testdatei.txt
Lösungshinweise anzeigen

Nach touch hat die Datei typischerweise -rw-r--r-- (644) – der Standard, den die umask 022 ergibt. Nach chmod 640 wird sie zu -rw-r-----: Andere haben jetzt keinen Zugriff mehr.

Nach chmod u+x steht -rwxr----- (740). Das x beim Besitzer ist hinzugekommen. Beim Entziehen mit o= bleibt das Ergebnis gleich, weil Andere ohnehin schon nichts durften.

AUFGABE 11.2 Gemeinsames Projektverzeichnis einrichten

Du richtest ein Verzeichnis für Teamarbeit ein – mit korrekten Gruppen-Berechtigungen und SGID, damit alle Teammitglieder reibungslos zusammenarbeiten können.

🖥️ Alle Schritte auf dem Server
1
Erstelle das Projektverzeichnis: sudo mkdir -p /shared/projekt
2
Setze die Gruppe auf projekt (aus Modul 08): sudo chgrp projekt /shared/projekt
3
Setze Berechtigungen mit SGID-Bit: sudo chmod 2775 /shared/projekt
4
Erstelle als Gruppen-Mitglied eine Testdatei: touch /shared/projekt/test.txt. Prüfe mit ls -la /shared/projekt/ – welche Gruppe hat die neue Datei?
5
Prüfe das Verzeichnis selbst: ls -ld /shared/projekt. Siehst du das s in den Gruppen-Rechten (drwxrwsr-x)?
Lösungshinweise anzeigen

Dank SGID (das s bei den Gruppenrechten) erbt die neue Datei automatisch die Gruppe projekt – egal welcher Benutzer sie erstellt hat. Ohne SGID würde die primäre Gruppe des Erstellers gesetzt, was zu Problemen im Team führt.

2775 setzt sich zusammen aus: SGID (2) + Besitzer rwx (7) + Gruppe rwx (7) + Andere rx (5).

AUFGABE 11.3 SSH-Schlüssel absichern

SSH verweigert die Verbindung, wenn der private Schlüssel falsche Berechtigungen hat. Du übst, die richtigen Berechtigungen für sicherheitskritische Dateien zu prüfen und zu setzen.

🖥️ Alle Schritte auf dem Server
1
Zeige die Berechtigungen des SSH-Verzeichnisses und seiner Dateien: ls -la ~/.ssh/. Was siehst du?
2
Das Verzeichnis ~/.ssh/ sollte 700 haben: chmod 700 ~/.ssh. Prüfe das Ergebnis.
3
Die Datei authorized_keys sollte 600 haben: chmod 600 ~/.ssh/authorized_keys. Prüfe das Ergebnis.
4
Verstehe warum: Lies die Berechtigungsketten mit ls -la ~/.ssh/ nochmals und erkläre in eigenen Worten, was 700 und 600 hier konkret bedeuten.
Lösungshinweise anzeigen

chmod 700 ~/.ssh bedeutet: Nur du (der Besitzer) darfst das Verzeichnis lesen, beschreiben und betreten. Gruppe und Andere sehen gar nichts.

chmod 600 ~/.ssh/authorized_keys bedeutet: Nur du darfst die Datei lesen und schreiben. Wenn diese Datei für andere lesbar wäre, könnte SSH theoretisch fremde Schlüssel enthalten, ohne dass es auffällt – deshalb erzwingt SSH die strengen Berechtigungen.

🤖
KI-Tipp: Oktalwerte verstehen und berechnen

Wenn du unsicher bist, was ein bestimmter Oktalwert bedeutet oder welchen du für einen Anwendungsfall brauchst, frag direkt: „Was bedeutet chmod 2750 genau? Wer darf was? Und welchen chmod-Wert brauche ich, wenn der Besitzer alles darf, die Gruppe nur lesen und ausführen, und alle anderen gar nichts?"

Modul 123 Unterrichtseinheiten

SFTP, SSHFS & SAMBA

Netzlaufwerke verbinden Server und Clients -- ob Linux, Windows oder Mac. Du lernst drei Wege, Dateien übers Netz zu teilen: SFTP für sichere Übertragungen, SSHFS zum Einbinden als lokales Laufwerk und SAMBA für die Windows-Welt.

Voraussetzung: Modul 02 (SSH) Voraussetzung: Modul 10 (mount & fstab) Voraussetzung: Modul 11 (Berechtigungen) SFTP · SSHFS · SAMBA · smb.conf
Bevor wir starten: Zwei Kontexte

In diesem Modul arbeitest du gleichzeitig auf zwei Rechnern. SFTP und SSHFS bedienst du von deinem Rechner aus. SAMBA installierst und konfigurierst du auf dem Server. Ab jetzt markieren wir immer klar, wo du gerade bist:

💻 Dein Rechner

Befehle, die du in deinem eigenen Terminal eingibst -- SFTP-Client, SSHFS-Mount, Windows-Zugriff.

🖥️ Server

Befehle, die auf dem entfernten Server laufen -- SAMBA installieren, smb.conf konfigurieren, Nutzer anlegen.

Die drei Wege zum Netzlaufwerk

Es gibt nicht den einen Weg, Dateien über das Netzwerk zu teilen. Welcher am besten passt, hängt davon ab, wer auf die Daten zugreifen soll und wie:

ProtokollBeste fürSicherheitAufwand
SFTPDateiübertragung, Skripte, einzelne DateienSehr hoch (SSH)Sofort -- kein extra Setup
SSHFSLinux-Clients, dauerhaftes EinbindenSehr hoch (SSH)Gering -- nur Client-Paket
SAMBAWindows-Clients, Heimnetz, Mixed-OSMittel (SMB)Mittel -- Server konfigurieren
💡 Analogie: Drei Arten, Post zu liefern

SFTP ist wie ein sicherer Kurier -- du schickst Pakete einzeln, gezielt, direkt. SSHFS ist wie ein Briefkasten direkt in deiner Wohnung -- der Server-Ordner sieht aus wie ein lokaler Ordner auf deinem Rechner. SAMBA ist wie die Post im Büronetz -- alle im Netz greifen auf den gemeinsamen Ordner zu, sogar Windows-Nutzer ohne Extra-Software.

SFTP -- Sicherer Dateitransfer

SFTP (SSH File Transfer Protocol) ist kein eigener Dienst, sondern ein Subsystem von SSH. Auf jedem Server, auf dem SSH läuft, ist SFTP bereits aktiv -- du brauchst nichts extra zu installieren.

💻 Auf deinem Rechner

Eine SFTP-Sitzung öffnest du wie eine SSH-Verbindung -- nur mit sftp statt ssh. Danach landest du in einem interaktiven Prompt, wo du Dateien übertragen kannst.

SFTP-Sitzung starten
sftp benutzer@192.168.1.10
# Authentifizierung wie bei SSH (Schlüssel oder Passwort)
# Du landest im SFTP-Prompt: sftp>

SFTP-Befehle im Überblick

Im SFTP-Prompt stehen dir diese Befehle zur Verfügung:

BefehlBedeutungBeispiel
lsDateien auf dem Server auflistenls /home/admin
llsDateien auf deinem Rechner auflistenlls ~/Downloads
cd ordnerVerzeichnis auf dem Server wechselncd /var/www
lcd ordnerVerzeichnis auf deinem Rechner wechselnlcd ~/Downloads
get dateiDatei vom Server herunterladenget nginx.conf
put dateiDatei auf den Server hochladenput config.txt /tmp/
mkdir nameVerzeichnis auf dem Server erstellenmkdir backup
exitSFTP-Sitzung beendenexit
💻 Auf deinem Rechner -- im SFTP-Prompt

Praktisches Beispiel: Du lädst eine Konfigurationsdatei auf den Server und holst anschließend ein Log zurück:

Typische SFTP-Arbeitssitzung
# Aktuellen Ordner auf dem Server anzeigen:
sftp> pwd
# Datei hochladen:
sftp> put meine-config.conf /etc/nginx/conf.d/
# Ganzen Ordner herunterladen (-r = rekursiv):
sftp> get -r /var/log/nginx ./logs/
# Fertig -- Verbindung schliessen:
sftp> exit
🧠 SFTP vs. SCP -- wann was?

Nutze sftp, wenn du interaktiv mehrere Dateien verwalten oder den Server-Ordner erst erkunden willst. Nutze scp (aus Modul 02) für schnelle Einzelübertragungen in Skripten. Für große Synchronisierungen zwischen Verzeichnissen ist rsync (Modul 23) die bessere Wahl.

SSHFS -- Server-Ordner als lokales Laufwerk

SSHFS (SSH Filesystem) lässt dich einen Ordner vom Server so einbinden, als wäre er ein lokales Verzeichnis auf deinem Rechner. Du siehst die Dateien im Dateimanager, bearbeitest sie wie gewohnt -- alle Änderungen landen über SSH auf dem Server. Der Server braucht kein extra Paket -- nur SSH muss laufen.

💻 Auf deinem Rechner -- SSHFS installieren und mounten

SSHFS wird auf dem Client (deinem Rechner) installiert, nicht auf dem Server.

SSHFS installieren
sudo apt install sshfs

Dann einen Einhängepunkt erstellen und den Server-Ordner einbinden:

Server-Ordner einbinden
# Einhängepunkt erstellen:
mkdir -p ~/mnt/server

# Server-Verzeichnis einbinden:
sshfs benutzer@192.168.1.10:/home/benutzer ~/mnt/server

# Mit Optionen (empfohlen -- stabilere Verbindung):
sshfs -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 benutzer@192.168.1.10:/home/benutzer ~/mnt/server

# Prüfen ob eingebunden:
df -h

# Laufwerk wieder aushängen:
fusermount -u ~/mnt/server

SSHFS dauerhaft via /etc/fstab

Damit der Server-Ordner nach jedem Neustart automatisch eingehängt wird, trägst du ihn in /etc/fstab ein -- genauso wie in Modul 10 für lokale Laufwerke.

💻 Auf deinem Rechner -- /etc/fstab bearbeiten
/etc/fstab -- SSHFS-Eintrag
# Format: user@server:/pfad  /lokaler/mountpunkt  fuse.sshfs  optionen  0 0
benutzer@192.168.1.10:/home/benutzer /home/lokal/mnt/server fuse.sshfs defaults,_netdev,reconnect,uid=1000,gid=1000,IdentityFile=/home/lokal/.ssh/id_ed25519 0 0
💡 _netdev ist wichtig

Die Option _netdev sagt dem System: "Dieses Laufwerk braucht eine Netzwerkverbindung." Ohne sie kann der Boot-Vorgang hängen bleiben, wenn das Netzwerk noch nicht bereit ist -- der Rechner wartet dann ewig auf ein Laufwerk, das noch nicht erreichbar ist.

SAMBA installieren und konfigurieren

SAMBA ist wie ein Netzlaufwerk aus Windows -- du siehst den Server-Ordner direkt im Explorer, kannst Dateien rein- und rausschieben, als wäre es ein lokales Laufwerk. SAMBA implementiert das SMB-Protokoll, das Windows-Rechner von Haus aus verstehen. Installiert und konfiguriert wird es auf dem Server.

🖥️ Auf dem Server -- per SSH eingeloggt

Zuerst SAMBA installieren und die Dienste starten:

SAMBA installieren
sudo apt update
sudo apt install samba

# Status prüfen (smbd = Dateidienst, nmbd = Namensauflösung):
sudo systemctl status smbd nmbd

# Dienste beim Start automatisch aktivieren:
sudo systemctl enable smbd nmbd

# Firewall-Freigabe, falls ufw aktiv (aus Modul 14):
sudo ufw allow Samba

smb.conf -- die Konfigurationsdatei

Die zentrale Konfiguration liegt in /etc/samba/smb.conf. Die Datei ist in Sektionen aufgeteilt: [global] für allgemeine Einstellungen, dann benannte Abschnitte für jede Freigabe.

🖥️ Auf dem Server -- smb.conf bearbeiten
/etc/samba/smb.conf -- Grundkonfiguration mit Freigaben
[global]
   workgroup = WORKGROUP
   server string = Mein Linux Server
   security = user
   map to guest = bad user

# Passwortgeschützte Freigabe (empfohlen):
[daten]
   comment = Gemeinsame Daten
   path = /srv/samba/daten
   browseable = yes
   read only = no
   valid users = admin
   create mask = 0660
   directory mask = 0770

# Öffentliche Freigabe -- nur lesen, kein Passwort:
[public]
   comment = Oeffentliche Dateien
   path = /srv/samba/public
   browseable = yes
   read only = yes
   guest ok = yes

Verzeichnisse anlegen und Berechtigungen setzen (aus Modul 11):

Verzeichnisse und Berechtigungen
# Verzeichnisse erstellen:
sudo mkdir -p /srv/samba/daten /srv/samba/public

# Besitzer setzen:
sudo chown admin:admin /srv/samba/daten
sudo chmod 750 /srv/samba/daten

# Öffentliches Verzeichnis (alle dürfen lesen):
sudo chown nobody:nogroup /srv/samba/public
sudo chmod 755 /srv/samba/public

# Konfiguration prüfen (zeigt Fehler und aktive Einstellungen):
testparm

# SAMBA neu starten:
sudo systemctl restart smbd
⚠️ Offene Freigaben ohne Passwort

Die Option guest ok = yes erlaubt Zugriff ohne Anmeldung. Das ist nur für wirklich unkritische Dateien im vertrauenswürdigen Heimnetz vertretbar. Im Büronetz oder bei sensiblen Daten immer valid users mit Passwort nutzen -- sonst kann jeder im Netz auf deine Dateien zugreifen.

SAMBA-Nutzer einrichten

SAMBA hat ein eigenes Passwort-System, das vom Linux-Login unabhängig ist. Ein Benutzer muss zunächst als Linux-Benutzer existieren -- dann erhält er ein separates SAMBA-Passwort.

🖥️ Auf dem Server -- SAMBA-Passwort setzen
SAMBA-Benutzer einrichten
# SAMBA-Passwort für bestehenden Linux-Benutzer setzen:
sudo smbpasswd -a admin
# Du wirst nach dem neuen SAMBA-Passwort gefragt (2x eingeben)

# Benutzer aktivieren (nach smbpasswd -a normalerweise automatisch):
sudo smbpasswd -e admin

# Aktive SAMBA-Benutzer anzeigen:
sudo pdbedit -L

# Verbindungen prüfen (wer ist gerade verbunden?):
sudo smbstatus
⚠️ Zwei Passwörter -- Linux und SAMBA sind getrennt

Das SAMBA-Passwort und das Linux-Login-Passwort sind unabhängig. Wenn du das Linux-Passwort änderst, ändert sich das SAMBA-Passwort nicht automatisch. Du musst beide separat verwalten. Das ist eine häufige Fehlerquelle.

SAMBA von Windows und Linux verbinden

Zugriff von Windows

Unter Windows erreichst du eine SAMBA-Freigabe direkt im Explorer -- kein zusätzliches Programm nötig:

💻 Auf deinem Windows-Rechner

Öffne den Explorer und gib in die Adresszeile ein:

Windows-Explorer -- Netzwerkpfad
\\192.168.1.10\daten
# Oder mit dem Servernamen (falls DNS funktioniert):
\\mein-server\daten

Windows fragt nach Benutzername und Passwort -- gib deine SAMBA-Zugangsdaten ein. Danach kannst du die Freigabe als Netzlaufwerk verbinden (Rechtsklick -- "Netzlaufwerk verbinden").

Zugriff von Linux

💻 Auf deinem Linux-Rechner -- SAMBA-Freigabe einbinden

Auf einem Linux-Client brauchst du das Paket cifs-utils:

cifs-utils installieren und Freigabe mounten
# Einmalig installieren:
sudo apt install cifs-utils

# Einhängepunkt erstellen:
sudo mkdir -p /mnt/samba-daten

# Freigabe temporär einbinden:
sudo mount -t cifs //192.168.1.10/daten /mnt/samba-daten -o username=admin

Für dauerhafte Einbindung via /etc/fstab legst du eine Credentials-Datei an:

Credentials-Datei und fstab-Eintrag
# Datei /etc/samba/.credentials erstellen:
sudo nano /etc/samba/.credentials
# Inhalt der Datei:
# username=admin
# password=dein-samba-passwort

# Datei nur für root lesbar machen:
sudo chmod 600 /etc/samba/.credentials
sudo chown root:root /etc/samba/.credentials

# Eintrag in /etc/fstab:
# //192.168.1.10/daten /mnt/samba-daten cifs _netdev,credentials=/etc/samba/.credentials,uid=1000 0 0
🚨 Passwörter niemals direkt in /etc/fstab

Trage Passwörter niemals im Klartext in /etc/fstab ein -- die Datei ist für alle Benutzer lesbar (ls -l /etc/fstab zeigt -rw-r--r--). Nutze immer eine separate Credentials-Datei mit Berechtigungen 600 (nur root darf lesen).

smb.conf -- Optionen auf einen Blick
OptionBedeutungTypischer Wert
pathVerzeichnis auf dem Server/srv/samba/name
browseableIn Netzwerkumgebung sichtbaryes / no
read onlyNur lesbar (kein Schreiben)yes / no
guest okZugriff ohne Passwort erlaubtyes / no
valid usersErlaubte Benutzer oder Gruppenadmin anna @gruppe
create maskBerechtigungen für neue Dateien0660
directory maskBerechtigungen für neue Ordner0770
force userAlle Zugriffe laufen als dieser Benutzerwww-data
🤖
KI-Tipp: smb.conf für eigene Anforderungen

Die smb.conf hat Hunderte von Optionen. Wenn du eine spezifische Anforderung hast -- z.B. Drucker teilen, Time Machine für Mac, oder Berechtigungen für mehrere Gruppen -- frag eine KI: „Schreibe mir einen smb.conf-Abschnitt für eine Freigabe, auf die nur die Gruppe 'buchhaltung' mit Schreibrecht zugreifen darf, alle anderen Benutzer aber nur lesen können. Server ist Ubuntu 24.04."

🤖
KI-Tipp: SAMBA-Fehler diagnostizieren

SAMBA-Verbindungsprobleme können viele Ursachen haben: Firewall, Berechtigungen, falsches Passwort, falsche Workgroup. Führe sudo smbstatus und sudo journalctl -u smbd -n 50 aus und frag: „Windows findet meine SAMBA-Freigabe nicht. Hier ist die Ausgabe von smbstatus und die letzten SAMBA-Logeinträge -- was könnte falsch sein?"

Praxisaufgaben
AUFGABE 12.1 Dateien mit SFTP übertragen

Du überträgst Dateien sicher auf einen Server und zurück -- der schnellste Weg ohne extra Software. Alle Schritte laufen auf deinem Rechner im SFTP-Prompt.

💻 Alle Schritte auf deinem Rechner
1
Erstelle eine lokale Testdatei: echo "Hallo vom Laptop" > testdatei.txt
2
Verbinde dich per SFTP mit deinem Server: sftp benutzer@server-ip. Du solltest den sftp>-Prompt sehen.
3
Lade die Datei hoch: put testdatei.txt. Prüfe mit ls, ob sie auf dem Server angekommen ist.
4
Erstelle ein lokales Zielverzeichnis und lade die Datei zurück: erst lmkdir download, dann get testdatei.txt download/.
5
Beende die SFTP-Sitzung mit exit. Prüfe lokal mit ls download/, ob die Datei angekommen ist.
Lösungshinweise anzeigen

Im SFTP-Prompt zeigt ls den Server-Inhalt, lls den lokalen. Nach put testdatei.txt sollte sie bei ls auf dem Server erscheinen. Der get-Befehl lädt sie in das lokale download/-Verzeichnis.

Fehlermeldung "Couldn't get handle"? Dann fehlt das lokale Zielverzeichnis -- erst lmkdir download ausführen, dann get wiederholen.

AUFGABE 12.2 SAMBA-Freigabe einrichten und verbinden

Du richtest auf dem Server eine passwortgeschützte SAMBA-Freigabe ein und verbindest dich anschließend vom Client aus. Das Einrichten passiert auf dem Server, das Verbinden auf deinem Rechner.

🖥️ Schritte 1--4: Du bist per SSH auf dem Server eingeloggt
1
Installiere SAMBA: sudo apt install samba. Prüfe danach den Status: sudo systemctl status smbd. Der Dienst sollte "active (running)" anzeigen.
2
Erstelle das Freigabe-Verzeichnis und setze den Besitzer: sudo mkdir -p /srv/samba/share, dann sudo chown admin:admin /srv/samba/share (ersetze admin durch deinen Benutzernamen auf dem Server).
3
Öffne /etc/samba/smb.conf mit sudo nano /etc/samba/smb.conf und füge am Ende diesen Block ein (Benutzernamen anpassen):
[share]
   path = /srv/samba/share
   valid users = admin
   read only = no
4
Setze das SAMBA-Passwort: sudo smbpasswd -a admin. Prüfe die Konfiguration mit testparm. Starte SAMBA neu: sudo systemctl restart smbd.
💻 Schritt 5: Zurück auf deinem Rechner -- tippe exit um den Server zu verlassen
5
Teste die Verbindung: smbclient //server-ip/share -U admin. Gib dein SAMBA-Passwort ein. Bei Erfolg erscheint der smb: \>-Prompt -- tippe ls und dann exit.
Lösungshinweise anzeigen

testparm gibt "Loaded services file OK" aus, wenn smb.conf syntaktisch korrekt ist. Beim smbclient-Test erscheint nach dem Passwort ein smb: \>-Prompt, wo du mit ls den Freigabe-Inhalt siehst.

Von Windows erreichst du die Freigabe mit \\server-ip\share im Explorer-Adressfeld. Windows fragt nach Benutzername und Passwort -- trage deine SAMBA-Zugangsdaten ein.

AUFGABE 12.3 SSHFS-Netzlaufwerk einbinden

Du bindest ein Server-Verzeichnis so ein, dass es sich wie ein lokaler Ordner anfühlt -- ideal für regelmäßige Arbeit mit Server-Dateien. Alle Schritte laufen auf deinem Rechner.

💻 Alle Schritte auf deinem Rechner
1
Installiere SSHFS auf deinem Rechner (nicht auf dem Server): sudo apt install sshfs
2
Erstelle einen lokalen Einhängepunkt: mkdir -p ~/mnt/server
3
Hänge das Home-Verzeichnis des Servers ein: sshfs benutzer@server-ip:/home/benutzer ~/mnt/server
4
Prüfe mit df -h, ob das Laufwerk eingebunden ist. Schau dann mit ls ~/mnt/server in den Server-Ordner -- du siehst die Dateien des Servers.
5
Erstelle eine Testdatei direkt im eingebundenen Ordner: echo "Hallo Server" > ~/mnt/server/test.txt. Verbinde dich per SSH und prüfe: ls ~ -- die Datei liegt auf dem Server.
6
Trenne das Laufwerk wieder: fusermount -u ~/mnt/server
Lösungshinweise anzeigen

df -h zeigt eine Zeile wie benutzer@192.168.1.10:/home/benutzer ... ~/mnt/server -- das bestätigt, dass der Mount aktiv ist. Dateien, die du dort erstellst, liegen physisch auf dem Server.

Wenn fusermount -u mit "device is busy" scheitert: Stelle sicher, dass du das Verzeichnis nicht mehr im Terminal geöffnet hast. Notfalls hilft sudo umount ~/mnt/server.

Modul 134 Unterrichtseinheiten

Webserver & Reverse Proxy

Ein Webserver liefert Dateien an Browser aus – und ein Reverse Proxy leitet Anfragen an interne Dienste weiter. In diesem Modul lernst du Nginx und Caddy kennen, richtest HTTPS ein und betreibst mehrere Dienste auf einem einzigen Server.

Voraussetzung: Modul 05 Voraussetzung: Modul 06 Nginx · Caddy · Virtual Hosts · Reverse Proxy · HTTPS
Bevor wir starten: Alles läuft auf dem Server

In diesem Modul richtest du einen Webserver ein. Alle Befehle und Konfigurationen laufen auf dem Server – du bist per SSH eingeloggt (Modul 02). Auf deinem eigenen Rechner öffnest du nur den Browser, um das Ergebnis zu testen.

🖥️ Server

Alle Befehle in diesem Modul laufen auf dem Server – nach dem SSH-Login.

Was ist ein Webserver? – HTTP erklärt

Wenn du eine Adresse im Browser eingibst, passiert folgendes:

  1. Der Browser fragt DNS: „Welche IP hat example.com?" – und bekommt eine IP-Adresse zurück.
  2. Der Browser verbindet sich mit dieser IP auf Port 80 (HTTP) oder 443 (HTTPS).
  3. Der Webserver empfängt die Anfrage, sucht die passende Datei und schickt sie zurück.
  4. Der Browser stellt die Seite dar.

Ein Reverse Proxy ist wie ein Empfang im Betrieb: Alle Anrufe kommen dort an und werden an die richtige Stelle weitergeleitet. Statt Port 3000 oder 8080 direkt zu öffnen, nimmt der Reverse Proxy alle Anfragen auf Port 80/443 entgegen und reicht sie intern weiter.

BegriffBedeutungAnalogie
WebserverLiefert Dateien auf Anfrage ausLagerist, der Pakete herausgibt
Virtual HostMehrere Domains auf einer IPMehrere Firmen im gleichen Gebäude
Reverse ProxyLeitet Anfragen an interne Dienste weiterEmpfang, der Anrufe verteilt
SSL/TLSVerschlüsselte HTTPS-VerbindungVersiegelter Brief statt Postkarte
Let's EncryptKostenlose SSL-ZertifikateKostenloser Notar
⚠️ HTTP ist unverschlüsselt – nutze immer HTTPS

Bei HTTP sieht jeder im Netzwerk mit, was übertragen wird – Passwörter, Formulardaten, alles im Klartext. HTTPS verschlüsselt die Verbindung. Für echte Domains empfiehlt sich Let's Encrypt mit Certbot (bei Nginx) oder die automatische Zertifikatsverwaltung von Caddy. Im lokalen Testnetz ohne echte Domain kannst du zunächst mit HTTP arbeiten.

HTTP-Statuscodes – was antwortet der Server?

Jede Serverantwort enthält einen dreistelligen Statuscode. Du begegnest ihnen in Logs und beim Debuggen ständig.

CodeBedeutungTypische Ursache
200 OKAlles gut, Datei geliefertNormaler Seitenaufruf
301 Moved PermanentlySeite dauerhaft verschobenHTTP → HTTPS-Weiterleitung
302 FoundSeite vorübergehend woandersLogin-Weiterleitung
403 ForbiddenZugriff verweigertFalsche Datei-Berechtigungen
404 Not FoundDatei nicht gefundenFalscher Pfad, Datei fehlt
500 Internal Server ErrorFehler im Server/AnwendungDefekte Konfiguration, PHP-Fehler
502 Bad GatewayUpstream-Dienst antwortet nichtReverse Proxy, aber Dienst läuft nicht
503 Service UnavailableServer überlastet oder in WartungDienst gestartet, noch nicht bereit
Nginx – der bewährte Klassiker

Nginx (sprich: „Engine-X") ist einer der meistgenutzten Webserver weltweit. Er ist schnell, stabil und kann alles: statische Dateien ausliefern, als Reverse Proxy dienen, mehrere Domains auf einem Server betreiben. Die Konfiguration ist etwas technischer als bei Caddy, aber sehr mächtig.

🖥️ Auf dem Server – per SSH eingeloggt

Nginx lässt sich direkt aus den Ubuntu-Paketquellen installieren:

Nginx installieren
sudo apt update
sudo apt install -y nginx

# Status prüfen:
sudo systemctl status nginx

# Nginx startet automatisch mit dem System:
sudo systemctl enable nginx

Nach der Installation läuft Nginx sofort. Öffne http://server-ip im Browser – du siehst die Nginx-Willkommensseite.

Statische Website mit Nginx ausliefern

Nginx legt Websites standardmäßig unter /var/www/ ab. Jede Domain bekommt dort ein eigenes Verzeichnis.

🖥️ Auf dem Server
Webverzeichnis anlegen und Testseite erstellen
# Verzeichnis anlegen:
sudo mkdir -p /var/www/meinsite

# Einfache HTML-Seite erstellen:
echo '<h1>Hallo vom Webserver</h1>' | sudo tee /var/www/meinsite/index.html

# Berechtigungen setzen – nginx-Prozess läuft als www-data:
sudo chown -R www-data:www-data /var/www/meinsite
sudo chmod -R 755 /var/www/meinsite
💡 Warum www-data?

Nginx läuft unter dem Benutzer www-data. Damit der Server Dateien lesen darf, müssen die Verzeichnisse diesem Benutzer gehören oder für alle lesbar sein. Ein 403-Fehler im Browser bedeutet meistens: falsche Berechtigungen.

Nginx-Virtual-Host konfigurieren

Nginx-Konfigurationen für einzelne Websites heißen Server Blocks. Jede Domain bekommt eine eigene Datei unter /etc/nginx/sites-available/.

🖥️ Auf dem Server
/etc/nginx/sites-available/meinsite – anlegen mit sudo nano
server {
    listen 80;
    server_name meinsite.local 192.168.1.50;

    root /var/www/meinsite;
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    # Logs:
    access_log /var/log/nginx/meinsite-access.log;
    error_log  /var/log/nginx/meinsite-error.log;
}

Jetzt aktivieren und testen:

# Symlink anlegen – aktiviert die Konfiguration:
sudo ln -s /etc/nginx/sites-available/meinsite /etc/nginx/sites-enabled/

# Konfiguration auf Fehler prüfen:
sudo nginx -t

# Nginx neu laden (ohne Unterbrechung):
sudo systemctl reload nginx
🧠 sites-available vs. sites-enabled

Nginx nutzt zwei Verzeichnisse: sites-available enthält alle Konfigurationen (aktive und inaktive). sites-enabled enthält nur Symlinks auf aktive Konfigurationen. Mit ln -s aktivierst du eine Seite – mit rm im sites-enabled-Verzeichnis deaktivierst du sie, ohne die Konfigurationsdatei zu löschen.

Nginx als Reverse Proxy

Der häufigste Einsatz von Nginx in der Praxis: Als Reverse Proxy vor einem internen Dienst. Zum Beispiel läuft eine Anwendung auf Port 3000 und soll unter einer schönen URL erreichbar sein.

🖥️ Auf dem Server
/etc/nginx/sites-available/app – Reverse Proxy Konfiguration
server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
💡 Wozu die proxy_set_header-Zeilen?

Ohne diese Header sieht die interne Anwendung nur die IP von Nginx (127.0.0.1) – nicht die echte Client-IP. Mit X-Real-IP und X-Forwarded-For gibt Nginx die ursprüngliche Client-IP weiter. Das ist wichtig für Logs, Rate-Limiting und Sicherheitsfilter.

Caddy – die moderne Alternative

Caddy ist jünger als Nginx, aber in vielen Szenarien die bessere Wahl für Einsteiger. Der größte Vorteil: automatisches HTTPS. Du gibst einen Domain-Namen an – Caddy holt sich das Let's Encrypt-Zertifikat von alleine und erneuert es auch automatisch.

MerkmalNginxCaddy
KonfigurationssyntaxKomplex, viele DirektivenEinfach, fast lesbar wie Prosa
Automatisches HTTPSNein (Certbot nötig)Ja, eingebaut
ZertifikatserneuerungManuell oder CronjobVollautomatisch
PaketquellenStandard-Ubuntu-RepoEigenes Repo nötig
VerbreitungSehr weit verbreitet, viel DokuWächst stark, moderne Doku
Bester EinsatzKomplexe Setups, viel KontrolleEinfache Setups, schneller Start

Caddy installieren

🖥️ Auf dem Server

Caddy ist nicht im Standard-Ubuntu-Repository – du fügst das offizielle Caddy-Repository hinzu:

Caddy installieren (Debian/Ubuntu)
# Abhängigkeiten:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

# GPG-Schlüssel herunterladen:
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

# Repository eintragen:
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list

# Caddy installieren:
sudo apt update
sudo apt install -y caddy

# Status prüfen:
sudo systemctl status caddy

Das Caddyfile – Konfiguration für Menschen

Die Konfigurationsdatei von Caddy (/etc/caddy/Caddyfile) ist bewusst einfach gehalten. Ein Block pro Domain, klare Direktiven, keine Symlink-Acrobatik.

🖥️ Auf dem Server
/etc/caddy/Caddyfile – Beispiele
# Statische Website (automatisches HTTPS bei echter Domain):
example.com {
    root * /var/www/example.com
    file_server
}

# Reverse Proxy zu einem internen Dienst:
app.example.com {
    reverse_proxy localhost:3000
}

# Mehrere Dienste auf einem Server:
grafana.example.com {
    reverse_proxy localhost:3001
}

# Lokal testen ohne echte Domain (kein automatisches HTTPS):
:8080 {
    root * /var/www/test
    file_server
}

Nach Änderungen Konfiguration prüfen und neu laden:

# Konfiguration validieren:
caddy validate --config /etc/caddy/Caddyfile

# Caddy neu laden (kein Neustart, keine Downtime):
sudo systemctl reload caddy
🧠 Automatisches HTTPS mit Caddy

Sobald du einen echten Domain-Namen im Caddyfile angibst (nicht :8080 oder eine IP), holt Caddy automatisch ein kostenloses Let's Encrypt-Zertifikat. Voraussetzungen: DNS-A-Record zeigt auf den Server, Ports 80 und 443 sind in der Firewall offen (Port 80 braucht Let's Encrypt für die Verifikation).

HTTPS mit Nginx – Certbot

Bei Nginx musst du HTTPS selbst einrichten. Das Standardwerkzeug dafür ist Certbot – es holt das Let's Encrypt-Zertifikat und trägt es automatisch in die Nginx-Konfiguration ein.

🖥️ Auf dem Server
Certbot installieren und Zertifikat holen
# Certbot installieren:
sudo apt install -y certbot python3-certbot-nginx

# Zertifikat für eine Domain holen und Nginx-Config anpassen:
sudo certbot --nginx -d example.com

# Zertifikat-Erneuerung testen (Certbot richtet Cronjob ein):
sudo certbot renew --dry-run
⚠️ Ports 80 und 443 müssen offen sein

Let's Encrypt muss deinen Server über Port 80 erreichen, um die Domain-Inhaberschaft zu bestätigen. Danach läuft alles über Port 443. Öffne beide Ports in der Firewall – ausführlich erklärt in Modul 14. Kurzform: sudo ufw allow 80/tcp und sudo ufw allow 443/tcp.

Logs verstehen

Webserver schreiben in zwei Log-Dateien: Access-Log (jede Anfrage) und Error-Log (Fehler und Warnungen). Diese Logs sind dein wichtigstes Werkzeug beim Debuggen.

🖥️ Auf dem Server
Log-Dateien lesen und beobachten
# Nginx-Logs:
sudo tail -f /var/log/nginx/access.log   # Live-Ansicht Anfragen
sudo tail -f /var/log/nginx/error.log    # Live-Ansicht Fehler

# Caddy-Logs (über systemd journal):
sudo journalctl -u caddy -f             # Live-Ansicht
sudo journalctl -u caddy -n 50          # Letzte 50 Zeilen

# Nur Fehler im Nginx-Error-Log zählen:
grep -c "error" /var/log/nginx/error.log

Eine typische Zeile im Nginx-Access-Log sieht so aus – so liest du sie:

Beispiel-Ausgabe: access.log
192.168.1.5 - - [15/Mar/2026:14:23:01 +0100] "GET /index.html HTTP/1.1" 200 1234 "-" "Mozilla/5.0"
Teil der Log-ZeileBedeutung
192.168.1.5IP-Adresse des Besuchers
15/Mar/2026:14:23:01Datum und Uhrzeit der Anfrage
GET /index.html HTTP/1.1Angeforderte Datei und Methode
200HTTP-Statuscode (200 = OK)
1234Größe der Antwort in Bytes
🤖
KI-Tipp: Nginx-Konfiguration erstellen lassen

Nginx-Konfigurationen können schnell komplex werden – besonders für Reverse Proxy mit SSL, WebSocket-Unterstützung oder speziellen HTTP-Headern. Beschreibe deinen Anwendungsfall einer KI: „Erstelle mir eine vollständige Nginx-Server-Block-Konfiguration für Nextcloud unter nextcloud.meinserver.de. Sie läuft intern auf Port 8080. HTTPS soll über Certbot eingerichtet sein."

Firewall-Ports freigeben

Damit der Webserver von außen erreichbar ist, müssen die Ports 80 (HTTP) und 443 (HTTPS) in der Firewall freigegeben sein. Die Firewall-Administration ist das Thema von Modul 14 – hier die Kurzversion für dieses Modul:

🖥️ Auf dem Server
Ports 80 und 443 mit ufw öffnen
# HTTP und HTTPS freigeben:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Alternativ – vordefiniertes Nginx-Profil nutzen:
sudo ufw allow 'Nginx Full'

# Status prüfen:
sudo ufw status
💡 ufw-Profile für Webserver

Nach der Nginx-Installation registriert sich Nginx automatisch als ufw-Applikation mit drei Profilen: Nginx HTTP (nur Port 80), Nginx HTTPS (nur Port 443), Nginx Full (beide). Mit sudo ufw app list siehst du alle verfügbaren Profile.

🤖
KI-Tipp: Caddyfile für deinen Anwendungsfall

Caddy hat viele Direktiven für spezielle Szenarien: WebSocket-Support, Authentifizierung, Komprimierung, Health Checks. Wenn du einen konkreten Dienst einrichten willst, frag eine KI: „Schreibe mir ein vollständiges Caddyfile für Gitea unter git.meinserver.de mit Reverse Proxy auf Port 3000, aktiviertem gzip und den nötigen Sicherheits-Headern."

Praxisaufgaben
AUFGABE 13.1 Nginx installieren und erste Website ausliefern

Du installierst Nginx und richtest eine einfache statische Website ein – die Grundlage für alle weiteren Webprojekte.

🖥️ Alle Schritte auf dem Server – per SSH eingeloggt
1
Installiere Nginx: sudo apt update && sudo apt install -y nginx. Prüfe danach den Status: sudo systemctl status nginx – der Dienst sollte als „active (running)" angezeigt werden.
2
Erstelle ein Webverzeichnis und eine Testseite: sudo mkdir -p /var/www/meinsite, dann echo '<h1>Hallo Welt</h1>' | sudo tee /var/www/meinsite/index.html.
3
Setze die Berechtigungen: sudo chown -R www-data:www-data /var/www/meinsite. Ohne das bekommst du einen 403-Fehler im Browser.
4
Lege eine neue Nginx-Konfiguration an: sudo nano /etc/nginx/sites-available/meinsite. Schreibe einen Server-Block, der auf Port 80 lauscht und Dateien aus /var/www/meinsite ausliefert.
5
Aktiviere die Seite: sudo ln -s /etc/nginx/sites-available/meinsite /etc/nginx/sites-enabled/. Prüfe die Konfiguration: sudo nginx -t. Lade Nginx neu: sudo systemctl reload nginx.
6
Öffne http://server-ip im Browser deines Rechners. Du solltest „Hallo Welt" sehen.
Lösungshinweise anzeigen

Ein minimaler Server-Block für diese Aufgabe: server { listen 80; server_name _; root /var/www/meinsite; index index.html; location / { try_files $uri $uri/ =404; } }. server_name _ ist ein Platzhalter, der auf alle Hostnamen passt.

Wenn der Browser nichts zeigt: Prüfe mit sudo journalctl -u nginx -n 20 ob Nginx läuft. Bei einem 403: Berechtigungen mit ls -la /var/www/meinsite kontrollieren.

AUFGABE 13.2 Nginx als Reverse Proxy einrichten

Du leitest Anfragen an einen internen Dienst weiter – das ist der häufigste Einsatz von Nginx in der Praxis.

🖥️ Alle Schritte auf dem Server
1
Starte einen einfachen Test-Webserver auf Port 3000 im Hintergrund: python3 -m http.server 3000 &. Prüfe ob er läuft: curl http://localhost:3000.
2
Erstelle eine neue Nginx-Konfiguration: sudo nano /etc/nginx/sites-available/proxy. Konfiguriere einen Server-Block auf Port 8080, der alle Anfragen mit proxy_pass an http://127.0.0.1:3000 weiterleitet.
3
Aktiviere die Konfiguration, prüfe sie und lade Nginx neu: sudo ln -s /etc/nginx/sites-available/proxy /etc/nginx/sites-enabled/ && sudo nginx -t && sudo systemctl reload nginx.
4
Teste den Proxy: curl http://localhost:8080. Du solltest die Antwort des Python-HTTP-Servers sehen.
5
Beobachte das Nginx-Access-Log während des Tests: sudo tail -f /var/log/nginx/access.log. Öffne in einem zweiten Terminal nochmal curl http://localhost:8080 und lies den neuen Log-Eintrag.
Lösungshinweise anzeigen

Der Server-Block braucht mindestens: server { listen 8080; location / { proxy_pass http://127.0.0.1:3000; } }. Im Access-Log erscheint jede Anfrage mit Statuscode 200 und der Antwortgröße.

Wenn curl http://localhost:8080 einen 502-Fehler gibt: Der Python-Server läuft nicht mehr. Prüfe mit jobs oder ps aux | grep python3.

AUFGABE 13.3 Caddy installieren und statische Website hosten

Du installierst Caddy als moderne Alternative zu Nginx und lernst den Unterschied in der Konfiguration kennen.

🖥️ Alle Schritte auf dem Server
1
Falls Nginx noch läuft, stoppe es zuerst um Port-Konflikte zu vermeiden: sudo systemctl stop nginx.
2
Installiere Caddy gemäß der Anleitung im Modul (Repository hinzufügen, dann sudo apt install -y caddy). Prüfe mit sudo systemctl status caddy.
3
Passe /etc/caddy/Caddyfile an: Konfiguriere Caddy auf Port 8080 mit root * /var/www/meinsite und file_server. Nutze die :8080 { ... }-Syntax.
4
Validiere und starte Caddy neu: caddy validate --config /etc/caddy/Caddyfile && sudo systemctl restart caddy.
5
Öffne http://server-ip:8080 im Browser. Beobachte gleichzeitig die Logs: sudo journalctl -u caddy -f.
Lösungshinweise anzeigen

Das Caddyfile für diese Aufgabe besteht aus vier Zeilen: :8080 {, dann root * /var/www/meinsite, dann file_server, dann }. Die geschwungenen Klammern müssen auf eigenen Zeilen stehen – Caddy ist da streng.

Vergleiche den Aufwand mit der Nginx-Konfiguration aus Aufgabe 13.1: Caddy braucht keine sites-available/sites-enabled-Struktur, keinen Symlink-Befehl. Sobald du eine echte Domain angibst, kommt HTTPS automatisch dazu.

AUFGABE 13.4 Logs auswerten und Fehler gezielt finden

Du lernst, Webserver-Logs zu lesen und gezielt nach Fehlern zu suchen – eine grundlegende Fähigkeit im Server-Betrieb.

🖥️ Alle Schritte auf dem Server
1
Starte Nginx: sudo systemctl start nginx. Öffne das Access-Log in Echtzeit in einem Terminal: sudo tail -f /var/log/nginx/access.log.
2
Rufe in einem zweiten Terminal verschiedene URLs auf und beobachte die Log-Einträge: curl http://localhost/ (sollte 200 liefern) und curl http://localhost/nichtvorhanden (sollte 404 liefern).
3
Suche im Error-Log nach Fehlern: sudo grep "error" /var/log/nginx/error.log | tail -20.
4
Provoziere absichtlich einen Berechtigungsfehler: sudo chmod 000 /var/www/meinsite/index.html, dann rufe die Seite auf. Beobachte den 403-Fehler im Access-Log und den Hinweis im Error-Log.
5
Stelle die Berechtigungen wieder her: sudo chmod 644 /var/www/meinsite/index.html. Prüfe ob die Seite wieder erreichbar ist.
Lösungshinweise anzeigen

Der 403-Fehler erscheint sowohl im Access-Log (Statuscode 403 in der Log-Zeile) als auch im Error-Log mit einem Hinweis wie permission denied und dem Dateipfad. So findest du Berechtigungsprobleme im echten Betrieb schnell.

Merke: 404 = Datei fehlt, 403 = Datei existiert aber darf nicht gelesen werden. Beide sehen im Browser ähnlich aus – die Logs verraten den Unterschied sofort.

Modul 143 Unterrichtseinheiten

Firewall-Administration

Ein Server ohne Firewall ist wie ein Haus ohne Türschloss -- jeder kann rein. In diesem Modul lernst du, mit ufw eine Firewall einzurichten, Ports gezielt zu öffnen und zu schließen, und Regeln sicher zu verwalten.

Voraussetzung: Modul 01 Voraussetzung: Modul 06 ufw · Ports · Regeln · iptables · Logging
Kontext: Alles läuft auf dem Server

Firewall-Befehle werden direkt auf dem Server ausgeführt -- du brauchst dafür sudo-Rechte. Verbinde dich zuerst per SSH auf deinen Server (Modul 02), und führe dann alle Befehle aus diesem Modul dort aus.

🖥️ Alle Befehle in diesem Modul: auf dem Server

Du bist per SSH eingeloggt und gibst alle Befehle direkt auf dem Server ein. Dein lokaler Rechner bleibt im Hintergrund.

Was ist eine Firewall?

Eine Firewall entscheidet, welche Netzwerkverbindungen zu deinem Server erlaubt sind und welche geblockt werden. Sie arbeitet mit Regeln: Für jeden eingehenden Datenpaket wird geprüft, ob er durchkommt oder blockiert wird.

Stell dir die Firewall als Türsteher vor: Er hat eine Gästeliste. Port 22 (SSH) -- rein. Port 443 (HTTPS) -- rein. Unbekannter Port 3306 (Datenbank) -- draußen bleiben. Was nicht auf der Liste steht, kommt nicht rein.

💡 Warum braucht ein Server eine Firewall?

Ohne Firewall ist jeder Port erreichbar, auf dem ein Dienst lauscht. Datenbanken, Admin-Panels oder interne Dienste wären dann direkt aus dem Internet zugänglich. Eine Firewall schränkt den Zugriff auf das Nötigste ein -- das ist Grundlage jeder Sicherheitsstrategie.

EbeneWerkzeugRolle
Kernelnftables / iptablesDie eigentliche Firewall im Linux-Kern
VerwaltungufwEinfaches Frontend für iptables/nftables
Anzeigeufw statusAktuelle Regeln im Überblick
ufw einrichten und aktivieren

ufw steht für "Uncomplicated Firewall" -- zu Recht. Was mit iptables viele Zeilen braucht, geht mit ufw in einem Befehl. Auf Ubuntu und Debian ist ufw meistens bereits installiert, aber noch nicht aktiv.

🚨 SSH-Regel setzen, BEVOR du ufw aktivierst!

Wenn du ufw aktivierst, ohne vorher SSH zu erlauben, sperrst du dich sofort selbst aus. Auf einem Remote-Server ohne lokalen Bildschirmzugang gibt es dann keinen Weg zurück. Die Reihenfolge ist zwingend: 1. SSH erlauben, 2. ufw aktivieren. Kein einziger Schritt darf umgedreht werden.

🖥️ Auf dem Server -- ufw installieren und aktivieren

Installiere ufw, falls es noch nicht vorhanden ist, und richte die Grundkonfiguration ein.

ufw installieren und Grundregeln setzen
# ufw installieren (auf Debian/Ubuntu meist schon dabei):
sudo apt install ufw

# Aktuellen Status prüfen:
sudo ufw status

# Standard-Richtlinien setzen -- IMMER als erstes:
sudo ufw default deny incoming
sudo ufw default allow outgoing

# SSH erlauben -- VOR dem Aktivieren!
sudo ufw allow ssh

# ufw aktivieren:
sudo ufw enable

# Status mit allen Regeln anzeigen:
sudo ufw status verbose

Nach ufw enable fragt ufw noch einmal nach, ob du sicher bist. Bestätige mit y. Deine laufende SSH-Verbindung bleibt dabei erhalten -- nur neue Regeln greifen ab sofort.

🧠 Was bedeutet "deny incoming / allow outgoing"?

deny incoming bedeutet: Alles, was von außen kommt, ist gesperrt -- außer du erlaubst es explizit. allow outgoing bedeutet: Dein Server darf selbst Verbindungen nach draußen aufbauen (z.B. für apt update). Das ist die sichere Standardeinstellung.

Ports öffnen und schließen

Mit ufw allow öffnest du einen Port, mit ufw deny sperrst du ihn explizit. Du kannst Ports entweder über ihren Namen (z.B. ssh, http) oder direkt über die Nummer (z.B. 22/tcp) ansprechen.

🖥️ Auf dem Server -- Ports und Dienste freigeben
Häufige ufw-Regeln
# Dienste nach Name erlauben (ufw kennt die Standard-Ports):
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https

# Ports direkt nach Nummer erlauben:
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 8080/tcp

# Nginx mit HTTP und HTTPS in einem Schritt:
sudo ufw allow 'Nginx Full'

# Port explizit sperren:
sudo ufw deny 3306/tcp

# Port-Bereich erlauben:
sudo ufw allow 6000:6100/tcp

Zugriff auf bestimmte IP-Adressen einschränken

Manchmal soll ein Port nur für bestimmte Rechner erreichbar sein -- z.B. der Datenbank-Port nur aus dem internen Netzwerk. Das erreichst du mit from-Regeln.

🖥️ Auf dem Server -- IP-basierte Regeln
Zugriff nach IP oder Subnetz einschränken
# Nur eine bestimmte IP darf auf Port 22 (SSH) zugreifen:
sudo ufw allow from 192.168.1.100 to any port 22

# Ganzes internes Subnetz darf auf den Server zugreifen:
sudo ufw allow from 192.168.1.0/24

# Nur internes Netz darf auf MySQL (Port 3306) zugreifen:
sudo ufw allow from 192.168.1.0/24 to any port 3306

# Rate Limiting für SSH (max. 6 Versuche pro 30 Sekunden):
sudo ufw limit ssh
Regeln anzeigen und löschen

Um den Überblick zu behalten, zeigst du die Regeln nummeriert an. Das macht das Löschen einzelner Regeln einfach -- du gibst einfach die Nummer an.

🖥️ Auf dem Server -- Regeln verwalten
Regeln anzeigen und entfernen
# Alle Regeln nummeriert anzeigen:
sudo ufw status numbered

# Regel nach Nummer löschen (Nummer aus obigem Befehl):
sudo ufw delete 3

# Regel nach Name/Port löschen:
sudo ufw delete allow 8080/tcp
sudo ufw delete allow http

# ufw vorübergehend deaktivieren (ohne Regeln zu löschen):
sudo ufw disable

# ufw wieder aktivieren:
sudo ufw enable
🚨 ufw --force reset löscht ALLE Regeln

sudo ufw --force reset setzt die Firewall auf den Werkszustand zurück -- alle Regeln sind weg, und die Firewall ist deaktiviert. Auf einem Remote-Server bedeutet das: alle Ports offen, keine Sicherheit mehr. Verwende diesen Befehl nur, wenn du weißt was du tust, und richte danach sofort neue Regeln ein.

Häufige Ports -- Referenz

Merke: Weniger ist mehr -- öffne nur, was wirklich gebraucht wird.

PortProtokollDienstufw-Empfehlung
22TCPSSHallow ssh + limit ssh
80TCPHTTPallow http
443TCPHTTPSallow https
25TCPSMTP (Mail)Nur wenn Mailserver betrieben
53TCP/UDPDNSNur wenn DNS-Server (Modul 15)
3306TCPMySQLNiemals offen! Nur lokal / Tunnel
5432TCPPostgreSQLNiemals offen! Nur lokal / Tunnel
3389TCPRDP (Remote Desktop)Nur bei Bedarf, IP einschränken
8080TCPAnwendungsserverNur wenn benötigt
⚠️ Datenbanken niemals direkt ans Internet

MySQL (3306), PostgreSQL (5432) und Redis (6379) sollten grundsätzlich nicht über die Firewall freigegeben werden. Sie sind nur lokal oder über einen SSH-Tunnel (Modul 02) erreichbar. Wer diese Ports nach außen öffnet, riskiert automatisierte Angriffe innerhalb von Minuten.

Übersicht aller ufw-Befehle

BefehlBedeutung
sudo ufw statusStatus und Regeln anzeigen
sudo ufw status verboseStatus mit Details und Policies
sudo ufw status numberedRegeln mit Nummern anzeigen
sudo ufw enableFirewall aktivieren
sudo ufw disableFirewall deaktivieren
sudo ufw allow sshSSH erlauben (Port 22)
sudo ufw deny 3306/tcpPort explizit sperren
sudo ufw delete 3Regel Nr. 3 löschen
sudo ufw limit sshRate Limiting für SSH
sudo ufw logging onLogging aktivieren
Logging aktivieren

ufw kann geblockte Verbindungen protokollieren. So siehst du, wer versucht auf deinen Server zuzugreifen -- und auf welchen Port.

🖥️ Auf dem Server -- Logging einrichten und Logs lesen
ufw-Logging aktivieren und auswerten
# Logging aktivieren:
sudo ufw logging on

# Logging-Stufe anpassen (low = wenig, high = viel):
sudo ufw logging medium
# Stufen: off, low, medium, high, full

# Geblockte Verbindungen in Echtzeit beobachten:
sudo journalctl -k --grep "UFW BLOCK" -f

# Oder im syslog nachschauen:
sudo grep "UFW BLOCK" /var/log/syslog | tail -20

Ein typischer Log-Eintrag sieht so aus:

# UFW BLOCK IN=eth0 SRC=185.220.101.34 DST=192.168.1.10 PROTO=TCP DPT=3306
# Das bedeutet: Jemand von 185.220.101.34 wollte auf Port 3306 (MySQL) -- geblockt!
🤖
KI-Tipp: Firewall-Regeln auditieren

Wenn du nicht sicher bist, welche Ports offen oder riskant sind, kombiniere sudo ufw status verbose mit ss -tlnp (zeigt alle Ports, auf denen ein Dienst lauscht). Kopiere beide Ausgaben und frag: „Hier sind meine Firewall-Regeln und alle lauschenden Dienste meines Servers. Welche Ports sollten laut Best Practice geschlossen werden und warum?"

iptables -- der Motor hinter ufw

ufw ist nur ein bequemes Werkzeug vorne -- im Hintergrund arbeitet immer iptables (oder das modernere nftables). Du wirst iptables selten direkt brauchen, aber ein Grundverständnis hilft.

Stell dir iptables wie den Motor vor und ufw wie das Lenkrad: Du steuerst mit ufw, aber der Motor (iptables) macht die eigentliche Arbeit. Wenn du mal tief in die Regeln schauen musst, hilft iptables weiter.

🖥️ Auf dem Server -- iptables zur Diagnose nutzen
iptables-Regeln anzeigen
# Aktuelle Regeln anzeigen (zeigt auch was ufw eingerichtet hat):
sudo iptables -L -n --line-numbers

# Regeln mit Paket-Statistiken:
sudo iptables -L -n -v

# Alle Regeln komplett exportieren:
sudo iptables-save
💡 ufw vs. iptables direkt

Verwende für den Alltag immer ufw. Direkte iptables-Befehle werden nach einem Neustart nicht gespeichert (außer mit extra Konfiguration). ufw dagegen speichert alle Regeln persistent. iptables direkt nutzt du nur zur Diagnose oder wenn du sehr spezifische Regeln brauchst, die ufw nicht unterstützt.

🤖
KI-Tipp: ufw-Fehlermeldungen verstehen

ufw-Fehler wie "ERROR: Could not load logging rules" oder unerwartetes Verhalten nach einem Neustart sind manchmal schwer zu diagnostizieren. Führe sudo ufw status verbose aus, kopiere die Ausgabe und frag: „Meine ufw-Konfiguration zeigt diesen Status. Ist das korrekt für einen Webserver, der nur SSH, HTTP und HTTPS erlauben soll? Was muss ich anpassen?"

Praxisaufgaben
AUFGABE 14.1 ufw einrichten und aktivieren

Du richtest die Firewall-Grundkonfiguration auf deinem Server ein. Das ist der erste Schritt zu einem sicheren System -- und die Reihenfolge ist entscheidend.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Prüfe den aktuellen Status der Firewall: sudo ufw status. Ist sie aktiv oder inaktiv?
2
Setze die Standard-Richtlinien: sudo ufw default deny incoming und sudo ufw default allow outgoing.
3
Erlaube SSH, bevor du die Firewall aktivierst: sudo ufw allow ssh. Prüfe mit sudo ufw show added, ob die Regel vorhanden ist.
4
Aktiviere die Firewall: sudo ufw enable. Bestätige mit y. Prüfe danach mit sudo ufw status verbose.
5
Erlaube HTTP und HTTPS: sudo ufw allow http und sudo ufw allow https. Zeige den finalen Status mit sudo ufw status numbered.
Lösungshinweise anzeigen

sudo ufw status verbose sollte anzeigen: Status: active, Default: deny (incoming), allow (outgoing). In der Regelliste stehen SSH (22), HTTP (80) und HTTPS (443).

Teste, ob du noch per SSH erreichbar bist, indem du ein zweites Terminal öffnest und dich erneut verbindest. Wenn das klappt, ist alles korrekt eingerichtet.

AUFGABE 14.2 Regeln gezielt verwalten

Du lernst, einzelne Regeln hinzuzufügen, zu prüfen und wieder zu entfernen -- ohne die gesamte Firewall zu verändern.

🖥️ Auf dem Server
1
Füge einen Test-Port hinzu: sudo ufw allow 9999/tcp. Zeige die Regeln nummeriert an: sudo ufw status numbered. Notiere die Nummer der 9999/tcp-Regel.
2
Schränke SSH auf dein lokales Netzwerk ein: sudo ufw allow from 192.168.1.0/24 to any port 22. (Passe das Subnetz an dein Netzwerk an.)
3
Aktiviere Rate Limiting für SSH: sudo ufw limit ssh. Das schützt vor automatisierten Brute-Force-Angriffen.
4
Lösche die Test-Regel per Nummer: sudo ufw delete [NUMMER]. Bestätige und prüfe mit sudo ufw status numbered, ob Port 9999 verschwunden ist.
5
Vergleiche die Firewall-Regeln mit den tatsächlich lauschenden Diensten: ss -tlnp. Welche Ports lauschen, aber sind in ufw nicht geöffnet?
Lösungshinweise anzeigen

Nach dem Löschen darf Port 9999 nicht mehr in sudo ufw status erscheinen. ss -tlnp zeigt alle Ports, auf denen ein Dienst lauscht -- das können mehr sein als in ufw geöffnet, weil ufw nur eingehende Verbindungen filtert. Dienste, die nur auf 127.0.0.1 lauschen, sind ohnehin nur lokal erreichbar.

Rate Limiting (limit) erlaubt maximal 6 Verbindungsversuche von einer IP innerhalb von 30 Sekunden. Danach wird diese IP kurzzeitig geblockt.

AUFGABE 14.3 Logging aktivieren und Logs lesen

Du aktivierst das ufw-Logging und lernst, geblockte Verbindungen zu erkennen und zu interpretieren.

🖥️ Auf dem Server
1
Aktiviere das Logging: sudo ufw logging on. Setze danach die Stufe: sudo ufw logging medium.
2
Prüfe den aktuellen Status inklusive Logging-Einstellungen: sudo ufw status verbose. In der Ausgabe sollte "Logging: on (medium)" erscheinen.
3
Schaue in die Logs nach blockierten Verbindungen: sudo grep "UFW BLOCK" /var/log/syslog | tail -20. Gibt es Einträge?
4
Lese einen Log-Eintrag: Welche IP-Adresse steht bei SRC=? Welcher Port wurde versucht (DPT=)? Welches Interface (IN=)?
Lösungshinweise anzeigen

Ein typischer Eintrag sieht so aus: UFW BLOCK IN=eth0 SRC=185.220.101.34 DST=10.0.0.1 PROTO=TCP DPT=22. Das bedeutet: Eine IP hat versucht, auf SSH (Port 22) zuzugreifen -- und wurde geblockt. SRC ist die Quell-IP des Angreifers, DPT der Ziel-Port.

Wenn keine Einträge erscheinen, ist das gut -- dein Server wird gerade nicht angegriffen. Auf öffentlich erreichbaren Servern sind SSH-Scan-Versuche jedoch innerhalb weniger Minuten nach der Inbetriebnahme normal.

Modul 152 Unterrichtseinheiten

DNS-Server mit dnsmasq

Statt IP-Adressen auswendig zu lernen, gibst du deinen Netzgeräten sprechende Namen wie nas.local oder drucker.local. dnsmasq ist dabei dein Werkzeug: klein, einfach und auf jedem Debian/Ubuntu-Server zu Hause.

Voraussetzung: Modul 01 Voraussetzung: Modul 05 dnsmasq · Lokales DNS · DHCP · Cache · Forwarding

Alle Befehle in diesem Modul laufen auf dem Server – du bist bereits per SSH eingeloggt (Modul 02). Dein eigener Rechner ist nicht beteiligt.

🖥️ Server

Alle Befehle in diesem Modul laufen auf dem Server – du bist bereits per SSH eingeloggt.

Was ist DNS – und warum brauchst du es lokal?

DNS steht für Domain Name System – das Telefonbuch des Internets. Du tippst google.com und dein Rechner fragt im Hintergrund: „Welche IP-Adresse steckt dahinter?" Ein DNS-Server antwortet mit z.B. 142.250.185.46. Aus Modul 01 kennst du bereits IP-Adressen und die Grundfunktion von DNS.

Im lokalen Netz läuft das genauso – nur dass es hier um deine eigenen Geräte geht. Ohne lokalen DNS-Server musst du für jeden Dienst die IP-Adresse kennen. Mit dnsmasq vergibst du Namen:

Ohne DNSMit dnsmasq
192.168.1.20nas.local
192.168.1.30drucker.local
192.168.1.50kamera1.local
192.168.1.10server.local

Ändert sich eine IP, trägst du sie einmal nach – fertig. Alle Geräte im Netz, die deinen dnsmasq nutzen, bekommen die Änderung automatisch.

💡 Was dnsmasq alles kann

dnsmasq vereint drei Funktionen in einem Dienst: DNS-Cache (Anfragen zwischenspeichern, schnellere Wiederholung), lokales DNS (eigene Namen für deine Geräte) und optional DHCP (automatische IP-Vergabe im Netz). Du kannst jede Funktion einzeln aktivieren.

dnsmasq installieren

Bevor du dnsmasq installierst, prüfst du ob Ubuntu bereits einen DNS-Dienst auf Port 53 betreibt. Ubuntu nutzt standardmäßig systemd-resolved – das belegt denselben Port und verhindert, dass dnsmasq startet.

🖥️ Auf dem Server – du bist per SSH eingeloggt

Zuerst prüfst du, ob Port 53 belegt ist:

Port 53 prüfen
ss -tlnp | grep :53
# Wenn eine Zeile erscheint: Port 53 ist belegt (oft systemd-resolved)
# Wenn keine Ausgabe: Port 53 ist frei → direkt zu Installation springen

Falls systemd-resolved läuft, deaktivierst du es zuerst:

systemd-resolved deaktivieren (nur falls nötig)
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved
# Temporären DNS-Server eintragen, damit der Server noch Namen auflösen kann:
sudo rm /etc/resolv.conf
echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf

Jetzt installierst du dnsmasq:

dnsmasq installieren und Status prüfen
sudo apt update
sudo apt install dnsmasq
sudo systemctl status dnsmasq
# Sollte "active (running)" zeigen
ss -tlnp | grep :53
# Jetzt sollte dnsmasq auf Port 53 lauschen
⚠️ Fehler bei der dnsmasq-Konfiguration trifft das ganze Netz

Wenn dnsmasq als DNS-Server für alle Geräte im Netz konfiguriert ist und der Dienst abstürzt oder falsch konfiguriert wird, verliert jedes Gerät im Netz die Namensauflösung. Webseiten laden nicht mehr, E-Mail funktioniert nicht, interne Dienste sind nicht erreichbar. Teste Konfigurationsänderungen immer mit dnsmasq --test bevor du den Dienst neustartest.

dnsmasq Grundkonfiguration

Die Konfigurationsdateien liegen in /etc/dnsmasq.conf (Hauptdatei, sehr lang und kommentiert) und in /etc/dnsmasq.d/ (eigene Dateien, werden automatisch eingelesen). Lege deine Einstellungen immer in einer eigenen Datei unter /etc/dnsmasq.d/ ab – so bleibt die Original-Datei unangetastet.

🖥️ Auf dem Server

Erstelle deine eigene Konfigurationsdatei:

/etc/dnsmasq.d/meinetz.conf anlegen
sudo nano /etc/dnsmasq.d/meinetz.conf

Füge folgenden Inhalt ein (passe die Netzwerkschnittstelle an – eth0 oder ens3 usw.):

/etc/dnsmasq.d/meinetz.conf – Grundkonfiguration
# Welche Netzwerkschnittstelle dnsmasq nutzen soll:
interface=eth0

# Nur auf dieser Schnittstelle lauschen (Sicherheit):
bind-interfaces

# Upstream-DNS-Server – wohin externe Anfragen gehen:
server=1.1.1.1
server=8.8.8.8

# Lokale Domain – .local-Anfragen nicht nach außen schicken:
domain=local
local=/local/

# DNS-Cache-Größe (Standard: 150, höherer Wert = schneller):
cache-size=1000

# Logs für Debugging (optional, kann viel schreiben):
log-queries

Konfiguration prüfen und dnsmasq neu starten:

Konfiguration testen und anwenden
# Syntax prüfen – IMMER vor dem Neustart:
dnsmasq --test
# Ausgabe bei Erfolg: "dnsmasq: syntax check OK."

sudo systemctl restart dnsmasq
sudo systemctl status dnsmasq
OptionBedeutungBeispiel
interfaceSchnittstelle, auf der dnsmasq lauschtinterface=eth0
bind-interfacesNur auf angegebene Schnittstellen bindenkein Wert nötig
serverUpstream-DNS-Server für externe Anfragenserver=1.1.1.1
domainLokale Domain-Endungdomain=local
localDiese Domain nicht nach außen weiterleitenlocal=/local/
cache-sizeAnzahl gecachter DNS-Einträgecache-size=1000
log-queriesAlle DNS-Anfragen ins Log schreibenkein Wert nötig
Lokale Hostnamen vergeben

dnsmasq liest automatisch aus /etc/hosts – du trägst dort IP und Name ein und dnsmasq liefert die Antwort. Das ist der einfachste Weg für statische Geräte in deinem Netz.

🖥️ Auf dem Server

Trage deine Netzgeräte in /etc/hosts ein:

/etc/hosts – lokale Hostnamen eintragen
sudo nano /etc/hosts

Füge deine Geräte unterhalb der bestehenden Einträge ein:

# Lokale Netzgeräte:
192.168.1.1     router.local router
192.168.1.10    server.local server
192.168.1.20    nas.local nas
192.168.1.30    drucker.local drucker
192.168.1.50    kamera1.local kamera1

Nach der Änderung reicht ein Reload – bestehende Verbindungen bleiben erhalten:

sudo systemctl reload dnsmasq

# Auflösung testen:
dig nas.local @127.0.0.1
# Im ANSWER SECTION siehst du die zugehörige IP
🧠 Direkte Einträge in dnsmasq – ohne /etc/hosts

Du kannst Hostnamen auch direkt in einer dnsmasq-Konfigurationsdatei eintragen. Füge in /etc/dnsmasq.d/hosts.conf ein: address=/nas.local/192.168.1.20. Nützlich für Wildcards (address=/*.intern.local/192.168.1.10) oder wenn du viele Einträge nach Schema verwalten willst.

DNS testen mit dig und nslookup

Mit dig und nslookup fragst du deinen dnsmasq direkt ab – ohne dass andere Systemeinstellungen dazwischenfunken. Du kannst den DNS-Server mit @127.0.0.1 direkt ansprechen.

🖥️ Auf dem Server
DNS-Auflösung testen
# Lokalen Namen auflösen:
dig nas.local @127.0.0.1
# Im "ANSWER SECTION" siehst du die IP

# Externe Domain auflösen (testet Upstream-Weiterleitung):
dig google.com @127.0.0.1
# Zweite Anfrage sollte "Query time: 0 msec" zeigen (Cache)
dig google.com @127.0.0.1

# Alternativ mit nslookup:
nslookup nas.local 127.0.0.1

# Reverse Lookup – IP zu Name:
dig -x 192.168.1.20 @127.0.0.1

# DNS-Anfragen live beobachten (mit log-queries in der Konfiguration):
sudo journalctl -u dnsmasq -f
# Strg+C zum Beenden
🤖
KI-Tipp: dnsmasq-Fehler verstehen

dnsmasq gibt bei Fehlern oft kryptische Meldungen aus – besonders beim Start. Kopiere die Fehlermeldung aus sudo journalctl -u dnsmasq -n 30 und frag: „Ich bekomme diesen dnsmasq-Fehler auf Ubuntu 24.04. Was bedeutet er und wie behebe ich ihn?"

DNS-Weiterleitung an Upstream-Server

Alle Anfragen, die dnsmasq nicht selbst beantworten kann (alles außer deinen lokalen Namen), leitet er an einen Upstream-DNS-Server weiter. Das sind meist öffentliche Server wie Cloudflare (1.1.1.1) oder Google (8.8.8.8). Du kannst bestimmte Domains auch gezielt an andere Server weiterleiten – das nennt sich Split-DNS:

🖥️ Auf dem Server
/etc/dnsmasq.d/forwarding.conf – gezieltes Weiterleiten
# Anfragen für eine Firmendomain an den Firmen-DNS-Server:
server=/firma.intern/10.0.0.1

# Anfragen für .local NICHT nach außen weiterleiten:
local=/local/

# Alle anderen Anfragen an Cloudflare:
server=1.1.1.1

# Domain komplett sperren (leere Antwort statt IP):
address=/werbung-example.com/0.0.0.0
DHCP mit dnsmasq und Clients einrichten

dnsmasq kann auch IP-Adressen automatisch verteilen – als Ersatz für die DHCP-Funktion deines Routers. Der Vorteil: dnsmasq kennt dann automatisch alle Gerätenamen im Netz und trägt sie in seine DNS-Datenbank ein.

🖥️ Auf dem Server
/etc/dnsmasq.d/dhcp.conf – DHCP aktivieren
# IP-Bereich für automatische Vergabe (von .100 bis .200, Lease-Zeit 24h):
dhcp-range=192.168.1.100,192.168.1.200,24h

# Standard-Gateway mitteilen (meist der Router):
dhcp-option=3,192.168.1.1

# DNS-Server mitteilen – dieser Server selbst:
dhcp-option=6,192.168.1.10

# Feste IP für ein bestimmtes Gerät (per MAC-Adresse):
dhcp-host=aa:bb:cc:dd:ee:ff,drucker.local,192.168.1.30,infinite

Aktuelle DHCP-Leases anzeigen:

cat /var/lib/misc/dnsmasq.leases
# Zeigt: Ablaufzeit, MAC-Adresse, vergebene IP, Hostname
⚠️ Kein doppelter DHCP-Server im Netz

Wenn dnsmasq DHCP aktiviert ist, muss der DHCP-Server auf dem Router ausgeschaltet werden. Zwei DHCP-Server im selben Netz führen zu Konflikten: Geräte bekommen zufällig vom falschen Server eine IP – mit falschen DNS-Einstellungen. Schalte erst DHCP auf dem Router ab, dann aktiviere es in dnsmasq.

Linux-Clients auf dnsmasq umstellen

Damit andere Geräte im Netz die lokalen Namen auflösen können, müssen sie deinen Server als DNS-Server kennen. Auf Linux-Clients trägst du die IP deines Servers in Netplan ein (Modul 05):

🖥️ Auf dem Server selbst – eigenen DNS nutzen
/etc/resolv.conf – eigenen dnsmasq als Nameserver eintragen
# Server nutzt seinen eigenen dnsmasq:
echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf

# Testen – lokaler Name sollte jetzt ohne @127.0.0.1 klappen:
ping -c 2 nas.local
🖥️ Auf einem Linux-Client im Netz (per SSH eingeloggt)

Trage die IP des dnsmasq-Servers in die Netplan-Konfiguration ein:

/etc/netplan/01-netcfg.yaml – DNS-Server eintragen
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: true
      nameservers:
        addresses: [192.168.1.10]

Konfiguration anwenden:

sudo netplan apply
# Testen: lokaler Name sollte jetzt auflösbar sein
nslookup nas.local
# Server: 192.168.1.10 ← zeigt, dass dnsmasq-Server genutzt wird
🤖
KI-Tipp: vollständige Konfiguration generieren lassen

dnsmasq hat dutzende Optionen und die Kombination DNS + DHCP kann schnell komplex werden. Beschreibe deinen Anwendungsfall und lass dir eine fertige Konfiguration erstellen: „Ich möchte dnsmasq als DNS- und DHCP-Server für mein Heimnetz einrichten. Netz: 192.168.1.0/24, Router: 192.168.1.1, dnsmasq-Server: 192.168.1.10, DHCP-Bereich: .100 bis .200. Schreibe mir alle nötigen Konfigurationsdateien."

Praxisaufgaben
AUFGABE 15.1 dnsmasq installieren und ersten Test machen

Du installierst dnsmasq und testest, ob die DNS-Auflösung und der Cache funktionieren.

🖥️ Alle Schritte auf dem Server – du bist per SSH eingeloggt
1
Prüfe ob Port 53 belegt ist: ss -tlnp | grep :53. Falls systemd-resolved läuft, deaktiviere es gemäß Modulanleitung und setze /etc/resolv.conf auf nameserver 1.1.1.1.
2
Installiere dnsmasq: sudo apt install dnsmasq. Prüfe danach den Status: sudo systemctl status dnsmasq. Du solltest "active (running)" sehen.
3
Teste die DNS-Auflösung über dnsmasq direkt: dig google.com @127.0.0.1. Notiere dir die Zahl hinter "Query time:".
4
Führe denselben Befehl nochmal aus: dig google.com @127.0.0.1. Ist die Query time jetzt 0? Das ist der Cache in Aktion.
5
Schau dir die letzten Log-Einträge an: sudo journalctl -u dnsmasq -n 20. Du siehst die weitergeleiteten und gecachten Anfragen.
Lösungshinweise anzeigen

Die erste dig-Anfrage zeigt typischerweise 20–50 ms (Anfrage geht bis 1.1.1.1 und zurück). Die zweite Anfrage zeigt "Query time: 0 msec" – der Eintrag kommt aus dem lokalen Cache. Das ist der Hauptvorteil eines DNS-Caches.

Wenn dnsmasq nicht startet: sudo journalctl -u dnsmasq -n 30 zeigt die Fehlermeldung. Häufig ist Port 53 noch von systemd-resolved belegt.

AUFGABE 15.2 Lokale Hostnamen einrichten und testen

Du gibst deinen Netzgeräten sprechende Namen und testest, ob dnsmasq sie korrekt auflöst.

🖥️ Auf dem Server – per SSH eingeloggt
1
Öffne /etc/hosts mit sudo nano /etc/hosts und trage deinen Server ein, z.B.: 192.168.1.10 meinserver.local meinserver. Trage noch ein weiteres Gerät aus deinem Netz ein.
2
Lade die Konfiguration neu: sudo systemctl reload dnsmasq. Ein Reload reicht – kein voller Neustart nötig, bestehende Verbindungen bleiben erhalten.
3
Teste die Auflösung: dig meinserver.local @127.0.0.1. Im Abschnitt "ANSWER SECTION" sollte deine IP erscheinen.
4
Teste den Reverse-Lookup (IP zu Name): dig -x 192.168.1.10 @127.0.0.1. dnsmasq sollte "meinserver.local" zurückgeben.
5
Stelle deinen Server auf seinen eigenen DNS um: echo "nameserver 127.0.0.1" | sudo tee /etc/resolv.conf. Teste danach: ping -c 2 meinserver.local.
Lösungshinweise anzeigen

dig meinserver.local @127.0.0.1 sollte im ANSWER SECTION eine Zeile zeigen: meinserver.local. 0 IN A 192.168.1.10. Die "0" ist die TTL – lokale Einträge aus /etc/hosts haben keine Ablaufzeit.

Reverse Lookups funktionieren bei dnsmasq automatisch für alle Einträge aus /etc/hosts. Nach dem Eintragen von nameserver 127.0.0.1 in /etc/resolv.conf klappt auch ping meinserver.local ohne das @127.0.0.1.

AUFGABE 15.3 Eigene dnsmasq-Konfigurationsdatei erstellen

Du legst eine saubere eigene Konfiguration an und beobachtest dnsmasq live beim Arbeiten.

🖥️ Auf dem Server – per SSH eingeloggt
1
Erstelle die Datei /etc/dnsmasq.d/meinetz.conf mit sudo nano /etc/dnsmasq.d/meinetz.conf. Trage ein: deine Netzwerkschnittstelle (interface=eth0 oder den richtigen Namen), bind-interfaces, zwei Upstream-Server (server=1.1.1.1 und server=8.8.8.8), cache-size=1000 und log-queries.
2
Prüfe die Syntax bevor du neustartst: dnsmasq --test. Du solltest "dnsmasq: syntax check OK." lesen. Bei Fehlern: Konfiguration korrigieren und nochmal prüfen.
3
Starte dnsmasq neu: sudo systemctl restart dnsmasq. Prüfe den Status: sudo systemctl status dnsmasq.
4
Öffne das Live-Log in einem zweiten Terminal: sudo journalctl -u dnsmasq -f. Lass dieses Terminal offen.
5
Führe im ersten Terminal mehrere DNS-Anfragen aus: dig github.com @127.0.0.1, dig ubuntu.com @127.0.0.1, dann dieselben nochmals. Beobachte im Log wie "forwarded" und "cached" wechseln.
Lösungshinweise anzeigen

dnsmasq --test gibt "dnsmasq: syntax check OK." aus, wenn die Konfiguration syntaktisch korrekt ist. Im Live-Log siehst du bei der ersten Anfrage "forwarded github.com to 1.1.1.1" – die Anfrage geht nach außen. Bei der zweiten Anfrage erscheint "cached github.com is ..." – der Wert kommt aus dem Cache.

Alle Dateien unter /etc/dnsmasq.d/ werden automatisch eingelesen. Trenne verschiedene Bereiche sauber: eine Datei für Hosts, eine für DHCP, eine für Forwarding.

Modul 165 Unterrichtseinheiten

Datenbank-Administration

Datenbanken sind das Gedächtnis deiner Webanwendungen. In diesem Modul lernst du, MariaDB zu installieren, abzusichern und zu verwalten -- Benutzer anlegen, SQL-Abfragen schreiben, Backups erstellen und die Datenbank für den Einsatz mit Webanwendungen vorbereiten.

Voraussetzung: Modul 06 (APT) Voraussetzung: Modul 13 (Webserver) MariaDB · SQL · mysqldump · Benutzerrechte

In diesem Modul arbeitest du ausschließlich auf dem Server -- alle Befehle, alle SQL-Abfragen, alle Konfigurationsdateien. Du verbindest dich zuerst per SSH (Modul 02) mit deinem Server und führst dann dort alles aus:

💻 Dein Rechner

Hier öffnest du nur das Terminal und verbindest dich per SSH auf den Server. Sonst nichts.

🖥️ Server

Alle Befehle dieses Moduls laufen hier -- nach dem SSH-Login.

Was ist eine Datenbank?

Eine Datenbank ist wie eine geordnete Werkstatt-Kartei: Jeder Eintrag hat seinen festen Platz, kann schnell gefunden und gezielt geändert werden. Der Datenbankserver (MariaDB oder MySQL) ist der Archivar -- er verwaltet alle Daten, nimmt Anfragen entgegen und liefert Ergebnisse zurück.

BegriffErklärungWerkstatt-Analogie
DatenbankSammlung zusammengehöriger TabellenDer ganze Aktenschrank
TabelleStrukturierte Daten mit Spalten und ZeilenEin Schubfach mit Karteikarten
Spalte (Column)Definiert den Datentyp (Name, Datum, Betrag…)Feld auf der Karteikarte
Zeile (Row)Ein einzelner DatensatzEine ausgefüllte Karteikarte
SQLAbfragesprache für DatenbankenDie Sprache des Archivars
Primary KeyEindeutige ID pro Zeile -- nie doppeltDie Karteinummer
💡 MariaDB vs. MySQL vs. PostgreSQL

MariaDB ist eine quelloffene Abspaltung von MySQL -- die Befehle sind nahezu identisch. Auf Debian/Ubuntu ist MariaDB der Standard. PostgreSQL ist eine weitere verbreitete Alternative, häufig für komplexere Anwendungen (Django, GIS-Daten). Für WordPress, Nextcloud und die meisten PHP-Anwendungen: MariaDB. Für Python-Projekte: oft PostgreSQL.

MerkmalMariaDB / MySQLPostgreSQL
VerbreitungSehr hoch (WordPress, Nextcloud)Hoch (Django, Ruby on Rails)
EinstiegEinfach, gut dokumentiertEtwas steiler, sehr mächtig
Shell-Befehlmysqlpsql
Backup-Toolmysqldumppg_dump
Standard-Port33065432
MariaDB installieren und absichern
🖥️ Auf dem Server -- du bist per SSH eingeloggt

Zuerst installierst du MariaDB und stellst sicher, dass der Dienst läuft und beim Systemstart automatisch startet.

MariaDB installieren (Bash-Shell)
sudo apt update
sudo apt install mariadb-server mariadb-client

# Dienststatus prüfen -- sollte "active (running)" zeigen:
sudo systemctl status mariadb

# Autostart beim Hochfahren aktivieren:
sudo systemctl enable mariadb

Nach der Installation läuft der Sicherheits-Assistent. Führe ihn immer sofort nach der Installation aus -- er setzt ein Root-Passwort, entfernt Test-Datenbanken und sperrt anonyme Zugriffe:

MariaDB absichern (Bash-Shell)
sudo mariadb-secure-installation

# Beantworte die Fragen so:
# Enter current password for root: [Enter drücken -- noch kein Passwort]
# Switch to unix_socket authentication? → n
# Change the root password? → y → [sicheres Passwort eingeben und merken]
# Remove anonymous users? → y
# Disallow root login remotely? → y
# Remove test database? → y
# Reload privilege tables? → y
🚨 Root-Passwort sicher aufbewahren

Das MariaDB-Root-Passwort ist nicht das Linux-Root-Passwort -- es ist ein separates Passwort nur für die Datenbank. Notiere es an einem sicheren Ort. Du brauchst es für Backups mit mysqldump -u root -p und für die Benutzerverwaltung.

💡 unix_socket vs. Passwort-Authentifizierung

MariaDB bietet zwei Methoden für den Root-Zugang: unix_socket (Zugriff nur als Linux-Root via sudo mysql, kein Datenbankpasswort nötig) oder ein eigenes Datenbankpasswort. Beide Methoden sind sicher. Wir wählen ein Passwort, weil es für externe Tools wie mysqldump -u root -p benötigt wird. Auf einem reinen CLI-Server ohne solche Tools wäre unix_socket die elegantere Wahl.

Die MariaDB-Shell -- Verbinden und Grundbefehle

MariaDB hat eine eigene Kommandozeile. Du öffnest sie aus der Bash-Shell heraus und befindest dich dann im MariaDB-Prompt. Die beiden Eingabeumgebungen sehen unterschiedlich aus -- damit du immer weißt, wo du bist:

🖥️ Auf dem Server -- Bash-Shell

Mit diesen Befehlen öffnest du die MariaDB-Shell aus der Bash heraus:

MariaDB-Shell öffnen (Bash-Shell)
# Als Linux-Root verbinden (unix_socket -- ohne Datenbankpasswort):
sudo mysql

# Als Root mit Datenbankpasswort verbinden:
mysql -u root -p

# Als Anwendungsbenutzer direkt in eine bestimmte Datenbank:
mysql -u werkstatt_app -p werkstatt
🖥️ Auf dem Server -- MariaDB-Prompt (nach dem Login)

Sobald du eingeloggt bist, siehst du: MariaDB [(none)]>. SQL-Befehle enden immer mit einem Semikolon ;. Mit EXIT; verlässt du die Shell und kommst zurück in die Bash.

Grundbefehle im MariaDB-Prompt
-- Alle Datenbanken anzeigen:
SHOW DATABASES;

-- In eine Datenbank wechseln:
USE werkstatt;

-- Alle Tabellen der aktiven Datenbank anzeigen:
SHOW TABLES;

-- Tabellenstruktur anzeigen:
DESCRIBE kunden;

-- Aktiven Benutzer und gewählte Datenbank prüfen:
SELECT USER(), DATABASE();

-- Shell verlassen (zurück zur Bash):
EXIT;
🧠 SQL-Befehle in Großbuchstaben -- Konvention, keine Pflicht

SQL-Schlüsselwörter wie SELECT, FROM oder WHERE werden traditionell in Großbuchstaben geschrieben -- das hilft, sie von Tabellen- und Spaltennamen zu unterscheiden. MariaDB ist nicht case-sensitive: select * from kunden; funktioniert genauso.

Datenbank und Tabellen erstellen
🖥️ Auf dem Server -- MariaDB-Prompt

Erstelle eine Datenbank mit dem richtigen Zeichensatz (utf8mb4 unterstützt alle Zeichen inklusive Umlaute und Sonderzeichen), dann eine Tabelle darin.

Datenbank und Tabelle erstellen (MariaDB-Prompt)
-- Datenbank erstellen mit UTF-8-Zeichensatz:
CREATE DATABASE werkstatt
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

-- Datenbank auswählen:
USE werkstatt;

-- Tabelle erstellen:
CREATE TABLE kunden (
  id       INT AUTO_INCREMENT PRIMARY KEY,
  name     VARCHAR(100) NOT NULL,
  email    VARCHAR(150),
  telefon  VARCHAR(30),
  erstellt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Tabellenstruktur prüfen:
DESCRIBE kunden;

-- Datenbank löschen (VORSICHT -- unwiderruflich!):
DROP DATABASE test_db;
DatentypVerwendungBeispiel
INTGanze Zahlenid, Alter, Menge
VARCHAR(n)Text bis n ZeichenName, E-Mail, Telefon
TEXTLanger Text ohne LängenlimitBeschreibungen, Notizen
DECIMAL(m,d)Dezimalzahlen mit d NachkommastellenPreise: DECIMAL(10,2)
DATEDatum (ohne Uhrzeit)Geburtstag, Termin
TIMESTAMPDatum und Uhrzeit kombiniertErstell- und Änderungszeit
BOOLEANWahr/Falsch (intern TINYINT 0/1)aktiv, bezahlt
CRUD -- Daten einfügen, lesen, ändern und löschen

Die vier Grundoperationen einer Datenbank nennt man CRUD: Create (INSERT), Read (SELECT), Update (UPDATE), Delete (DELETE). Mit diesen vier Befehlen erledigst du 90 % der täglichen Datenbankarbeit.

🖥️ Auf dem Server -- MariaDB-Prompt, Datenbank werkstatt aktiv (USE werkstatt;)
CRUD-Operationen (MariaDB-Prompt)
-- CREATE: Daten einfügen:
INSERT INTO kunden (name, email, telefon)
  VALUES ('Max Mustermann', 'max@werkstatt.de', '0171-1234567');

INSERT INTO kunden (name, email, telefon)
  VALUES ('Anna Schmidt', 'anna@werkstatt.de', '0172-9876543');

-- READ: Alle Datensätze abfragen:
SELECT * FROM kunden;

-- READ: Nur bestimmte Spalten und mit Filter:
SELECT name, email FROM kunden
  WHERE name LIKE '%Muster%';

-- UPDATE: Einen Datensatz ändern:
UPDATE kunden
  SET telefon = '0173-5555555'
  WHERE id = 1;

-- DELETE: Einen Datensatz löschen:
DELETE FROM kunden
  WHERE id = 2;
🚨 UPDATE und DELETE immer mit WHERE!

Ein DELETE FROM kunden; ohne WHERE-Klausel löscht alle Datensätze sofort und unwiderruflich. Ein UPDATE kunden SET name='Test'; ohne WHERE überschreibt alle Namen in der Tabelle. Teste dein WHERE immer zuerst mit einem SELECT, bevor du UPDATE oder DELETE ausführst.

🤖
KI-Tipp: SQL-Abfragen erstellen lassen

Du brauchst eine komplexere SQL-Abfrage? Beschreibe dein Schema und was du willst -- die KI schreibt das SQL. Beispiel: „Ich habe eine Tabelle 'kunden' mit den Spalten id, name, email, ort und umsatz (DECIMAL). Schreibe mir eine SQL-Abfrage, die alle Kunden aus Hamburg mit einem Umsatz über 5000 Euro, sortiert nach Umsatz absteigend, anzeigt."

Benutzer anlegen, Berechtigungen und Sicherheit

Wie bei Linux-Benutzern gilt auch bei Datenbanken: Jede Anwendung bekommt ihren eigenen Datenbankbenutzer -- mit nur den Rechten, die sie wirklich braucht. Deine WordPress-Installation braucht niemals Root-Rechte auf der Datenbank.

🖥️ Auf dem Server -- MariaDB-Prompt (als Root eingeloggt)
Datenbankbenutzer verwalten (MariaDB-Prompt)
-- Benutzer erstellen (nur lokaler Zugriff):
CREATE USER 'werkstatt_app'@'localhost'
  IDENTIFIED BY 'S!ch3res_Passwort';

-- Alle Rechte auf eine bestimmte Datenbank vergeben:
GRANT ALL PRIVILEGES ON werkstatt.* TO 'werkstatt_app'@'localhost';

-- Nur Leserecht vergeben (z.B. für Monitoring):
GRANT SELECT ON werkstatt.* TO 'leser'@'localhost';

-- Rechte sofort anwenden:
FLUSH PRIVILEGES;

-- Rechte eines Benutzers anzeigen:
SHOW GRANTS FOR 'werkstatt_app'@'localhost';

-- Benutzer löschen:
DROP USER 'werkstatt_app'@'localhost';
RechtBedeutungTypischer Einsatz
ALL PRIVILEGESAlle Rechte auf die DatenbankAnwendungs-User (WordPress, Nextcloud)
SELECTNur lesenReporting, Monitoring
SELECT, INSERT, UPDATELesen, Einfügen, ÄndernAnwendungen ohne Löschrecht
SELECT, INSERT, UPDATE, DELETEVollständiges CRUDStandard-Webanwendung

Remote-Zugriff absichern

Standardmäßig lauscht MariaDB nur auf 127.0.0.1 -- also nur für lokale Verbindungen auf dem Server selbst. Das ist die richtige Einstellung. Wenn du von deinem Rechner aus auf die Datenbank zugreifen musst, nutze immer einen SSH-Tunnel (Modul 02) statt den Port direkt zu öffnen.

🖥️ Auf dem Server -- Bash-Shell
Bind-Adresse und Port prüfen (Bash-Shell)
# Prüfen, auf welcher Adresse MariaDB lauscht:
sudo ss -tulpn | grep mysql
# Ergebnis: tcp LISTEN 0 80 127.0.0.1:3306 -- das ist korrekt

# Konfigurationsdatei, falls du die Bind-Adresse prüfen willst:
grep bind-address /etc/mysql/mariadb.conf.d/50-server.cnf
🚨 Port 3306 niemals direkt ins Internet öffnen

Öffne den MariaDB-Port 3306 niemals in der Firewall für Internetzugang. Datenbanken sind ein beliebtes Angriffsziel. Wenn du von deinem Rechner auf die Datenbank zugreifen musst, nutze einen SSH-Tunnel: ssh -L 3306:127.0.0.1:3306 admin@dein-server -- dann erreichst du die Datenbank sicher über localhost:3306 auf deinem Rechner, ohne Port 3306 zu öffnen.

Datenbankbenutzer für Remote-Zugriff immer auf eine feste IP beschränken: 'benutzer'@'10.0.0.5' statt 'benutzer'@'%' (% = alle IPs -- gefährlich!).

Backups mit mysqldump

Datenbanken sind meistens das Wertvollste auf dem Server -- der Code lässt sich neu installieren, aber Kundendaten nicht. Lerne das Sichern und Wiederherstellen jetzt -- bevor du es brauchst.

🖥️ Auf dem Server -- Bash-Shell (nicht der MariaDB-Prompt!)

mysqldump wird aus der normalen Bash-Shell aufgerufen -- nicht aus dem MariaDB-Prompt. Es erstellt eine SQL-Textdatei mit allen Befehlen, die die Datenbank vollständig wiederherstellen.

Datenbank-Backups erstellen und wiederherstellen (Bash-Shell)
# Einzelne Datenbank sichern:
mysqldump -u root -p werkstatt > werkstatt_backup.sql

# Alle Datenbanken sichern:
mysqldump -u root -p --all-databases > alle_dbs_backup.sql

# Komprimiert sichern (spart Speicherplatz):
mysqldump -u root -p werkstatt | gzip > werkstatt_backup.sql.gz

# Backup wiederherstellen (Datenbank muss vorher existieren!):
mysql -u root -p werkstatt < werkstatt_backup.sql

# Komprimiertes Backup wiederherstellen:
gunzip -c werkstatt_backup.sql.gz | mysql -u root -p werkstatt
🧠 Automatische tägliche Backups

Kombiniere mysqldump mit einem Cron-Job (Modul 22), damit die Datenbank täglich automatisch gesichert wird. Das Backup-Skript sollte alte Dateien nach z.B. 14 Tagen löschen, damit die Festplatte nicht volläuft. Ergänze den Dateinamen mit einem Zeitstempel: mysqldump ... > werkstatt_$(date +%Y%m%d).sql

Ausblick: Datenbankverbindung aus PHP

In Modul 17 (LAMP-Stack) lernst du, wie du aus PHP eine Verbindung zur Datenbank herstellst. Hier ein kurzer Vorgeschmack -- damit du siehst, wie Webserver, PHP und Datenbank zusammenarbeiten:

🖥️ Auf dem Server -- PHP-Datenbankverbindung (Vorschau auf Modul 17)
PHP-Verbindung zu MariaDB
<?php
// Verbindungsdaten für die Datenbank:
$host     = 'localhost';
$dbname   = 'werkstatt';
$user     = 'werkstatt_app';
$password = 'S!ch3res_Passwort';

// PDO-Verbindung aufbauen (empfohlene Methode):
$pdo = new PDO(
  "mysql:host={$host};dbname={$dbname};charset=utf8mb4",
  $user,
  $password
);

// Alle Kunden abrufen:
$stmt    = $pdo->query("SELECT * FROM kunden");
$kunden  = $stmt->fetchAll();

Python-Anwendungen verwenden das Paket mysql-connector-python -- das Prinzip ist dasselbe: Verbindung aufbauen, SQL-Abfrage schicken, Ergebnisse verarbeiten.

🤖
KI-Tipp: Datenbankschema entwerfen lassen

Eine KI kann dir das komplette Datenbankschema für dein Projekt entwerfen. Beschreibe was du verwalten willst: „Ich baue eine Webanwendung für eine Kfz-Werkstatt. Ich brauche Tabellen für Kunden, Fahrzeuge und Reparaturaufträge. Erstelle mir die CREATE TABLE-Befehle mit sinnvollen Spalten, Datentypen und Fremdschlüssel-Beziehungen (Foreign Keys) für MariaDB."

Praxisaufgaben
AUFGABE 16.1 MariaDB installieren und absichern

Du installierst MariaDB auf deinem Server und führst die Grundabsicherung durch. Am Ende hast du eine laufende, gesicherte Datenbank.

🖥️ Alle Schritte auf dem Server -- verbinde dich zuerst per SSH
1
Installiere MariaDB: sudo apt update && sudo apt install mariadb-server mariadb-client
2
Prüfe den Dienststatus: sudo systemctl status mariadb. Du solltest "active (running)" sehen.
3
Führe den Sicherheits-Assistenten aus: sudo mariadb-secure-installation. Setze ein starkes Root-Passwort und beantworte alle Fragen mit der empfohlenen Antwort aus dem Modul.
4
Verbinde dich mit der Datenbank: sudo mysql. Du siehst jetzt den MariaDB-Prompt.
5
Zeige alle Datenbanken an: SHOW DATABASES; -- du solltest information_schema, mysql und performance_schema sehen, aber keine test-Datenbank mehr.
6
Verlasse die Shell wieder mit: EXIT;
Lösungshinweise anzeigen

sudo systemctl status mariadb zeigt "Active: active (running) since...". Wenn der Dienst nicht läuft: sudo systemctl start mariadb.

Nach mariadb-secure-installation ist die test-Datenbank weg. SHOW DATABASES; listet nur noch die drei System-Datenbanken. Prüfe auch: sudo systemctl is-enabled mariadb sollte "enabled" zurückgeben.

AUFGABE 16.2 Datenbank, Tabelle und CRUD-Operationen

Du erstellst eine Datenbank für eine fiktive Werkstatt, legst eine Kundentabelle an und übst alle vier CRUD-Operationen.

🖥️ Auf dem Server -- öffne die MariaDB-Shell mit sudo mysql
1
Erstelle die Datenbank: CREATE DATABASE werkstatt CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
2
Wechsle in die Datenbank: USE werkstatt;
3
Erstelle die Tabelle kunden mit den Spalten id (INT AUTO_INCREMENT PRIMARY KEY), name (VARCHAR(100) NOT NULL), email (VARCHAR(150)) und erstellt (TIMESTAMP DEFAULT CURRENT_TIMESTAMP).
4
Füge mindestens drei Datensätze ein: INSERT INTO kunden (name, email) VALUES ('Max Mustermann', 'max@test.de');
5
Lies alle Daten ab: SELECT * FROM kunden; und filtere dann nach einer bestimmten id: SELECT name FROM kunden WHERE id = 2;
6
Ändere eine E-Mail-Adresse mit UPDATE und lösche danach einen Datensatz mit DELETE -- immer mit WHERE!
Lösungshinweise anzeigen

Die Ausgabe von SELECT * FROM kunden; zeigt alle Zeilen mit automatisch vergebenen IDs und dem automatisch gesetzten Zeitstempel in "erstellt".

Prüfe nach dem DELETE mit SELECT COUNT(*) FROM kunden; ob die Anzahl gesunken ist. Mit DESCRIBE kunden; siehst du jederzeit die Tabellenstruktur.

AUFGABE 16.3 Datenbankbenutzer anlegen und Rechte vergeben

Du erstellst einen dedizierten Datenbankbenutzer für eine Webanwendung -- mit genau den Rechten, die nötig sind, und nicht mehr.

🖥️ Auf dem Server -- öffne die MariaDB-Shell als Root: sudo mysql
1
Erstelle einen neuen Benutzer: CREATE USER 'werkstatt_app'@'localhost' IDENTIFIED BY 'TestPasswort123!';
2
Vergib alle Rechte auf die werkstatt-Datenbank: GRANT ALL PRIVILEGES ON werkstatt.* TO 'werkstatt_app'@'localhost';
3
Wende die Rechte an: FLUSH PRIVILEGES; und prüfe dann: SHOW GRANTS FOR 'werkstatt_app'@'localhost';
4
Verlasse die Shell: EXIT;
5
Teste den neuen Benutzer: mysql -u werkstatt_app -p werkstatt -- du solltest in die Datenbank kommen. Prüfe mit SHOW DATABASES; -- du siehst nur werkstatt, nicht die System-Datenbanken.
Lösungshinweise anzeigen

SHOW GRANTS zeigt: GRANT ALL PRIVILEGES ON werkstatt.* TO 'werkstatt_app'@'localhost'. Der Login mit dem neuen Benutzer funktioniert, aber der Zugriff auf andere Datenbanken wie "mysql" wird verweigert -- genau so soll es sein.

AUFGABE 16.4 Backup erstellen und wiederherstellen

Du sicherst die werkstatt-Datenbank mit mysqldump und stellst sie in einer neuen Testdatenbank wieder her -- so übst du den kompletten Backup-Restore-Zyklus.

🖥️ Auf dem Server -- in der Bash-Shell (nicht im MariaDB-Prompt)
1
Erstelle ein Backup: mysqldump -u root -p werkstatt > /tmp/werkstatt_backup.sql
2
Prüfe den Inhalt: head -30 /tmp/werkstatt_backup.sql -- du siehst SQL-Befehle (CREATE TABLE, INSERT INTO).
3
Erstelle eine leere Zieldatenbank für die Wiederherstellung: Öffne die MariaDB-Shell mit sudo mysql, dann: CREATE DATABASE werkstatt_restore CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; und EXIT;
4
Stelle das Backup wieder her: mysql -u root -p werkstatt_restore < /tmp/werkstatt_backup.sql
5
Prüfe das Ergebnis: Öffne die MariaDB-Shell, dann: USE werkstatt_restore; SELECT * FROM kunden; -- die Daten sollten identisch mit der Original-Datenbank sein. Räume danach auf: DROP DATABASE werkstatt_restore;
Lösungshinweise anzeigen

Die Backup-Datei beginnt mit Kommentarzeilen (-- MariaDB dump...) gefolgt von CREATE TABLE- und INSERT INTO-Befehlen. Die Wiederherstellung schlägt fehl, wenn die Zieldatenbank noch nicht existiert.

Nach der Wiederherstellung liefert SELECT * FROM kunden; in werkstatt_restore dieselben Zeilen wie in der Originaldatenbank. Das beweist: das Backup ist vollständig und funktioniert.

Modul 174 Unterrichtseinheiten

LAMP-Stack & PHP-FPM

LAMP ist wie eine vollständig eingerichtete Werkstatt: Linux ist die Halle, Apache der Empfang, MariaDB das Lager und PHP der Mechaniker. In diesem Modul baust du den Stack Schritt für Schritt auf – von der PHP-Installation bis zur ersten dynamischen Seite mit Datenbankanbindung.

Voraussetzung: Modul 13 Voraussetzung: Modul 16 PHP-FPM · Nginx · PDO · php.ini
Kontext: Alles läuft auf dem Server

In diesem Modul arbeitest du ausschließlich auf dem Server – du bist bereits per SSH eingeloggt (Modul 02). Alle Befehle, Konfigurationsdateien und PHP-Skripte liegen auf dem Server, nicht auf deinem eigenen Rechner.

🖥️ Server

Alle Befehle dieses Moduls laufen auf dem Server – nach dem SSH-Login.

Was ist der LAMP-Stack?

LAMP steht für vier Komponenten, die zusammen eine vollständige Webserver-Umgebung bilden. Jede hat eine klare Aufgabe – wie in einer gut organisierten Werkstatt:

BuchstabeKomponenteAufgabePaket (Debian/Ubuntu)
LLinuxDas Betriebssystem – die Halle
AApache (oder Nginx)Webserver – der Empfang, leitet Anfragen weiterapache2 / nginx
MMariaDB/MySQLDatenbank – das Lager, speichert allesmariadb-server
PPHPSkriptsprache – der Mechaniker, verarbeitet Logikphp-fpm
💡 LAMP vs. LEMP

Neben LAMP gibt es LEMP – dasselbe, aber mit Nginx statt Apache. Nginx ist schlanker und performanter bei vielen gleichzeitigen Verbindungen. In diesem Modul arbeitest du mit Nginx und PHP-FPM: das ist die empfohlene Variante für neue Projekte und lässt sich flexibel einsetzen.

PHP-FPM installieren

PHP-FPM (FastCGI Process Manager) ist der moderne Weg, PHP zu betreiben. Statt PHP direkt in den Webserver zu laden, läuft PHP-FPM als eigener Dienst. Das ist schneller, sicherer und lässt sich besser konfigurieren.

🖥️ Auf dem Server

PHP-FPM und die wichtigsten Erweiterungen installieren. Die PHP-Version kann sich unterscheiden – prüfe mit apt show php-fpm, welche Version installiert wird.

PHP-FPM und Extensions installieren
sudo apt update
sudo apt install php-fpm php-mysql php-xml php-mbstring php-curl php-zip php-gd php-intl

# PHP-Version prüfen:
php -v

# PHP-FPM-Status prüfen (Version anpassen, z.B. php8.3-fpm):
sudo systemctl status php8.3-fpm
ExtensionWozu?
php-mysqlVerbindung zu MariaDB/MySQL (PDO)
php-xmlXML verarbeiten (RSS, APIs)
php-mbstringUmlaute und Sonderzeichen korrekt verarbeiten
php-curlHTTP-Anfragen aus PHP heraus senden
php-gdBilder verarbeiten und skalieren
php-zipZIP-Dateien erzeugen und entpacken
Nginx + PHP-FPM konfigurieren

Bei Nginx übernimmt PHP-FPM die Verarbeitung von PHP-Dateien. Nginx selbst kann kein PHP ausführen – es reicht Anfragen per FastCGI an PHP-FPM weiter. Das Stichwort in der Nginx-Konfiguration ist fastcgi_pass.

🖥️ Auf dem Server

Nginx installieren, falls noch nicht vorhanden (aus Modul 13 eventuell schon vorhanden), und eine Site-Konfiguration für PHP anlegen:

Nginx installieren
sudo apt install nginx
sudo systemctl enable nginx
sudo systemctl start nginx

Konfigurationsdatei für die neue PHP-Site erstellen:

/etc/nginx/sites-available/meine-seite.conf
server {
    listen 80;
    server_name meine-seite.local;
    root /var/www/meine-seite;
    index index.php index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    # PHP-Anfragen an PHP-FPM weiterleiten:
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }

    # .htaccess-Dateien nicht ausliefern:
    location ~ /\.ht {
        deny all;
    }
}

Webverzeichnis erstellen, Site aktivieren und Nginx neu laden:

sudo mkdir -p /var/www/meine-seite
sudo chown -R www-data:www-data /var/www/meine-seite

# Site aktivieren:
sudo ln -s /etc/nginx/sites-available/meine-seite.conf /etc/nginx/sites-enabled/

# Konfiguration testen:
sudo nginx -t

# Nginx neu laden:
sudo systemctl reload nginx
🧠 Was ist ein Unix-Socket?

fastcgi_pass unix:/run/php/php8.3-fpm.sock – der .sock-Pfad ist ein Unix-Socket: eine direkte interne Verbindung zwischen Nginx und PHP-FPM auf demselben Server. Das ist schneller als eine TCP-Verbindung über 127.0.0.1:9000.

PHP testen und phpinfo() sofort wieder löschen

🖥️ Auf dem Server

Teste, ob PHP-FPM korrekt funktioniert. Diese Datei wird nur kurz zum Testen angelegt und danach sofort gelöscht.

PHP-Testdatei anlegen
echo '<?php phpinfo(); ?>' | sudo tee /var/www/meine-seite/info.php

# Im Browser aufrufen: http://SERVER-IP/info.php
# Unter "Server API" sollte "FPM/FastCGI" stehen

# SOFORT DANACH LÖSCHEN:
sudo rm /var/www/meine-seite/info.php
🚨 phpinfo() sofort löschen!

Die phpinfo()-Seite verrät die genaue PHP-Version, alle geladenen Module, Dateipfade und Serverkonfiguration. Das ist ein Willkommensschild für Angreifer. Lass diese Datei nie dauerhaft auf dem Server liegen.

PHP-FPM Pool-Konfiguration

PHP-FPM verwaltet Prozesse in sogenannten Pools. Jeder Pool ist ein Satz laufender PHP-Prozesse. Die Standard-Pool-Konfiguration liegt unter /etc/php/8.3/fpm/pool.d/www.conf.

🖥️ Auf dem Server
/etc/php/8.3/fpm/pool.d/www.conf – wichtige Einstellungen
; Unter welchem Benutzer PHP-Prozesse laufen:
user = www-data
group = www-data

; Socket-Pfad (muss mit Nginx-Konfiguration übereinstimmen):
listen = /run/php/php8.3-fpm.sock

; Wie PHP-FPM Prozesse verwaltet:
pm = dynamic

; Maximale Anzahl gleichzeitiger PHP-Prozesse:
pm.max_children = 10

; Beim Start bereits gestartete Prozesse:
pm.start_servers = 2

; Mindestanzahl freier Prozesse:
pm.min_spare_servers = 1

; Maximale Anzahl freier Prozesse:
pm.max_spare_servers = 3

Nach Änderungen PHP-FPM neu starten:

sudo systemctl restart php8.3-fpm
💡 pm = dynamic

pm = dynamic bedeutet: PHP-FPM startet eine variable Anzahl Prozesse je nach Last. Für einen kleinen Server ist das ideal – es werden nicht dauerhaft viele Prozesse offen gehalten. Für stark frequentierte Server gibt es pm = static (immer dieselbe feste Anzahl).

MariaDB mit PHP verbinden: PDO

Aus Modul 16 kennst du bereits MariaDB. Jetzt verbindest du PHP über PDO (PHP Data Objects) mit der Datenbank. PDO ist der sichere, moderne Weg – er verhindert SQL-Injection-Angriffe durch sogenannte Prepared Statements.

🚨 Niemals Benutzereingaben direkt in SQL einbauen!

Schreibe nie: $sql = "SELECT * FROM users WHERE name = '$_POST[name]'". Das ist eine SQL-Injection-Lücke – ein Angreifer kann damit deine gesamte Datenbank auslesen oder löschen. Verwende immer PDO mit Prepared Statements (Platzhalter ? im SQL-Befehl).

🖥️ Auf dem Server

Eine PHP-Datei mit PDO-Verbindung anlegen. Diese Datei liegt auf dem Server im Webverzeichnis.

/var/www/meine-seite/db-test.php
<?php
// Datenbankverbindung per PDO herstellen
$host = 'localhost';
$db   = 'meine_db';
$user = 'db_benutzer';
$pass = 'geheimes_passwort';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$db;charset=utf8mb4", $user, $pass);
    // Fehler als Exceptions ausgeben (nur in der Entwicklung!)
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo "Verbindung erfolgreich!";
} catch (PDOException $e) {
    // Fehlermeldung in Produktion NICHT ausgeben – ins Log schreiben!
    error_log($e->getMessage());
    echo "Verbindungsfehler – Details im Serverlog.";
}
?>

Formular schreibt Daten sicher in die Datenbank

🖥️ Auf dem Server

Ein vollständiges Beispiel: ein Formular nimmt eine Eingabe entgegen und speichert sie sicher mit einem Prepared Statement.

/var/www/meine-seite/eintrag.php
<?php
$pdo = new PDO('mysql:host=localhost;dbname=meine_db;charset=utf8mb4', 'db_benutzer', 'passwort');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // Prepared Statement: ? ist Platzhalter, KEIN String-Einbetten
    $stmt = $pdo->prepare('INSERT INTO eintraege (name, nachricht) VALUES (?, ?)');
    $stmt->execute([$_POST['name'], $_POST['nachricht']]);
    echo "<p>Gespeichert!</p>";
}
?>
<form method="post">
  <input type="text" name="name" placeholder="Dein Name">
  <textarea name="nachricht"></textarea>
  <button type="submit">Speichern</button>
</form>
🧠 Warum Prepared Statements?

Der ?-Platzhalter in prepare() sorgt dafür, dass Benutzereingaben niemals als SQL-Code interpretiert werden. MariaDB bekommt die Daten getrennt vom SQL-Befehl – wie ein versiegelter Briefumschlag im Vergleich zu einer offenen Postkarte.

php.ini – Wichtige Einstellungen

Die php.ini steuert das Verhalten von PHP. Für PHP-FPM liegt sie unter /etc/php/8.3/fpm/php.ini. Nach jeder Änderung muss PHP-FPM neu gestartet werden.

🖥️ Auf dem Server
php.ini bearbeiten
sudo nano /etc/php/8.3/fpm/php.ini

# Nach Änderungen:
sudo systemctl restart php8.3-fpm
EinstellungStandardwertEmpfehlungBedeutung
upload_max_filesize2M64MMaximale Dateigröße beim Upload
post_max_size8M64MMaximale POST-Datenmenge gesamt
memory_limit128M256MRAM-Limit pro PHP-Prozess
max_execution_time3060–300Maximale Laufzeit eines Skripts (Sekunden)
display_errorsOnOff (Produktion)Fehler im Browser anzeigen – nur in der Entwicklung!
log_errorsOffOnFehler ins Serverlog schreiben
error_log/var/log/php_errors.logPfad zur Fehlerlog-Datei
⚠️ display_errors auf dem Produktionsserver

Wenn display_errors = On auf einem öffentlich erreichbaren Server steht, können Fehlermeldungen Datenbankpfade, Zugangsdaten und Codestruktur preisgeben. Auf dem Produktionsserver immer display_errors = Off und log_errors = On setzen.

Composer – Abhängigkeiten für PHP-Projekte

Composer ist das Werkzeug zum Einbinden externer PHP-Bibliotheken – vergleichbar mit apt für Pakete, aber für PHP-Code. Fast jedes moderne PHP-Projekt nutzt Composer.

🖥️ Auf dem Server
Composer installieren
# Composer herunterladen und global installieren:
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

# Testen:
composer --version

# Beispiel: eine Bibliothek in ein Projekt einbinden:
cd /var/www/meine-seite
composer require monolog/monolog
💡 Wann brauchst du Composer?

Für einfache PHP-Seiten brauchst du Composer noch nicht. Sobald du ein Framework oder fertige Bibliotheken (z.B. für E-Mail-Versand, PDF-Erzeugung, API-Clients) einsetzen willst, ist Composer der Standard-Weg. Er erzeugt eine composer.json-Datei mit allen Abhängigkeiten – ähnlich wie eine Teileliste in der Werkstatt.

🤖
KI-Tipp: PHP-Fehler und 502-Probleme lösen

PHP-Fehlermeldungen können kryptisch sein: Fatal error: Uncaught PDOException, Call to undefined function oder 502 Bad Gateway (Nginx kann PHP-FPM nicht erreichen). Kopiere die Fehlermeldung aus /var/log/php_errors.log oder /var/log/nginx/error.log und frag: „Ich bekomme diesen PHP-Fehler auf meinem Nginx/PHP-FPM-Server unter Ubuntu. Was bedeutet er und wie behebe ich ihn Schritt für Schritt?"

🤖
KI-Tipp: PDO-Verbindung und Datenbankabfragen

PDO-Verbindungen müssen je nach Datenbankstruktur angepasst werden. Zeig der KI deine Tabelle und frag: „Schreibe mir eine PHP-Funktion mit PDO, die sicher einen neuen Datensatz in diese Tabelle schreibt und einen bestehenden Eintrag anhand der ID aktualisiert. Benutze Prepared Statements."

Praxisaufgaben
AUFGABE 17.1 PHP-FPM installieren und mit Nginx verbinden

Du installierst PHP-FPM und richtest Nginx so ein, dass PHP-Anfragen korrekt verarbeitet werden. Am Ende siehst du die phpinfo()-Seite im Browser – und löschst sie sofort wieder.

🖥️ Alle Schritte auf dem Server – du bist per SSH eingeloggt
1
Installiere PHP-FPM und die MySQL-Extension: sudo apt install php-fpm php-mysql. Prüfe danach mit php -v die installierte Version.
2
Lege das Webverzeichnis an: sudo mkdir -p /var/www/meine-seite und setze den Besitzer: sudo chown -R www-data:www-data /var/www/meine-seite
3
Erstelle unter /etc/nginx/sites-available/meine-seite.conf eine Nginx-Konfiguration mit dem fastcgi_pass-Block aus dem Abschnitt oben. Passe den Socket-Pfad an deine PHP-Version an.
4
Aktiviere die Site: sudo ln -s /etc/nginx/sites-available/meine-seite.conf /etc/nginx/sites-enabled/. Teste mit sudo nginx -t und lade Nginx neu: sudo systemctl reload nginx
5
Erstelle die Testdatei: echo '<?php phpinfo(); ?>' | sudo tee /var/www/meine-seite/info.php. Rufe http://SERVER-IP/info.php im Browser auf. Lösche die Datei danach sofort: sudo rm /var/www/meine-seite/info.php
Lösungshinweise anzeigen

Unter „Server API" in der phpinfo()-Ausgabe muss FPM/FastCGI stehen – das bestätigt, dass Nginx die Anfragen korrekt an PHP-FPM weiterleitet. Falls du einen 502-Fehler siehst, stimmt der Socket-Pfad in der Nginx-Konfiguration nicht mit dem tatsächlichen PHP-FPM-Socket überein. Prüfe mit ls /run/php/, wie die Socket-Datei heißt.

AUFGABE 17.2 PDO-Verbindung zur Datenbank einrichten

Du verbindest PHP mit deiner MariaDB-Datenbank über PDO – sicher und ohne SQL-Injection-Risiko. Als Grundlage nutzt du eine Datenbank aus Modul 16 oder legst eine neue an.

🖥️ Alle Schritte auf dem Server
1
Melde dich in MariaDB an: sudo mysql. Erstelle eine neue Datenbank: CREATE DATABASE testdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
2
Erstelle einen Datenbankbenutzer: CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'SicheresPasswort123!'; und vergib Rechte: GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'localhost'; FLUSH PRIVILEGES; EXIT;
3
Erstelle im Webverzeichnis die Datei /var/www/meine-seite/db-test.php mit der PDO-Verbindung aus dem Modul-Beispiel. Passe Datenbankname, Benutzer und Passwort an.
4
Erstelle eine Tabelle: In MariaDB (sudo mysql testdb) führe aus: CREATE TABLE eintraege (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100), nachricht TEXT, erstellt TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
5
Erstelle /var/www/meine-seite/eintrag.php mit dem Formular-Beispiel. Teste das Formular im Browser und prüfe in MariaDB, ob der Eintrag gespeichert wurde: sudo mysql testdbSELECT * FROM eintraege;
Lösungshinweise anzeigen

Nach dem Absenden des Formulars solltest du „Gespeichert!" sehen. In MariaDB erscheint der neue Datensatz mit Zeitstempel. Ein häufiger Fehler: die PHP-Extension php-mysql ist nicht installiert – dann scheitert der PDO-Treiber. Prüfe mit php -m | grep pdo, ob PDO und pdo_mysql geladen sind.

AUFGABE 17.3 php.ini anpassen und Ergebnis prüfen

Du passt wichtige PHP-Einstellungen an und verifizierst, dass die Änderungen wirksam sind. Das Upload-Limit und das Fehler-Logging werden korrekt konfiguriert.

🖥️ Alle Schritte auf dem Server
1
Öffne die php.ini für PHP-FPM: sudo nano /etc/php/8.3/fpm/php.ini (Version ggf. anpassen). Suche mit Strg+W nach upload_max_filesize.
2
Setze diese Werte: upload_max_filesize = 32M, post_max_size = 32M, memory_limit = 256M, display_errors = Off, log_errors = On. Speichere mit Strg+O, beende mit Strg+X.
3
Starte PHP-FPM neu: sudo systemctl restart php8.3-fpm
4
Prüfe die aktiven Einstellungen: php -i | grep upload_max_filesize und php -i | grep memory_limit. Die neuen Werte sollten erscheinen.
Lösungshinweise anzeigen

php -i zeigt die aktuelle PHP-Konfiguration. Erscheinen die alten Werte, wurde entweder die falsche php.ini bearbeitet (es gibt mehrere – für CLI, FPM und Apache) oder PHP-FPM wurde nicht neu gestartet. Prüfe mit php --ini, welche Datei für die Kommandozeile gilt. Für den Webserver ist die FPM-Datei unter /etc/php/8.3/fpm/php.ini maßgeblich.

AUFGABE 17.4 PHP-FPM Pool-Status überwachen

Du aktivierst den PHP-FPM Status-Endpunkt und liest Laufzeitinformationen des Pools ab – nützlich, wenn die Webseite langsam wird oder Prozesse hängen.

🖥️ Alle Schritte auf dem Server
1
Öffne die Pool-Konfiguration: sudo nano /etc/php/8.3/fpm/pool.d/www.conf. Suche nach pm.status_path und entferne das Semikolon davor, sodass die Zeile lautet: pm.status_path = /status
2
Füge in die Nginx-Site-Konfiguration (/etc/nginx/sites-available/meine-seite.conf) vor der letzten schließenden Klammer einen neuen Block ein – öffne die Datei mit sudo nano und ergänze diesen Abschnitt: den Location-Block für /status mit fastcgi_pass auf den PHP-FPM-Socket und allow 127.0.0.1; deny all; zum Schutz.
3
Starte beide Dienste neu: sudo systemctl restart php8.3-fpm und sudo systemctl reload nginx
4
Ruf den Status lokal ab: curl http://127.0.0.1/status. Du siehst Informationen wie aktive Prozesse, Anfragen pro Sekunde und Pool-Name.
Lösungshinweise anzeigen

Die Ausgabe zeigt unter anderem active processes (aktuell arbeitende PHP-Prozesse) und total requests (Gesamtzahl aller Anfragen seit dem Start). Wenn active processes dauerhaft den Wert von max_children erreicht, ist der Pool ausgelastet – dann pm.max_children erhöhen oder Seiten-Caching einrichten.

Modul 183 Unterrichtseinheiten

Git – Versionskontrolle

Git ist dein digitales Reparaturprotokoll: jede Änderung wird festgehalten, du kannst jederzeit zu einem früheren Stand zurück. In diesem Modul lernst du die tägliche Arbeit mit Git – vom ersten Commit bis zum eigenen Server-Repository.

Voraussetzung: Modul 03 Commits · Branches · Merge Bare-Repo · Push · Pull
Bevor wir starten: Wo läuft Git?

Git läuft in diesem Modul primär auf deinem eigenen Rechner. Du versionierst Dateien lokal. Optional richtest du am Ende ein Bare-Repository auf dem Server ein – das ist dein privates Remote, auf das du deine Commits hochlädst. Ab jetzt markieren wir immer, wo ein Befehl ausgeführt wird:

💻 Dein Rechner

Hier läuft Git fast immer: git init, git add, git commit, git push – alles in deinem lokalen Terminal.

🖥️ Server

Nur für das Bare-Repository: du richtest es einmalig per SSH auf dem Server ein. Danach pushst du wieder vom eigenen Rechner.

Was ist Versionskontrolle?

Stell dir vor, du arbeitest an der Konfiguration eines Servers. Du änderst eine Zeile – und plötzlich startet der Dienst nicht mehr. Ohne Git musst du raten, was du verändert hast. Mit Git rewindest du einfach auf den letzten funktionierenden Stand.

Die Analogie aus der Werkstatt: Git ist wie ein lückenloses Reparaturprotokoll. Jeder Eingriff wird notiert – wer, wann, was. Du kannst jederzeit nachvollziehen, was sich geändert hat, und im Notfall zurückblättern.

💡 Git ≠ GitHub

Git ist das Werkzeug, das auf deinem Rechner läuft. GitHub (oder GitLab, Gitea) ist eine Plattform im Internet, die dein Git-Repository online speichert. Du kannst Git vollständig ohne GitHub nutzen – auch mit einem eigenen Server als Remote.

BegriffErklärungAnalogie
Repository (Repo)Projektordner mit vollständigem ÄnderungsverlaufAkte mit allen Protokollblättern
CommitGespeicherter Zustand zu einem ZeitpunktEintrag im Reparaturprotokoll
BranchParalleler EntwicklungszweigTestfahrt ohne das Original anzufassen
MergeZwei Branches zusammenführenTestergebnis ins Hauptprotokoll übernehmen
RemoteKopie des Repos auf einem anderen Rechner/ServerKopie der Akte beim Meister
PushLokale Commits zum Remote hochladenKopie abgeben
PullÄnderungen vom Remote herunterladenAktualisierte Kopie abholen
CloneKomplettes Repo von einem Remote herunterladenVollständige Akte kopieren
Git installieren und einrichten
💻 Auf deinem Rechner

Git installierst du einmalig. Danach richtest du deinen Namen und deine E-Mail-Adresse ein – diese Angaben landen in jedem Commit und sind Pflicht.

Git installieren (Debian/Ubuntu)
sudo apt install git

# Version prüfen:
git --version
Globale Konfiguration setzen
# Dein Name erscheint in jedem Commit -- einmalig setzen:
git config --global user.name "Max Mustermann"
git config --global user.email "max@example.com"

# Standard-Branch "main" statt "master":
git config --global init.defaultBranch main

# Konfiguration prüfen:
git config --list
Erstes Repository – der Basis-Workflow

Der tägliche Git-Workflow besteht aus drei Schritten: Änderungen vorbereiten (git add), speichern (git commit) und bei Bedarf hochladen (git push). Dazwischen prüfst du immer wieder den aktuellen Stand.

🧠 Die drei Bereiche von Git

Working Directory – deine Dateien, so wie sie gerade sind. Staging Area – hier sammelst du Änderungen mit git add, bevor du sie commitest. Repository – der dauerhafte Verlauf, den git commit schreibt. Wie beim Packen eines Pakets: erst einpacken (add), dann verschicken (commit).

💻 Auf deinem Rechner

Erstelle einen neuen Projektordner und initialisiere Git. Der Befehl git init legt einen versteckten Ordner .git/ an – dort speichert Git den gesamten Verlauf.

Repository erstellen und ersten Commit machen
mkdir mein-projekt
cd mein-projekt
git init

# Erste Datei anlegen:
echo "# Mein Projekt" > README.md

# Status prüfen -- zeigt unverfolgte Dateien:
git status

# Datei zum Staging-Bereich hinzufügen:
git add README.md

# Commit mit Nachricht erstellen:
git commit -m "Projekt gestartet: README hinzugefügt"

# Verlauf anzeigen:
git log --oneline

Ab jetzt läuft der Workflow immer gleich: Dateien ändern → git add .git commit -m "Was habe ich getan?".

Änderungen anzeigen und rückgängig machen
# Änderungen seit letztem Commit anzeigen:
git diff

# Nur gestagte Änderungen anzeigen:
git diff --staged

# Staging rückgängig machen (Datei bleibt geändert, aber nicht im nächsten Commit):
git restore --staged dateiname.txt

# Änderungen an einer Datei verwerfen (Vorsicht: unwiderruflich!):
git restore dateiname.txt
Branches – Änderungen sicher ausprobieren

Ein Branch ist ein isolierter Arbeitszweig. Du testest neue Konfigurationen oder Änderungen auf einem Branch, ohne den funktionierenden Hauptzweig (main) zu gefährden. Wenn alles klappt, führst du den Branch zusammen (Merge).

💻 Auf deinem Rechner

Branches anlegen, wechseln und zusammenführen:

Branches erstellen, wechseln und mergen
# Alle Branches anzeigen (* = aktueller Branch):
git branch

# Neuen Branch erstellen und dorthin wechseln:
git switch -c feature/neue-config

# Zurück zu main wechseln:
git switch main

# Feature-Branch in main mergen:
git merge feature/neue-config

# Branch nach dem Merge löschen (-d prüft, ob er bereits gemerged ist):
git branch -d feature/neue-config

# Verlauf mit Branch-Struktur anzeigen:
git log --oneline --graph
⚠️ Merge-Konflikte

Ein Merge-Konflikt entsteht, wenn dieselbe Stelle in zwei Branches unterschiedlich geändert wurde. Git markiert die Konfliktstellen mit <<<<<<< und >>>>>>> in der Datei. Du öffnest die Datei, entscheidest welche Version du behältst, entfernst die Markierungen und machst dann git add . und git commit.

.gitignore – Was nicht ins Repo gehört

Nicht jede Datei soll versioniert werden. Passwörter, API-Keys, temporäre Editor-Dateien und Logs gehören nicht ins Repository. Die Datei .gitignore im Projektordner legt fest, was Git ignorieren soll. Committe sie als eine der ersten Dateien im Projekt.

💻 Auf deinem Rechner

Lege die .gitignore-Datei im Projektordner an. Git liest sie automatisch beim nächsten git status.

.gitignore – typische Einträge
# Passwörter und Secrets -- NIEMALS ins Repo!
.env
*.key
*.pem
secrets/

# Editor-Hilfsdateien:
*.swp
*~
.vscode/

# Betriebssystem-Reste:
.DS_Store
Thumbs.db

# Log-Dateien:
*.log
/logs/

# Abhängigkeiten (werden über Paketmanager geladen):
node_modules/
vendor/
MusterWas wird ignoriert
.envDatei genau mit diesem Namen
*.logAlle Dateien mit Endung .log
/logs/Ordner "logs" direkt im Projektstamm
secrets/Ordner "secrets" an beliebiger Stelle im Projekt
*.pemAlle Zertifikatsdateien
🚨 Passwörter im Repo sind dauerhaft

Wenn du versehentlich ein Passwort oder einen API-Key commitest, reicht es nicht, die Datei danach zu löschen. Der Eintrag bleibt im Verlauf erhalten und ist jederzeit einsehbar. Wechsle sofort das Passwort oder den Key. Zum Bereinigen des Verlaufs gibt es git filter-repo – das ist aber aufwendig. Nutze .gitignore konsequent von Anfang an.

Bare-Repository auf dem Server einrichten

Du brauchst kein GitHub für ein Remote-Repository. Du kannst auf deinem eigenen Linux-Server ein sogenanntes Bare-Repository einrichten. Das ist ein Repo ohne Arbeitskopie – nur der reine Git-Verlauf. Dein Rechner pusht dorthin, und du kannst von jedem anderen Rechner pullen oder klonen.

🖥️ Auf dem Server – per SSH eingeloggt

Erstelle auf dem Server einen Ordner für das Bare-Repository. Die Konvention ist, Bare-Repos mit .git enden zu lassen – so erkennst du sofort, dass es kein normales Arbeitsverzeichnis ist.

Bare-Repository auf dem Server anlegen
# Ordner anlegen (im Home-Verzeichnis des Benutzers):
mkdir -p ~/repos/mein-projekt.git
cd ~/repos/mein-projekt.git

# Bare-Repository initialisieren:
git init --bare

# Kontrollausgabe: du siehst HEAD, config, objects/, refs/ -- kein src-Ordner
ls

Das Bare-Repo hat kein Working Directory – du siehst dort keine Projektdateien, nur Git-interne Strukturen. Das ist normal und gewollt. Verlasse den Server jetzt wieder:

exit
💻 Zurück auf deinem Rechner – jetzt verbindest du dein lokales Repo mit dem Server
💻 Auf deinem Rechner

Verbinde dein lokales Repository mit dem Bare-Repo auf dem Server und lade deinen ersten Stand hoch.

Remote verbinden und pushen
# Remote "origin" auf das Server-Repo zeigen lassen:
git remote add origin ssh://admin@192.168.1.50/home/admin/repos/mein-projekt.git

# Ersten Push durchführen (-u setzt den Upstream, danach reicht "git push"):
git push -u origin main

# Täglicher Push nach einem Commit:
git push

# Änderungen vom Server holen und mergen:
git pull

# Repo auf einem anderen Rechner vollständig herunterladen:
git clone ssh://admin@192.168.1.50/home/admin/repos/mein-projekt.git
⚠️ git push --force ist gefährlich

git push --force überschreibt den Verlauf auf dem Remote ohne Rücksicht auf vorhandene Commits. Im Alleinbetrieb selten nötig, im Team fast immer eine Katastrophe: andere verlieren ihre Arbeit. Nutze stattdessen git push --force-with-lease – das prüft zumindest, ob du den aktuellen Stand des Remotes kennst.

Nützliche Git-Befehle im Überblick
💻 Auf deinem Rechner

Diese Befehle brauchst du regelmäßig im Alltag, wenn etwas nicht wie geplant läuft:

Git-Werkzeugkasten
# Verlauf kompakt mit Branch-Struktur anzeigen:
git log --oneline --graph

# Letzten Commit rückgängig machen -- Änderungen bleiben erhalten:
git reset --soft HEAD~1

# Änderungen temporär wegspeichern (z.B. um schnell den Branch zu wechseln):
git stash
git stash pop    # Änderungen wieder zurückholen

# Einzelne Datei aus einem älteren Commit wiederherstellen:
# (abc1234 = Hash des Commits aus "git log --oneline")
git restore --source abc1234 server.conf

# Wer hat welche Zeile zuletzt geändert?
git blame server.conf

# Remote-Verbindungen anzeigen:
git remote -v
BefehlWas er tut
git statusAktuellen Stand anzeigen (was ist geändert, was ist gestaged)
git add .Alle Änderungen stagen
git commit -m "..."Commit mit Nachricht erstellen
git log --onelineVerlauf kompakt anzeigen
git diffUngestagete Änderungen anzeigen
git switch -c nameNeuen Branch anlegen und dorthin wechseln
git merge nameBranch in den aktuellen Branch mergen
git stashÄnderungen zwischenparken
git pushCommits zum Remote hochladen
git pullÄnderungen vom Remote holen und mergen
🤖
KI-Tipp: Git-Verlauf verstehen lassen

Die Ausgabe von git log --oneline --graph sieht für Einsteiger kryptisch aus. Kopiere sie und frag: „Erkläre mir diese git log Ausgabe auf Deutsch. Was bedeuten die Symbole, welcher Commit ist der neueste, und welche Branches gibt es?"

🤖
KI-Tipp: Merge-Konflikte lösen

Merge-Konflikte mit den <<<<<<<-Markierungen sind für Einsteiger verwirrend. Kopiere den Inhalt der Konflikt-Datei und frag: „Ich habe einen Git-Merge-Konflikt in dieser Datei. Erkläre mir, welche Version ich behalten soll, und zeige mir die fertige Datei ohne Konfliktmarkierungen."

Praxisaufgaben
AUFGABE 18.1 Erstes Repository anlegen und Commits machen

Du übst den grundlegenden Git-Workflow: Repository erstellen, Dateien tracken, Commits machen und den Verlauf lesen.

💻 Alle Schritte auf deinem Rechner im Terminal
1
Prüfe, ob Git installiert ist: git --version. Falls es fehlt: sudo apt install git. Richte Name und E-Mail ein: git config --global user.name "Dein Name" und git config --global user.email "du@example.com".
2
Erstelle einen neuen Ordner und initialisiere Git: mkdir git-uebung && cd git-uebung && git init. Prüfe mit ls -la – du solltest einen versteckten Ordner .git/ sehen.
3
Lege eine Datei an: echo "# Mein Übungsprojekt" > README.md. Prüfe den Status mit git status – die Datei erscheint als "untracked" (noch nicht verfolgt).
4
Stage und committe die Datei: git add README.md und dann git commit -m "Erster Commit: README angelegt".
5
Öffne die README.md in einem Editor und füge eine zweite Zeile hinzu. Prüfe die Änderung mit git diff und erstelle einen zweiten Commit mit einer aussagekräftigen Nachricht.
6
Zeige den Verlauf: git log --oneline. Du solltest zwei Commits sehen – der neueste steht oben.
Lösungshinweise anzeigen

git log --oneline zeigt z.B.: b4f1a2c README erweitert und darunter e9d3c1a Erster Commit: README angelegt. Jeder Commit hat einen eindeutigen Hash – die kurze Buchstaben-Zahlen-Kombination. Mit diesem Hash kannst du später auf jeden Zustand zurückspringen.

Falls git status nach dem Commit "nothing to commit, working tree clean" zeigt – perfekt. Das bedeutet, alle Änderungen sind gespeichert.

AUFGABE 18.2 Branch erstellen, mergen und .gitignore anlegen

Du übst Branches und schützt dein Repository davor, dass versehentlich Passwörter versioniert werden.

💻 Alle Schritte auf deinem Rechner – im selben git-uebung-Ordner wie Aufgabe 18.1
1
Erstelle einen neuen Branch und wechsle dorthin: git switch -c feature/config. Prüfe mit git branch – der Stern (*) zeigt deinen aktuellen Branch.
2
Erstelle eine Konfigurationsdatei: echo "port=8080" > server.conf. Stage und committe sie auf dem Feature-Branch: git add server.conf && git commit -m "server.conf hinzugefügt".
3
Wechsle zurück zu main: git switch main. Prüfe mit ls – die Datei server.conf ist verschwunden! Sie existiert nur auf dem Feature-Branch. Das ist kein Fehler – genau so soll es sein.
4
Merge den Branch: git merge feature/config. Prüfe erneut mit lsserver.conf ist jetzt in main angekommen. Lösche den Branch: git branch -d feature/config.
5
Lege eine .gitignore-Datei an: echo ".env" > .gitignore. Erstelle dann eine Testdatei: touch .env. Prüfe mit git status – die .env-Datei sollte nicht als "untracked" erscheinen. Committe dann die .gitignore selbst: git add .gitignore && git commit -m ".gitignore angelegt".
Lösungshinweise anzeigen

Nach Schritt 3 scheint die Datei "weg" zu sein – das ist das Kernprinzip von Branches. Git wechselt deinen Arbeitsordner auf den exakten Stand des gewählten Branches.

Nach Schritt 5 zeigt git status die .env-Datei nicht, weil sie in .gitignore steht. Die .gitignore-Datei selbst wird aber gezeigt – sie muss selbst committet werden, damit Git sie in jedem Checkout kennt.

AUFGABE 18.3 Bare-Repository auf dem Server einrichten

Du richtest auf deinem Server ein eigenes Remote-Repository ein – ohne GitHub. Danach pushst du dein lokales Repository dorthin und prüfst, ob der Verlauf ankommt.

🖥️ Schritt 1–2: per SSH auf dem Server anmelden
1
Verbinde dich per SSH mit deinem Server: ssh admin@IP-ADRESSE. Stelle sicher, dass Git installiert ist: git --version. Falls nicht: sudo apt install git.
2
Lege das Bare-Repository an: mkdir -p ~/repos/git-uebung.git && cd ~/repos/git-uebung.git && git init --bare. Du siehst Ordner wie objects/ und refs/ – das ist ein normales Bare-Repo ohne Projektdateien. Verlasse den Server: exit.
💻 Schritt 3–5: zurück auf deinem Rechner
3
Wechsle in deinen lokalen Übungsordner: cd git-uebung. Füge das Server-Repo als Remote hinzu – ersetze IP-ADRESSE und den Benutzernamen: git remote add origin ssh://admin@IP-ADRESSE/home/admin/repos/git-uebung.git. Prüfe mit git remote -v.
4
Pushe alle deine Commits zum Server: git push -u origin main. Das -u setzt den Upstream, danach reicht ein einfaches git push.
5
Teste den vollständigen Weg: Ändere eine Datei lokal, committe sie und pushe. Melde dich dann erneut per SSH auf dem Server an und führe dort cd ~/repos/git-uebung.git && git log --oneline aus – du siehst deinen neuen Commit.
Lösungshinweise anzeigen

Das Bare-Repo auf dem Server zeigt dir mit git log den vollständigen Verlauf, obwohl keine Projektdateien sichtbar sind. Das ist das Wesen eines Bare-Repos: es ist nur für den Datenaustausch zuständig, nicht zum direkten Arbeiten.

Falls git push einen Fehler "Permission denied" gibt, prüfe, ob dein SSH-Schlüssel auf dem Server hinterlegt ist (Modul 02). Falls der Fehler "Repository not found" erscheint, stimmt der Pfad im Remote nicht – prüfe den absoluten Pfad zum Repo-Ordner auf dem Server.

Modul 195 Unterrichtseinheiten

Docker & Docker Compose

Docker packt eine Anwendung mit allem, was sie braucht, in einen Container – und der Container läuft auf jedem Server gleich. In diesem Modul lernst du Docker von Grund auf: einzelne Container, eigene Images und komplette Multi-Container-Stacks mit Docker Compose.

Voraussetzung: Modul 06 – APT Voraussetzung: Modul 18 – Git Container · Images · Volumes · Compose
🖥️ Alles in diesem Modul läuft auf dem Server

Docker wird auf dem Server installiert und dort betrieben. Du verbindest dich per SSH (Modul 02) auf den Server und gibst alle Befehle in diesem Modul dort ein. Auf deinem eigenen Rechner tust du in diesem Modul nichts – außer den Browser öffnen, um laufende Webdienste zu prüfen.

🖥️ Server

Alle Befehle in diesem Modul laufen auf dem Server – nach dem SSH-Login.

Container vs. Virtuelle Maschine – der Unterschied

Bevor du Docker installierst, musst du verstehen, was Docker eigentlich ist – und warum es so anders ist als eine virtuelle Maschine.

Analogie Transportcontainer: Stell dir vor, du schickst Werkzeug auf eine Baustelle. Früher hast du jeden Schraubenzieher einzeln eingepackt und gehofft, dass am Zielort alles passt. Mit Docker packst du das ganze Werkzeugset – Schraubenzieher, Bohrmaschine, Steckdosenleiste – in einen genormten Transportcontainer. Der Container passt auf jedes Schiff (jeden Server) und der Inhalt funktioniert immer gleich.

EigenschaftVirtuelle Maschine (VM)Docker-Container
Startzeit1–5 MinutenSekunden
SpeicherbedarfGigabytes (volles OS)Megabytes (nur App + Libs)
IsolationVollständig (eigener Kernel)Prozess-Ebene (gemeinsamer Kernel)
PortierbarkeitEingeschränktLäuft überall gleich
Typischer EinsatzKomplette SystemeEinzelne Dienste/Apps
BegriffErklärungAnalogie
ImageUnveränderlicher Bauplan für einen ContainerKochrezept
ContainerLaufende Instanz eines ImagesDas fertige Gericht
DockerfileTextdatei, die beschreibt wie ein Image gebaut wirdDein eigenes Rezept schreiben
VolumeDauerhafter Speicher außerhalb des ContainersUSB-Stick, der beim Neubau erhalten bleibt
RegistryOnline-Bibliothek für Images (z.B. Docker Hub)App Store für Container
Docker ComposeMehrere Container als Stack in einer YAML-DateiMenüplan für ein ganzes Essen
Docker installieren

Docker aus dem Standard-Ubuntu-Repository ist oft veraltet. Du installierst Docker immer aus dem offiziellen Docker-Repository – das ist aktuell und offiziell unterstützt.

🖥️ Auf dem Server – du bist per SSH eingeloggt

Installiere zuerst die nötigen Hilfspakete, dann füge das offizielle Docker-Repository hinzu:

Schritt 1: Voraussetzungen und GPG-Schlüssel
sudo apt update
sudo apt install -y ca-certificates curl gnupg

# Verzeichnis für Schlüssel anlegen:
sudo install -m 0755 -d /etc/apt/keyrings

# Docker-GPG-Schlüssel herunterladen (für Ubuntu):
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Schritt 2: Repository einbinden und Docker installieren
# Docker-Repository zur Paketliste hinzufügen:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Schritt 3: Docker ohne sudo nutzen
# Deinen Benutzer zur docker-Gruppe hinzufügen:
sudo usermod -aG docker $USER

# Relogin erforderlich! Danach testen:
docker run hello-world
# Ausgabe: "Hello from Docker!" = Installation erfolgreich
💡 Debian vs. Ubuntu

Der Installationsbefehl oben ist für Ubuntu. Auf Debian ersetzt du ubuntu durch debian in der Repository-URL. Der Rest ist identisch.

⚠️ Nicht aus dem Ubuntu-Standardrepo installieren

Das Paket docker.io aus dem Ubuntu-Standard-Repository ist oft sehr veraltet. Installiere immer aus dem offiziellen Docker-Repository wie oben gezeigt. Das Paket heißt dort docker-ce (Community Edition).

Container starten und verwalten

Docker-Container leben nach einem einfachen Lebenszyklus: Image herunterladen → Container starten → Container nutzen → Container stoppen → Container löschen. Das Image bleibt dabei erhalten und kann jederzeit für neue Container genutzt werden.

🖥️ Auf dem Server
Grundlegende Container-Befehle
# Image herunterladen (ohne sofort zu starten):
docker pull nginx:latest

# Container starten:
docker run -d --name mein-nginx -p 8080:80 nginx
# -d         = im Hintergrund laufen (detached)
# --name     = Container einen Namen geben
# -p 8080:80 = Port weiterleiten: Server-Port 8080 → Container-Port 80

# Laufende Container anzeigen:
docker ps

# Alle Container inkl. gestoppte:
docker ps -a

# Container stoppen:
docker stop mein-nginx

# Gestoppten Container wieder starten:
docker start mein-nginx

# Container sofort stoppen UND löschen:
docker rm -f mein-nginx
Container inspizieren und debuggen
# Logs eines Containers anzeigen:
docker logs mein-nginx

# Logs live verfolgen (Strg+C zum Beenden):
docker logs -f mein-nginx

# Shell in einem laufenden Container öffnen:
docker exec -it mein-nginx /bin/bash
# Tipp: Wenn bash nicht verfügbar: /bin/sh verwenden

# Ressourcenverbrauch aller laufenden Container:
docker stats
BefehlWofür
docker run -d --name NAME -p HOST:CONT IMAGEContainer starten
docker psLaufende Container anzeigen
docker ps -aAlle Container (auch gestoppte)
docker stop NAMEContainer sauber stoppen
docker start NAMEGestoppten Container starten
docker rm -f NAMEContainer sofort löschen
docker logs -f NAMELogs live verfolgen
docker exec -it NAME /bin/bashShell im Container öffnen
⚠️ Vorsicht bei --privileged und Root-Containern

Mit docker run --privileged erhält ein Container vollen Zugriff auf alle Kernel-Funktionen und Geräte des Hosts – das ist ein erhebliches Sicherheitsrisiko. Nutze --privileged nur wenn absolut notwendig und nur auf Servern, die nicht direkt aus dem Internet erreichbar sind. Ähnlich verhält es sich mit Containern, die als Root laufen: Gut gepflegte Images verwenden interne Benutzer statt Root.

Images verwalten
🖥️ Auf dem Server
Docker-Images verwalten
# Lokale Images anzeigen:
docker images

# Ein bestimmtes Image löschen:
docker rmi nginx:latest

# Ungenutzte Images aufräumen (kein laufender Container nutzt sie):
docker image prune

# ALLES aufräumen: Images, gestoppte Container, Netzwerke:
docker system prune -a
🚨 docker system prune -a löscht alles

Dieser Befehl entfernt alle ungenutzten Images, gestoppten Container und Netzwerke – auch Images, die du extra heruntergeladen hast. Auf einem Produktionsserver besser nicht verwenden. Nutze stattdessen docker image prune oder lösche gezielt einzelne Images mit docker rmi IMAGE.

Volumes – Daten dauerhaft speichern

Container sind kurzlebig: Wenn du einen Container löschst, sind alle Daten im Container weg. Das ist wie ein Wegwerf-Feuerzeug – praktisch, aber nichts für wichtige Daten. Volumes speichern Daten außerhalb des Containers auf dem Server. Das Volume überlebt, wenn der Container gelöscht oder aktualisiert wird.

🖥️ Auf dem Server
Docker Volumes erstellen und nutzen
# Benanntes Volume erstellen:
docker volume create meine-daten

# Container mit Volume starten:
# -v VOLUME-NAME:PFAD-IM-CONTAINER
docker run -d --name db -v meine-daten:/var/lib/mysql mariadb:latest

# Bind-Mount: Ordner auf dem Server direkt in Container einbinden:
docker run -d --name web \
  -v /home/user/html:/usr/share/nginx/html \
  -p 80:80 nginx

# Alle Volumes anzeigen:
docker volume ls

# Volume-Details anzeigen (z.B. wo es auf dem Server liegt):
docker volume inspect meine-daten
🧠 Benanntes Volume vs. Bind-Mount

Benannte Volumes (-v meine-daten:/pfad) werden von Docker verwaltet und liegen unter /var/lib/docker/volumes/. Bind-Mounts (-v /dein/pfad:/pfad) verknüpfen einen beliebigen Serverordner direkt mit dem Container – praktisch für Konfigurationsdateien, die du bearbeiten willst.

Docker Compose – mehrere Container als Stack

Einzelne Container per docker run zu starten ist für einfache Fälle gut. Sobald mehrere Container zusammenarbeiten – z.B. eine Web-App und eine Datenbank – wird es unübersichtlich. Docker Compose beschreibt den gesamten Stack in einer einzigen docker-compose.yml-Datei. Du startest und stoppst alles mit einem Befehl.

🖥️ Auf dem Server – Verzeichnis anlegen und Datei erstellen

Lege für jeden Stack ein eigenes Verzeichnis an. Die docker-compose.yml gehört immer in dieses Verzeichnis.

Verzeichnis für den Stack anlegen
mkdir -p ~/stacks/wordpress
cd ~/stacks/wordpress
docker-compose.yml – WordPress mit MariaDB
services:
  db:
    image: mariadb:10.11
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: geheim123
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wp_user
      MYSQL_PASSWORD: wp_geheim
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress:latest
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_NAME: wordpress
      WORDPRESS_DB_USER: wp_user
      WORDPRESS_DB_PASSWORD: wp_geheim
    volumes:
      - wp_data:/var/www/html

volumes:
  db_data:
  wp_data:
Stack starten und verwalten
# Stack starten (im Verzeichnis mit docker-compose.yml):
docker compose up -d

# Status aller Services anzeigen:
docker compose ps

# Logs aller Container des Stacks:
docker compose logs

# Logs eines bestimmten Services live verfolgen:
docker compose logs -f wordpress

# Stack stoppen (Container bleiben erhalten, Volumes auch):
docker compose down

# Images aktualisieren und neu starten:
docker compose pull
docker compose up -d
🚨 docker compose down -v löscht alle Volumes

Der Befehl docker compose down -v stoppt den Stack und löscht alle Volumes – damit sind Datenbankdaten und Uploads unwiederbringlich weg. Nutze immer docker compose down ohne -v, wenn du den Stack nur stoppen willst.

Compose-DirektiveBedeutung
image:Welches Docker-Image genutzt wird
restart: unless-stoppedContainer startet automatisch nach Reboot
ports:Port-Weiterleitung HOST:CONTAINER
environment:Umgebungsvariablen (Passwörter, Konfiguration)
volumes:Volume- oder Bind-Mount-Zuordnung
depends_on:Startreihenfolge: dieser Service wartet auf einen anderen
networks:In welchem internen Netzwerk der Container läuft
🤖
KI-Tipp: Docker Compose generieren lassen

Docker Compose YAML zu schreiben ist ein perfekter KI-Anwendungsfall – die Syntax ist präzise und Fehler führen zu kryptischen Meldungen. Beschreibe einfach, was du brauchst: „Erstelle mir eine docker-compose.yml für einen Stack mit Nextcloud, MariaDB und Caddy als Reverse-Proxy mit automatischem HTTPS. Nextcloud soll unter cloud.meinserver.de erreichbar sein. Erkläre jede Zeile kurz als Kommentar."

Eigene Images bauen (Dockerfile)

Fertige Images von Docker Hub reichen für die meisten Fälle. Wenn du aber eigene Anwendungen containerisieren willst – z.B. ein Python-Skript oder eine selbst geschriebene Web-App – baust du dein eigenes Image mit einem Dockerfile.

🖥️ Auf dem Server

Erstelle ein Verzeichnis für das Projekt. Das Dockerfile beschreibt Schicht für Schicht, wie das Image aufgebaut wird:

Dockerfile – einfaches Beispiel (Python-App)
# Basis-Image (Python 3.11, schlank):
FROM python:3.11-slim

# Arbeitsverzeichnis im Container setzen:
WORKDIR /app

# Abhängigkeitsliste zuerst kopieren (nutzt Docker-Cache):
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Anwendungscode kopieren:
COPY . .

# Welcher Port wird freigegeben (nur Dokumentation):
EXPOSE 8000

# Was läuft beim Containerstart:
CMD ["python", "app.py"]
Image bauen und testen
# Image bauen (. = Dockerfile im aktuellen Verzeichnis):
docker build -t meine-app:1.0 .

# Alle lokalen Images anzeigen:
docker images

# Container aus eigenem Image starten:
docker run -d --name app -p 8000:8000 meine-app:1.0

# Oder direkt in Compose nutzen:
# build: . (statt image: ...) in der docker-compose.yml
Dockerfile-AnweisungBedeutung
FROM image:tagBasis-Image (immer erste Zeile)
WORKDIR /pfadArbeitsverzeichnis im Container setzen
COPY quelle zielDatei vom Server in das Image kopieren
RUN befehlBefehl beim Build ausführen (z.B. apt install)
EXPOSE portPort dokumentieren (kein echtes Port-Mapping)
CMD ["befehl"]Startbefehl beim Container-Start
ENV KEY=wertUmgebungsvariable setzen
🤖
KI-Tipp: Dockerfile-Fehler beheben

Beim Build eines eigenen Images treten häufig Fehler auf, die schwer zu googeln sind – oft in der Layer-Reihenfolge oder bei apt-Paketnamen. Kopiere die Fehlermeldung und frag: „Mein Docker-Build schlägt mit folgendem Fehler fehl. Was ist die Ursache und wie passe ich das Dockerfile an? Basis-Image: python:3.11-slim, Fehler: [Fehlermeldung einfügen]"

Praxisaufgaben
AUFGABE 19.1 Docker installieren und ersten Container starten

Du installierst Docker aus dem offiziellen Repository und startest deinen ersten Container. Alle Schritte laufen auf dem Server.

🖥️ Alle Schritte auf dem Server – per SSH eingeloggt
1
Installiere Docker nach der Anleitung im Abschnitt „Docker installieren". Führe abschließend docker run hello-world aus – du siehst die Ausgabe „Hello from Docker!".
2
Starte einen Nginx-Container im Hintergrund: docker run -d --name test-web -p 8080:80 nginx. Das Image wird automatisch heruntergeladen.
3
Prüfe ob der Container läuft: docker ps. Du siehst Name, Image, Port-Mapping und Laufzeit.
4
Öffne im Browser http://SERVER-IP:8080. Du siehst die Nginx-Willkommensseite – der Container liefert sie aus.
5
Zeige die Logs an: docker logs test-web. Dein Browser-Aufruf aus Schritt 4 sollte als Zugriff erscheinen.
6
Stoppe und lösche den Container: docker rm -f test-web. Prüfe mit docker ps -a, dass er weg ist.
Lösungshinweise anzeigen

docker ps zeigt Spalten: CONTAINER ID, IMAGE, COMMAND, CREATED, STATUS, PORTS, NAMES. Bei Port-Mapping steht dort 0.0.0.0:8080->80/tcp – das bedeutet: Port 8080 des Servers leitet an Port 80 im Container weiter.

Nach docker rm -f test-web ist der Container weg. Das Image nginx ist aber noch lokal – prüfe das mit docker images.

AUFGABE 19.2 WordPress-Stack mit Docker Compose

Du startest einen kompletten WordPress-Stack (Web-App + Datenbank) mit einer einzigen Compose-Datei und prüfst, dass Volumes die Daten nach einem Neustart erhalten.

🖥️ Alle Schritte auf dem Server
1
Lege ein Verzeichnis für den Stack an: mkdir -p ~/stacks/wordpress && cd ~/stacks/wordpress
2
Erstelle die Datei docker-compose.yml nach dem Beispiel im Abschnitt „Docker Compose". Öffne sie mit einem Editor: nano docker-compose.yml.
3
Starte den Stack: docker compose up -d. Docker lädt beide Images herunter und startet die Container.
4
Prüfe den Status: docker compose ps. Beide Services (db und wordpress) müssen „running" zeigen. Falls wordpress noch startet, kurz warten.
5
Öffne http://SERVER-IP:8080 im Browser und schließe die WordPress-Einrichtung ab. Stoppe danach den Stack: docker compose down.
6
Starte den Stack erneut: docker compose up -d und öffne wieder den Browser. Deine WordPress-Installation ist noch da – dank Volumes.
Lösungshinweise anzeigen

docker compose ps zeigt beide Services als „running". Falls wordpress immer wieder neu startet, liegt es meist daran, dass die Datenbank noch nicht bereit ist – kurz warten, dann läuft auch WordPress.

Die Volumes db_data und wp_data bleiben bei docker compose down erhalten. Prüfe das mit docker volume ls.

AUFGABE 19.3 Eigenes Docker-Image bauen

Du erstellst ein einfaches eigenes Image, das eine statische HTML-Seite über Nginx ausliefert. So lernst du den Dockerfile-Workflow Schritt für Schritt.

🖥️ Alle Schritte auf dem Server
1
Lege ein Verzeichnis an: mkdir ~/mein-image && cd ~/mein-image
2
Erstelle eine einfache HTML-Datei: echo "<h1>Hallo aus meinem Container!</h1>" > index.html
3
Erstelle das Dockerfile: nano Dockerfile. Inhalt: erste Zeile FROM nginx:alpine, zweite Zeile COPY index.html /usr/share/nginx/html/
4
Baue das Image: docker build -t meine-seite:1.0 .. Beobachte, wie Docker die Layer aufbaut.
5
Starte einen Container mit deinem Image: docker run -d --name test -p 9090:80 meine-seite:1.0 und öffne http://SERVER-IP:9090.
Lösungshinweise anzeigen

Im Browser siehst du deine eigene HTML-Seite, ausgeliefert von Nginx im Container. docker images zeigt meine-seite:1.0 in der Liste. Das Image kannst du auf jeden anderen Server mit Docker übertragen – es läuft überall identisch.

Alpine-basierte Images sind sehr klein (wenige MB). Das ist gut für Produktions-Images – weniger Inhalt bedeutet weniger Angriffsfläche.

AUFGABE 19.4 Passwörter in .env-Datei auslagern

Passwörter direkt in der docker-compose.yml zu haben ist unpraktisch – beim Committen in Git wären sie für alle sichtbar. Du lagerst sie in eine separate .env-Datei aus.

🖥️ Alle Schritte auf dem Server, im Verzeichnis ~/stacks/wordpress
1
Erstelle eine .env-Datei: nano .env. Trage die Passwörter ein, z.B.: MYSQL_ROOT_PASSWORD=geheim123 und MYSQL_PASSWORD=wp_geheim – jede Variable in einer eigenen Zeile.
2
Passe die docker-compose.yml an: Ersetze die festen Passwörter durch Variable-Referenzen ohne geschweifte Klammern, z.B. MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD.
3
Falls Git vorhanden: Erstelle eine .gitignore-Datei und trage .env ein, damit die Passwörter nicht ins Repository gelangen: echo ".env" > .gitignore
4
Starte den Stack neu: docker compose down && docker compose up -d. Docker liest die .env-Datei automatisch ein.
5
Prüfe, ob alles läuft: docker compose ps. WordPress sollte wieder unter http://SERVER-IP:8080 erreichbar sein.
Lösungshinweise anzeigen

Docker Compose liest .env im gleichen Verzeichnis automatisch ein – du musst nichts extra angeben. Die Variablen werden in der YAML-Datei mit $VARIABLENNAME referenziert.

Die .env-Datei enthält die echten Geheimnisse und darf nie in Git landen. Die docker-compose.yml hingegen kann problemlos committet werden – sie enthält nur noch Variablennamen, keine Passwörter.

Modul 204 Unterrichtseinheiten

Virtualisierung

Eine virtuelle Maschine ist wie ein zweiter Arbeitsplatz im Computer -- vollständig abgetrennt, mit eigenem Betriebssystem. In diesem Modul lernst du, wie du mit KVM/QEMU auf deinem Server echte VMs betreibst, sie verwaltest und mit Snapshots absicherst.

Voraussetzung: Modul 09 Voraussetzung: Modul 19 KVM · QEMU · virsh · Snapshots · LXC
Alles läuft auf dem Server

In diesem Modul arbeitest du ausschließlich auf dem Server. KVM und QEMU laufen dort -- du richtest sie ein, startest VMs und verwaltest sie. Von deinem eigenen Rechner aus verbindest du dich nur per SSH auf den Server, um Befehle einzugeben.

🖥️ Server

Alle Befehle in diesem Modul laufen auf dem Server. Du bist per SSH eingeloggt -- genau wie in Modul 02 gelernt.

Bare Metal, VM oder Container -- wann was?

Bevor wir loslegen, klären wir kurz, welche Option wann sinnvoll ist. Stell dir einen Parkplatz vor: Bare Metal ist ein einzelnes Auto direkt auf dem Platz. Eine VM ist ein Parkhaus -- mehrere Fahrzeuge übereinander, jedes vollständig abgetrennt. Ein Container ist ein Kleinbus mit mehreren Personen -- teilt sich das Fahrzeug, aber jeder hat seinen eigenen Sitz.

Eigenschaft Bare Metal Virtuelle Maschine (VM) Container (Docker)
Betriebssystem Direkt auf Hardware Eigener Kernel, beliebig Teilt Host-Kernel
Startzeit Minuten (Reboot) 1--3 Minuten Sekunden
Isolation Keine (alles direkt) Hardware-Level Prozess-Level
Ressourcenverbrauch Minimal Hoch (eigener Kernel) Gering
Andere OS möglich? Nein Ja (Windows, BSD, ...) Nein (nur Linux)
Typischer Einsatz Einzelne dedizierte Dienste Komplette Server, Tests, Windows Anwendungen, Microservices
💡 VM oder Container? Die Faustregel

Du brauchst eine VM, wenn: du ein anderes Betriebssystem brauchst (z.B. Windows), du komplette Isolation bis auf Hardware-Ebene willst, oder du eine ganze Server-Umgebung nachbauen willst. Für Webanwendungen, Datenbanken und einzelne Dienste reicht Docker (aus Modul 19) fast immer.

KVM/QEMU -- Voraussetzungen prüfen und installieren

KVM (Kernel-based Virtual Machine) ist direkt im Linux-Kernel eingebaut. QEMU übernimmt die Emulation der Hardware. Zusammen bilden sie die Basis für professionelle Virtualisierung -- auch Proxmox und viele Cloud-Anbieter bauen darauf auf.

Damit KVM funktioniert, muss deine CPU Hardware-Virtualisierung unterstützen. Das ist bei allen modernen Prozessoren der Fall, muss aber manchmal im BIOS aktiviert werden.

🖥️ Auf dem Server -- du bist per SSH eingeloggt

Prüfe zuerst, ob die CPU deines Servers Hardware-Virtualisierung unterstützt. Das Tool kvm-ok ist am einfachsten:

Virtualisierungs-Unterstützung prüfen
# Schnellprüfung mit kvm-ok (aus dem Paket cpu-checker):
sudo apt install cpu-checker
kvm-ok
# Erwartete Ausgabe: "KVM acceleration can be used"

# Alternativ: CPU-Flags direkt prüfen
# vmx = Intel VT-x, svm = AMD-V
grep -cE 'vmx|svm' /proc/cpuinfo
# Ergebnis muss größer 0 sein

Wenn kvm-ok meldet "KVM acceleration can NOT be used", aktiviere Virtualisierung im BIOS (Intel VT-x oder AMD-V).

🖥️ Auf dem Server

Jetzt installierst du alle nötigen Pakete. libvirt ist die Verwaltungsschicht, über die du VMs mit virsh steuern kannst:

KVM, QEMU und libvirt installieren
sudo apt update
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst

# Deinen Benutzer zu den nötigen Gruppen hinzufügen:
sudo usermod -aG libvirt $USER
sudo usermod -aG kvm $USER

# Abmelden und neu einloggen, damit die Gruppenänderungen greifen!
# Danach: Dienst prüfen
sudo systemctl status libvirtd
Erste VM erstellen mit virt-install

virt-install ist ein Kommandozeilen-Werkzeug, mit dem du VMs direkt auf dem Server erstellen kannst. Du gibst an, wie viel RAM, wie viele CPU-Kerne und wie viel Speicher die VM bekommt -- und von welchem ISO sie starten soll.

⚠️ Ressourcen nicht überprovisionieren

Ein häufiger Anfängerfehler: VMs bekommen zusammen mehr RAM zugewiesen als der Server physisch hat. Linux erlaubt zwar RAM-Overcommitment, aber wenn alle VMs gleichzeitig viel Arbeitsspeicher brauchen, bricht das System zusammen. Faustregel: Weise nie mehr als 80 % des physischen RAMs an VMs zu. Behalte immer genug für das Host-System (mindestens 1--2 GB).

🖥️ Auf dem Server

Lade zuerst ein ISO-Image herunter, dann erstelle die VM. Das ISO wird im Standard-Speicherverzeichnis von libvirt abgelegt:

ISO herunterladen und VM erstellen
# ISO in den libvirt-Bildordner herunterladen (Debian Netinstall, ~400 MB):
sudo wget -O /var/lib/libvirt/images/debian-12.iso \
  https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.10.0-amd64-netinst.iso

# VM erstellen (Debian mit 2 GB RAM, 2 CPUs, 20 GB Disk):
sudo virt-install \
  --name debian-test \
  --ram 2048 \
  --vcpus 2 \
  --disk path=/var/lib/libvirt/images/debian-test.qcow2,size=20 \
  --os-variant debian12 \
  --cdrom /var/lib/libvirt/images/debian-12.iso \
  --network network=default \
  --graphics vnc,listen=0.0.0.0 \
  --noautoconsole
# --noautoconsole: VM startet im Hintergrund
# Verbindung über VNC-Client: Server-IP:5900

Die VM läuft jetzt im Hintergrund. Du verbindest dich zur grafischen Konsole über einen VNC-Client (z.B. Remmina oder TigerVNC) auf Port 5900 deines Servers, um die Installation abzuschließen.

VMs verwalten mit virsh

virsh ist dein zentrales Werkzeug für alles rund um VMs. Denk daran wie an einen Schalttafel-Meister: Er startet Maschinen, fährt sie runter, zeigt Status und erstellt Sicherungen -- alles über kurze Befehle.

🖥️ Auf dem Server
Wichtige virsh-Befehle
# Alle VMs anzeigen (laufende und gestoppte):
sudo virsh list --all

# VM starten:
sudo virsh start debian-test

# VM sauber herunterfahren (wie "shutdown -h now" von innen):
sudo virsh shutdown debian-test

# VM sofort stoppen (wie Stecker ziehen -- Datenverlust möglich!):
sudo virsh destroy debian-test

# VM neu starten:
sudo virsh reboot debian-test

# Detaillierte Infos zur VM:
sudo virsh dominfo debian-test

# VM-Konfiguration anzeigen (XML):
sudo virsh dumpxml debian-test

# VM löschen (mit allen Disk-Images!):
sudo virsh undefine debian-test --remove-all-storage
🚨 virsh undefine --remove-all-storage löscht dauerhaft

virsh destroy stoppt die VM sofort (wie Stecker ziehen), löscht aber keine Dateien. virsh undefine --remove-all-storage hingegen löscht die VM und ihr gesamtes Disk-Image unwiderruflich -- ohne Rückfrage. Vor dem Löschen immer prüfen, ob ein Backup oder Snapshot existiert.

Die wichtigsten virsh-Befehle auf einen Blick:

Befehl Wirkung Analogie
virsh list --all Alle VMs anzeigen Fuhrparkübersicht
virsh start VM starten Zündung an
virsh shutdown VM sauber herunterfahren Motor sauber abstellen
virsh destroy VM sofort stoppen Notaus-Schalter
virsh snapshot-create-as Snapshot erstellen Sicherungspunkt setzen
virsh snapshot-revert Snapshot wiederherstellen Auf Sicherungspunkt zurück
virsh undefine VM löschen Fahrzeug aus Fuhrpark aussondern
Snapshots -- der Sicherheitsgurt beim Experimentieren

Ein Snapshot speichert den exakten Zustand einer VM zu einem bestimmten Zeitpunkt: Dateisystem und optional den Arbeitsspeicher. Wenn danach etwas schiefläuft -- ein Update die VM zerstört, eine Konfiguration nicht funktioniert -- rollst du einfach zum Snapshot zurück. Kein Datenverlust, keine Neuinstallation.

🖥️ Auf dem Server
Snapshots erstellen, verwalten und wiederherstellen
# Snapshot erstellen (VM sollte gestoppt oder pausiert sein für konsistente Daten):
sudo virsh snapshot-create-as debian-test \
  --name "vor-update" \
  --description "Zustand vor apt upgrade"

# Alle Snapshots einer VM anzeigen:
sudo virsh snapshot-list debian-test

# Details eines Snapshots anzeigen:
sudo virsh snapshot-info debian-test vor-update

# Zum Snapshot zurückkehren (VM wird gestoppt und neu gestartet):
sudo virsh snapshot-revert debian-test vor-update

# Snapshot löschen (wenn er nicht mehr gebraucht wird):
sudo virsh snapshot-delete debian-test vor-update
🧠 Snapshot-Routine für den Alltag

Mach dir zur Gewohnheit: Vor jedem größeren Eingriff (System-Update, neue Software, Konfigurationsänderung) einen Snapshot. Der Name sollte selbsterklärend sein: "vor-nginx-update" statt "snapshot1". Alte Snapshots kosten Speicherplatz -- lösche sie, wenn die Änderung stabil läuft.

Netzwerk -- NAT oder Bridge?

Jede VM braucht Netzwerkzugang. libvirt bietet zwei Hauptmodi:

  • NAT (Network Address Translation): Die VM bekommt eine private IP (z.B. 192.168.122.x) und kommt über den Host ins Internet. Von außen ist die VM nicht direkt erreichbar. Gut für: Test-VMs, Entwicklungsumgebungen.
  • Bridge: Die VM hängt direkt im Heimnetzwerk, wie ein eigener Rechner. Sie bekommt eine IP vom Router (z.B. 192.168.1.x) und ist von überall im Netz erreichbar. Gut für: Server-VMs, die Dienste nach außen anbieten.
🖥️ Auf dem Server

Das Standard-Netzwerk von libvirt nutzt NAT über die virtuelle Bridge virbr0. So prüfst und verwaltest du es:

Netzwerk in libvirt verwalten
# Alle libvirt-Netzwerke anzeigen:
sudo virsh net-list --all

# Details des Standard-Netzwerks (NAT, 192.168.122.0/24):
sudo virsh net-info default

# Standard-Netzwerk starten (falls inaktiv):
sudo virsh net-start default

# Standard-Netzwerk beim Systemstart automatisch starten:
sudo virsh net-autostart default

# Welche IP-Adressen hat libvirt vergeben? (DHCP-Leases):
sudo virsh net-dhcp-leases default

Für eine Bridge-Konfiguration (VM direkt im Heimnetz) erstellst du auf dem Host eine Linux-Bridge und verbindest deine Netzwerkkarte damit. Das konfigurierst du in /etc/netplan/ (Ubuntu) oder /etc/network/interfaces (Debian) -- wie in Modul 05 gelernt.

LXC/LXD -- die leichtgewichtige Alternative

Wenn du eine VM vor allem brauchst, weil du ein vollständiges Ubuntu oder Debian isoliert betreiben willst -- aber kein Windows oder andere Betriebssysteme -- dann schau dir LXC/LXD an. LXC-Container sind wie VMs von außen betrachtet, teilen aber den Kernel mit dem Host. Sie starten in Sekunden und brauchen deutlich weniger Ressourcen.

🖥️ Auf dem Server
LXD installieren und ersten Container starten
# LXD installieren (via Snap -- empfohlene Methode auf Ubuntu):
sudo snap install lxd

# LXD initialisieren (setzt Netzwerk und Speicher auf Standardwerte):
lxd init --minimal

# Deinen Benutzer zur lxd-Gruppe hinzufügen:
sudo usermod -aG lxd $USER
# Danach: Abmelden und neu einloggen!

# Ersten Container starten (Ubuntu 22.04):
lxc launch ubuntu:22.04 mein-container

# In den Container einsteigen (wie SSH, aber lokal):
lxc exec mein-container -- bash

# Container stoppen und löschen:
lxc stop mein-container
lxc delete mein-container

# Alle Container anzeigen:
lxc list
💡 VM, LXC oder Docker -- eine Entscheidungshilfe

Docker (Modul 19): Einzelne Anwendungen und Microservices, schnell deployen und portabel.
LXC/LXD: Vollständige Linux-Umgebung ohne den Overhead einer VM -- z.B. ein komplettes Ubuntu mit eigenem Netzwerk-Stack, aber kein Windows möglich.
KVM/QEMU VM: Wenn du ein anderes Betriebssystem brauchst (z.B. Windows), oder wenn maximale Isolation gefordert ist (Sicherheits-Tests, Kunden-Isolation).

🤖
KI-Tipp: virt-install konfigurieren

virt-install hat Dutzende Parameter. Wenn du eine spezielle Konfiguration brauchst -- z.B. mehrere Netzwerkkarten, UEFI statt BIOS, oder verschachtelte Virtualisierung (nested KVM) -- beschreibe dein Ziel: „Ich möchte mit virt-install eine VM erstellen, die zwei Netzwerkkarten hat: eine im NAT-Netzwerk und eine direkt auf meiner Bridge br0. Zeige mir den vollständigen virt-install-Befehl für Debian 12."

Praxisaufgaben
AUFGABE 20.1 KVM einrichten und Unterstützung prüfen

Du prüfst, ob dein Server Virtualisierung unterstützt, und installierst alle nötigen Pakete. Das ist die Grundlage für alle weiteren VM-Aufgaben.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Installiere cpu-checker und prüfe die Virtualisierungs-Unterstützung: sudo apt install cpu-checker && kvm-ok. Notiere, was die Ausgabe meldet.
2
Installiere KVM und libvirt: sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients virtinst.
3
Prüfe, ob der libvirtd-Dienst läuft: sudo systemctl status libvirtd. Er sollte als "active (running)" angezeigt werden.
4
Füge deinen Benutzer zur libvirt-Gruppe hinzu: sudo usermod -aG libvirt $USER. Logge dich per exit aus und verbinde dich per SSH neu, damit die Gruppenänderung wirkt.
5
Zeige alle konfigurierten Netzwerke an: sudo virsh net-list --all. Das Netzwerk "default" sollte dort erscheinen. Starte es bei Bedarf: sudo virsh net-start default.
Lösungshinweise anzeigen

kvm-ok meldet entweder "KVM acceleration can be used" (gut) oder "can NOT be used" (BIOS-Einstellung prüfen: Intel VT-x bzw. AMD-V aktivieren). virsh net-list --all zeigt "default" mit Status "active" oder "inactive". Das Standard-Netzwerk nutzt NAT mit dem Adressbereich 192.168.122.0/24 über die Bridge virbr0.

AUFGABE 20.2 Erste VM erstellen und mit Snapshots arbeiten

Du lädst ein Debian-ISO herunter, erstellst eine virtuelle Maschine mit virt-install und sicherst den Zustand mit einem Snapshot. Du brauchst mindestens 5 GB freien Speicher auf dem Server.

🖥️ Auf dem Server
1
Prüfe den freien Speicher: df -h /var/lib/libvirt/images/. Du brauchst mindestens 5 GB.
2
Lade das Debian-Netinstall-ISO herunter: sudo wget -O /var/lib/libvirt/images/debian-12.iso https://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-12.10.0-amd64-netinst.iso. Das dauert je nach Leitung einige Minuten (ca. 400 MB).
3
Erstelle die VM mit virt-install (2 GB RAM, 2 CPUs, 5 GB Disk): sudo virt-install --name debian-test --ram 2048 --vcpus 2 --disk path=/var/lib/libvirt/images/debian-test.qcow2,size=5 --os-variant debian12 --cdrom /var/lib/libvirt/images/debian-12.iso --network network=default --graphics vnc,listen=0.0.0.0 --noautoconsole.
4
Prüfe, dass die VM angelegt wurde: sudo virsh list --all. Notiere den Status.
5
Fahre die VM herunter: sudo virsh destroy debian-test (sofortiger Stopp, da noch kein OS installiert). Erstelle dann einen Snapshot: sudo virsh snapshot-create-as debian-test --name "nach-erstellung" --description "Leere VM nach virt-install".
6
Zeige den Snapshot an: sudo virsh snapshot-list debian-test. Lösche danach die Test-VM: sudo virsh undefine debian-test --remove-all-storage.
Lösungshinweise anzeigen

virsh list --all zeigt VMs mit Status "running", "shut off" oder "idle". Der Snapshot-Name "nach-erstellung" erscheint in snapshot-list mit Erstellungszeit. undefine --remove-all-storage löscht die VM-Definition und das .qcow2-Disk-Image -- danach ist beides weg. Das ISO in /var/lib/libvirt/images/ bleibt erhalten.

AUFGABE 20.3 LXC-Container starten und erkunden

Du startest einen LXC-Container mit Ubuntu, erkundest ihn von innen und vergleichst, was sich vom Host-System unterscheidet.

🖥️ Auf dem Server
1
Installiere LXD: sudo snap install lxd. Füge deinen Benutzer zur lxd-Gruppe hinzu: sudo usermod -aG lxd $USER. Abmelden und neu einloggen per SSH.
2
Initialisiere LXD mit Standardwerten: lxd init --minimal.
3
Starte einen Ubuntu-Container: lxc launch ubuntu:22.04 test-lxc. Beobachte, wie schnell er bereit ist -- Sekunden statt Minuten.
4
Steige in den Container ein: lxc exec test-lxc -- bash. Prüfe darin: uname -a (Kernel -- derselbe wie der Host!), hostname (Container-Name), ip addr (eigene IP). Tippe exit um zurückzukehren.
5
Zeige Infos zum Container an: lxc info test-lxc. Stoppe und lösche ihn: lxc stop test-lxc && lxc delete test-lxc. Prüfe mit lxc list, dass er weg ist.
Lösungshinweise anzeigen

Im Container zeigt uname -a denselben Kernel wie der Host -- das ist der Kernunterschied zu einer KVM-VM, die einen eigenen Kernel lädt. lxc info test-lxc zeigt CPU- und Speicherverbrauch: ein LXC-Container im Leerlauf belegt oft unter 50 MB RAM, während eine KVM-VM mit eigenem Kernel 200--500 MB benötigt. lxc list nach dem Löschen zeigt eine leere Liste.

🤖
KI-Tipp: VM vs. Container für dein Szenario

Nicht sicher, welche Virtualisierungsform für dein Vorhaben passt? Beschreibe es konkret: „Ich möchte auf meinem Heimserver drei Dienste betreiben: eine Windows-Anwendung für Buchhaltung, einen Nextcloud-Server und einen Pi-hole-DNS. Soll ich KVM-VMs, LXC-Container, Docker-Container oder eine Kombination nutzen? Erkläre Vor- und Nachteile für jede Option und nenne mir die nötigen Ressourcen."

Modul 214 Unterrichtseinheiten

Bash-Scripting

Wiederkehrende Aufgaben von Hand ausführen? Das überlässt du ab jetzt einem Skript. Ein Bash-Skript ist wie eine Checkliste – du schreibst einmal auf, was zu tun ist, und der Server arbeitet sie selbstständig ab.

Voraussetzung: Modul 03 Variablen · Schleifen · Bedingungen Funktionen · Argumente · Fehlerbehandlung
Bevor wir starten: Alles läuft auf dem Server

Bash-Skripte schreibst und führst du auf dem Server aus – du bist also bereits per SSH eingeloggt, bevor du in diesem Modul irgendeinen Befehl tippst. In diesem Modul gilt durchgängig der Server-Kontext:

🖥️ Server

Alle Skripte und Befehle dieses Moduls laufen auf dem Server – nach dem SSH-Login aus Modul 02.

💡 Voraussetzung: SSH-Verbindung

Verbinde dich zuerst per SSH auf deinen Server (Modul 02). Alle Skripte in diesem Modul erstellst und führst du dort aus. Du brauchst kein separates lokales Terminal.

Dein erstes Skript

Ein Bash-Skript ist eine ganz normale Textdatei. Du schreibst Befehle hinein – einen pro Zeile – und der Server führt sie der Reihe nach aus. Wie eine Checkliste in der Werkstatt: Schritt 1, Schritt 2, Schritt 3 – fertig.

🖥️ Auf dem Server – du bist bereits per SSH eingeloggt

Erstelle eine neue Datei mit nano, mach sie ausführbar und starte sie:

Skript erstellen, ausführbar machen, starten
# 1. Skript erstellen (öffnet den nano-Editor):
nano hallo.sh

# 2. Ausführbar machen (ohne diesen Schritt passiert nichts):
chmod +x hallo.sh

# 3. Skript starten:
./hallo.sh

Das ./ vor dem Dateinamen sagt Bash: „Suche die Datei im aktuellen Verzeichnis, nicht irgendwo im Systempfad."

🖥️ Auf dem Server – Inhalt der Datei hallo.sh
hallo.sh – das erste Skript
#!/bin/bash
# Mein erstes Bash-Skript

echo "Hallo! Ich bin ein Bash-Skript."
echo "Heute ist: $(date +%d.%m.%Y)"
echo "Du bist eingeloggt als: $(whoami)"
echo "Dein Server heißt: $(hostname)"
💡 Der Shebang: #!/bin/bash

Die erste Zeile #!/bin/bash heißt „Shebang". Sie sagt dem System, welches Programm das Skript ausführen soll. Ohne diese Zeile weiß Linux nicht, dass es ein Bash-Skript ist. Der Shebang muss immer in der allerersten Zeile stehen – keine Leerzeile davor!

Variablen und Eingabe

Variablen speichern Werte, die du im Skript mehrfach verwenden kannst. Stell dir eine Variable wie ein Etikett auf einem Behälter vor: du schreibst etwas drauf (Zuweisung) und liest es später ab (Auslesen).

🖥️ Auf dem Server
variablen.sh – Variablen setzen und auslesen
#!/bin/bash

# Variablen setzen – KEIN Leerzeichen um das = !
NAME="Max"
ALTER=30
SERVER="webserver-01"

# Variablen auslesen – mit $ davor:
echo "Hallo $NAME, du bist $ALTER Jahre alt."
echo "Server: ${SERVER}"

# Befehlsausgabe in einer Variable speichern:
DATUM=$(date +%Y-%m-%d)
HOSTNAME_SERVER=$(hostname)
echo "Datum: $DATUM, Server: $HOSTNAME_SERVER"

# Benutzereingabe einlesen:
read -p "Wie heißt du? " EINGABE
echo "Willkommen, $EINGABE!"
⚠️ Kein Leerzeichen um das Gleichheitszeichen!

NAME="Max" ist korrekt. NAME = "Max" ist ein Fehler! Bash versucht dann den Befehl NAME mit dem Argument = auszuführen – was nicht existiert. Das ist einer der häufigsten Anfängerfehler.

Skripte können auch Argumente von der Kommandozeile entgegennehmen – ähnlich wie Befehle Optionen akzeptieren. Die speziellen Variablen $1, $2 usw. enthalten diese Argumente:

🖥️ Auf dem Server
argumente.sh – Argumente übergeben
#!/bin/bash
# Aufruf: ./argumente.sh Max 30

echo "Skriptname: $0"
echo "Erstes Argument: $1"
echo "Zweites Argument: $2"
echo "Alle Argumente: $@"
echo "Anzahl Argumente: $#"
VariableBedeutungBeispiel
$0Name des Skripts selbst./backup.sh
$1, $2Argumente (1., 2. Argument …)$1 = erster Wert nach dem Skriptnamen
$@Alle Argumente als Listenützlich in Schleifen
$#Anzahl der übergebenen Argumente0 wenn keins übergeben
$?Rückgabecode des letzten Befehls0 = Erfolg, alles andere = Fehler
$$Prozess-ID des laufenden Skriptsnützlich für temporäre Dateinamen
Bedingungen (if/else)

Mit Bedingungen reagiert dein Skript auf verschiedene Situationen – wie eine Weiche an einer Schiene: Je nach Zustand wird ein anderer Weg eingeschlagen.

🖥️ Auf dem Server
bedingungen.sh – if/else/elif/fi
#!/bin/bash

# Prüfen ob eine Datei existiert:
if [ -f "/etc/nginx/nginx.conf" ]; then
    echo "Nginx ist installiert."
else
    echo "Nginx ist NICHT installiert."
fi

# Prüfen ob ein Verzeichnis existiert:
if [ -d "/var/www/html" ]; then
    echo "Webverzeichnis vorhanden."
fi

# Zahlenvergleich mit elif:
AUSLASTUNG=$(df / --output=pcent | tail -1 | tr -d ' %')
if [ $AUSLASTUNG -gt 80 ]; then
    echo "WARNUNG: Festplatte zu ${AUSLASTUNG}% belegt!"
elif [ $AUSLASTUNG -gt 60 ]; then
    echo "Hinweis: Festplatte zu ${AUSLASTUNG}% belegt."
else
    echo "Festplatte OK: ${AUSLASTUNG}% belegt."
fi

# String-Vergleich:
if [ "$USER" = "root" ]; then
    echo "Du bist Root – Vorsicht!"
fi
TestBedeutung
-f dateiDatei existiert (und ist eine reguläre Datei)
-d pfadVerzeichnis existiert
-e pfadDatei oder Verzeichnis existiert (beides)
-z "$var"Variable ist leer (Zero length)
-n "$var"Variable ist nicht leer (Non-zero)
-eq / -neGleich / Ungleich (Zahlen)
-gt / -ltGrößer als / Kleiner als (Zahlen)
-ge / -leGrößer-gleich / Kleiner-gleich (Zahlen)
= / !=Gleich / Ungleich (Zeichenketten)
Schleifen

Schleifen führen einen Codeblock mehrfach aus – wie ein Monteur, der dieselbe Inspektion an jedem Fahrzeug in der Reihe macht, ohne den Ablauf jedes Mal neu zu beschreiben.

for-Schleife

🖥️ Auf dem Server
for-Schleifen
#!/bin/bash

# Über eine feste Liste iterieren:
for DIENST in ssh cron nginx; do
    echo "Prüfe Dienst: $DIENST"
    systemctl is-active --quiet $DIENST \
        && echo "  OK: laeuft" \
        || echo "  GESTOPPT"
done

# Über Dateien iterieren:
for DATEI in /var/log/*.log; do
    GROESSE=$(du -h "$DATEI" | awk '{print $1}')
    echo "$DATEI: $GROESSE"
done

# Zahlenbereich mit seq:
for i in $(seq 1 5); do
    echo "Schritt $i von 5"
done

while-Schleife

🖥️ Auf dem Server
while-Schleifen
#!/bin/bash

# Datei Zeile für Zeile einlesen:
while IFS= read -r ZEILE; do
    echo "Verarbeite: $ZEILE"
done < /etc/hosts

# Dauerhaft auf ein Ereignis warten (Monitoring-Schleife):
while true; do
    if ! systemctl is-active --quiet nginx; then
        echo "$(date): Nginx gestoppt – starte neu"
        sudo systemctl start nginx
    fi
    sleep 60
done
Funktionen

Funktionen fassen Codeblöcke zusammen, die du mehrfach aufrufen willst – wie eine Subroutine im Werkstatt-Handbuch: einmal definiert, beliebig oft einsetzbar.

🖥️ Auf dem Server
funktionen.sh – Funktionen definieren und aufrufen
#!/bin/bash

# Funktion definieren – geschweifte Klammern enthalten den Rumpf:
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}

# Funktion die prüft ob ein Dienst läuft:
dienst_laeuft() {
    systemctl is-active --quiet "$1"
}

# Funktionen aufrufen:
log "Skript gestartet"

if dienst_laeuft "nginx"; then
    log "Nginx laeuft."
else
    log "Nginx ist gestoppt!"
fi

log "Skript beendet"
🧠 Funktionen: Wo definieren?

Definiere Funktionen immer vor dem ersten Aufruf – am besten am Anfang des Skripts, direkt nach den Variablen. Bash liest Skripte von oben nach unten. Eine Funktion, die erst nach dem Aufruf steht, ist noch nicht bekannt.

Robuste Skripte: set -e, set -u und exit

Ein Skript, das bei einem Fehler einfach weiterläuft, kann gefährlich sein – wie ein Mechaniker, der trotz Fehler-Anzeige weitermacht. Mit ein paar Sicherheitsoptionen machst du dein Skript von Anfang an widerstandsfähig.

🖥️ Auf dem Server
sicherheit.sh – Sicherheitsoptionen, $? und exit
#!/bin/bash
# Sicherheitsoptionen – direkt nach dem Shebang:
set -euo pipefail
# -e: Bei jedem Fehler sofort abbrechen
# -u: Abbrechen wenn eine undefinierte Variable benutzt wird
# -o pipefail: Fehler in Pipes nicht ignorieren

QUELLE="/var/www/html"

# Prüfung mit gezieltem exit (besser als $? bei set -e):
if [ ! -d "$QUELLE" ]; then
    echo "FEHLER: $QUELLE existiert nicht!"
    exit 1
fi

# $? direkt nach einem Befehl auslesen (ohne set -e):
ls "$QUELLE" &>/dev/null
if [ $? -eq 0 ]; then
    echo "Verzeichnis lesbar – OK"
fi

echo "Alles OK."
exit 0
💡 set -e und $? vertragen sich nicht gut

Mit set -e bricht Bash bei jedem Fehler sofort ab. Das bedeutet: Eine Prüfung wie if [ $? -ne 0 ] nach einem fehlgeschlagenen Befehl wird nie erreicht – das Skript ist vorher schon abgebrochen. Verwende daher bei aktivem set -e immer direkte Prüfungen mit if befehl; then oder if [ -f ... ] statt nachträglichem $?.

⚠️ rm -rf in Skripten – immer absichern

Skripte mit rm -rf können Daten unwiederbringlich löschen, wenn eine Variable leer oder falsch belegt ist. Prüfe immer zuerst mit if [ -n "$VARIABLE" ], dass die Variable nicht leer ist. Noch besser: Teste das Skript zuerst mit echo statt dem echten Befehl.

🚨 Niemals blind rm -rf mit Variablen

rm -rf $VERZEICHNIS/ kann bei einer leeren Variable das gesamte Wurzelverzeichnis löschen. Mit set -u fängt Bash eine undefinierte Variable ab und bricht ab. Ohne diesen Schutz passiert die Katastrophe still. Nutze immer set -euo pipefail und explizite Pfadprüfungen.

Dieses vollständige Server-Health-Check-Skript kombiniert alles aus diesem Modul:

🖥️ Auf dem Server
server-check.sh – vollständiges Überwachungsskript
#!/bin/bash
set -euo pipefail

LOGFILE="/var/log/server-check.log"
WARN_DISK=80

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOGFILE"
}

check_disk() {
    USAGE=$(df / --output=pcent | tail -1 | tr -d ' %')
    if [ $USAGE -gt $WARN_DISK ]; then
        log "WARNUNG: Festplatte bei ${USAGE}%"
    else
        log "OK: Festplatte bei ${USAGE}%"
    fi
}

check_service() {
    if systemctl is-active --quiet "$1"; then
        log "OK: $1 laeuft"
    else
        log "FEHLER: $1 ist gestoppt!"
    fi
}

log "=== Server Health-Check ==="
check_disk
check_service "nginx"
check_service "ssh"
log "=== Check abgeschlossen ==="
🤖
KI-Tipp: Bash-Skripte generieren lassen

Bash-Scripting ist ein idealer KI-Anwendungsfall: Beschreibe, was dein Skript tun soll, und lass es erstellen. Beispiel-Prompt: „Schreibe mir ein Bash-Skript, das jeden Tag um 3 Uhr nachts alle MariaDB-Datenbanken sichert, die Backups mit Zeitstempel benennt und Backups älter als 7 Tage löscht. Mit set -euo pipefail, einer log()-Funktion und Fehlermeldung falls mysqldump nicht gefunden wird."

🤖
KI-Tipp: Bash-Fehler diagnostizieren

Bash-Fehlermeldungen sind manchmal kryptisch. Wenn dein Skript abbricht, kopiere die Fehlermeldung und frag: „Mein Bash-Skript bricht mit dieser Fehlermeldung ab: [Fehlermeldung einfügen]. Das Skript macht folgendes: [Kurzbeschreibung]. Was ist der Fehler und wie behebe ich ihn?"

Praxisaufgaben
AUFGABE 21.1 Erstes Bash-Skript schreiben

Du schreibst dein erstes eigenes Skript auf dem Server und lernst den kompletten Workflow: Erstellen, ausführbar machen, starten.

🖥️ Alle Schritte auf dem Server – du bist bereits per SSH eingeloggt
1
Erstelle eine neue Datei: nano sysinfo.sh. Tippe den Shebang als erste Zeile: #!/bin/bash
2
Füge Befehle hinzu, die Hostname, IP-Adresse, Kernel-Version (uname -r), Uptime und Festplattenbelegung (df -h /) ausgeben. Nutze echo und Befehlssubstitution mit $(befehl).
3
Speichere die Datei mit Strg+O, bestätige mit Enter, verlasse nano mit Strg+X.
4
Mach das Skript ausführbar: chmod +x sysinfo.sh
5
Starte das Skript: ./sysinfo.sh – du solltest alle Systeminformationen sehen.
6
Erweitere das Skript: Speichere die Ausgabe zusätzlich in einer Logdatei mit tee -a sysinfo.log. Prüfe das Ergebnis mit cat sysinfo.log.
Lösungshinweise anzeigen

Das Skript gibt alle Systeminformationen auf dem Bildschirm aus. Mit ./sysinfo.sh | tee sysinfo.log wird die Ausgabe gleichzeitig in eine Datei geschrieben. Alternativ direkt im Skript: echo "$(hostname)" | tee -a sysinfo.log. Schau dir nach dem ersten Lauf die Logdatei an – alle Zeilen sollten dort stehen.

AUFGABE 21.2 Dienst-Check-Skript mit Schleifen

Du schreibst ein Skript, das mehrere Dienste in einer Schleife prüft und am Ende eine Zusammenfassung ausgibt.

🖥️ Alle Schritte auf dem Server
1
Erstelle nano dienst-check.sh. Beginne mit #!/bin/bash. Lasse set -e hier weg – die Schleife soll auch bei gestoppten Diensten weiterlaufen.
2
Definiere eine Variable mit der Dienst-Liste: DIENSTE="ssh cron" (diese laufen auf jedem Ubuntu-Server – füge weitere hinzu wie nginx oder mariadb wenn installiert).
3
Schreibe eine for-Schleife, die jeden Dienst mit systemctl is-active --quiet prüft und per if/else ausgibt, ob er läuft. Initialisiere einen Zähler vor der Schleife: RUNNING=0. Erhöhe ihn bei laufenden Diensten: RUNNING=$((RUNNING + 1)).
4
Berechne die Gesamtzahl: TOTAL=$(echo $DIENSTE | wc -w). Gib am Ende aus: echo "$RUNNING von $TOTAL Diensten laufen."
5
Mach das Skript ausführbar und teste es: chmod +x dienst-check.sh && ./dienst-check.sh. Alle bekannten Dienste sollten als laufend gemeldet werden.
Lösungshinweise anzeigen

systemctl is-active --quiet DIENST gibt Exit-Code 0 zurück wenn der Dienst läuft, sonst einen anderen Wert. if nutzt diesen Exit-Code direkt aus – ohne $? prüfen zu müssen. Der Zähler läuft nur hoch, wenn ein Dienst aktiv ist. wc -w zählt die Wörter in einer Zeichenkette – das entspricht der Anzahl der Dienstnamen.

AUFGABE 21.3 Backup-Skript mit Funktionen und Fehlerbehandlung

Du schreibst ein robustes Backup-Skript, das Voraussetzungen prüft, eine log()-Funktion nutzt und bei Fehlern kontrolliert abbricht.

🖥️ Alle Schritte auf dem Server
1
Erstelle nano backup.sh. Beginne mit #!/bin/bash und set -euo pipefail. Definiere Variablen: QUELLE="/etc", ZIEL="/tmp/backups", LOGFILE="/tmp/backup.log".
2
Schreibe eine log()-Funktion: Sie gibt [Datum Uhrzeit] Nachricht aus und schreibt sie gleichzeitig in $LOGFILE (mit tee -a).
3
Prüfe mit if, ob $QUELLE existiert (-d). Falls nicht: Fehlermeldung ausgeben und mit exit 1 abbrechen. Erstelle das Zielverzeichnis falls nötig: mkdir -p "$ZIEL".
4
Erstelle das Backup: tar -czf "$ZIEL/backup_$(date +%Y%m%d_%H%M%S).tar.gz" "$QUELLE" 2>/dev/null. Logge Erfolg und Dateiname.
5
Mach das Skript ausführbar und starte es: chmod +x backup.sh && ./backup.sh. Prüfe danach mit ls -lh /tmp/backups/ und cat /tmp/backup.log.
Lösungshinweise anzeigen

Das Backup-Skript erstellt eine .tar.gz-Datei mit aktuellem Zeitstempel im Namen. Mit set -euo pipefail bricht es bei jedem unerwarteten Fehler ab. Die log()-Funktion nimmt $1 als Nachricht entgegen und schreibt sie mit Zeitstempel. Wenn du das Quellverzeichnis änderst, teste erst mit echo statt dem echten tar-Befehl, um den Skriptaufbau zu prüfen.

AUFGABE 21.4 Skript mit Argumenten aufrufen

Du erweiterst das Backup-Skript so, dass Quell- und Zielverzeichnis als Argumente übergeben werden – flexibler und für mehrere Zwecke wiederverwendbar.

🖥️ Alle Schritte auf dem Server
1
Kopiere das Backup-Skript: cp backup.sh backup-flexibel.sh. Öffne es mit nano backup-flexibel.sh.
2
Ersetze die festen Variablenwerte: QUELLE="$1" und ZIEL="$2". Das Skript liest jetzt Quell- und Zielverzeichnis aus den übergebenen Argumenten.
3
Füge vor den Variablen eine Prüfung hinzu: Wenn weniger als 2 Argumente übergeben wurden ($# -lt 2), gib eine Hilfsmeldung aus und brich ab: echo "Nutzung: $0 QUELLE ZIEL" und exit 1. Platziere diese Prüfung direkt nach dem Shebang und set-Optionen.
4
Teste das Skript ohne Argumente: ./backup-flexibel.sh – es sollte die Hilfsmeldung anzeigen. Dann mit Argumenten: ./backup-flexibel.sh /etc /tmp/test-backup.
5
Lass dir nach dem Lauf die erstellte Datei anzeigen: ls -lh /tmp/test-backup/.
Lösungshinweise anzeigen

Die Prüfung if [ $# -lt 2 ] fängt fehlende Argumente ab. $0 enthält den Skriptnamen – nützlich für verständliche Hilfsmeldungen. Die Argumentprüfung muss vor dem Zugriff auf $1 und $2 stehen, damit set -u nicht vorher wegen undefinierter Variable abbricht.

Modul 223 Unterrichtseinheiten

Linux-Services & Cron

Dienste starten, stoppen, überwachen und zeitgesteuerte Aufgaben einrichten – damit dein Server rund um die Uhr automatisch arbeitet. Du lernst systemd von Grund auf und richtest eigene Services und Timer ein.

Voraussetzung: Modul 03 Voraussetzung: Modul 21 systemd · systemctl · journalctl Cron · Timer · Automatisierung
🖥️ Alles auf dem Server

Alle Befehle in diesem Modul laufen auf dem Server – du bist per SSH eingeloggt (Modul 02). Auf deinem eigenen Rechner tippst du nur den SSH-Login. Alle Code-Blöcke sind mit der blauen Server-Zone markiert.

systemd – der Dienste-Manager deines Servers

systemd ist der zentrale Manager für alle Dienste auf deinem Linux-Server. Er startet Dienste beim Hochfahren, überwacht sie und startet sie bei Abstürzen neu. Stell dir systemd wie einen Schichtleiter vor: Er weiß, welche Mitarbeiter (Dienste) zu welchem Zeitpunkt eingesetzt werden müssen, in welcher Reihenfolge sie anfangen sollen – und was zu tun ist, wenn einer ausfällt.

Jeder Dienst wird durch eine Unit-Datei beschrieben – eine kleine Textdatei, die erklärt, was der Dienst tut und wie er gestartet werden soll. Unit-Dateien liegen unter /etc/systemd/system/ (eigene) oder /lib/systemd/system/ (vom System installiert).

Units und Targets

systemd unterscheidet verschiedene Unit-Typen. Die wichtigsten für den Alltag:

Unit-TypDateiendungVerwendung
Service.serviceHintergrunddienste (nginx, ssh, mysql)
Timer.timerZeitgesteuerte Aufgaben (moderne Cron-Alternative)
Mount.mountDateisystem-Einhängepunkte
Target.targetGruppen von Units – steuern die Boot-Reihenfolge

Ein Target bündelt mehrere Units. Das wichtigste Target ist multi-user.target – das entspricht dem normalen Serverbetrieb ohne grafische Oberfläche. Wenn du einen Dienst mit WantedBy=multi-user.target einrichtest, startet er beim normalen Hochfahren automatisch mit.

systemctl – Dienste verwalten

Mit systemctl steuerst du alle Dienste auf dem Server. Das ist dein täglich genutztes Werkzeug – vergleichbar mit dem Gaspedal, der Bremse und dem Tacho deines Servers.

🖥️ Auf dem Server – du bist per SSH eingeloggt

Dienst starten, stoppen, neu starten und Status prüfen:

Grundlegende Steuerung
# Dienst starten:
sudo systemctl start nginx

# Dienst stoppen:
sudo systemctl stop nginx

# Dienst neu starten (Stop + Start):
sudo systemctl restart nginx

# Konfiguration neu laden, ohne den Dienst zu stoppen:
sudo systemctl reload nginx

# Status und letzte Logs anzeigen:
systemctl status nginx

Autostart beim Boot steuern und Übersicht behalten:

Autostart und Übersicht
# Autostart aktivieren (startet ab nächstem Boot):
sudo systemctl enable nginx

# Autostart aktivieren und JETZT sofort starten:
sudo systemctl enable --now nginx

# Autostart deaktivieren:
sudo systemctl disable nginx

# Dienst komplett sperren (kann nicht mehr gestartet werden):
sudo systemctl mask nginx

# Sperre aufheben:
sudo systemctl unmask nginx

# Alle laufenden Dienste anzeigen:
systemctl list-units --type=service --state=running

# Alle fehlgeschlagenen Dienste:
systemctl --failed
BefehlWas er tutWann verwenden
startDienst sofort startenManuell einschalten
stopDienst sofort stoppenManuell ausschalten
restartStop + StartNach Konfigurationsänderung
reloadKonfig neu laden, Dienst läuft weiternginx/Apache nach Config-Änderung
enableAutostart aktivierenDienst soll nach Boot automatisch laufen
disableAutostart deaktivierenDienst nur manuell starten
maskDienst komplett sperrenDienst darf auf keinen Fall starten
statusStatus + letzte Logs anzeigenDiagnose, Fehlersuche
🧠 reload vs. restart

reload liest die Konfigurationsdatei neu, ohne den Dienst zu stoppen – bestehende Verbindungen bleiben erhalten. restart stoppt und startet komplett neu – alle Verbindungen werden kurz unterbrochen. Bei nginx oder Apache nutze reload wann immer möglich.

Eigene systemd-Services erstellen

Du kannst eigene Dienste erstellen – zum Beispiel für dein Bash-Skript aus Modul 21, eine Webanwendung oder einen Monitoring-Prozess. Ein Dienst besteht aus einer einzigen Textdatei mit drei Abschnitten: [Unit] (was ist das?), [Service] (wie starten?) und [Install] (wann automatisch starten?).

🖥️ Auf dem Server – Unit-Datei anlegen

Erstelle zuerst die Unit-Datei. Der Dateiname bestimmt später den Dienstnamen:

/etc/systemd/system/mein-dienst.service
[Unit]
Description=Mein eigener Dienst
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/meine-app
ExecStart=/opt/meine-app/start.sh
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Danach systemd die neue Datei bekanntmachen und den Dienst starten:

Dienst registrieren und starten
# systemd über die neue Unit informieren (immer nach Änderungen!):
sudo systemctl daemon-reload

# Dienst starten und Status prüfen:
sudo systemctl start mein-dienst
systemctl status mein-dienst

# Wenn alles läuft: Autostart aktivieren:
sudo systemctl enable mein-dienst
SektionFeldBedeutung
[Unit]Description=Kurze Beschreibung (erscheint in systemctl status)
[Unit]After=Erst starten, wenn dieser andere Dienst läuft (Abhängigkeit)
[Service]Type=simpleHauptprozess ist der gestartete Befehl direkt
[Service]User=Unter welchem Benutzer der Dienst läuft
[Service]ExecStart=Befehl zum Starten – immer vollständiger Pfad!
[Service]Restart=on-failureBei Absturz automatisch neu starten
[Install]WantedBy=In welchem Target (Boot-Stufe) automatisch starten
🚨 Fehlerhafte Unit-Dateien können den Boot blockieren!

Eine syntaktisch fehlerhafte Unit-Datei oder ein Dienst, der beim Start hängt, kann den Server-Boot stark verlangsamen oder unterbrechen. Teste neue Dienste immer zuerst manuell mit systemctl start und prüfe den Status mit systemctl status, bevor du enable aktivierst. Im Zweifel: Type=simple verwenden und den Start-Befehl vorher direkt auf der Kommandozeile testen.

🤖
KI-Tipp: systemd-Unit erstellen lassen

systemd-Unit-Dateien haben viele Optionen und die Syntax muss exakt stimmen. Beschreibe deinen Fall konkret: „Erstelle mir eine systemd-Unit-Datei für ein Python-Skript unter /opt/monitoring/check.py, das unter dem Benutzer 'monitoring' laufen soll, auf das Netzwerk warten muss und bei Fehlern nach 10 Sekunden 3-mal neu starten soll. Logs sollen ins Journal."

journalctl – Dienst-Logs lesen

systemd speichert alle Dienst-Logs zentral im Journal. Mit journalctl liest du sie aus – strukturiert, filterbar und viel übersichtlicher als in einzelnen Log-Dateien zu wühlen. Das Journal ist dein erster Anlaufpunkt bei Problemen.

🖥️ Auf dem Server – Logs mit journalctl auswerten
journalctl – die wichtigsten Filter
# Alle Logs eines bestimmten Dienstes:
sudo journalctl -u nginx

# Nur die letzten 50 Zeilen:
sudo journalctl -u nginx -n 50

# Live-Modus – neue Zeilen erscheinen sofort (Strg+C zum Beenden):
sudo journalctl -u nginx -f

# Logs seit heute:
sudo journalctl -u nginx --since today

# Logs aus einem Zeitfenster:
sudo journalctl -u nginx --since "2026-03-14 10:00" --until "2026-03-14 11:00"

# Nur Fehlermeldungen (Priorität err und schlimmer):
sudo journalctl -u nginx -p err

# Alle Dienste, nur Fehler, seit dem letzten Boot:
sudo journalctl -p err -b

# Speicherplatz des Journals prüfen:
sudo journalctl --disk-usage

# Alte Logs aufräumen (Journal auf 500 MB begrenzen):
sudo journalctl --vacuum-size=500M
💡 journalctl -f ist wie tail -f

Der -f-Parameter (follow) zeigt neue Log-Zeilen in Echtzeit – genau wie tail -f logdatei aus Modul 03. Unverzichtbar beim Debuggen: Dienst in einem Terminal neu starten, in einem anderen Terminal journalctl -u dienst -f laufen lassen und zusehen, was passiert.

Cron – Aufgaben automatisch planen

Cron ist wie ein Terminkalender für deinen Server: Du trägst ein, wann was passieren soll, und der Server hält sich daran – egal ob du schläfst oder Urlaub hast. Perfekt für Backups, Updates, Log-Bereinigung und Überwachungsskripte.

Die Crontab bearbeiten

🖥️ Auf dem Server – Crontab verwalten
Crontab-Befehle
# Eigene Crontab öffnen und bearbeiten (öffnet einen Editor):
crontab -e

# Aktuelle Crontab anzeigen:
crontab -l

# Crontab eines anderen Benutzers anzeigen (als root):
sudo crontab -u www-data -l

Die Cron-Syntax verstehen

Jede Zeile in der Crontab folgt diesem Muster – fünf Zeitfelder, dann der Befehl:

🖥️ Auf dem Server – Cron-Einträge
Cron-Zeitformat erklärt
# ┌───────── Minute  (0–59)
# │ ┌─────── Stunde  (0–23)
# │ │ ┌───── Tag     (1–31)
# │ │ │ ┌─── Monat   (1–12)
# │ │ │ │ ┌─ Wochentag (0–7, 0 und 7 = Sonntag)
# │ │ │ │ │
# * * * * *   Befehl

# Täglich um 03:00 Uhr:
0 3 * * *   /home/user/backup.sh

# Alle 15 Minuten:
*/15 * * * * /home/user/check.sh

# Jeden Sonntag um Mitternacht:
0 0 * * 0   /home/user/weekly-report.sh

# Um 06:00 und 18:00 Uhr:
0 6,18 * * * /home/user/sync.sh

# Am 1. jeden Monats um 02:30 Uhr:
30 2 1 * *  /home/user/monats-backup.sh

Ausgabe immer in eine Log-Datei umleiten – sonst siehst du nichts von der Ausführung:

Cron-Job mit Logging
# Ausgabe und Fehler in Log-Datei schreiben:
0 3 * * * /home/user/backup.sh >> /var/log/backup.log 2>&1

# Ausgabe unterdrücken, nur Fehler protokollieren:
*/5 * * * * /home/user/check.sh > /dev/null 2>&1
ZeichenBedeutungBeispiel
*Jeder mögliche Wert* * * * * = jede Minute
*/nAlle n Einheiten*/5 * * * * = alle 5 Minuten
a,bBestimmte Werte0 6,18 * * * = 6 und 18 Uhr
a-bBereich0 9-17 * * 1-5 = stündlich 9–17 Uhr, Mo–Fr
⚠️ Prozentzeichen in Crontab escapen

In der Crontab hat % eine Sonderbedeutung (Zeilenumbruch im Befehl). Wenn du date +%Y%m%d in einem Cron-Job nutzt, musst du jedes Prozentzeichen escapen: date +\%Y\%m\%d. Einfacher: Schreibe den Befehl in ein Skript und rufe das Skript per Cron auf – dann gilt das normale Shell-Verhalten ohne diese Falle.

🧠 Crontab-Generator nutzen

Die Cron-Syntax verwirrt am Anfang. Nutze crontab.guru im Browser: Trage dort die fünf Zeitfelder ein und siehst sofort auf Deutsch, wann der Job laufen wird – sehr hilfreich zum Testen und Überprüfen.

systemd-Timer – die moderne Cron-Alternative

systemd-Timer bieten gegenüber Cron einige Vorteile: bessere Logs (alles im Journal), Abhängigkeiten zu anderen Diensten, und Persistent=true holt verpasste Ausführungen nach einem Neustart automatisch nach. Für neue Setups sind Timer oft die bessere Wahl.

Ein Timer braucht immer zwei Dateien: die Timer-Datei (wann?) und eine Service-Datei (was?):

🖥️ Auf dem Server – Timer einrichten
/etc/systemd/system/backup.timer
[Unit]
Description=Taegliches Backup – jeden Tag um 03:00

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target
/etc/systemd/system/backup.service
[Unit]
Description=Taegliches Backup

[Service]
Type=oneshot
User=backup
ExecStart=/home/backup/backup.sh

Timer laden, starten und prüfen:

Timer aktivieren
sudo systemctl daemon-reload

# Timer aktivieren und sofort starten:
sudo systemctl enable --now backup.timer

# Alle aktiven Timer und nächste Ausführungszeit anzeigen:
systemctl list-timers

# Timer-Status prüfen:
systemctl status backup.timer

# Zugehörigen Service manuell testen:
sudo systemctl start backup.service
journalctl -u backup.service -n 20
Timer-FeldBedeutungBeispiel
OnCalendar=Fester Zeitplan (wie Cron)Mon *-*-* 02:00:00 = montags um 2 Uhr
OnBootSec=X Zeit nach dem Boot ausführenOnBootSec=5min
OnUnitActiveSec=Regelmäßig, relativ zur letzten AusführungOnUnitActiveSec=1h
Persistent=trueVerpasste Ausführung nach Neustart nachholenWichtig für Backup-Timer
🤖
KI-Tipp: Cron-Job als systemd-Timer umschreiben

Du hast einen Cron-Job, der nicht zuverlässig läuft, oder willst auf systemd-Timer umsteigen? Zeig der KI deinen bestehenden Crontab-Eintrag: „Ich habe diesen Cron-Job: '0 3 * * * /home/user/backup.sh'. Schreibe mir dafür eine systemd-Timer- und Service-Unit-Datei. Der Dienst soll unter dem Benutzer 'backup' laufen und verpasste Ausführungen nach einem Neustart nachholen."

at – einmalige geplante Aufgaben

Während Cron für wiederkehrende Aufgaben gedacht ist, plant at eine Aufgabe einmalig für einen bestimmten Zeitpunkt in der Zukunft. Praktisch für: „Starte diesen Prozess in 30 Minuten" oder „Führe das Update heute Nacht um 02:00 aus".

🖥️ Auf dem Server – at verwenden
at – einmalige Aufgaben planen
# at installieren (auf Debian/Ubuntu oft nicht vorinstalliert):
sudo apt install at

# Skript in 30 Minuten ausführen:
echo "/home/user/update.sh" | at now + 30 minutes

# Befehl um 02:00 Uhr heute Nacht (als root für systemctl):
echo "systemctl reboot" | sudo at 02:00

# Alle geplanten at-Aufgaben anzeigen:
atq

# Geplante Aufgabe löschen – Nummer aus atq entnehmen:
atrm 3
Praxisaufgaben
AUFGABE 22.1 Dienste mit systemctl erkunden

Lerne die wichtigsten systemctl-Befehle kennen, indem du bereits laufende Dienste auf deinem Server untersuchst.

🖥️ Alle Schritte auf dem Server – du bist per SSH eingeloggt
1
Zeige alle laufenden Dienste an: systemctl list-units --type=service --state=running. Wie viele Dienste laufen gerade auf dem Server?
2
Untersuche den SSH-Dienst: systemctl status ssh. Notiere: Ist er aktiv? Seit wann läuft er? Was steht in der letzten Log-Zeile?
3
Prüfe, ob der Cron-Dienst für den Autostart eingerichtet ist: systemctl is-enabled cron. Die Antwort sollte enabled sein.
4
Zeige alle fehlgeschlagenen Dienste: systemctl --failed. Gibt es Einträge? Falls ja, untersuche einen davon mit journalctl -u DIENSTNAME -n 30.
5
Lies die letzten 20 Log-Zeilen des SSH-Dienstes: sudo journalctl -u ssh -n 20. Erkennst du deinen eigenen Login in den Einträgen?
Lösungshinweise anzeigen

systemctl status ssh zeigt den Dienst als active (running). PID, Speicherverbrauch und die letzten Log-Zeilen sind direkt sichtbar – kein separates journalctl nötig für eine schnelle Übersicht.

systemctl --failed sollte auf einem frisch eingerichteten Server leer sein. Jeder Eintrag dort ist ein Hinweis auf ein Problem, das untersucht werden sollte.

Im Journal von SSH erkennst du deinen Login an Zeilen wie Accepted publickey for admin from 192.168.x.x.

AUFGABE 22.2 Eigenen systemd-Service erstellen

Du erstellst einen eigenen Dienst, der ein Bash-Skript dauerhaft laufen lässt – und siehst, wie systemd es überwacht und im Journal protokolliert.

🖥️ Alle Schritte auf dem Server
1
Erstelle die Datei /opt/hello-service.sh. Erste Zeile: #!/bin/bash. Zweite Zeile: while true; do echo "$(date): Service laeuft"; sleep 10; done. Die Schleife gibt alle 10 Sekunden eine Zeile aus – das Journal fängt sie auf.
2
Mache das Skript ausführbar: sudo chmod +x /opt/hello-service.sh. Starte es kurz im Hintergrund zum Testen: /opt/hello-service.sh &. Warte 15 Sekunden, prüfe die Ausgabe mit jobs, dann stoppe den Hintergrundprozess wieder: kill %1 (beendet Job Nr. 1 aus der jobs-Liste).
3
Erstelle die Unit-Datei /etc/systemd/system/hello.service. Nutze das Beispiel aus dem Modul: Type=simple, ExecStart=/opt/hello-service.sh, Restart=on-failure, WantedBy=multi-user.target. Trage als User= deinen eigenen Benutzernamen ein (nicht root).
4
Lade systemd neu und starte den Dienst: sudo systemctl daemon-reload, dann sudo systemctl start hello. Prüfe den Status: systemctl status hello.
5
Schaue in Echtzeit in die Logs: journalctl -u hello -f (Strg+C zum Beenden). Stoppe den Dienst danach sauber: sudo systemctl stop hello.
Lösungshinweise anzeigen

Nach systemctl start hello zeigt systemctl status hello den Dienst als active (running). PID und Laufzeit sind sichtbar.

journalctl -u hello -f zeigt die Ausgaben des Skripts in Echtzeit – jede Zeile, die das Skript ausgibt, landet im Journal.

Wenn der Status failed zeigt: journalctl -u hello -n 20 lesen – meistens ist ein Tippfehler im Pfad oder fehlende Ausführberechtigung (chmod +x vergessen) die Ursache.

AUFGABE 22.3 Cron-Job und systemd-Timer einrichten

Du richtest denselben automatischen Job einmal als Cron-Job und einmal als systemd-Timer ein – so siehst du beide Methoden im direkten Vergleich.

🖥️ Alle Schritte auf dem Server
1
Erstelle das Skript /home/user/disk-check.sh mit zwei Zeilen: #!/bin/bash und df -h / >> /tmp/disk-check.log. Mache es ausführbar und teste es manuell: /home/user/disk-check.sh – prüfe danach cat /tmp/disk-check.log.
2
Öffne deine Crontab: crontab -e. Füge einen Eintrag hinzu, der das Skript alle 5 Minuten ausführt: */5 * * * * /home/user/disk-check.sh. Speichere und schließe den Editor.
3
Prüfe deine Crontab: crontab -l. Warte 5 Minuten und schau ob die Log-Datei neue Einträge enthält: tail /tmp/disk-check.log.
4
Erstelle denselben Job als systemd-Timer: Lege /etc/systemd/system/disk-check.service an (Type=oneshot, ExecStart=/home/user/disk-check.sh) und /etc/systemd/system/disk-check.timer (OnCalendar=*:0/5 für alle 5 Minuten, Persistent=true).
5
Aktiviere den Timer: sudo systemctl daemon-reload, dann sudo systemctl enable --now disk-check.timer. Prüfe mit systemctl list-timers, wann die nächste Ausführung geplant ist.
Lösungshinweise anzeigen

Der Crontab-Eintrag für alle 5 Minuten: */5 * * * * /home/user/disk-check.sh. Cron-Aktivität im Syslog prüfen: grep CRON /var/log/syslog | tail

OnCalendar=*:0/5 im Timer bedeutet: jede Stunde, jede durch 5 teilbare Minute. systemctl list-timers zeigt in der Spalte NEXT, wann der Timer das nächste Mal feuert.

Der Unterschied im Alltag: Beim systemd-Timer siehst du alle Logs direkt mit journalctl -u disk-check.service – kein separates Log-File nötig, alles zentral im Journal.

Modul 233 Unterrichtseinheiten

Backups

Ein Backup ist wie eine Versicherung: Du merkst es erst, wenn du es brauchst. Wer keines hat, zahlt zweimal -- mit Datenverlust und Wiederherstellungsaufwand. In diesem Modul lernst du, wie du mit tar, rsync und automatischen Skripten zuverlässige Backups aufbaust.

Voraussetzung: Modul 03 Voraussetzung: Modul 21 Voraussetzung: Modul 22 tar · rsync · Cron · 3-2-1-Regel
Kontext: Alles auf dem Server

In diesem Modul arbeitest du ausschließlich auf dem Server -- du bist bereits per SSH eingeloggt (Modul 02). Alle Befehle, Skripte und Konfigurationsdateien liegen auf dem Server. Die Legende zur Erinnerung:

🖥️ Server

Alle Befehle in diesem Modul laufen auf dem Server -- du bist bereits per SSH eingeloggt.

Die 3-2-1-Backup-Regel

Die goldene Regel für Backups lässt sich einfach merken. Stell dir vor, dein Werkzeugschrank steht in der Werkstatt. Wenn die Werkstatt abbrennt, sind alle Werkzeuge weg -- es sei denn, du hast Ersatz an einem anderen Ort.

💡 Die 3-2-1-Regel

3 Kopien deiner Daten (Original + 2 Backups), auf 2 verschiedenen Medien (z.B. interne SSD + externe Festplatte), davon 1 an einem anderen Standort (z.B. Cloud-Speicher, zweiter Server). Wenn dein Serverraum abbrennt, bist du trotzdem abgesichert.

Backup-StrategieWas wird gespeichertVorteilNachteil
VollbackupAlle Daten komplettEinfache WiederherstellungBraucht viel Speicher
InkrementellNur Änderungen seit letztem BackupSchnell, wenig SpeicherAlle Inkremente nötig für Restore
DifferenziellAlle Änderungen seit letztem VollbackupSchnellerer RestoreWird mit der Zeit größer
DeduplizierungGleiche Datenblöcke nur einmalExtrem speichereffizientAbhängig vom Tool (z.B. borgbackup)
🚨 Backup auf dieselbe Festplatte ist kein echtes Backup!

Wenn du /var/www nach /backup sicherst und beide Verzeichnisse auf derselben Festplatte liegen, verlierst du bei einem Festplattendefekt alles auf einmal. Das ist kein Backup -- das ist eine Kopie. Ein echtes Backup liegt auf einem anderen physischen Gerät oder Speicherort: externe Festplatte, NAS, USB-Stick, Cloud-Speicher oder zweiter Server.

tar -- Archive erstellen und entpacken

tar (Tape Archiver) ist das klassische Werkzeug zum Packen und Entpacken von Dateien auf Linux. Es fasst viele Dateien in eine einzige Archivdatei zusammen und kann sie dabei komprimieren. Denk daran wie ein Umzugskarton: Alles kommt rein, beschriftet und verschlossen.

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt

Die wichtigsten tar-Befehle im Überblick:

tar -- Archiv erstellen
# Verzeichnis als komprimiertes Archiv sichern (gzip):
tar -czf /backup/www-backup.tar.gz /var/www
# -c = create (erstellen)
# -z = gzip-Komprimierung
# -f = Dateiname des Archivs (kommt gleich danach)

# Mit Zeitstempel im Dateinamen:
tar -czf /backup/www-$(date +%Y-%m-%d).tar.gz /var/www

# Mehrere Verzeichnisse sichern:
tar -czf /backup/server-backup.tar.gz /var/www /etc /home
tar -- Archiv prüfen und entpacken
# Inhalt des Archivs anzeigen (ohne zu entpacken):
tar -tzf /backup/www-backup.tar.gz

# Archiv entpacken (ins aktuelle Verzeichnis):
tar -xzf /backup/www-backup.tar.gz

# Archiv in ein bestimmtes Verzeichnis entpacken:
tar -xzf /backup/www-backup.tar.gz -C /tmp/restore/
OptionBedeutung
-cArchiv erstellen (create)
-xArchiv entpacken (extract)
-tInhalt anzeigen (list)
-zgzip-Komprimierung (.tar.gz)
-jbzip2-Komprimierung (.tar.bz2, kleiner aber langsamer)
-fDateiname des Archivs (immer am Ende der Optionen)
-vDateien beim Packen anzeigen (verbose)
-CZielverzeichnis beim Entpacken
🧠 Eselsbrücke: c-z-f oder x-z-f

Merke dir: c = create, x = extract. Die Optionen zf bleiben gleich. Also: tar -czf archiv.tar.gz ordner/ zum Packen und tar -xzf archiv.tar.gz zum Entpacken.

rsync -- Inkrementelles Synchronisieren

rsync kopiert Dateien intelligent: Es überträgt nur die Unterschiede zwischen Quelle und Ziel. Das spart Zeit und Bandbreite -- perfekt für tägliche Backups, weil nach dem ersten Durchlauf nur noch geänderte Dateien kopiert werden. Stell dir vor, du bringst nur die Teile mit zur Werkstatt, die wirklich erneuert werden müssen -- nicht den kompletten Wagen.

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt

Grundlegende rsync-Befehle für lokale und entfernte Backups:

rsync -- lokal und remote
# Lokales Backup (Verzeichnis → Backup-Festplatte):
rsync -avh /var/www/ /mnt/backup/www/
# -a = Archivmodus (Berechtigungen, Zeitstempel, Symlinks erhalten)
# -v = verbose (Fortschritt anzeigen)
# -h = human-readable (Größen in KB/MB/GB)

# Auf entfernten Backup-Server senden (per SSH):
rsync -avhz /var/www/ backup-user@192.168.1.100:/backup/www/
# -z = Daten während der Übertragung komprimieren

# Trockenlauf -- zeigt was passieren würde, ohne etwas zu ändern:
rsync -avhn /var/www/ /mnt/backup/www/

# Gelöschte Dateien im Backup auch löschen (Spiegel):
rsync -avh --delete /var/www/ /mnt/backup/www/

# Bestimmte Dateitypen ausschließen:
rsync -avh --exclude '*.log' --exclude 'cache/' /var/www/ /mnt/backup/www/
FlagBedeutung
-aArchivmodus: Berechtigungen, Zeitstempel, Symlinks erhalten
-vVerbose: zeigt übertragene Dateien an
-hGrößen in KB/MB/GB (human-readable)
-zKomprimierung während der Übertragung
-nTrockenlauf: zeigt was passieren würde
--deleteIm Ziel löschen, was in der Quelle nicht mehr existiert
--excludeDateien oder Verzeichnisse ausschließen
--progressFortschrittsbalken pro Datei anzeigen
⚠️ Trailing Slash bei rsync beachten!

/var/www/ (mit Schrägstrich) kopiert den Inhalt des Ordners. /var/www (ohne Schrägstrich) kopiert den Ordner selbst. Das klingt klein, macht aber einen großen Unterschied: Mit Slash landen alle Dateien direkt im Ziel, ohne Slash entsteht ein Unterordner www/ im Ziel.

Automatisches Backup-Skript mit Cron

Aus Modul 21 (Bash-Scripting) und Modul 22 (Services & Cron) kennst du bereits Skripte und Cron-Jobs. Hier kombinierst du beides: ein Backup-Skript, das automatisch täglich läuft.

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt

Erstelle das Skript unter /usr/local/bin/backup-daily.sh:

/usr/local/bin/backup-daily.sh
#!/bin/bash
set -euo pipefail

# Konfiguration -- hier anpassen:
QUELLE="/var/www"
ZIEL="/mnt/backup/www"
LOGFILE="/var/log/backup-daily.log"

# Backup-Ziel anlegen falls nicht vorhanden:
mkdir -p "$ZIEL"

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup gestartet" >> "$LOGFILE"

rsync -avh --delete \
  --exclude '*.log' \
  --exclude 'cache/' \
  "$QUELLE/" "$ZIEL/" >> "$LOGFILE" 2>&1

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup abgeschlossen" >> "$LOGFILE"

Skript ausführbar machen und Cron-Job einrichten:

# Skript ausführbar machen:
sudo chmod +x /usr/local/bin/backup-daily.sh

# Cron-Job für root einrichten (täglich um 3 Uhr):
sudo crontab -e
# Folgende Zeile hinzufügen:
0 3 * * * /usr/local/bin/backup-daily.sh

# Log-Datei auf Fehler prüfen:
tail -20 /var/log/backup-daily.log
🤖
KI-Tipp: Backup-Skript anpassen

Dein Server hat andere Verzeichnisse, vielleicht eine Datenbank, vielleicht mehrere Backup-Ziele. Beschreibe dein Setup und lass dir das Skript anpassen: „Ich habe einen Ubuntu-Server mit /var/www (WordPress), /home/user und einer MariaDB-Datenbank. Schreibe mir ein Bash-Backup-Skript, das täglich rsync und mysqldump ausführt, alles nach /mnt/nas/backup/ sichert und mir bei Fehler eine E-Mail schickt."

Datenbank-Backups mit mysqldump

Dateien und Verzeichnisse sicherst du mit tar oder rsync. Datenbanken wie MariaDB oder MySQL funktionieren aber anders -- ihre Daten liegen in einem internen Format, das nicht einfach kopiert werden kann, während die Datenbank läuft. Dafür gibt es mysqldump. Mehr Details zu Datenbanken lernst du in Modul 16.

🖥️ Auf dem Server -- du bist bereits per SSH eingeloggt
mysqldump -- Datenbank sichern und wiederherstellen
# Einzelne Datenbank sichern:
mysqldump -u root -p meine_datenbank > /backup/meine_datenbank-$(date +%Y-%m-%d).sql

# Alle Datenbanken sichern:
mysqldump -u root -p --all-databases > /backup/alle-datenbanken-$(date +%Y-%m-%d).sql

# Backup komprimieren (spart Speicher):
mysqldump -u root -p meine_datenbank | gzip > /backup/db-$(date +%Y-%m-%d).sql.gz

# Datenbank wiederherstellen:
mysql -u root -p meine_datenbank < /backup/meine_datenbank-2026-03-14.sql
💡 mysqldump ohne Passwortabfrage im Skript

Damit das Skript automatisch läuft, ohne nach einem Passwort zu fragen, kannst du eine Credentials-Datei anlegen: /root/.my.cnf mit dem Inhalt [client], user=root, password=deinPasswort. Die Datei muss Rechte 600 haben: chmod 600 /root/.my.cnf. Dann entfällt -p im Befehl.

Externe Speicherorte

Ein Backup, das neben dem Original liegt, schützt nur vor versehentlichem Löschen -- nicht vor Hardwareausfall, Brand oder Diebstahl. Die 3-2-1-Regel verlangt mindestens einen Standort außerhalb.

SpeicherortGeeignet fürHinweis
Externe USB-FestplatteKleinere Server, lokale BackupsMuss dauerhaft angeschlossen oder regelmäßig getauscht werden
NAS im Netzwerk (NFS/SAMBA)Heimnetz, kleine FirmenNFS/SAMBA mounten (Modul 12), dann rsync darauf
Zweiter Server (rsync per SSH)Produktionsserverrsync direkt per SSH, kein Passwort nötig mit SSH-Keys (Modul 02)
Cloud-Speicher (S3, Backblaze)Offsite-Backup, 3-2-1-PflichtTools wie rclone synchronisieren Ordner mit Cloud-Diensten
borgbackup auf Remote-ServerVerschlüsseltes Offsite-BackupDedupliziert, verschlüsselt, platzsparend -- moderne Alternative
🖥️ Auf dem Server -- USB-Festplatte einbinden

Bevor du auf eine externe Festplatte sichern kannst, muss sie eingebunden sein (Modul 10):

# Backup-Mountpoint anlegen:
sudo mkdir -p /mnt/backup

# USB-Festplatte einbinden:
sudo mount /dev/sdb1 /mnt/backup

# Prüfen ob Platz vorhanden:
df -h /mnt/backup

# Für dauerhaftes Einbinden beim Start: /etc/fstab (Modul 10)
borgbackup -- Moderne Alternative

borgbackup ist eine moderne Alternative zu tar und rsync für Backups. Es dedupliziert Daten (gleiche Blöcke werden nur einmal gespeichert), komprimiert automatisch und verschlüsselt optional. Statt täglich 50 GB neu zu kopieren, speichert Borg oft nur wenige MB für jede neue Version.

🖥️ Auf dem Server -- Borg installieren und einrichten
borgbackup -- Einstieg
# Borg installieren:
sudo apt install borgbackup

# Repository initialisieren (mit Verschlüsselung):
borg init --encryption=repokey /mnt/backup/borg-repo

# Backup erstellen (Archivname mit Datum):
borg create --stats /mnt/backup/borg-repo::server-$(date +%Y-%m-%d) /var/www /etc

# Alle Backups auflisten:
borg list /mnt/backup/borg-repo

# Alte Backups aufräumen (7 täglich, 4 wöchentlich, 6 monatlich behalten):
borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=6 /mnt/backup/borg-repo
🚨 Borg-Passphrase sichern -- sonst sind Backups unwiederbringlich verloren!

Wenn du bei borg init eine Passphrase wählst, sind deine Backups ohne diese Passphrase nicht wiederherstellbar. Exportiere den Schlüssel und speichere ihn außerhalb des Servers: borg key export /mnt/backup/borg-repo borg-key.txt -- danach die Datei herunterladen und in einem Passwort-Manager oder Tresor aufbewahren.

Backup prüfen -- Restore testen ist Pflicht

Ein Backup, das du nie getestet hast, ist kein Backup -- es ist Hoffnung. Der einzige Beweis, dass ein Backup funktioniert, ist die erfolgreiche Wiederherstellung. Plane mindestens einmal im Monat einen Restore-Test ein.

🖥️ Auf dem Server -- Backup testen und wiederherstellen
Restore-Tests durchführen
# tar-Archiv prüfen (Inhalt ohne Entpacken anzeigen):
tar -tzf /backup/www-backup.tar.gz | head -20

# tar-Archiv in Testverzeichnis entpacken:
mkdir -p /tmp/restore-test
tar -xzf /backup/www-backup.tar.gz -C /tmp/restore-test/

# Inhalt des Restore-Verzeichnisses anzeigen:
ls -la /tmp/restore-test/

# rsync-Backup prüfen -- Inhalt anzeigen:
ls -lh /mnt/backup/www/

# Einzelne Datei aus rsync-Backup zurückkopieren:
cp /mnt/backup/www/index.php /var/www/html/index.php
⚠️ Restore niemals direkt ins Produktivsystem

Stelle Daten immer zuerst in ein temporäres Verzeichnis wieder her (/tmp/restore-test/). Dort kannst du prüfen, ob alles vollständig ist, bevor du die Dateien ins echte System kopierst. Ein fehlerhafter Restore überschreibt sonst vielleicht funktionierende Daten.

🤖
KI-Tipp: Backup-Strategie für deinen Server

Jeder Server hat andere Anforderungen. Beschreibe dein konkretes Setup und lass dir eine passende Strategie erstellen: „Ich betreibe einen Ubuntu-Server mit WordPress (10 GB /var/www), MariaDB-Datenbanken und E-Mails in /home. Ich habe eine externe Festplatte unter /mnt/backup und möchte zusätzlich ein Offsite-Backup. Erstelle mir einen vollständigen Backup-Plan nach der 3-2-1-Regel mit Skripten und Cron-Jobs."

Praxisaufgaben
AUFGABE 23.1 tar-Archiv erstellen und wiederherstellen

Du erstellst ein tar-Archiv von einem Verzeichnis und stellst es in einem Testverzeichnis wieder her. Das trainiert den kompletten Backup-und-Restore-Zyklus.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Erstelle ein Test-Quellverzeichnis mit einigen Dateien: mkdir -p ~/test-daten && echo "Datei1" > ~/test-daten/datei1.txt && echo "Datei2" > ~/test-daten/datei2.txt
2
Erstelle ein komprimiertes tar-Archiv: tar -czf /tmp/test-backup.tar.gz ~/test-daten/
3
Prüfe den Inhalt des Archivs ohne es zu entpacken: tar -tzf /tmp/test-backup.tar.gz. Du siehst die gespeicherten Pfade -- merke dir die ersten zwei Zeilen.
4
Erstelle ein Wiederherstellungsverzeichnis und entpacke das Archiv dorthin: mkdir -p /tmp/restore-test && tar -xzf /tmp/test-backup.tar.gz -C /tmp/restore-test/
5
Zeige die wiederhergestellten Dateien an: ls -la /tmp/restore-test/ und dann mit dem gesehenen Pfad weiter navigieren: ls -la /tmp/restore-test/root/test-daten/ (als root-User) oder ls -la /tmp/restore-test/home/DEINUSER/test-daten/ (als normaler User).
Lösungshinweise anzeigen

Bei tar -tzf siehst du die gespeicherten Pfade -- tar speichert den Pfad relativ zum Wurzelverzeichnis, also z.B. root/test-daten/datei1.txt als root-User. Beim Entpacken nach /tmp/restore-test/ entsteht dieser Pfad dort vollständig. Mit ls -la /tmp/restore-test/ siehst du zuerst das Nutzerverzeichnis und kannst dann in test-daten/ navigieren.

AUFGABE 23.2 rsync-Backup einrichten und testen

Du richtest ein inkrementelles Backup mit rsync ein und erlebst live, wie rsync beim zweiten Durchlauf nur geänderte Dateien überträgt.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Erstelle ein Backup-Zielverzeichnis: mkdir -p /tmp/backup-ziel
2
Führe ein erstes rsync-Backup durch und beobachte die Ausgabe: rsync -avh ~/test-daten/ /tmp/backup-ziel/. Beide Dateien werden übertragen.
3
Ändere eine Datei in der Quelle: echo "geaendert" >> ~/test-daten/datei1.txt
4
Führe rsync erneut aus: rsync -avh ~/test-daten/ /tmp/backup-ziel/. Beobachte: Nur die geänderte Datei wird diesmal übertragen.
5
Führe einen Trockenlauf mit --delete durch: rsync -avhn --delete ~/test-daten/ /tmp/backup-ziel/. Der Trockenlauf zeigt was passieren würde -- ohne etwas zu verändern.
6
Stelle eine einzelne Datei wieder her: cp /tmp/backup-ziel/datei2.txt ~/wiederhergestellt.txt und prüfe den Inhalt: cat ~/wiederhergestellt.txt
Lösungshinweise anzeigen

Beim zweiten rsync-Lauf zeigt die Ausgabe nur datei1.txt -- die anderen Dateien sind unverändert und werden übersprungen. Das ist das inkrementelle Prinzip: rsync vergleicht Größe und Zeitstempel, nicht den Dateiinhalt. Der Trockenlauf (-n) ist immer eine gute Idee, bevor du --delete zum ersten Mal einsetzt -- --delete entfernt Dateien im Ziel, die in der Quelle nicht mehr existieren.

AUFGABE 23.3 Automatisches Backup-Skript mit Cron

Du erstellst ein Backup-Skript und richtest einen Cron-Job ein, der es täglich ausführt. Damit läuft dein Backup automatisch -- ohne dass du daran denken musst.

🖥️ Alle Schritte auf dem Server -- du bist per SSH eingeloggt
1
Erstelle das Skript: sudo nano /usr/local/bin/backup-daily.sh und füge den Skript-Inhalt aus dem Abschnitt "Automatisches Backup-Skript" ein. Passe QUELLE und ZIEL an deine Pfade an.
2
Mach das Skript ausführbar: sudo chmod +x /usr/local/bin/backup-daily.sh
3
Teste das Skript manuell: sudo /usr/local/bin/backup-daily.sh. Prüfe danach die Log-Datei: tail -20 /var/log/backup-daily.log
4
Richte den Cron-Job für root ein: sudo crontab -e und füge am Ende hinzu: 0 3 * * * /usr/local/bin/backup-daily.sh. Das bedeutet: täglich um 3:00 Uhr ausführen (Modul 22).
5
Prüfe den eingerichteten Cron-Job: sudo crontab -l. Du solltest den neuen Eintrag sehen.
Lösungshinweise anzeigen

Das Skript schreibt Start- und Endezeit in die Log-Datei. Nach dem manuellen Test siehst du dort zwei Zeilen: [Datum] Backup gestartet und [Datum] Backup abgeschlossen. Falls rsync Fehler meldet, stehen diese ebenfalls in der Log-Datei -- der Eintrag 2>&1 im Skript leitet Fehlermeldungen ins Log um. Das Cron-Muster 0 3 * * * bedeutet: Minute 0, Stunde 3, jeder Tag, jeder Monat, jeder Wochentag.

Modul 244 Unterrichtseinheiten

Sicherheitshärtung

Ein Server im Internet wird ständig angegriffen -- automatisierte Bots scannen rund um die Uhr nach offenen Türen. In diesem Modul lernst du, deinen Server systematisch zu sichern: SSH absichern, Brute-Force-Angriffe blockieren, Benutzerrechte beschränken und Sicherheitslücken aufspüren.

Voraussetzung: Modul 02 -- SSH Voraussetzung: Modul 08 -- Nutzer & Gruppen Voraussetzung: Modul 11 -- Datei-Berechtigungen Voraussetzung: Modul 14 -- Firewall Härtung · fail2ban · sudo · Audit
🖥️ Alles auf dem Server

In diesem Modul arbeitest du ausschließlich auf dem Server -- per SSH eingeloggt. Alle Befehle laufen dort. Stelle sicher, dass du bereits verbunden bist, bevor du anfängst.

Sicherheitsprinzipien: Wie Angreifer denken

Stell dir deinen Server wie eine Werkstatt vor. Eine frisch installierte Werkstatt hat viele Türen, die offen stehen könnten, Werkzeuge die jeder benutzen kann, und keine Liste darüber, wer wann was gemacht hat. Sicherheitshärtung bedeutet: Türen schließen, Werkzeuge einschließen und ein Logbuch führen.

Zwei Grundprinzipien gelten als Fundament jeder Härtung:

  • Minimalprinzip (Least Privilege): Jeder Benutzer und jeder Dienst bekommt nur genau die Rechte, die er wirklich braucht. Nicht mehr. Ein Webserver muss keine SSH-Schlüssel lesen können.
  • Defense in Depth (Mehrschichtschutz): Kein einzelner Schutz ist unfehlbar. Du kombinierst mehrere Schichten: Firewall + SSH-Härtung + fail2ban + Berechtigungen + Updates. Wenn eine Schicht versagt, hält die nächste.
💡 Automatisierte Angriffe -- nicht persönlich nehmen

Bots scannen das gesamte Internet in wenigen Minuten. Dein Server wird innerhalb von Stunden nach der Inbetriebnahme angegriffen -- nicht weil du jemand bist, sondern weil du erreichbar bist. Die Maßnahmen in diesem Modul machen deinen Server für diese automatisierten Angriffe uninteressant.

SSH absichern

SSH ist das Haupteinfallstor für Angreifer. Aus Modul 02 kennst du die Grundlagen -- hier gehen wir tiefer. Die Konfigurationsdatei des SSH-Servers heißt /etc/ssh/sshd_config und liegt auf dem Server.

🖥️ Auf dem Server -- per SSH eingeloggt

Öffne die Konfigurationsdatei mit einem Editor. Bearbeite nur die Zeilen, die unten aufgeführt sind -- der Rest bleibt unverändert:

/etc/ssh/sshd_config -- Härtungseinstellungen
# Root-Login komplett verbieten:
PermitRootLogin no

# Nur Schlüssel-Anmeldung erlauben (kein Passwort mehr):
PasswordAuthentication no
PubkeyAuthentication yes

# Nur bestimmte Benutzer erlauben (eigene Benutzernamen einsetzen):
AllowUsers admin deploy

# Leere Passwörter verbieten:
PermitEmptyPasswords no

# Login-Timeout verkürzen (30 Sekunden zum Einloggen):
LoginGraceTime 30

# Maximale Fehlversuche pro Verbindung:
MaxAuthTries 3

# Inaktive Verbindungen nach 10 Minuten trennen:
ClientAliveInterval 300
ClientAliveCountMax 2

# Nicht benötigte Weiterleitungen abschalten:
X11Forwarding no

Prüfe die Konfiguration auf Syntaxfehler, bevor du den Dienst neu startest:

# Syntax prüfen (zeigt Fehler an, ohne den Dienst zu starten):
sudo sshd -t

# Erst wenn keine Fehler -- SSH neu laden (bestehende Verbindungen bleiben!):
sudo systemctl reload sshd

Teste sofort im zweiten Terminal, ob du dich noch verbinden kannst.

🚨 Immer ein zweites Terminal offen halten!

Bevor du PasswordAuthentication no setzt: Öffne ein zweites Terminal und verbinde dich parallel mit deinem SSH-Schlüssel. Erst wenn das funktioniert, deaktiviere das Passwort. Wenn du dich aussperrst, kommst du -- vor allem bei Cloud-Servern ohne Konsolenzugang -- nicht mehr rein.

🚨 Root-Login deaktiviert lassen

Setze PermitRootLogin niemals auf yes. Direkter Root-Login über SSH ist ein enormes Sicherheitsrisiko -- ein erfolgreicher Angriff gibt dem Angreifer sofort volle Kontrolle. Melde dich immer als normaler Benutzer an und nutze sudo für administrative Aufgaben.

Fail2ban -- Brute-Force-Angriffe blockieren

Brute-Force bedeutet: ein Bot versucht tausende Passwörter in kurzer Zeit. Fail2ban beobachtet die Logdateien und sperrt IP-Adressen automatisch, wenn sie zu viele Fehlversuche produzieren. Wie ein Türsteher, der jemanden nach drei falschen Versuchen rauswirft.

🖥️ Auf dem Server -- per SSH eingeloggt

Fail2ban installieren und aktivieren:

Installation
sudo apt update
sudo apt install fail2ban

# Dienst starten und Autostart aktivieren:
sudo systemctl enable --now fail2ban

# Status prüfen:
sudo systemctl status fail2ban

Fail2ban wird über sogenannte "Jails" konfiguriert. Jede Jail überwacht einen bestimmten Dienst. Die lokale Konfiguration legst du in einer eigenen Datei an -- so werden deine Einstellungen nicht durch Updates überschrieben:

/etc/fail2ban/jail.local -- neue Datei anlegen
[DEFAULT]
# Wie lange wird eine IP gesperrt (in Sekunden, hier: 1 Stunde):
bantime  = 3600

# Wie lange wird das Zeitfenster beobachtet:
findtime = 600

# Wie viele Fehlversuche bis zur Sperre:
maxretry = 5

# Deine eigene IP niemals sperren (anpassen!):
ignoreip = 127.0.0.1/8 192.168.1.0/24

[sshd]
# SSH-Schutz aktivieren:
enabled = true
port    = ssh
logpath = /var/log/auth.log
maxretry = 3

Nach dem Speichern den Dienst neu starten und prüfen:

sudo systemctl restart fail2ban

# Status der SSH-Jail prüfen:
sudo fail2ban-client status sshd

# Alle aktiven Jails anzeigen:
sudo fail2ban-client status

# Eine gesperrte IP manuell entsperren:
sudo fail2ban-client set sshd unbanip 1.2.3.4
ParameterBedeutungEmpfohlener Wert
bantimeSperrdauer in Sekunden3600 (1 Stunde)
findtimeBeobachtungszeitraum in Sekunden600 (10 Minuten)
maxretryFehlversuche bis zur Sperre3--5
ignoreipIPs die niemals gesperrt werdenEigenes Netz eintragen
⚠️ Eigene IP in ignoreip eintragen

Trage dein eigenes Heimnetz oder die IP deines Rechners in ignoreip ein. Sonst sperrst du dich selbst aus, wenn du dich dreimal vertippst. Typisches Heimnetz: 192.168.1.0/24 oder 192.168.0.0/24.

Automatische Sicherheitsupdates

Bekannte Sicherheitslücken werden täglich gefunden und gepatcht. Wenn dein Server Wochen ohne Updates läuft, ist er angreifbar -- auch wenn alles andere perfekt eingerichtet ist. Automatische Updates schließen Lücken, ohne dass du täglich daran denken musst.

🖥️ Auf dem Server -- per SSH eingeloggt
Unattended-Upgrades einrichten
# Paket installieren:
sudo apt install unattended-upgrades apt-listchanges

# Automatische Updates aktivieren (beantworte die Frage mit "Yes"):
sudo dpkg-reconfigure -plow unattended-upgrades

# Prüfen ob die Konfiguration aktiv ist:
cat /etc/apt/apt.conf.d/20auto-upgrades
# Erwartete Ausgabe:
# APT::Periodic::Update-Package-Lists "1";
# APT::Periodic::Unattended-Upgrade "1";

# Trockenlauf testen (installiert nichts, zeigt nur was passieren würde):
sudo unattended-upgrades --dry-run --debug

# Log der letzten automatischen Updates prüfen:
sudo cat /var/log/unattended-upgrades/unattended-upgrades.log
🧠 Nur Sicherheitsupdates, keine Versions-Upgrades

Unattended-Upgrades installiert standardmäßig nur Sicherheitsupdates aus dem security-Repository -- keine neuen Versionen oder Feature-Updates. Das ist genau richtig: Sicherheitslücken werden automatisch geschlossen, aber keine unkontrollierten Änderungen am System vorgenommen.

Benutzerrechte -- sudo minimal halten

Aus Modul 08 weißt du, wie Benutzer und Gruppen funktionieren. Hier geht es darum, sudo-Rechte so knapp wie möglich zu vergeben. Jeder unnötige sudo-Zugang ist eine offene Tür.

🖥️ Auf dem Server -- per SSH eingeloggt

Prüfe zuerst, wer überhaupt sudo-Rechte hat:

sudo-Berechtigungen prüfen
# Alle Mitglieder der sudo-Gruppe anzeigen:
getent group sudo

# Prüfen welche Rechte ein bestimmter Benutzer hat:
sudo -l -U testuser

# Benutzer aus der sudo-Gruppe entfernen:
sudo deluser testuser sudo

# Letzte Logins aller Benutzer anzeigen:
lastlog
# Benutzer die sich noch nie eingeloggt haben erkennt man an "Never logged in"

# Nur Benutzer anzeigen, die sich schon eingeloggt haben:
lastlog | grep -v "Never logged in"

Benutzer die einen Dienst ausführen (z.B. einen Webserver) brauchen meist kein sudo. Lege für jeden Dienst einen eigenen Benutzer ohne Login-Shell an:

# Systembenutzer ohne Login-Shell anlegen (für Dienste):
sudo adduser --system --no-create-home --shell /usr/sbin/nologin webuser

# Prüfen dass der Benutzer sich nicht anmelden kann:
grep webuser /etc/passwd
# Die Shell /usr/sbin/nologin verhindert interaktiven Login
⚠️ Vorsicht bei sudoers-Änderungen

Bearbeite /etc/sudoers immer mit sudo visudo -- nie direkt mit einem Editor. visudo prüft die Syntax vor dem Speichern. Ein Syntaxfehler in /etc/sudoers kann dazu führen, dass du dich selbst aus sudo aussperrst.

Offene Ports und Datei-Berechtigungen prüfen

Offene Ports sind Einfallstore. Jeder Dienst der lauscht, ist ein potentielles Angriffsziel. Aus Modul 14 kennst du die Firewall -- hier geht es darum, zu prüfen was überhaupt läuft, bevor du Firewall-Regeln setzt. Aus Modul 11 weißt du, wie Berechtigungen funktionieren -- hier prüfen wir die kritischsten Dateien.

🖥️ Auf dem Server -- per SSH eingeloggt

Welche Ports sind offen und welcher Prozess hört dort?

Offene Ports prüfen
# Alle lauschenden TCP-Ports mit Prozessnamen anzeigen:
sudo ss -tlnp
# -t = TCP  -l = lauschend  -n = Nummern statt Namen  -p = Prozessname

# Auch UDP-Ports anzeigen:
sudo ss -ulnp

# Alternative mit netstat (falls installiert):
sudo netstat -tlnp

Sensible Dateien auf falsche Berechtigungen prüfen -- die Zahlen kennst du aus Modul 11:

Sensible Datei-Berechtigungen prüfen
# /etc/shadow: nur root und Gruppe shadow dürfen lesen:
ls -la /etc/shadow
# Erwartet: -rw-r----- root shadow ...

# SSH-Schlüssel des Benutzers prüfen:
ls -la ~/.ssh/
# id_ed25519 (privat) muss -rw------- sein (600)
# authorized_keys sollte -rw------- sein (600)

# Dateien mit SUID-Bit finden (können Rechte eskalieren):
find /usr/bin /usr/sbin -perm /4000 -ls

# World-writable Dateien in /etc finden (jeder kann schreiben -- Risiko!):
find /etc -perm -002 -type f -ls 2>/dev/null
Datei / VerzeichnisSoll-BerechtigungPrüfbefehl
/etc/shadow640 (root:shadow)ls -la /etc/shadow
~/.ssh/id_ed25519600ls -la ~/.ssh/
~/.ssh/authorized_keys600ls -la ~/.ssh/
/etc/ssh/sshd_config600 (root only)ls -la /etc/ssh/sshd_config
/etc/sudoers440ls -la /etc/sudoers
Rootkit-Check und Audit-Logs

Wenn ein Angreifer es trotzdem auf den Server geschafft hat, hinterlässt er Spuren. Rootkit-Scanner suchen nach bekannten Angriffswerkzeugen und verdächtigen Veränderungen am System.

🖥️ Auf dem Server -- per SSH eingeloggt
rkhunter -- Rootkit-Scanner
# rkhunter installieren:
sudo apt install rkhunter

# Datenbank aktualisieren (Referenzwerte für sauberes System speichern):
sudo rkhunter --update
sudo rkhunter --propupd

# System scannen:
sudo rkhunter --check --sk
# --sk = keine Bestätigung bei jedem Schritt nötig

# Nur Warnungen anzeigen:
sudo grep Warning /var/log/rkhunter.log
chkrootkit -- alternative Prüfung
# chkrootkit installieren:
sudo apt install chkrootkit

# System prüfen:
sudo chkrootkit

# Nur Treffer anzeigen:
sudo chkrootkit 2>/dev/null | grep INFECTED

Für dauerhafte Überwachung: auditd protokolliert Systemereignisse -- wer hat welche Datei wann geöffnet, welche Befehle wurden als root ausgeführt.

auditd -- Systemereignisse überwachen
# auditd installieren und aktivieren:
sudo apt install auditd
sudo systemctl enable --now auditd

# Letzte Audit-Ereignisse anzeigen:
sudo ausearch -ts today

# Alle fehlgeschlagenen Logins anzeigen:
sudo ausearch -m USER_LOGIN -sv no

# Audit-Log direkt lesen:
sudo tail -f /var/log/audit/audit.log
🧠 Erst das saubere System scannen, dann regelmäßig prüfen

Führe rkhunter --propupd direkt nach einer Neuinstallation aus, bevor der Server öffentlich erreichbar ist. Das speichert die Referenzwerte eines sauberen Systems. Spätere Scans vergleichen dann mit diesem Ausgangszustand -- so erkennst du Veränderungen zuverlässig.

Härtungs-Checkliste

Diese Checkliste fasst alle Maßnahmen zusammen. Hake sie nach und nach ab:

MaßnahmeModulPriorität
SSH: PermitRootLogin no02 + 24Kritisch
SSH: PasswordAuthentication no (nur Keys)02 + 24Kritisch
SSH: AllowUsers -- nur bekannte Nutzer24Hoch
Fail2ban aktiv und konfiguriert24Kritisch
Firewall aktiv (ufw), nur nötige Ports offen14Kritisch
Automatische Sicherheitsupdates aktiviert24Hoch
sudo: nur notwendige Benutzer haben Zugang08 + 24Hoch
Berechtigungen: /etc/shadow, SSH-Keys korrekt11 + 24Hoch
Offene Ports geprüft und dokumentiert24Mittel
rkhunter einmalig nach Neuinstallation ausgeführt24Mittel
auditd aktiv für kritische Systeme24Mittel
Backups: automatisiert und getestet23Hoch
🤖
KI-Tipp: Fail2ban-Logs auswerten

Fail2ban-Logs zeigen dir, wie viele Angriffe abgeblockt wurden und von wo. Wenn du verstehen willst, was passiert, kopiere ein paar Log-Zeilen und frag: „Hier sind meine fail2ban-Logs. Erkläre mir auf Deutsch, was diese Einträge bedeuten und ob die Konfiguration sinnvoll ist."

Praxisaufgaben
AUFGABE 24.1 SSH-Konfiguration härten

Du sicherst den SSH-Zugang deines Servers mit den wichtigsten Einstellungen ab. Das ist die wirkungsvollste Einzelmaßnahme zur Absicherung.

🖥️ Alle Schritte auf dem Server -- per SSH eingeloggt
1
Öffne ein zweites Terminal und verbinde dich parallel per SSH mit dem Server. Dieser zweite Zugang ist dein Rettungsanker.
2
Prüfe den aktuellen Zustand: sudo sshd -T | grep -E "permitrootlogin|passwordauthentication|maxauthtries". Notiere die aktuellen Werte.
3
Bearbeite die Konfiguration: sudo nano /etc/ssh/sshd_config. Setze PermitRootLogin no, MaxAuthTries 3 und LoginGraceTime 30.
4
Prüfe die Syntax: sudo sshd -t. Kein Fehler? Dann Dienst neu laden: sudo systemctl reload sshd.
5
Teste im zweiten Terminal: Öffne eine neue Verbindung. Funktioniert die Anmeldung noch? Prüfe auch ob Root abgelehnt wird.
Lösungshinweise anzeigen

Nach dem Reload sollte sudo sshd -T | grep permitrootlogin den Wert no ausgeben. Eine neue SSH-Verbindung als normaler Benutzer muss funktionieren. Ein Versuch mit ssh root@server sollte mit "Permission denied" fehlschlagen.

Falls sich niemand mehr einloggen kann: Du hast noch das zweite Terminal offen -- bearbeite die Konfiguration dort und lade den Dienst neu.

AUFGABE 24.2 Fail2ban einrichten

Du installierst fail2ban und konfigurierst den SSH-Schutz. Danach werden Brute-Force-Angriffe automatisch blockiert.

🖥️ Alle Schritte auf dem Server -- per SSH eingeloggt
1
Installiere fail2ban: sudo apt install fail2ban. Aktiviere den Dienst: sudo systemctl enable --now fail2ban.
2
Erstelle die lokale Konfiguration: sudo nano /etc/fail2ban/jail.local. Füge die SSH-Jail mit maxretry = 3 und bantime = 3600 ein. Trage dein eigenes Netz in ignoreip ein.
3
Starte den Dienst neu: sudo systemctl restart fail2ban. Prüfe den Status: sudo fail2ban-client status sshd.
4
Prüfe im Log ob fail2ban läuft: sudo tail -20 /var/log/fail2ban.log. Du solltest Einträge mit "INFO" und "NOTICE" sehen.
5
Prüfe die Anzahl blockierter IPs: sudo fail2ban-client status sshd. Auf einem öffentlichen Server siehst du oft schon nach kurzer Zeit gebannte Adressen.
Lösungshinweise anzeigen

sudo fail2ban-client status sshd zeigt "Currently banned" (aktuell gesperrte IPs) und "Total banned" (gesamt gesperrte IPs seit Start). Auch 0 ist korrekt -- das bedeutet noch hat niemand versucht sich einzuloggen.

Falls der Dienst nicht startet: Prüfe die Konfiguration auf Syntaxfehler mit sudo fail2ban-client -t.

AUFGABE 24.3 Offene Ports und Berechtigungen prüfen

Du machst eine Bestandsaufnahme: Welche Ports sind offen? Sind sensible Dateien korrekt gesichert?

🖥️ Alle Schritte auf dem Server -- per SSH eingeloggt
1
Zeige alle lauschenden TCP-Ports: sudo ss -tlnp. Notiere jeden Port und den zugehörigen Prozess. Kennst du alle Prozesse?
2
Prüfe die Berechtigung von /etc/shadow: ls -la /etc/shadow. Nur root und die Gruppe shadow dürfen lesen -- Rechte sollten 640 sein.
3
Prüfe deine SSH-Schlüssel: ls -la ~/.ssh/. Der private Schlüssel muss die Rechte 600 haben. Ist das der Fall?
4
Suche nach SUID-Programmen: find /usr/bin /usr/sbin -perm /4000 -ls. Erkennst du alle Programme in der Liste?
5
Prüfe alle sudo-Berechtigten: getent group sudo. Sind das wirklich alle Personen, die Administratorrechte brauchen?
Lösungshinweise anzeigen

Typische legitime SUID-Programme: sudo, su, passwd, ping, newgrp. Wenn unbekannte Programme auftauchen, ist das ein Warnsignal.

Falls SSH-Schlüssel falsche Rechte haben, korrigiere sie: chmod 600 ~/.ssh/id_ed25519 und chmod 700 ~/.ssh/.

AUFGABE 24.4 Automatische Updates und Rootkit-Check

Du aktivierst automatische Sicherheitsupdates und führst einen ersten Rootkit-Scan durch -- eine gute Baseline für einen sauberen Server.

🖥️ Alle Schritte auf dem Server -- per SSH eingeloggt
1
Installiere und konfiguriere automatische Updates: sudo apt install unattended-upgrades, dann sudo dpkg-reconfigure -plow unattended-upgrades -- beantworte die Frage mit "Yes".
2
Prüfe die Konfiguration: cat /etc/apt/apt.conf.d/20auto-upgrades. Siehst du beide Zeilen mit dem Wert "1"?
3
Installiere rkhunter: sudo apt install rkhunter. Aktualisiere die Datenbank: sudo rkhunter --update && sudo rkhunter --propupd.
4
Führe den ersten Scan durch: sudo rkhunter --check --sk. Lies die Zusammenfassung am Ende -- wie viele Warnungen gibt es?
5
Prüfe die Warnungen im Detail: sudo grep Warning /var/log/rkhunter.log. Auf einem frischen Debian/Ubuntu-System sind die meisten Warnungen false positives -- bekannte harmlose Abweichungen.
Lösungshinweise anzeigen

rkhunter gibt auf Debian/Ubuntu typischerweise einige Warnungen aus, die bekannte harmlose Abweichungen sind -- z.B. Skripte die durch das System verändert wurden. Echte Bedrohungen erkennst du an unbekannten Dateien in Systempfaden oder versteckten Prozessen.

Die Datei /etc/apt/apt.conf.d/20auto-upgrades muss beide Zeilen mit "1" enthalten. Falls nicht, öffne die Datei manuell und füge sie hinzu.

🤖
KI-Tipp: Härtungsplan für deinen Server

Jeder Server hat andere Anforderungen. Lass dir einen individuellen Plan erstellen: „Mein Debian 12 Server läuft mit SSH, Nginx und MariaDB und ist direkt im Internet erreichbar. Ich habe Modul 24 des Linux-Kompendiums durchgearbeitet. Welche weiteren Härtungsmaßnahmen empfiehlst du mir, in welcher Reihenfolge, und warum?"

Modul 253 Unterrichtseinheiten

Systemrettung & Wiederherstellung

Wenn der Server streikt, nicht mehr bootet oder der Bootloader weg ist -- genau dann brauchst du die Werkzeuge aus diesem Modul. Systemrettung ist wie Pannenhilfe: ruhig bleiben, systematisch vorgehen, das richtige Werkzeug wählen.

Voraussetzung: Modul 09 Voraussetzung: Modul 22 Voraussetzung: Modul 23 Recovery · GRUB · fsck · chroot · Live-System
Zwei Kontexte bei der Systemrettung

Systemrettung findet an zwei verschiedenen Orten statt: Manchmal kommst du noch per SSH rein und kannst Diagnose-Befehle ausführen. Manchmal ist das System komplett weg -- dann musst du direkt vor dem Server sitzen oder eine Rescue-Konsole nutzen. Ab jetzt markieren wir in diesem Modul immer klar, wo du dich befindest:

🖥️ Server (per SSH)

Befehle, die du per SSH auf dem noch erreichbaren Server eingibst -- System läuft noch teilweise.

🔧 Direkt am Server (physischer Zugriff)

Befehle an der Server-Konsole -- bei Live-System, Recovery-Mode oder GRUB. Kein SSH möglich.

System reagiert nicht -- erste Schritte

Dein Server antwortet nicht mehr. Wie gehst du vor? Genau wie ein Kfz-Meister beim Pannenauto: zuerst von außen prüfen, bevor du die Motorhaube öffnest.

🖥️ Server (per SSH) -- Diagnose-Befehle, solange du noch reinkommst

Falls SSH noch antwortet, prüfe als erstes diese Punkte:

Erreichbarkeit prüfen (von deinem lokalen Rechner)
# Ist der Server im Netz erreichbar?
ping -c 4 192.168.1.50

# SSH-Verbindungstest mit mehr Ausgabe:
ssh -v admin@192.168.1.50
# -v = verbose: zeigt genau, wo die Verbindung hängt

Wenn du per SSH draufkommst: prüfe Systemlast und freien Speicher:

Systemzustand prüfen
# Festplattenplatz -- läuft das System voll?
df -h

# RAM-Auslastung prüfen:
free -h

# Wer frisst die CPU? (q zum Beenden)
top

# Letzte System-Ereignisse anzeigen:
journalctl -n 50 --no-pager
SymptomWahrscheinliche UrsacheErster Schritt
SSH: "Connection refused"SSH-Dienst gestoppt oder Port geändertKonsolen-Zugriff nötig
SSH: Timeout (hängt ewig)Netzwerk-Problem oder FirewallPing-Test, Router prüfen
SSH: "Connection reset"System gestürzt oder rebootetKurz warten, erneut versuchen
Ping: kein ResponseServer aus, Netz down oder blockiertPhysischer Zugriff nötig
System langsam, kein LoginCPU/RAM/Disk überlastettop, df -h
Boot-Logs auswerten: journalctl und dmesg

Die wichtigsten Diagnose-Werkzeuge sind die Boot-Logs. Sie erzählen dir, was beim letzten Start passiert ist -- wie ein Fahrtenschreiber im LKW. Du brauchst dafür Zugang zum laufenden System (per SSH oder direkt an der Konsole).

🖥️ Server (per SSH oder direkt an der Konsole)
journalctl -- der Systemlog-Viewer
# Boot-Log des letzten Starts anzeigen (-x = erklärender Text, b = aktueller Boot):
journalctl -xb

# Nur Fehler und Warnungen anzeigen:
journalctl -b -p err

# Log eines bestimmten Dienstes anzeigen:
journalctl -u nginx.service --no-pager

# Log des vorletzten Boots (nützlich nach Absturz):
journalctl -b -1

# Live-Ausgabe verfolgen (wie "tail -f" für den Systemlog):
journalctl -f
dmesg -- Kernel-Nachrichten
# Alle Kernel-Meldungen anzeigen (besonders Hardware-Fehler):
dmesg

# Nur Fehler und kritische Meldungen:
dmesg --level=err,crit

# Live-Kernel-Meldungen verfolgen:
dmesg -w

# Nach einem bestimmten Begriff suchen:
dmesg | grep -i error
🧠 Was suche ich in den Logs?

Filtere nach diesen Stichwörtern: error, failed, panic, killed, oom (Out of Memory). Ein typischer Hinweis auf einen kaputten Dienst sieht so aus: "nginx.service: Start request repeated too quickly" -- der Dienst startet und stürzt sofort ab.

🤖
KI-Tipp: Boot-Fehler deuten

Boot-Logs können lang und kryptisch sein. Kopiere die relevanten Zeilen und frag: „Mein Debian-Server zeigt beim Booten diese journalctl-Ausgabe: [Zeilen einfügen]. Was bedeuten die Fehlermeldungen und wie behebe ich das Problem Schritt für Schritt?"

Recovery-Modus und Single-User-Mode

Wenn das System noch teilweise bootet, aber du dich nicht einloggen kannst, hilft der Recovery-Modus. Du brauchst dafür physischen Zugang zum Server oder eine Remote-Konsole (z.B. IPMI, KVM oder die Konsole deines Cloud-Anbieters).

🔧 Direkt am Server -- am Boot-Bildschirm

Beim Starten des Servers erscheint das GRUB-Menü. Falls es nicht erscheint, halte Shift (BIOS) oder drücke Esc (UEFI) gedrückt.

Recovery-Mode aus dem GRUB-Menü starten
# 1. Im GRUB-Menü: "Advanced options for Debian GNU/Linux" wählen
# 2. Dann: "... (recovery mode)" auswählen
# 3. Du landest im Recovery-Menü mit diesen Optionen:
#    clean    -- Speicherplatz freigeben
#    dpkg     -- kaputte Pakete reparieren
#    fsck     -- Dateisystem prüfen
#    grub     -- GRUB-Bootloader reparieren
#    network  -- Netzwerk aktivieren
#    root     -- Root-Shell öffnen

Mit der Option root öffnest du eine Root-Shell. Dort kannst du z.B. das Root-Passwort zurücksetzen oder einen kaputten Dienst deaktivieren.

🔧 Direkt am Server -- GRUB-Eintrag manuell bearbeiten

Wenn kein Recovery-Modus vorhanden ist (z.B. auf minimalen Installationen), kannst du im GRUB-Menü einen Eintrag direkt bearbeiten:

init=/bin/bash -- direkt zur Root-Shell
# 1. Im GRUB-Menü: Kernel-Eintrag markieren, dann 'e' drücken
# 2. In der Zeile, die mit "linux /boot/vmlinuz..." beginnt:
#    Am Ende der Zeile 'quiet splash' entfernen und ersetzen durch:
init=/bin/bash
# 3. Booten mit Ctrl+X
# 4. Du landest in einer minimalen Root-Shell (read-only)

# Dateisystem read-write mounten:
mount -o remount,rw /

# Passwort zurücksetzen:
passwd root

# Synchronisieren und Neustart erzwingen:
sync
reboot -f
⚠️ Passwort zurücksetzen = physische Sicherheit

Diese Methode zeigt: Wer physischen Zugriff auf einen Server hat, kann das Root-Passwort zurücksetzen. Deshalb müssen Server immer in abgeschlossenen Serverräumen stehen. Bei Cloud-Servern ist diese Methode nur über die Konsole des Anbieters möglich.

GRUB -- Bootloader reparieren

GRUB ist das erste, was beim Serverstart läuft -- bevor der Linux-Kernel geladen wird. Wenn GRUB kaputt ist, bleibt der Bildschirm schwarz oder du siehst einen grub rescue>-Prompt. In diesem Fall brauchst du ein Live-System (USB-Stick oder ISO).

🔧 Direkt am Server -- vom Live-System aus (nach chroot)

Boote zuerst von einem Live-System, führe dann die chroot-Prozedur durch (siehe Abschnitt "Live-System mounten und chroot"), und repariere dann GRUB von dort aus:

GRUB neu installieren (im chroot)
# (Du bist bereits im chroot -- siehe Abschnitt unten)

# GRUB auf BIOS/MBR-System installieren:
grub-install /dev/sda
# Wichtig: /dev/sda ist die GESAMTE Festplatte, keine Partition!

# GRUB auf UEFI-System installieren:
grub-install --target=x86_64-efi --efi-directory=/boot/efi

# GRUB-Konfiguration neu generieren (findet alle Kernel):
update-grub
# Gut: "Found linux image: /boot/vmlinuz-6.1.0-..."
# Schlecht: keine Ausgabe oder nur Fehlermeldungen

Nach update-grub und exit aus dem chroot: alles aushängen und neu starten.

GRUB-SymptomBedeutungLösung
Schwarzer Bildschirm nach POSTGRUB-MBR/GPT beschädigtgrub-install vom Live-System
grub rescue> PromptGRUB-Module fehlen oder Pfad falschchroot + grub-install
error: file not foundKernel-Datei fehlt oder Pfad falschupdate-grub im chroot
Altes System wird gebootetupdate-grub nach Kernel-Update vergessensudo update-grub
fsck -- Dateisystem reparieren

Ein Dateisystem kann nach einem plötzlichen Stromausfall oder Systemabsturz inkonsistent werden -- wie ein Buch, aus dem jemand mitten im Schreiben herausgerissen wurde. fsck prüft das Dateisystem und repariert es, wenn nötig.

🚨 fsck NIE auf eingehängtem Dateisystem!

fsck auf einer eingehängten (aktiven) Partition kann das Dateisystem endgültig zerstören. Führe fsck immer im abgehängten Zustand aus -- also vom Live-System oder aus dem Recovery-Modus heraus.

🔧 Direkt am Server -- vom Live-System oder Recovery-Modus
Dateisystem prüfen und reparieren
# Zuerst herausfinden, welche Partitionen es gibt:
lsblk
fdisk -l
# Typisch: /dev/sda1 = /boot, /dev/sda2 = / (Root)

# Probelauf -- nur prüfen, nichts reparieren:
sudo fsck -n /dev/sda2

# Prüfen und automatisch reparieren (alle Fragen mit "yes" beantworten):
sudo fsck -y /dev/sda2

# Tiefenprüfung mit e2fsck (für ext4-Dateisysteme):
sudo e2fsck -f /dev/sda2

Nach der Reparatur neu starten. Das System sollte jetzt wieder normal booten.

Live-System mounten und chroot

Wenn gar nichts mehr geht, bootest du von einem Live-System (USB-Stick). Von dort aus steigst du per chroot in dein kaputtes System ein -- wie ein Pannendienst, der von außen in die Motorsteuerung eingreift. Diese Technik ist universell: GRUB reparieren, Passwort zurücksetzen, kaputte Pakete beheben -- alles geht über chroot.

🔧 Direkt am Server -- vom Live-System gebootet

Stecke den USB-Stick ein, boote vom Live-Medium (Boot-Reihenfolge im BIOS/UEFI anpassen) und öffne ein Terminal.

Schritt 1: Partitionen des kaputten Systems finden
lsblk
# Zeigt alle Festplatten und Partitionen
# Typisch: /dev/sda1 = Boot, /dev/sda2 = Root (größere Partition)

fdisk -l
# Detaillierter: zeigt Partitionstypen (Linux, EFI, Swap)
Schritt 2: Partitionen einbinden und chroot starten
# Root-Partition einbinden:
sudo mount /dev/sda2 /mnt

# Boot-Partition einbinden (wenn vorhanden):
sudo mount /dev/sda1 /mnt/boot

# EFI-Partition einbinden (nur bei UEFI-Systemen):
sudo mount /dev/sda1 /mnt/boot/efi

# Pseudo-Dateisysteme einbinden (nötig für GRUB, apt, etc.):
sudo mount --bind /dev /mnt/dev
sudo mount --bind /dev/pts /mnt/dev/pts
sudo mount -t proc proc /mnt/proc
sudo mount -t sysfs sys /mnt/sys

# DNS für apt-Zugriff ermöglichen:
sudo cp /etc/resolv.conf /mnt/etc/resolv.conf

# Ins kaputte System einsteigen:
sudo chroot /mnt /bin/bash
# Ab jetzt bist du "im" kaputten System
Schritt 3: Aufräumen und Neustart
# chroot verlassen:
exit

# Alles rekursiv aushängen:
sudo umount -R /mnt

# Neu starten:
sudo reboot
🧠 Live-USB erstellen und bereit halten

Lade das Debian-Live-ISO von cdimage.debian.org herunter und schreibe es auf einen USB-Stick. Unter Windows empfiehlt sich das Tool Rufus, unter Linux nutze dd. Den USB-Stick immer griffbereit halten -- im Notfall sucht man ihn sonst vergeblich.

Häufige Boot-Probleme und Lösungen

Die meisten Boot-Probleme fallen in wenige Kategorien. Diese Tabelle ist deine erste Anlaufstelle, wenn das System nach einem Eingriff nicht mehr bootet.

ProblemSymptomUrsacheLösung
fstab-Fehler"Give root password for maintenance"Falsche UUID oder Partition in /etc/fstabRecovery-Shell, fstab korrigieren
Volle FestplatteSystem hängt, Dienste starten nichtPartition zu 100 % volldf -h, Logs löschen
Defekter DienstBoot stoppt, Timeout-MeldungenDienst schlägt beim Start fehlsystemctl disable dienst, neu starten
Kernel-Panik"Kernel panic -- not syncing"Kernel-Bug, Hardware, defekte initramfsÄlteren Kernel aus GRUB wählen
Fehlende Abhängigkeit"A dependency job failed"Dienst braucht anderen Dienstjournalctl -xb, Fehler finden

fstab-Fehler korrigieren

🔧 Direkt am Server -- in der Recovery-Shell

Der häufigste Boot-Stopper: eine falsche /etc/fstab. Passiert gern nach einem Festplatten-Tausch oder wenn man UUIDs durcheinanderbringt (Modul 10).

/etc/fstab prüfen und reparieren
# Aktuelle Block-Geräte mit UUIDs anzeigen:
blkid

# fstab ansehen (lies die UUIDs):
cat /etc/fstab

# fstab bearbeiten:
nano /etc/fstab
# UUID anpassen falls nötig, dann Ctrl+X, Y, Enter

# fstab testen ohne Neustart:
mount -a
# Keine Ausgabe = alles OK. Fehlermeldung = noch ein Fehler in fstab

Volle Festplatte -- Notfall-Aufräumen

🖥️ Server (per SSH) -- solange du noch reinkommst
Schnell Platz schaffen
# Wo ist der Platz weg?
df -h
du -sh /var/log/* | sort -rh | head -20

# Alte Log-Dateien bereinigen:
sudo journalctl --vacuum-size=100M

# APT-Cache leeren:
sudo apt clean

# Große Dateien finden (Verzeichnis /proc ausschließen):
sudo find / -type f -size +100M -not -path '/proc/*' 2>/dev/null
Backup wiederherstellen

Manchmal ist die schnellste Lösung das Backup. Wenn du mit Borg Backup aus Modul 23 arbeitest, kannst du einzelne Dateien oder den ganzen Server gezielt wiederherstellen.

🖥️ Server (per SSH) -- Borg-Wiederherstellung
Borg Backup wiederherstellen (aus Modul 23)
# Liste aller verfügbaren Backups anzeigen:
borg list /backup/borg-repo

# Einzelne Datei wiederherstellen (Beispiel: nginx-Konfiguration):
borg extract /backup/borg-repo::server-2025-11-01 etc/nginx/nginx.conf

# Ganzes Verzeichnis wiederherstellen:
borg extract /backup/borg-repo::server-2025-11-01 etc/nginx/

# Komplette Wiederherstellung in ein Verzeichnis:
cd /tmp/restore
borg extract /backup/borg-repo::server-2025-11-01
💡 Backup-Strategie aus Modul 23

In Modul 23 hast du gelernt, wie du mit Borg automatische Backups einrichtest. Teste dein Backup regelmäßig -- am besten monatlich -- damit du im Ernstfall sicher bist, dass es funktioniert. Ein Backup, das noch nie getestet wurde, ist kein echtes Backup.

🤖
KI-Tipp: Systemrettungs-Checkliste erstellen

Jeder Server ist etwas anders. Lass dir eine maßgeschneiderte Checkliste erstellen: „Mein Debian-Server läuft mit UEFI, Borg-Backups und nginx. Erstelle mir eine Schritt-für-Schritt-Notfall-Checkliste für den Fall, dass das System nach einem Update nicht mehr bootet." Diese Checkliste druckst du aus und legst sie neben den Server.

Praxisaufgaben
AUFGABE 25.1 Boot-Logs lesen und auswerten

Du lernst, Boot-Logs systematisch auszuwerten. Das ist die Grundlage jeder Diagnose -- immer zuerst in die Logs schauen, bevor du etwas änderst.

🖥️ Per SSH auf dem Server angemeldet
1
Zeige die Log-Einträge des aktuellen Boots an: journalctl -xb | head -100. Scrolle durch die Ausgabe und suche nach Zeilen mit "failed" oder "error".
2
Filtere direkt nach Fehlern: journalctl -b -p err. Was siehst du?
3
Zeige die Kernel-Meldungen des aktuellen Boots: dmesg --level=err,crit. Gibt es Hardware-Fehler oder Speicherprobleme?
4
Prüfe den Zustand aller Systemdienste: systemctl --failed. Diese Ansicht zeigt dir sofort, welche Dienste nicht gestartet sind.
5
Prüfe den freien Speicher: df -h und free -h. Halte die Ausgaben fest -- das ist dein Basis-Gesundheitscheck.
Lösungshinweise anzeigen

journalctl -b -p err zeigt nur Meldungen mit Priorität "error" oder höher. Auf einem gesunden System sind das meist nur Warnungen über fehlende optionale Hardware. systemctl --failed zeigt im normalen Betrieb "0 loaded units listed" -- das ist der Idealzustand.

Wenn du einen fehlgeschlagenen Dienst siehst, schau mit journalctl -u dienstname.service nach den Details.

AUFGABE 25.2 chroot-Umgebung in einer VM üben

Du übst die vollständige chroot-Prozedur in einer sicheren VM-Umgebung. Das ist die wichtigste Rettungstechnik -- sie hilft bei GRUB-Problemen, Paket-Schäden und vergessenen Passwörtern.

🔧 Direkt an der VM-Konsole -- vom Live-ISO gebootet
1
Starte deine Test-VM vom Debian-Live-ISO. Im Live-System: Öffne ein Terminal und zeige alle Partitionen: lsblk und fdisk -l. Notiere dir, welche Partition die Root-Partition des installierten Systems ist (meist die größte).
2
Binde die Root-Partition ein: sudo mount /dev/sda2 /mnt (passe sda2 an deine Situation an). Dann die Pseudo-Dateisysteme: sudo mount --bind /dev /mnt/dev, sudo mount -t proc proc /mnt/proc, sudo mount -t sysfs sys /mnt/sys.
3
Steige ins System ein: sudo chroot /mnt /bin/bash. Prüfe, dass du wirklich im installierten System bist: cat /etc/hostname und cat /etc/debian_version.
4
Führe im chroot aus: update-grub. Du solltest sehen, dass GRUB die Kernel-Dateien findet. Dann: grub-install /dev/sda.
5
Verlasse chroot mit exit und hänge alles aus: sudo umount -R /mnt. Starte die VM neu -- sie sollte normal booten.
Lösungshinweise anzeigen

Im chroot zeigt cat /etc/hostname den Hostnamen des installierten Systems -- nicht den des Live-Systems. Das bestätigt, dass du im richtigen System bist. update-grub gibt aus "Found linux image: /boot/vmlinuz-..." -- das ist die Bestätigung, dass GRUB die Kernel-Datei gefunden hat.

umount -R /mnt hängt rekursiv alle Unterverzeichnisse aus. Falls umount meldet "target is busy", hat noch ein Prozess die Dateien geöffnet -- erst exit tippen, dann erneut versuchen.

AUFGABE 25.3 fstab-Fehler simulieren und beheben

Ein falscher fstab-Eintrag ist einer der häufigsten Gründe, warum ein Server nach einem Umbau nicht mehr bootet. Du simulierst diesen Fehler in einer VM und behebst ihn über den Recovery-Modus.

🖥️ Per SSH -- auf der Test-VM
1
Mache eine Sicherungskopie von fstab: sudo cp /etc/fstab /etc/fstab.bak. Dann füge eine ungültige Zeile ein: echo "/dev/sdz1 /mnt/fake ext4 defaults 0 0" | sudo tee -a /etc/fstab
2
Teste die kaputte fstab: sudo mount -a. Du siehst eine Fehlermeldung -- das Gerät existiert nicht. Starte die VM neu: sudo reboot.
🔧 Direkt an der VM-Konsole -- am Boot-Bildschirm
3
Die VM bleibt mit "Give root password for maintenance" stehen. Gib das Root-Passwort ein, um die Recovery-Shell zu betreten. (Falls du kein Root-Passwort hast: über GRUB mit init=/bin/bash starten.)
4
Im Recovery: Mounte das Dateisystem read-write: mount -o remount,rw /. Entferne dann die ungültige Zeile: nano /etc/fstab -- lösche die Zeile mit /dev/sdz1, speichere mit Ctrl+X.
5
Teste die korrigierte fstab: mount -a. Keine Fehlermeldung = Erfolg. Starte neu: reboot -f. Das System sollte jetzt normal booten.
Lösungshinweise anzeigen

Die Fehlermeldung beim Boot lautet typisch: "Dependency failed for /mnt/fake" oder "failed to mount /mnt/fake". Das System bleibt dann in einem eingeschränkten Modus mit der Aufforderung, das Root-Passwort einzugeben.

In der Recovery-Shell ist das Dateisystem zunächst read-only -- deshalb zuerst mount -o remount,rw /. Nach dem Beheben des fstab-Fehlers und mount -a ohne Fehler-Ausgabe ist das System wieder bootfähig.

Du hast es geschafft -- alle 25 Module!

Herzlichen Glückwunsch. Du hast das gesamte Linux Server Administration Kompendium abgeschlossen -- 25 Module, 76 Unterrichtseinheiten, von den Grundlagen der Netzwerktechnik bis zur Systemrettung.

Du weißt jetzt, wie du einen Server per SSH fernverwaltest, Dienste mit systemd steuerst, Backups einrichtest, eine Firewall konfigurierst, Docker-Container betreibst und -- genau wie in diesem Modul -- ein kaputtes System wieder zum Laufen bringst. Das ist kein Einsteigerwissen mehr.

🧠 Was jetzt?

Praxis ist alles. Richte einen eigenen Server ein -- ob zuhause auf alter Hardware, auf einem Raspberry Pi oder bei einem günstigen Cloud-Anbieter. Bringe Dienste zum Laufen, mache Fehler, lerne aus den Logs. Das Kompendium ist dein Nachschlagewerk -- komm bei Bedarf zurück.