
Django auf einem VPS mit Docker bereitstellen: Schritt-für-Schritt-Anleitung
Lukas MauserDie Bereitstellung einer Django-Anwendung auf einem Virtual Private Server (VPS) ist eine günstige, datenschutzfreundliche und flexible Möglichkeit, deine Projekte zu hosten. In dieser Anleitung führen wir dich durch den Prozess, eine Django-App mit Docker auf einem VPS bereitzustellen. Wir behandeln alles von der Vorbereitung deiner Django-App für Docker, der Auswahl eines VPS-Anbieters, der Serverkonfiguration bis hin zur eigentlichen Bereitstellung.
Für wen ist diese Anleitung?
Diese Anleitung ist für dich, wenn du:
- neugierig auf Self-Hosting bist und grundlegende Kenntnisse erwerben möchtest
- kleine Projekte oder Nebenprojekte betreiben willst
- Hosting-Kosten sparen möchtest
Diese Anleitung ist nicht für dich, wenn du:
- den absolut schnellsten Weg suchst, um loszulegen
- laufende Wartung vermeiden möchtest
- geschäftskritische Workloads betreiben musst und keine Erfahrung hast
Für einen einfachen, verwalteten Einstieg schau dir unser Produkt an: sliplane.io
Voraussetzungen
- Eine einsatzbereite Django-Anwendung
- Ein Konto bei Hetzner (oder einem anderen VPS-Anbieter deiner Wahl)
- Ein Domainname
Kurz und knapp
Wir verwenden Docker, um unsere Django-App zu containerisieren, und Postgres als Datenbank. Anschließend wählen wir einen VPS-Anbieter, richten den Server ein und stellen die App mit Docker Compose und einem Reverse Proxy (Caddy) für SSL bereit.
Die Django-App dockerisieren
Warum Docker?
Docker macht es einfach, eigene Software in der Cloud auszuführen. Du kannst alles, was deine Django-App benötigt, in einer Dockerfile definieren und die App dann in einem isolierten Container mit allen Abhängigkeiten starten.
Zum Beispiel benötigt unsere Django-App eine bestimmte Python-Version und einen Webserver (wie Gunicorn) für die Anfragen. All das können wir in einer Dockerfile festlegen und daraus ein Image bauen. Ist das Image gebaut, können wir es auf unserem Server ausführen.
Auch die Postgres-Datenbank läuft in einem separaten Container, sodass es keine Abhängigkeitskonflikte gibt. Docker bietet dir Zugriff auf ein riesiges Ökosystem an vorgefertigten Images für Datenbanken, Caches, Webserver und vieles mehr.
Docker für Django einrichten
Wenn du eine ausführliche Einführung möchtest, schau dir mein Django in Docker Tutorial an.
Kurzfassung: Erstelle zwei Dateien namens Dockerfile und docker-compose.yml im Root-Verzeichnis deines Django-Projekts und füge folgenden Inhalt hinzu:
Dockerfile:
# Stage 1: Base build stage
FROM python:3.13-slim AS builder
# Erstelle das App-Verzeichnis
RUN mkdir /app
# Setze das Arbeitsverzeichnis
WORKDIR /app
# Setze Umgebungsvariablen für Python
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Aktualisiere pip und installiere Abhängigkeiten
RUN pip install --upgrade pip
# Kopiere die requirements-Datei (besseres Caching)
COPY requirements.txt /app/
# Installiere Python-Abhängigkeiten
RUN pip install --no-cache-dir -r requirements.txt
# Stage 2: Production stage
FROM python:3.13-slim
RUN useradd -m -r appuser && \
mkdir /app && \
chown -R appuser /app
# Kopiere die Python-Abhängigkeiten aus dem Builder-Stage
COPY --from=builder /usr/local/lib/python3.13/site-packages/ /usr/local/lib/python3.13/site-packages/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
# Setze das Arbeitsverzeichnis
WORKDIR /app
# Kopiere den Anwendungscode
COPY --chown=appuser:appuser . .
# Setze Umgebungsvariablen für Python
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Wechsel zu nicht-root User
USER appuser
# Öffne den Anwendungsport
EXPOSE 8000
# Starte die Anwendung mit Gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "myproject.wsgi:application"]
docker-compose.yml:
services:
web:
build: .
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:17
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- .env
volumes:
postgres_data:
Um lokal zu testen, stelle sicher, dass Docker installiert und gestartet ist. Docker installieren. Du kannst lokal testen, ob alles funktioniert, indem du Folgendes ausführst:
docker compose up
Das startet die Django-App und eine Postgres-Datenbank. Die App erreichst du unter http://localhost:8000. Bevor du deine Django-App bereitstellst, stelle sicher, dass alles lokal funktioniert.
Das Django-Docker-Image bauen und pushen
Die obige Compose-Datei ist super für die lokale Entwicklung, aber nicht ideal für die Produktion, da der Server das Image bei jedem Deployment neu bauen müsste. In der Produktion willst du das Image vorab bauen und in einer Container Registry speichern, damit der Server es einfach nur noch ziehen und starten kann (wie beim Postgres-Container).
Du kannst dein Image so bauen:
docker build -t my-django-app .
Nach dem Build pushen wir das Image in eine Container Registry – ein Lagerhaus für Docker-Images.
In eine Container Registry pushen: Ich empfehle das GitHub Container Registry (GHCR), da es kostenlos für private Images ist. Erstelle dazu zuerst ein Personal Access Token bei GitHub.
Das Token benötigt die Scopes write:packages, read:packages und delete:packages. Siehe GitHubs Doku für Details.
Mit diesem Token kannst du dich dann authentifizieren, was für das Pushen in dein privates Workspace nötig ist:
Mit GHCR authentifizieren:
echo $GITHUB_TOKEN | docker login ghcr.io -u DEIN_GITHUB_USERNAME --password-stdin
Image taggen und pushen:
docker tag my-django-app ghcr.io/DEIN_GITHUB_USERNAME/DEIN_REPO_NAME:latest
docker push ghcr.io/DEIN_GITHUB_USERNAME/DEIN_REPO_NAME:latest
Hier nutzen wir der Einfachheit halber den Tag latest, du kannst aber auch Semantic Versioning oder Git-Commit-Hashes verwenden, um Versionierung und Rollbacks zu erleichtern.
Jedes Mal, wenn du Änderungen an deiner Django-App machst, baue und pushe das Image neu. Das kann bei häufigen Deployments schnell mühsam werden, weshalb diese Schritte oft in einer CI/CD-Pipeline automatisiert werden. Die Details dazu sprengen den Rahmen dieses Tutorials, aber ich habe einen separaten Beitrag dazu geschrieben, wie du eine CI/CD-Pipeline mit GitHub Actions erstellst.
Ist das Image gepusht, geht es an die Server-Einrichtung.
Die Wahl des VPS
1. Welchen VPS wählen?
Wir haben einige beliebte Anbieter in diesem Beitrag zu den 5 günstigsten VPS-Anbietern verglichen und sehr gute Erfahrungen mit Hetzner gemacht. Sie sind günstig, zuverlässig und wir haben dort tausende Server bereitgestellt. Wenn du unseren Hetzner-Affiliate-Link nutzt, bekommst du 20 € Guthaben.
2. Wie groß muss mein VPS sein?
Starte mit der kleinsten Option und skaliere bei Bedarf hoch. Du wirst überrascht sein, wie weit du mit einem einfachen VPS kommst – eine Postgres-Datenbank und eine kleine Django-App laufen schon mit 1 GB RAM. Du kannst den Server später jederzeit vergrößern. Starte einfach: Lass Datenbank und Django-App auf demselben Server laufen (siehe unseren Guide zum Betrieb mehrerer Apps auf einem VPS). Komplexere Setups brauchst du erst, wenn du wirklich skalieren musst.
3. Wo soll mein VPS stehen? Wähle einen Standort in der Nähe deiner Nutzer für beste Performance. Wenn Latenz keine große Rolle spielt, nimm den günstigsten Standort. Die Preise variieren wegen Strom, Steuern usw. Hetzner hat z. B. Rechenzentren in Deutschland und Finnland, die meist günstiger sind als andere Standorte.
4. Welche Prozessorarchitektur – x86 oder arm?
Arm wird immer beliebter, weil es günstiger ist, aber wir sind auf Verfügbarkeits- und Kompatibilitätsprobleme gestoßen. Wir bleiben meist bei x86. Wenn du auf x86 entwickelst und auf arm deployest, kann es zu unerwarteten Problemen kommen. Das Gute an VPS: Du zahlst nur für die Laufzeit, kannst also für ein paar Cent einen Arm-Server testen und bei Problemen wieder zu x86 wechseln.
5. Shared oder Dedicated?
Starte mit Shared und upgrade bei Bedarf. Shared ist meist langsamer und manchmal unvorhersehbar, daher ist die Anbieterwahl wichtig. Mit Hetzner haben wir gute Erfahrungen gemacht, die Performance war immer stabil und zuverlässig.
6. Welches Betriebssystem? Linux ist für Server die beste Wahl: kostenlos, sicher, zuverlässig. Die beliebtesten Distributionen sind Ubuntu, Debian, CentOS, Fedora und Arch Linux.
Ich nutze Ubuntu, weil ich es gelernt habe – nimm die neueste LTS-Version. Die Unterschiede sind meist Geschmackssache. Wenn du unsicher bist, nimm Ubuntu. Bei speziellen Anforderungen weißt du ohnehin, was du brauchst.
Im Allgemeinen gilt: Bleib bei populären Systemen, dann findest du leichter Hilfe online.
Server einrichten
Mit dem Server verbinden
Nachdem dein Server läuft, verbindest du dich per SSH. Meist bekommst du von deinem Anbieter einen Root-User und ein Passwort, oft kannst du aber auch schon beim Setup deinen SSH-Public-Key angeben – das ist sicherer.
Öffne ein Terminal auf deinem Rechner und führe aus:
ssh root@deine-server-ip
Ersetze deine-server-ip durch die IP-Adresse deines Servers. Die findest du meist im Dashboard deines Anbieters oder in einer Willkommensmail.
Wenn du neu bei SSH bist, schau dir diese Anleitung von GitHub an, wie du SSH-Keys generierst und zum Agent hinzufügst.
Server absichern
Absichern bedeutet, es Angreifern schwerer zu machen, deinen Server zu kompromittieren. Das sollte das Erste nach dem Setup sein. Dazu gehören: Root-Login deaktivieren, SSH-Keys statt Passwörter, Firewall einrichten, System aktuell halten, fail2ban nutzen usw. Am besten nutzt du ein Hardening-Script, damit du nichts Wichtiges vergisst. Ich will hier kein veraltetes Script posten, aber du findest viele gute Hardening-Scripts online oder schreibst dein eigenes. Wenn du ein Script aus dem Internet nutzt, verstehe, was es tut, und vertraue der Quelle.
Firewall
Hetzner bietet eine einfache Firewall im Dashboard. Erlaube nur Traffic auf den Ports 22 (SSH), 80 (HTTP) und 443 (HTTPS).
Empfohlen ist, die Hetzner-Firewall zusätzlich zu einer lokalen Firewall wie UFW oder iptables zu nutzen, da sie Traffic schon vor dem Server blockt. Das spart Ressourcen und bietet eine zusätzliche Schutzschicht (vor allem, da Docker lokale Firewalls manchmal umgeht).
Docker installieren
Folge der offiziellen Docker-Installationsanleitung, um Docker auf deinem Server zu installieren.
Jetzt sind wir bereit, die Django-App bereitzustellen.
Die Django-App auf dem Server starten
Wir nutzen wieder Docker Compose, um sowohl die Django-App als auch die Postgres-Datenbank zu starten. Für die Produktion müssen wir die Compose-Datei aber leicht anpassen.
Zuerst legst du deine Umgebungsvariablen fest. Du kannst Docker-Secrets oder .env-Dateien nutzen, um sensible Daten wie Datenbankpasswörter zu speichern. Für ein einfaches Setup erstelle eine .env-Datei im Projektverzeichnis auf dem Server:
POSTGRES_DB=mydb
POSTGRES_USER=myuser
POSTGRES_PASSWORD=mypassword
DATABASE_URL=postgres://myuser:mypassword@db:5432/mydb
DJANGO_SECRET_KEY=dein-geheimer-schlüssel
Wenn du es mit der Sicherheit ernster meinst, nutze Docker-Secrets.
Hier sind 2 Änderungen, die wir an der docker-compose.yml für die Produktion machen müssen:
- Die
web-Service-Konfiguration so anpassen, dass das vorgebaute Image aus der Container Registry gezogen wird, statt lokal gebaut zu werden. Außerdem fügen wir einen dritten Service hinzu: einen Reverse Proxy. - Einen Reverse Proxy-Service hinzufügen. Der Reverse Proxy ist in der Produktion nötig, weil er SSL-Termination übernimmt und Anfragen an die Django-App im Docker weiterleitet. Viele Reverse Proxies können noch mehr, z. B. Caching, Komprimierung usw. Ich habe 5 verschiedene Reverse Proxies verglichen. Einer der einfachsten ist Caddy, der automatisch SSL via Let's Encrypt einrichtet und sehr leicht zu konfigurieren ist.
Deine finale docker-compose.yml sieht so aus:
services:
web:
image: ghcr.io/DEIN_GITHUB_USERNAME/DEIN_REPO_NAME:latest
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:17
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- .env
caddy:
image: caddy:2.10.2
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- "80:80"
- "443:443"
volumes:
- $PWD/conf:/etc/caddy
- caddy_data:/data
- caddy_config:/config
Um Caddy zu konfigurieren, erstelle ein conf-Verzeichnis im selben Ordner wie deine docker-compose.yml und lege eine Caddyfile darin an:
deinedomain.de {
reverse_proxy web:8000
}
Damit leitet Caddy alle Anfragen von deiner Domain an die Django-App auf Port 8000 weiter. Wichtig: Trage hier deine echte Domain ein, da Caddy sie für die automatische SSL-Zertifikatsausstellung nutzt. Leite deine Domain per A/AAAA-Record auf die Server-IP, damit Anfragen ankommen.
Sobald die Domain eingerichtet ist, kannst du die Services starten mit:
docker compose up -d
Das war's! Deine Django-App läuft jetzt auf deinem VPS.
Um eine neue Version zu deployen, ziehe das neue Image und starte den Web-Service neu:
docker compose pull web
docker compose up -d web
Wie erwähnt, kannst du Deployments mit einer CI/CD-Pipeline automatisieren.
Zusammenfassung
Django auf einem VPS zu betreiben ist günstig und ein super Einstieg in Infrastruktur.
Was wir in dieser Anleitung genutzt haben:
- Docker zur Containerisierung der Django-App
- Postgres als Datenbank
- Caddy als Reverse Proxy für SSL
- Hetzner als VPS-Anbieter
- GitHub Container Registry für das Docker-Image
Es gibt unzählige Möglichkeiten, dieses Setup zu erweitern: Backups, Monitoring, Logging, Skalierung usw. Wenn du mit Self-Hosting startest, wirst du viel lernen! Wenn du dir den Aufwand sparen willst, schau dir unser Produkt an: sliplane.io, das all das out-of-the-box bietet. Es ist ein Mittelweg, der dir die Vorteile von Self-Hosting ohne den Wartungsaufwand bringt.