linux
docker
linux · docker · grundlagen

Ubuntu Server + Docker
auf einem Dell Wyse 5070

Vom nackten Thin Client zum vollwertigen Homelab-Server — Schritt für Schritt. Ubuntu Server 24.04 LTS, Docker, Portainer, statische IP via Netplan. Inklusive aller Wyse-spezifischen BIOS-Fallstricke die beim ersten Mal garantiert Probleme machen, und dem systemd-resolved Konflikt der Pi-hole am Start blockiert.

Ubuntu 24.04 LTS Docker Portainer CE Dell Wyse 5070 ✓ Kein GUI nötig ⚠ Secure Boot deaktivieren ⚠ systemd-resolved Konflikt
01 Vorbereitung 02 BIOS / Boot 03 Ubuntu installieren 04 Statische IP 05 Docker 06 Portainer 07 Pi-hole Konflikt 08 Externe HDD 09 Fallstricke
01 — Vorbereitung

Was du brauchst

Vor dem Start: Ubuntu Server ISO herunterladen und einen bootfähigen USB-Stick erstellen. Für den Wyse 5070 reicht USB 2.0, aber USB 3.0 ist deutlich schneller beim Installieren.

Windows PowerShellBootfähigen USB mit Rufus oder balenaEtcher
# Ubuntu Server 24.04 LTS ISO herunterladen:
# https://ubuntu.com/download/server
#
# Auf USB-Stick schreiben mit:
# Rufus (Windows) — https://rufus.ie
# balenaEtcher (Mac/Win/Linux) — https://etcher.balena.io
#
# Modus: ISO Image (nicht DD!)
# Partition: GPT (für UEFI-Boot)
Warum Ubuntu Server statt Proxmox?

Proxmox ist mächtig, aber für einen einzelnen Thin Client mit 8 GB RAM unnötiger Overhead. Ubuntu Server + Docker direkt ist ressourcenschonender, einfacher zu debuggen und für ein Homelab vollkommen ausreichend. Proxmox lohnt sich erst wenn man mehrere VMs parallel betreiben will.

02 — BIOS / Boot

Wyse 5070 BIOS-Einstellungen

Der Dell Wyse 5070 hat ab Werk Einstellungen die Ubuntu-Installation verhindern. Zwei Dinge müssen vor der Installation angepasst werden — sonst bootet der USB-Stick entweder gar nicht oder Ubuntu lässt sich nicht installieren.

1
BIOS öffnen
Beim Start F2 drücken (Dell-Logo). Falls zu schnell: F12 für Boot-Menü, dort BIOS Setup wählen.
2
Secure Boot deaktivieren
Security → Secure Boot → Secure Boot Enable → Disabled
Ohne diese Einstellung bootet der Ubuntu-USB-Stick nicht.
3
Boot-Reihenfolge anpassen
Boot → Boot Sequence → USB-Gerät nach oben schieben.
Falls USB nicht erscheint: Legacy Boot aktivieren unter General → Advanced Boot Options → Enable Legacy Option ROMs.
4
Speichern und neu starten
F10 → Save and Exit. Wyse startet vom USB-Stick.
03 — Ubuntu installieren

Ubuntu Server 24.04 LTS Setup

Der Ubuntu Server Installer ist textbasiert aber intuitiv. Die wichtigsten Entscheidungen während der Installation:

1
Sprache & Tastatur
Sprache: English (Fehlermeldungen auf Englisch sind googlebarer). Tastatur: German.
2
Netzwerk
Vorerst DHCP lassen — statische IP konfigurieren wir nach der Installation via Netplan. Sicherstellen dass das Kabel eingesteckt ist und eine IP zugewiesen wurde.
3
Storage
Use entire disk → das interne eMMC (16–64 GB) auswählen. Kein LVM nötig für ein einfaches Setup. Externe USB-Festplatten später separat mounten — nicht als Installationsziel.
4
Benutzerkonto
Benutzername und Passwort festlegen. Den Benutzernamen merken — er wird für sudo und SSH gebraucht.
5
OpenSSH installieren
Install OpenSSH server → Yes — unbedingt auswählen! Danach ist der Server per SSH erreichbar und man braucht keinen Monitor mehr.
6
Snaps — überspringen
Der Installer bietet Snap-Pakete an (Docker, etc.) — alle abwählen. Docker installieren wir danach manuell über das offizielle Script. Snap-Docker hat Eigenheiten die Probleme machen können.
Nach der Installation: SSH von Windows aus

