Warum Linux die Serverwelt beherrscht
Gehen Sie in ein beliebiges Rechenzentrum, öffnen Sie eine beliebige Cloud-Konsole oder docker exec in einen beliebigen Container, und Sie befinden sich fast sicher auf einem Linux-Kernel. Er treibt die Mehrheit der Webserver, jedes Android-Smartphone, die meisten Router und die überwältigende Mehrheit der Cloud-Instanzen an. Die Gründe dafür sind altbewährt: Es ist kostenlos, läuft auf fast jeder Hardware, ist stabil genug, um jahrelang ohne Unterbrechung zu laufen, und lässt sich von oben bis unten skripten.
Für Entwickler ist der praktische Aspekt spezifischer. In dem Moment, in dem Sie deployen, hören Sie auf, eine Person zu sein, die Dateien in einem Editor bearbeitet, und werden zu jemandem, der Befehle in eine Shell tippt – oft über SSH auf einer Maschine, die Sie nicht sehen können. Die Fähigkeiten in diesem Guide sind genau diejenigen, die diese Maschine lesbar machen, anstatt beängstigend.
Sie müssen kein Systemadministrator werden. Sie benötigen lediglich genügend Routine, um sich zurechtzufinden, Logs zu lesen, Berechtigungen zu korrigieren, einen Service neu zu starten und zu verstehen, welcher Prozess auf einem Port lauscht.
WSL und macOS: Du weißt bereits mehr, als du denkst
Wenn du macOS nutzt, befindest du dich bereits auf einem Unix-System. Das Terminal, die Struktur des Dateisystems und die meisten Befehle — ls, cd, grep, chmod, ssh — funktionieren auf die gleiche Weise. Die Unterschiede liegen hauptsächlich im Paketmanager und in einigen wenigen BSD- gegenüber GNU-Flags.
Unter Windows bietet dir WSL 2 einen echten Linux-Kernel innerhalb einer leichtgewichtigen virtuellen Maschine. wsl --install installiert dir Ubuntu mit einer Shell, und deine Dateien sind von beiden Seiten aus erreichbar. Dies ist der empfohlene Weg, da es dieselbe Umgebung ist, in der dein Code später laufen wird.
Selbst wenn du Linux nie direkt installierst, lässt sich das mentale Modell vollständig auf Container übertragen, welche im Grunde Linux-Userland-Prozesse in einem sehr überzeugenden Kostüm sind.
Das Dateisystem ist ein einziger Baum
Im Gegensatz zu Windows, wo Laufwerke separate Wurzeln bilden, hat Linux einen einzigen Baum mit der Wurzel bei /. Jede Festplatte, jeder Netzwerkshare und jedes Gerät wird irgendwo darin eingehängt (mounted). Eine Handvoll Verzeichnisse haben konventionelle Bedeutungen – wenn man diese kennt, weiß man immer, wo man suchen muss.
/ the root of everything
├── bin essential user binaries (ls, cp, bash)
├── etc system-wide configuration files
├── home per-user home directories
├── opt optional third-party software
├── proc kernel and process state, as files
├── root the root user's home
├── tmp temporary files, cleared on reboot
├── usr installed programs and libraries
│ ├── bin local binaries
│ └── lib shared libraries
└── var variable data: logs, caches, databases
├── log system and application logs
└── www web content on Debian systems
Die beiden Verzeichnisse, die Sie am häufigsten besuchen werden, sind /etc für Konfigurationen und /var/log für Logs. Wenn etwas nicht funktioniert, sind dies die ersten Orte, an denen man nachsieht. Wenn Sie eine Anwendung selbst installieren, halten /opt oder /usr/local diese vom Paketmanager fern.
Pfade sind entweder absolut (beginnen mit /, wie z. B. /etc/hosts) oder relativ (werden ausgehend von Ihrem aktuellen Verzeichnis aufgelöst). ~ ist eine Abkürzung für Ihr Home-Verzeichnis, . steht für das aktuelle Verzeichnis und .. für dessen übergeordnetes Verzeichnis. Diese drei Symbole tauchen in fast jedem Befehl auf, den Sie eingeben.
Alles ist eine Datei
Die grundlegendste Unix-Idee ist, dass fast alles als Datei dargestellt wird. Eine Festplatte ist /dev/sda. Ein Terminal ist /dev/pts/0. Informationen über laufende Prozesse befinden sich unter /proc/<pid>/. Zufallszahlen kommen aus /dev/urandom. Auch ein Unix-Domain-Socket ist eine Datei.
Diese Einheitlichkeit ist es, was die Shell so mächtig macht. Dieselben cat, grep, less und Redirection-Operatoren funktionieren bei einer Log-Datei, der Memory-Map eines Prozesses oder einem Device, da sie alle im Grunde nur Byte-Streams hinter einem Pfad sind. Wenn man das versteht, wirken /proc und /sys nicht mehr wie Magie, sondern werden analysierbar.
cat /proc/cpuinfo | grep 'model name' | head -1
ls -l /dev/null # the bit bucket
Navigation und die Datei-Befehle, die Sie täglich nutzen werden
Die Shell ist eine Schleife: Sie liest eine Zeile, erweitert sie, sucht das Programm und führt es aus. Sechs Befehle decken den Großteil der Navigation ab.
pwd # print working directory
ls -lah # list, long format, human sizes, hidden files
cd /var/log # change directory
cd - # back to the previous directory
cd ~ # home
tree -L 2 # a readable tree, two levels deep
Das Erstellen, Kopieren, Verschieben und Löschen von Dateien erfordert ein ebenso kleines Vokabular. mkdir -p erstellt bei Bedarf übergeordnete Verzeichnisse. cp -r kopiert Verzeichnisse rekursiv. mv benennt Dateien innerhalb eines Dateisystems um und verschiebt sie zwischen verschiedenen Dateisystemen. rm -rf löscht einen gesamten Verzeichnisbaum, weshalb dieser Befehl Respekt verdient: In der Kommandozeile gibt es keinen Papierkorb.
mkdir -p app/{src,test,docs}
cp -r app app.bak
mv notes.txt docs/notes.txt
rm -rf build/
Zwei Gewohnheiten sorgen für Ihre Sicherheit. Nutzen Sie ls oder find, um zu bestätigen, welche Dateien ein Glob-Pattern matcht, bevor Sie rm damit ausführen. Und bevorzugen Sie mv in ein Backup-Verzeichnis, anstatt etwas zu löschen, bei dem Sie unsicher sind. Die Shell-History ist kein Sicherheitsnetz, sobald Sie Enter drücken.
Dateien lesen, ohne einen Editor zu öffnen
Um etwas auf einem Server zu prüfen, benötigt man selten einen vollständigen Editor. Diese Tools geben nur den Teil aus, den Sie tatsächlich benötigen.
cat /etc/os-release # print the whole file
less /var/log/syslog # page through, / to search, q to quit
head -n 20 access.log # first 20 lines
tail -n 50 access.log # last 50 lines
tail -f app.log # follow a live log
wc -l access.log # count lines
tail -f ist der nützlichste Befehl während eines Incidents: Er streamt neue Zeilen in Echtzeit, während sie geschrieben werden. Drücken Sie Ctrl+C, um den Vorgang zu stoppen. less ist schneller als ein Editor und verändert die Datei niemals versehentlich, was besonders in Produktionsumgebungen wichtig ist.
Suchen mit find und grep
find durchläuft das Dateisystem und filtert nach Metadaten; grep durchsucht die Inhalte von Dateien. Zusammen beantworten sie die meisten „Wo ist das?“-Fragen.
find /etc -name '*.conf' # by name
find . -type d -name node_modules -prune -o -type f -name '*.ts' -print
find /var/log -type f -mtime -1 # modified in the last day
find . -type f -size +50M # larger than 50 MB
find . -type f -name '*.tmp' -delete # delete matches
grep -RIn 'TODO' src/ # recursive, line numbers, ignore binary
grep -c 'ERROR' app.log # count matches
grep -E 'timeout|refused' app.log # extended regex
grep -v '^#' config.ini # invert: drop comments
Wenn grep keine Ergebnisse liefert, ist dies ein Erfolg und kein Fehler, allerdings wird es mit dem Status 1 beendet. Das führt bei Skripten unter set -e oft zu Problemen; hängen Sie || true an, wenn ein leeres Ergebnis akzeptabel ist.
Berechtigungen: rwx und die oktale Kurzschreibweise
Jede Datei hat einen Besitzer, eine Gruppe und jeweils drei Berechtigungs-Bits: lesen (r), schreiben (w) und ausführen (x). ls -l zeigt diese als zehn Zeichen langen String an.
-rwxr-xr-- 1 deploy www-data 512 Sep 16 10:00 deploy.sh
Oktal ist die Kurzschreibweise. Jedes Triplett ist die Summe aus 4 (lesen), 2 (schreiben) und 1 (ausführen), sodass rwx 7 ist, r-x 5 ist und r-- 4 ist. Das bedeutet, dass 755 für rwxr-xr-x steht und 644 für rw-r--r--.
chmod 755 deploy.sh # scripts and directories
chmod 644 index.html # regular files
chmod 600 .env # secrets only the owner can read
chmod u+x,g-w,o-rwx script # symbolic form, easier to review
Verzeichnisse benötigen das Execute-Bit, um betreten werden zu können. Deshalb verbirgt das Entfernen von x bei einem Verzeichnis dessen Inhalt, selbst wenn das Read-Bit noch gesetzt ist. Dies ist eine subtile Ursache für “permission denied”-Fehler, obwohl die Leseberechtigungen korrekt aussehen.
Besitz, Gruppen und umask
chown ändert den Besitzer und die Gruppe; chgrp ändert nur die Gruppe. Setzen Sie sudo als Präfix davor, da nur root Dateien übertragen kann.
sudo chown deploy:www-data /var/www/app
sudo chgrp -R www-data /var/www/app/uploads
Neue Dateien erhalten ihre Berechtigungen über die umask, eine Maske, die vom Standardwert abgezogen wird. Eine umask von 022 ergibt 644 für Dateien und 755 für Verzeichnisse; 027 ergibt 640 und 750. Setzen Sie diese in Ihrem Shell-Profil oder in der Unit-Datei eines Dienstes, wenn ein strengerer Standard erforderlich ist.
umask # show current, e.g. 0022
umask 027 # stricter for this shell
sudo und die Gewohnheit der minimalen Rechtevergabe
sudo führt einen einzelnen Befehl als ein anderer Benutzer aus – standardmäßig als root –, nachdem /etc/sudoers überprüft wurde. Dies ist bewusst eng gefasst: Gewähren Sie nur die spezifischen Befehle, die eine Person oder ein Dienst benötigt, anstatt eine root-Shell bereitzustellen. Bevorzugen Sie sudo -u www-data <cmd>, anstatt Dateien als root zu bearbeiten und sie so im Besitz von root zu lassen.
sudo systemctl restart my-api
sudo -u postgres psql -c '\l'
sudo -l # what am I allowed to run?
Eine Faustregel: root besitzt die Systemkonfiguration, ein dedizierter Service-User besitzt die Anwendungsdateien und Ihre App läuft niemals als root. Wenn eine Kompromittierung Ihrer App einem Angreifer root-Rechte auf dem Host verschaffen würde, sind die Berechtigungen wirkungslos.
Benutzer und Gruppen
Benutzer werden durch einen Namen und eine numerische uid identifiziert; Gruppen durch einen Namen und eine gid. Das Mapping befindet sich in /etc/passwd und /etc/group, während die gehashten Passwörter in /etc/shadow gespeichert sind und nur für root lesbar sind.
whoami # current user
id # uid, gid and groups
groups deploy # groups a user belongs to
sudo adduser appuser # create a user (Debian/Ubuntu)
sudo usermod -aG docker appuser # add to a group
sudo userdel -r appuser # remove the user and home
Service-Accounts haben in der Regel kein Passwort und keine Login-Shell. Das ist beabsichtigt: Sie existieren dazu, Dateien zu besitzen und einen einzelnen Prozess auszuführen, nicht um sich darin einzuloggen.
Prozesse: ps, top und Signale
Jedes laufende Programm ist ein Prozess mit einer pid, einem Besitzer und einem Elternprozess. ps erstellt eine Momentaufnahme; top und htop aktualisieren live.
ps aux | grep node # find a process
ps -eo pid,ppid,user,%cpu,%mem,cmd --sort=-%cpu | head
top -o %MEM # interactive, sort by memory
pgrep -af node # pids and full command lines
Prozesse kommunizieren über Signale. SIGTERM (15) bittet einen Prozess, zu beenden, und ist der Standard für kill; SIGINT (2) ist Ctrl+C; SIGHUP (1) bedeutet traditionell ein Neuladen; SIGKILL (9) kann nicht abgefangen werden und sollte das letzte Mittel sein.
kill 1234 # SIGTERM, graceful
kill -HUP 1234 # reload config
kill -9 1234 # force, no cleanup
pkill -f 'node server.js'
Sende zuerst SIGTERM und gib dem Prozess einige Sekunden Zeit, um Verbindungen zu schließen und den Status zu flushen. Eskaliere erst zu -9, wenn der Prozess wirklich feststeckt, da dieser jeden Cleanup-Pfad deiner App überspringt.
Hintergrundjobs, & und nohup
Das Anhängen von & führt einen Befehl im Hintergrund aus; jobs, fg und bg dienen dazu, diesen aus der aktuellen Shell heraus zu verwalten. Ein Hintergrundjob wird jedoch trotzdem beendet, wenn Sie das Terminal schließen, es sei denn, Sie lösen ihn mit nohup oder einem Terminal-Multiplexer vom Hangup-Signal.
long-task & # background in this shell
jobs -l # list background jobs
fg %1 # bring job 1 to the foreground
nohup ./worker.sh > worker.log 2>&1 &
disown # detach from the shell's job table
Für alles, was länger laufen soll, nutzen Sie tmux oder screen. Diese halten eine Session auch bei Verbindungsabbrüchen aufrecht, was extrem wertvoll ist, wenn ein Deploy länger dauert als Ihre SSH-Verbindung.
tmux new -s deploy
# Ctrl+B, then D to detach
tmux attach -t deploy
systemd services mit systemctl
Auf modernen Distributionen ist systemd das Init-System, das Services beim Bootvorgang startet und überwacht. Sie definieren einen Service in einer Unit-Datei unter /etc/systemd/system/.
# /etc/systemd/system/my-api.service
[Unit]
Description=My API
After=network.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/opt/my-api
Environment=NODE_ENV=production
EnvironmentFile=/opt/my-api/.env
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
Nachdem Sie eine Unit erstellt oder bearbeitet haben, laden Sie den Manager neu und aktivieren Sie den Service, damit dieser beim Booten startet.
sudo systemctl daemon-reload
sudo systemctl enable --now my-api
systemctl status my-api --no-pager
sudo systemctl restart my-api
sudo systemctl reload my-api # if the service supports it
Restart=on-failure ist das Feature, das einen abgestürzten Prozess in einen selbstheilenden Service verwandelt. EnvironmentFile hält Secrets aus der Unit fern, welche oft weltweit lesbar ist. Verwenden Sie Type=notify nur, wenn das Programm das Notification-Protokoll tatsächlich unterstützt; simple ist der sichere Standardwert.
Logs mit journalctl
systemd fängt stdout und stderr eines Services im Journal ab. journalctl fragt dieses ab und ihr werdet es ständig benutzen.
journalctl -u my-api # all logs for one unit
journalctl -u my-api -n 100 # last 100 lines
journalctl -u my-api -f # follow live
journalctl -u my-api --since today
journalctl -u my-api --since '10 min ago' -p err
journalctl -b -p warning # this boot, warnings and worse
journalctl --disk-usage
sudo journalctl --vacuum-time=7d # keep a week
Das Flag -p filtert nach Priorität, von emerg bis hin zu debug. Einem Unit mit -f zu folgen, während ihr einen Endpoint aufruft, ist der schnellste Weg, um die Ursache eines 500-Fehlers zu finden.
Umgebungsvariablen und PATH
Umgebungsvariablen sind Key-Value-Strings, die ein Prozess von seinem Elternprozess erbt. PATH ist dabei die wichtigste: Hier werden die Verzeichnisse aufgelistet, in denen die Shell nacheinander nach einem Befehlsnamen sucht.
echo "$PATH" | tr ':' '\n'
export NODE_ENV=production
export PATH="$HOME/.local/bin:$PATH"
printenv DATABASE_URL
Da ein Service nicht deine interaktive Shell erbt, setze Variablen in seiner Unit-Datei oder in einer EnvironmentFile. Wenn eine Variable in deinem Terminal funktioniert, aber nicht unter systemd, ist fast immer dies die Ursache. Um deine eigenen Einstellungen dauerhaft zu speichern, füge die export-Zeilen zu ~/.bashrc oder ~/.profile hinzu.
Paketmanager: apt, dnf, apk
Jede Distributionsfamilie hat ihren eigenen Paketmanager, aber die Befehle sind ähnlich: Index aktualisieren, installieren, upgraden, entfernen, suchen.
# Debian / Ubuntu
sudo apt update && sudo apt upgrade -y
sudo apt install nginx
sudo apt remove --purge nginx
# Fedora / RHEL
sudo dnf install nginx
sudo dnf upgrade --refresh
# Alpine (common in containers)
sudo apk add nginx
sudo apk upgrade
Installieren Sie nach Möglichkeit nur aus offiziellen Repositories; diese sind signiert und gepatcht. Nutzen Sie PPAs oder Drittanbieter-Repos nur bewusst und pinnen Sie Versionen in Produktions-Images, damit ein Rebuild nicht stillschweigend die laufende Software ändert.
Pipes, Redirection und kleine Skripte
Ein Pipe leitet die Ausgabe eines Programms in die Eingabe eines anderen weiter. Redirection leitet diese entweder in eine Datei um oder liest sie aus einer aus. Zusammen verwandeln sie kleine Tools in Pipelines.
ls -l | wc -l # count files
grep ' 500 ' access.log | wc -l # count 500s
cmd > out.txt # stdout to file, overwrite
cmd >> out.txt # append
cmd 2> err.txt # stderr to file
cmd > all.txt 2>&1 # both streams together
cmd < input.txt # read stdin from a file
Jeder Prozess startet mit drei File-Deskriptoren: stdin (0), stdout (1) und stderr (2). 2>&1 bedeutet „leite stderr dorthin weiter, wo auch stdout hingeht“, wobei die Reihenfolge entscheidend ist – es muss nach der stdout-Redirection stehen.
Wenn du eine solche Sequenz in ein Skript packst, hast du eine Automatisierung. Zwei Zeilen am Anfang machen Skripte wesentlich sicherer:
#!/usr/bin/env bash
set -euo pipefail
-e beendet das Skript beim ersten fehlgeschlagenen Befehl, -u meldet Fehler bei undefinierten Variablen und -o pipefail lässt eine Pipeline fehlschlagen, wenn eine beliebige Stufe darin fehlschlägt. Zusammen verwandeln sie stille Teilfehler in deutliche Fehlermeldungen – genau das, was man in einem Deploy-Skript möchte.
SSH und Keys
SSH ist die Methode, mit der du auf eine Remote-Maschine zugreifst. Passwort-Logins funktionieren zwar, aber Keys sind sicherer und lassen sich automatisieren. Du behältst einen Private Key geheim und hinterlegst den passenden Public Key auf dem Server.
ssh-keygen -t ed25519 -C "you@laptop" # creates ~/.ssh/id_ed25519(.pub)
ssh-copy-id [email protected] # install the public key
ssh [email protected] # log in
Ein Host-Alias in ~/.ssh/config erspart Tipparbeit und fixiert nützliche Optionen:
Host prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519
ServerAliveInterval 30
Anschließend verbindet ssh prod die Sitzung. Sobald du Keys vertraust, solltest du die Passwort-Authentifizierung in /etc/ssh/sshd_config (PasswordAuthentication no) deaktivieren und sshd neu laden. scp und rsync verwenden dieselben Keys zum Kopieren von Dateien; rsync -avz --delete ist der übliche Weg, um ein Verzeichnis zu synchronisieren.
rsync -avz --exclude node_modules ./app/ prod:/opt/app/
ssh prod 'sudo systemctl restart my-api'
Festplatte und Arbeitsspeicher: df, du, free
Server fallen selten wegen der CPU aus; sie fallen aus, weil eine Festplatte vollläuft oder der Arbeitsspeicher aufgebraucht ist. Diese Befehle beantworten die Fragen „Wie viel ist noch übrig?“ und „Wer verbraucht den Platz?“.
df -h # free space per filesystem
df -i # inode usage — a disk can be full of inodes
du -sh /var/log/* # size per entry
du -h --max-depth=1 / | sort -h
free -h # memory and swap
ls -lhS /var/log | head # biggest log files
Wenn /var voll ist, sind fast immer Logs, ein Paket-Cache oder eine außer Kontrolle geratene Datenbank die Ursache. Räumen Sie gezielt auf — journalctl --vacuum-time, apt clean, Log-Rotation — anstatt Dateien zu löschen, die eine Anwendung erwartet.
Networking: ss, curl, dig
ss zeigt Sockets und listening ports an und ersetzt das ältere netstat. Es beantwortet die Frage: „Hört irgendetwas zu und wer ist verbunden?“.
ss -tulpn # TCP, UDP, listening, process names
curl -I https://example.com # response headers only
curl -sS localhost:3000/health
curl -X POST -H 'content-type: application/json' \
-d '{"name":"ada"}' localhost:3000/users
dig example.com +short # DNS resolution
dig @1.1.1.1 example.com MX
curl -I ist der schnellste Weg, um zu bestätigen, dass ein Server antwortet und welchen Status er zurückgibt. Wenn ss nichts auf einem Port anzeigt, die App aber meldet, dass sie gestartet ist, ist sie möglicherweise an 127.0.0.1 statt an 0.0.0.0 gebunden, was von außerhalb des Hosts nicht sichtbar ist.
Zeitplanung mit cron
cron führt Befehle nach einem festgelegten Zeitplan aus. Jeder Benutzer verfügt über eine crontab mit fünf Zeitfeldern, gefolgt vom eigentlichen Befehl.
# ┌ min (0-59)
# │ ┌ hour (0-23)
# │ │ ┌ day of month (1-31)
# │ │ │ ┌ month (1-12)
# │ │ │ │ ┌ day of week (0-6, Sun=0)
# * * * * * command
crontab -e # edit your crontab
crontab -l # list it
0 3 * * * /opt/app/backup.sh >> /var/log/backup.log 2>&1
*/5 * * * * curl -fsS localhost:3000/health > /dev/null
0 7 * * 1 /opt/app/weekly-report.sh
Die Umgebung von cron ist minimal: Sie hat einen anderen PATH, kein Shell-Profil und keine interaktiven Variablen. Verwenden Sie absolute Pfade, leiten Sie die Ausgabe in ein Log um, damit Fehler sichtbar sind, und denken Sie daran, dass cron einen fehlgeschlagenen Durchlauf nicht automatisch wiederholt. Für komplexere Anforderungen sollten Sie stattdessen einen systemd-Timer planen oder einen Job in eine Queue einreihen.
Best Practices
- Verwenden Sie in Skripten und Unit-Dateien absolute Pfade; verlassen Sie sich niemals auf die interaktive Umgebung.
- Setzen Sie
set -euo pipefailan den Anfang jedes nicht-trivialen Shell-Skripts. - Gewähren Sie minimale Berechtigungen: dedizierte Service-User,
sudofür spezifische Befehle, keine App, die als root läuft. - Bevorzugen Sie
SIGTERMund lassen Sie Services ordnungsgemäß herunterfahren, bevor Sie zukill -9greifen. - Konfigurieren Sie
Restart=on-failureund lesen Siejournalctl -u <unit>beim Debugging. - Halten Sie die Konfiguration in der Versionsverwaltung und ändern Sie auf einem Live-Host immer nur eine Sache gleichzeitig.
- Rotieren Sie Logs und behalten Sie
df -hunddf -iim Auge; Festplatten füllen sich lautlos. - Verwenden Sie SSH-Keys statt Passwörter und speichern Sie private Keys nicht auf Servern.
- Lernen Sie
find,grep,awkund Pipes — sie ersetzen viele Einzellösungen. - Testen Sie eine Konfiguration, bevor Sie den Service neu laden, der sie einliest.
Häufige Fehler
- Anwendungen als root ausführen und so jeden Bug in eine vollständige Kompromittierung des Systems verwandeln.
chmod -R 777verwenden, um Berechtigungen zu “fixen”, wodurch jeder Schutz zwischen Benutzern entfernt wird.- Dateien mit einem ungeprüften Wildcard und ohne Backup löschen.
- Zuerst
kill -9senden und dadurch den State korrumpieren, den ein graceful shutdown ordnungsgemäß geschrieben hätte. - Umgebungsvariablen in der Shell setzen und erwarten, dass systemd diese erkennt.
- Davon ausgehen, dass ein Dienst down ist, obwohl er nur an
127.0.0.1gebunden ist. 2>&1in cron-Einträgen vergessen und dadurch die Fehlermeldung verlieren, die ein fehlgeschlagenen Job erklärt.- Konfigurationen direkt auf einem Server ohne Versionsverwaltung bearbeiten, ohne eine Möglichkeit zum Zurückrollen zu haben.
- Die Erschöpfung der Inodes ignorieren, weil
df -himmer noch freien Speicherplatz anzeigt. - Die Passwort-Authentifizierung an einem öffentlich zugänglichen SSH-Port aktiviert lassen.
Wie geht es weiter?
Linux ist das Fundament für alles, was du deployst. Sobald du dich auf einem Server zurechtfindest, Logs lesen und Dienste neu starten kannst, zeigt dir der Nginx-Guide den Webserver, den du vor deine App schaltest. Docker & Deployment verwandelt diese Grundlagen in wiederholbare, isolierte Images. Um dieselben Befehle bei jedem Push zu automatisieren, lies den Guide zu CI/CD, und um den Prozess zu verstehen, unter dem dein Service tatsächlich läuft, schau dir noch einmal die Node.js Basics an.