Tobias Ludwig
Start
ErstgesprächKontakt
$whoami
Tobias Ludwig
DevOps · Application Manager · Software Engineer
$ls /pages
projekte/kontakt/kalender/impressum/
$git remote
github.com/nexas105
online·next.js 16·hono·postgresql
© 2026 tjl·stay curious_
/blog/Infrastruktur/linux-server-einrichten-teil-3

Linux Server einrichten – Teil 3: Dienste & Deployment

Linux Server einrichten Teil 3: Nginx Reverse Proxy, Docker Compose, HTTPS mit Let's Encrypt, systemd-Services und Backup-Strategie – vom gehärteten Server zur laufenden App.

16. Juni 20267 min Lesezeit1.458 Wörter
LinuxServerNginxDockerLet's EncryptsystemdDevOps
ReiheLinux Server einrichtenTeil 3 / 3
  1. 01Linux Server einrichten – Teil 1: Grundlagen & Erstzugriff
  2. 02Linux Server einrichten – Teil 2: Absicherung & Härtung
  3. 03Linux Server einrichten – Teil 3: Dienste & Deployment

In den ersten beiden Teilen dieser Reihe hast du deinen Linux-Server aufgesetzt und gehärtet. Jetzt wird es ernst: Im dritten und letzten Teil deployen wir echte Dienste. Du lernst, wie du Nginx als Reverse Proxy konfigurierst, Docker-Anwendungen per Compose betreibst, HTTPS mit Let's Encrypt automatisierst, eigene Prozesse als systemd-Services verwaltest und deinen Server grundlegend überwachst. Am Ende steht ein produktionsreifer Stack, den du für eigene Projekte direkt nutzen kannst.

Voraussetzungen

Bevor du weitermachst, stelle sicher, dass folgendes vorhanden ist:

  • Ein gehärteter Ubuntu 22.04 / Debian 12 Server (aus Teil 1 und Teil 2)
  • SSH-Zugang als nicht-root-Benutzer mit sudo-Rechten
  • Eine Domain, die per A-Record auf die Server-IP zeigt (für TLS zwingend)
  • UFW-Firewall aktiv, Ports 22, 80 und 443 geöffnet
# Ports prüfen (aus Teil 2)
sudo ufw status

# Sicherstellen, dass Port 80 und 443 offen sind
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Nginx als Reverse Proxy

Installation

Nginx ist in den Standard-Paketquellen beider Distributionen enthalten. Die Installation ist unkompliziert:

sudo apt update && sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl start nginx

Nach der Installation erreichst du die Default-Seite über http://DEINE-IP. Gut — der Webserver läuft.

Server Block anlegen

Nginx arbeitet mit sogenannten Server Blocks (das Äquivalent zu Apache Virtual Hosts). Lege für jede Domain eine eigene Konfigurationsdatei an:

sudo nano /etc/nginx/sites-available/meine-app.conf
server {
    listen 80;
    listen [::]:80;
    server_name meine-app.example.com;

    location / {
        proxy_pass         http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection 'upgrade';
        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;
        proxy_cache_bypass $http_upgrade;
    }
}

Config aktivieren und Nginx neu laden:

sudo ln -s /etc/nginx/sites-available/meine-app.conf /etc/nginx/sites-enabled/
sudo nginx -t          # Syntax prüfen — immer machen!
sudo systemctl reload nginx

Hinweis: nginx -t vor jedem Reload ausführen. Ein Syntaxfehler legt sonst den gesamten Webserver lahm.

Docker & Docker Compose installieren

Docker via offizielles Skript

Für Produktionsserver empfiehlt sich das offizielle Docker-Repository statt der oft veralteten Paketquellen:

# Abhängigkeiten
sudo apt install -y ca-certificates curl gnupg

# GPG-Schlüssel und Repo hinzufügen
sudo install -m 0755 -d /etc/apt/keyrings
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

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Installation
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Deinen User zur docker-Gruppe hinzufügen (kein sudo vor jedem Befehl)
sudo usermod -aG docker $USER
newgrp docker

Version prüfen:

docker --version
docker compose version

Beispiel-App per Docker Compose deployen

Erstelle ein Arbeitsverzeichnis und eine docker-compose.yml:

mkdir -p ~/apps/meine-app && cd ~/apps/meine-app
nano docker-compose.yml
services:
  web:
    image: nginx:alpine
    restart: unless-stopped
    ports:
      - "3000:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro
    environment:
      - NGINX_HOST=localhost
      - NGINX_PORT=80

  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: sicheres_passwort_hier
      POSTGRES_DB: appdb
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
# Statische Testseite erstellen
mkdir html
echo "<h1>App läuft!</h1>" > html/index.html

# Stack starten
docker compose up -d

# Status prüfen
docker compose ps
docker compose logs -f web