Nach dem Reboot und USB-Stick entfernen: IP-Adresse am Bildschirm ablesen, dann von Windows PowerShell aus verbinden:

ssh benutzername@10.0.1.71

Ab jetzt braucht man keinen Monitor mehr am Server.

04 — Statische IP

Netplan konfigurieren

Server brauchen feste IPs — sonst stimmen DNS-Einträge, Docker-Port-Bindings und FortiGate-Reservierungen irgendwann nicht mehr. Ubuntu 24 nutzt Netplan für die Netzwerkkonfiguration.

/etc/netplan/50-cloud-init.yamlStatische IP — Interface-Name vorher prüfen mit: ip a
network:
  version: 2
  ethernets:
    enp1s0:                    # Interface-Name — bei dir evtl. anders!
      addresses:
        - 10.0.1.71/24         # Gewünschte statische IP
      routes:
        - to: default
          via: 10.0.1.99         # Gateway (FortiGate LAN-IP)
      nameservers:
        addresses: [10.0.1.99, 9.9.9.9]
bashAnwenden
# Syntax prüfen
sudo netplan try

# Dauerhaft übernehmen
sudo netplan apply

# Prüfen
ip a
ping 9.9.9.9
Interface-Name vorher prüfen

Der Interface-Name ist nicht immer enp1s0 — mit ip a den tatsächlichen Namen herausfinden. Beim Wyse 5070 ist es meist enp1s0, beim OptiPlex kann es enp2s0 oder ähnlich sein. Falscher Interface-Name → nach netplan apply kein Netzwerk mehr.

05 — Docker

Docker Engine installieren

bashOffizielles Install-Script von Docker
# System updaten
sudo apt update && sudo apt upgrade -y

# Docker via offiziellem Script installieren
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Eigenen User zur docker-Gruppe hinzufügen
# (danach ausloggen + neu einloggen nötig!)
sudo usermod -aG docker $USER

# Testen (nach Re-Login)
docker run hello-world
docker compose v2

Das offizielle Script installiert Docker Compose v2 als Plugin mit. Der Befehl lautet docker compose (mit Leerzeichen), nicht das veraltete docker-compose (mit Bindestrich). Viele ältere Anleitungen im Internet nutzen noch die alte Syntax.

bashproxy-Netzwerk anlegen — einmalig pro Server
# Externes Docker-Netzwerk für Nginx-Reverse-Proxy
# Muss auf jedem Server einmalig angelegt werden
docker network create proxy

# Prüfen
docker network ls
06 — Portainer

Portainer CE — Web-UI für Docker

Portainer gibt Docker eine Web-Oberfläche — Container starten, Logs lesen, Stacks deployen, alles ohne CLI. Für den Homelab-Alltag sehr praktisch.

/opt/portainer/docker-compose.ymlServer1 — Port 9000
services:
  portainer:
    image: portainer/portainer-ce:latest
    container_name: portainer
    restart: always
    ports:
      - "9000:9000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - portainer_data:/data

volumes:
  portainer_data:
    external: true
bashVolume anlegen und starten
# Volume vorab anlegen
docker volume create portainer_data

mkdir -p /opt/portainer
cd /opt/portainer
# docker-compose.yml anlegen (siehe oben)
docker compose up -d

# Portainer erreichbar unter:
# http://10.0.1.71:9000 (im LAN direkt)
# http://<FORTIGATE-WAN>:9000 (via FortiGate VIP aus Mesh-Netz)
Erstes Login

Beim ersten Aufruf muss innerhalb von 5 Minuten ein Admin-Passwort gesetzt werden. Danach Get Started → Local wählen um den lokalen Docker-Daemon zu verwalten.

07 — Pi-hole Konflikt

systemd-resolved deaktivieren

Ubuntu 24 nutzt systemd-resolved als lokalen DNS-Stub-Resolver — der belegt Port 53. Pi-hole will aber auch Port 53. Ergebnis: Pi-hole startet nicht oder schlägt im Container mit "address already in use" fehl. Die Lösung ist systemd-resolved zu deaktivieren und durch eine statische resolv.conf zu ersetzen.

bashsystemd-resolved deaktivieren
# Prüfen ob Port 53 belegt ist
sudo ss -tulpn | grep :53

# systemd-resolved stoppen und deaktivieren
sudo systemctl stop systemd-resolved
sudo systemctl disable systemd-resolved

# Symlink entfernen und statische resolv.conf erstellen
sudo rm /etc/resolv.conf
sudo bash -c 'echo "nameserver 1.1.1.1" > /etc/resolv.conf'

# DNS testen
ping google.com
Nach Pi-hole-Start: DNS auf Pi-hole umstellen

Sobald Pi-hole läuft, kann resolv.conf auf nameserver 127.0.0.1 umgestellt werden — oder besser noch: DNS über die FortiGate/DHCP an alle Geräte verteilen und den Server selbst auf Pi-hole zeigen lassen.

08 — Externe HDD

USB-Festplatte dauerhaft mounten

bashUUID herausfinden und in fstab eintragen
# Festplatte und UUID anzeigen
lsblk -f

# Mountpoint anlegen
sudo mkdir -p /mnt/data

# /etc/fstab bearbeiten
sudo nano /etc/fstab
/etc/fstabNTFS-Festplatte — Eintrag
# NTFS externe HDD — UUID ohne Anführungszeichen!
UUID=DEINE-UUID-HIER  /mnt/data  ntfs-3g  uid=1000,gid=1000,dmask=022,fmask=133,big_writes,windows_names,nofail  0  0
UUID ohne Anführungszeichen — kritischer Fallstrick

Die UUID in /etc/fstab muss ohne Anführungszeichen stehen: UUID=ABC123 — nicht UUID="ABC123". Mit Anführungszeichen schlägt ntfs-3g still fehl und die Festplatte wird nicht gemountet. Kein Fehler beim Booten, einfach kein Mount.

bashTesten ohne Reboot
sudo mount -a
ls /mnt/data
Docker-Container nach Mount starten

Container die auf /mnt/data zeigen müssen nach dem Mount gestartet werden. Startet ein Container beim Boot bevor die externe Platte gemountet ist, mappt er auf ein leeres Verzeichnis und "sieht" die Daten nicht. Fix: docker compose down && docker compose up -d nach bestätigtem Mount.

09 — Fallstricke

Was schiefgehen kann

USB-Stick bootet nicht — schwarzer Bildschirm
Secure Boot ist noch aktiv. Im BIOS unter Security → Secure Boot → Disabled. Falls der USB-Stick im Boot-Menü gar nicht erscheint: Legacy Boot aktivieren unter General → Advanced Boot Options → Enable Legacy Option ROMs.
Pi-hole startet nicht — "port 53 already in use"
systemd-resolved belegt Port 53. Lösung: stoppen, deaktivieren, statische resolv.conf anlegen. Siehe Abschnitt 07.
Netplan apply — danach kein Netzwerk mehr
Falscher Interface-Name in der Netplan-Config. Mit ip a vorher prüfen. Beim Wyse 5070 meist enp1s0. Falls kein Zugriff mehr: Monitor und Tastatur anschließen, Interface-Name korrigieren, sudo netplan apply erneut.
Externe HDD zeigt nach Mount leere Ordner / fehlende Dateien
Falsche Mount-Optionen für NTFS. Die Option windows_names ist nötig damit Windows-Dateinamen korrekt angezeigt werden. Komplette Option in fstab: uid=1000,gid=1000,dmask=022,fmask=133,big_writes,windows_names,nofail
docker: permission denied — obwohl in docker-Gruppe
Nach sudo usermod -aG docker $USER muss man sich ausloggen und neu einloggen damit die Gruppenänderung wirksam wird. Ein einfaches su - $USER in der gleichen Session reicht nicht immer.
Disk voll — Docker startet keine Container mehr
Das interne eMMC füllt sich schnell mit ungenutzten Docker-Images. Aufräumen mit: docker system prune -a -f. Achtung: löscht alle ungenutzten Images, Container und Netzwerke. Das proxy-Netzwerk danach neu anlegen: docker network create proxy.