Der Nginx-Container läuft jetzt auf Port 3000, den wir oben im Nginx-Reverse-Proxy per proxy_pass weiterleiten. HTTP-Anfragen an meine-app.example.com landen damit direkt im Container.

HTTPS mit Let's Encrypt und Certbot

Certbot installieren

Let's Encrypt stellt kostenlose TLS-Zertifikate aus. Certbot automatisiert Ausstellung und Erneuerung vollständig:

sudo apt install -y certbot python3-certbot-nginx

Zertifikat ausstellen

sudo certbot --nginx -d meine-app.example.com

Certbot passt deinen Nginx-Server-Block automatisch für HTTPS an und richtet eine Weiterleitung von HTTP → HTTPS ein. Du wirst nach einer E-Mail-Adresse gefragt (für Ablaufwarnungen) und musst den Nutzungsbedingungen zustimmen.

Automatische Erneuerung

Let's Encrypt-Zertifikate laufen nach 90 Tagen ab. Certbot legt bei der Installation automatisch einen systemd-Timer an:

# Timer-Status prüfen
sudo systemctl status certbot.timer

# Erneuerung manuell testen (ohne tatsächliche Ausstellung)
sudo certbot renew --dry-run

Funktioniert der Dry-Run ohne Fehler, ist die automatische Erneuerung korrekt eingerichtet.

Eigene Dienste als systemd-Service

Nicht jede Anwendung läuft in Docker. Node.js-Apps, Python-Skripte oder eigene Binaries verwaltest du am besten als systemd-Service — das stellt sicher, dass sie nach einem Reboot automatisch neu starten.

Unit-File erstellen

sudo nano /etc/systemd/system/meine-node-app.service
[Unit]
Description=Meine Node.js Anwendung
Documentation=https://example.com
After=network.target

[Service]
Type=simple
User=deploy
WorkingDirectory=/home/deploy/apps/node-app
ExecStart=/usr/bin/node /home/deploy/apps/node-app/index.js
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=meine-node-app

# Sicherheits-Härtung
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=read-only
ReadWritePaths=/home/deploy/apps/node-app/data

[Install]
WantedBy=multi-user.target

Service aktivieren und starten

sudo systemctl daemon-reload
sudo systemctl enable meine-node-app
sudo systemctl start meine-node-app
sudo systemctl status meine-node-app

Service-Management auf einen Blick

BefehlWirkung
systemctl start <service>Service starten
systemctl stop <service>Service stoppen
systemctl restart <service>Service neu starten
systemctl reload <service>Config neu laden (ohne Stop)
systemctl enable <service>Autostart beim Boot aktivieren
systemctl disable <service>Autostart deaktivieren
systemctl status <service>Status und letzte Log-Zeilen
journalctl -u <service> -fLive-Logs des Service
journalctl -u <service> --since "1h ago"Logs der letzten Stunde

Monitoring-Grundlagen

Prozesse und Ressourcen

# Interaktiver Prozess-Monitor
htop

# Docker Container-Ressourcen live
docker stats

# Plattenplatz
df -h

# Speichernutzung (RAM)
free -h

# Top-Prozesse nach CPU
ps aux --sort=-%cpu | head -20

Logs im Blick behalten

# System-Log live
sudo journalctl -f

# Nginx-Fehler-Log
sudo tail -f /var/log/nginx/error.log

# Docker-App Logs
docker compose -f ~/apps/meine-app/docker-compose.yml logs -f --tail=100

Tipp: Für produktive Server lohnt sich ein einfaches Monitoring-Tool wie Netdata (selbst gehostet, minimaler Ressourcenverbrauch) oder externe Dienste wie Better Uptime für Erreichbarkeits-Checks.

Backup-Strategie

Dateien mit rsync sichern

rsync ist das Schweizer Taschenmesser für Backups unter Linux. Inkrementell, schnell, bewährt:

# Einmalig — lokales Backup auf externen Mount
rsync -avz --delete \
  /home/deploy/apps/ \
  /mnt/backup/apps/

# Auf Remote-Server sichern (SSH)
rsync -avz --delete \
  -e "ssh -i ~/.ssh/backup_key -p 22" \
  /home/deploy/apps/ \
  backup-user@backup-server.example.com:/backups/meine-app/

Automatisierung per Cron

crontab -e

Folgende Zeile sichert täglich um 03:00 Uhr:

0 3 * * * rsync -avz --delete /home/deploy/apps/ /mnt/backup/apps/ >> /var/log/backup.log 2>&1

Docker-Volumes sichern

# Postgres-Datenbank-Dump aus laufendem Container
docker exec -t <container_name> \
  pg_dumpall -c -U postgres > /tmp/db_backup_$(date +%F).sql

# Anschließend mit rsync wegsichern
rsync -avz /tmp/db_backup_*.sql backup-user@backup-server:/backups/db/

Wichtig: Teste deine Backups regelmäßig durch einen Restore-Versuch. Ein Backup, das du nie getestet hast, ist kein Backup.

Häufige Fehler

Nginx-Config-Fehler nicht geprüft Immer sudo nginx -t vor systemctl reload nginx. Ohne diesen Check kann ein Tippfehler in der Config den gesamten Webserver zum Absturz bringen.

Port bereits belegt Wenn docker compose up mit bind: address already in use scheitert, lauscht bereits ein Prozess auf dem Port. Diagnose: sudo ss -tlnp | grep :3000. Gegebenenfalls den bestehenden Prozess stoppen oder einen anderen Port verwenden.

Let's Encrypt Rate Limits Let's Encrypt erlaubt nur 5 Zertifikate pro Domain und Woche. Teste mit --dry-run, bevor du echte Zertifikate ausstellst, um das Limit nicht unnötig zu verbrauchen.

Docker ohne sudo nach Gruppe Nach usermod -aG docker $USER muss man sich neu einloggen (oder newgrp docker ausführen), damit die Gruppe aktiv wird. Viele vergessen das und wundern sich über permission denied.

systemd-Service startet nicht nach Reboot systemctl enable ohne anschließendes daemon-reload registriert den Service nicht korrekt. Reihenfolge beachten: daemon-reload → enable → start.

rsync löscht unbeabsichtigt Dateien Das Flag --delete entfernt Dateien im Ziel, die im Quellverzeichnis nicht mehr vorhanden sind. Das ist für Backups oft gewollt, kann aber überraschen. Beim ersten Einsatz lieber --dry-run voranstellen.

Certbot findet Domain nicht Wenn Let's Encrypt die Domain nicht validieren kann, ist oft Port 80 durch die Firewall blockiert. Certbot benötigt HTTP-Zugang während der Validierung — UFW muss Port 80 freigeben, auch wenn später nur HTTPS genutzt wird.

Nächste Schritte

Mit diesem dritten Teil hast du die Grundlagen eines produktionsreifen Linux-Servers vollständig erarbeitet: In Teil 1 hast du einen frischen Server aufgesetzt, Benutzer angelegt und die grundlegende Netzwerkkonfiguration vorgenommen. In Teil 2 haben wir den Server durch SSH-Härtung, Fail2ban und UFW abgesichert. Jetzt, in Teil 3, läuft eine echte Anwendung hinter Nginx mit HTTPS, automatischen Deployments per Docker Compose, prozesssicherer Dienstverwaltung via systemd und einem soliden Backup-Plan.

Dieser Stack ist kein Spielzeug — er ist die Basis, auf der Dutzende produktiver Dienste laufen. Natürlich gibt es immer mehr zu lernen: Kubernetes für größere Setups, Terraform für Infrastructure-as-Code, Prometheus und Grafana für ernsthaftes Monitoring. Aber mit dem Fundament aus dieser Reihe bist du bestens gerüstet.

Wenn du Unterstützung bei der Einrichtung deines Servers brauchst, einen individuellen Stack aufbauen möchtest oder Fragen zu Deployment-Strategien für dein Projekt hast — melde dich gerne. Ich helfe dir, die richtige Lösung für deine Anforderungen zu finden.

Verwandte Artikel

  • DevOps· 2 gemeinsame TagsCoolify als Heroku-Replacement — Self-Hosted PaaS in der Praxis
  • DevOps· 2 gemeinsame TagsDevOps-Pipeline mit Coolify, Next.js & GitHub Actions — Auto-Deploy ohne Vendor-Lockin
  • DevOps· 2 gemeinsame TagsSelf-Hosted Supabase mit Docker — Setup, Backups & Production-Härtung
  • KI / AI· 1 gemeinsame TagsOptimal mit KI arbeiten – Teil 3: Coden mit KI
Vorheriger TeilLinux Server einrichten – Teil 2: Absicherung & Härtung

Neue Artikel via RSS abonnieren

Inhalt
  • Voraussetzungen
  • Nginx als Reverse Proxy
  • Installation
  • Server Block anlegen
  • Docker & Docker Compose installieren
  • Docker via offizielles Skript
  • Beispiel-App per Docker Compose deployen
  • HTTPS mit Let's Encrypt und Certbot
  • Certbot installieren
  • Zertifikat ausstellen
  • Automatische Erneuerung
  • Eigene Dienste als systemd-Service
  • Unit-File erstellen
  • Service aktivieren und starten
  • Service-Management auf einen Blick
  • Monitoring-Grundlagen
  • Prozesse und Ressourcen
  • Logs im Blick behalten
  • Backup-Strategie
  • Dateien mit rsync sichern
  • Automatisierung per Cron
  • Docker-Volumes sichern
  • Häufige Fehler
  • Nächste Schritte
Tags
LinuxServerNginxDockerLet's EncryptsystemdDevOps
RSS-Feed

Neue Artikel im Reader.