
Strapi auf einem Hetzner Ubuntu Server selbst hosten
Yulei ChenStrapi ist ein beliebtes Open-Source Headless CMS, mit dem du leistungsstarke APIs und ein eingebautes Content-Management-Interface bekommst. Wenn du Strapi selbst hostest, hast du die volle Kontrolle über deine Daten, kein Vendor Lock-in und planbare Hosting-Kosten.
In dieser Anleitung zeige ich dir, wie du deine eigene Strapi-Instanz mit Docker und dem Caddy Webserver für automatisches HTTPS aufsetzt.
Für diesen Post nutzen wir einen günstigen Server von Hetzner. Hetzner ist bekannt für tollen Service bei einem super Preis-Leistungs-Verhältnis — ideal zum Hosten von Strapi.
Voraussetzungen
Bevor wir loslegen, brauchst du einen Hetzner Cloud Account (oder erstell dir einen).
Schritt 1: Hetzner Server einrichten
Falls du noch keinen Hetzner Server hast, folg diesen Schritten:
- Geh zur Hetzner Cloud Console, wähl ein Projekt oder erstell ein neues und geh dann zu Servers → Add Server

- Folg den Hetzner-Richtlinien und wähl:
- Server type: Wähl einen Servertyp, der zu deinen Anforderungen passt. Für Strapi mit PostgreSQL sind mindestens 2 GB RAM empfohlen.

- Location: Wähl ein Rechenzentrum in deiner Nähe oder nah an deinen Nutzern.

- Image: Wähl Ubuntu (neueste LTS-Version empfohlen).

- SSH Key hinzufügen: Füg deinen öffentlichen SSH Key für sicheren Zugang hinzu. Falls du noch keinen SSH Key hast, generier einen mit
ssh-keygen:
ssh-keygen -t ed25519 -C "your_email@example.com"
Schau ihn dir an mit cat ~/.ssh/id_ed25519.pub und füg ihn bei deinem Server ein.

- Konfigurer das Netzwerk falls nötig und klick auf Create & Pay

Sobald der Server erstellt ist, notier dir die IP-Adresse. Die brauchst du im nächsten Schritt für die SSH-Verbindung.

Schritt 2: Server aktualisieren
Öffne dein Terminal und verbinde dich per SSH mit deinem Ubuntu Server:
ssh root@your-server-ip
Dann aktualisier das System, damit die neuesten Sicherheitspatches installiert sind:
sudo apt-get update
sudo apt-get upgrade -y
Wenn das fertig ist, kann es losgehen mit der Software-Installation.
Schritt 3: UFW Firewall installieren und konfigurieren
Halt nur die nötigen Ports offen: SSH (22), HTTP (80), HTTPS (443).
Installier UFW und konfigurer die Firewall:
sudo apt install ufw -y
sudo ufw allow 22 # SSH
sudo ufw allow 80 # HTTP
sudo ufw allow 443 # HTTPS
sudo ufw enable
Prüf deine Firewall-Konfiguration:
sudo ufw status verbose
Docker kann manchmal UFW-Regeln umgehen. Um das zu verhindern, prüf die zusätzlichen Einstellungen wie hier beschrieben.
Schritt 4: Docker installieren
Docker führt Strapi und PostgreSQL in Containern aus. Installier Docker mit diesen Befehlen:
Dependencies und Dockers GPG Key einrichten:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
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
Docker Repository hinzufügen:
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
sudo apt-get update
Docker Engine und Compose-Plugin installieren:
sudo apt-get install docker-ce docker-ce-cli \
containerd.io docker-buildx-plugin docker-compose-plugin -y
Installation prüfen:
sudo docker run hello-world
Wenn du die "hello-world"-Nachricht siehst, ist Docker bereit.
Schritt 5: Caddy für automatisches HTTPS installieren
Caddy vereinfacht die HTTPS-Konfiguration, weil es SSL-Zertifikate automatisch von Let's Encrypt holt.
Caddy installieren:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy -y
Bevor du Caddy konfigurierst, musst du deine Domain auf die IP-Adresse deines Servers zeigen lassen. Falls du DNS noch nicht eingerichtet hast:
DNS für deine Domain konfigurieren
- Log dich beim Dashboard deines Domain-Registrars ein (wo du die Domain gekauft hast)
- Geh zu den DNS-Einstellungen
- Erstell einen A Record mit diesen Einstellungen:
- Type:
A - Name:
@(für die Root-Domain) oder eine Subdomain wiestrapi(fürstrapi.yourdomain.com) - Value/Target: Die IPv4-Adresse deines Hetzner Servers
- Type:
- Erstell einen AAAA Record für IPv6-Support:
- Type:
AAAA - Name:
@(für die Root-Domain) oder dieselbe Subdomain wie beim A Record - Value/Target: Die IPv6-Adresse deines Hetzner Servers
- Type:
DNS-Änderungen können ein paar Minuten bis mehrere Stunden brauchen. Du kannst mit Tools wie dig oder Online-DNS-Checkern prüfen, ob dein DNS korrekt konfiguriert ist. Sobald der DNS-Eintrag aktiv ist, kannst du mit der Caddy-Konfiguration weitermachen.
Caddy konfigurieren
Bearbeite die Caddyfile-Konfigurationsdatei:
sudo nano /etc/caddy/Caddyfile
Gib deine Domain ein und konfigurer den Reverse Proxy. Ersetze "yourdomain.com" mit deiner echten Domain:
yourdomain.com {
reverse_proxy localhost:1337
}
Falls du noch keine Domain hast, nutz das hier temporär:
:80 {
reverse_proxy localhost:1337
}
Caddy neustarten, um die Config zu laden:
sudo systemctl restart caddy
Schritt 6: Strapi mit Docker Compose starten
Wir nutzen Docker Compose für ein einfacheres Setup. Strapi braucht eine PostgreSQL-Datenbank, daher enthält die Compose-Datei beide Services.
Erstell zuerst ein Verzeichnis für Strapi, geh rein und erstell die Compose-Datei:
mkdir -p ~/strapi
cd ~/strapi
sudo nano compose.yml
Bevor du die Compose-Datei einfügst, generier sichere Secrets für deine Strapi-Instanz:
openssl rand -base64 32
Führ diesen Befehl viermal aus und speicher die Ergebnisse — du brauchst sie für JWT_SECRET, ADMIN_JWT_SECRET und APP_KEYS weiter unten.
Kopier folgenden Inhalt in die compose.yml und ersetze die Platzhalter-Secrets und Passwörter mit deinen generierten Werten:
services:
strapi:
image: elestio/strapi-production:v5.33.4
entrypoint: /bin/sh
command:
- -c
- |
cat > /opt/app/src/admin/vite.config.js << 'EOFVITE'
const { mergeConfig } = require('vite');
module.exports = (config) => {
return mergeConfig(config, {
server: {
allowedHosts: true
}
});
};
EOFVITE
exec npm run develop
restart: unless-stopped
- "127.0.0.1:1337:1337"
environment:
DATABASE_CLIENT: postgres
DATABASE_HOST: postgresql
DATABASE_PORT: "5432"
DATABASE_NAME: strapi
DATABASE_USERNAME: strapi
DATABASE_PASSWORD: replace-with-secure-db-password
JWT_SECRET: replace-with-generated-secret-1
ADMIN_JWT_SECRET: replace-with-generated-secret-2
APP_KEYS: replace-with-generated-secret-3,replace-with-generated-secret-4
NODE_ENV: development
STRAPI_TELEMETRY_DISABLED: "true"
volumes:
- strapi-config:/opt/app/config
- strapi-src:/opt/app/src
- strapi-uploads:/opt/app/public/uploads
depends_on:
postgresql:
condition: service_healthy
postgresql:
image: postgres:16.4
restart: unless-stopped
environment:
POSTGRES_DB: strapi
POSTGRES_USER: strapi
POSTGRES_PASSWORD: replace-with-secure-db-password
PGDATA: /var/lib/postgresql/data
volumes:
- strapi-postgresql-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U strapi -d strapi"]
interval: 5s
timeout: 20s
retries: 10
volumes:
strapi-config:
strapi-src:
strapi-uploads:
strapi-postgresql-data:
Die Image-Versionen oben waren zum Zeitpunkt des Schreibens aktuell. Prüf auf Docker Hub die neueste stabile Strapi-Version und auf Docker Hub die neueste PostgreSQL-Version.
Achte drauf, dass DATABASE_PASSWORD und POSTGRES_PASSWORD identisch sind. Für mehr Tipps zum Betrieb von PostgreSQL in Containern, schau dir unseren Guide zu Best Practices für Postgres in Docker an.
Strapi starten:
sudo docker compose up -d
Docker pullt die Strapi- und PostgreSQL-Images und startet sie im Hintergrund. Der erste Start kann ein bis zwei Minuten dauern, während Strapi das Admin Panel baut.
Du kannst die Logs verfolgen, um zu sehen, wann alles bereit ist:
sudo docker compose logs -f strapi
Warte, bis du eine Nachricht wie Strapi started oder Admin panel ready siehst, dann drück Ctrl+C um die Logs zu verlassen.
Schritt 7: Auf deine selbst gehostete Strapi-Instanz zugreifen
Deine Strapi-Instanz sollte jetzt unter https://yourdomain.com erreichbar sein. Falls du das temporäre HTTP-Setup nutzt, öffne http://your-server-ip:1337.
Beim ersten Besuch fordert Strapi dich auf, einen Admin-Account zu erstellen. Gib deinen Namen, deine E-Mail und ein starkes Passwort ein, um den ersten Administrator-User anzulegen.
Nach dem Login siehst du das Strapi Admin Panel, in dem du direkt mit dem Erstellen deiner Content Types und APIs loslegen kannst.
Sicherheitsempfehlungen
Öffentliche Server sollten immer abgesichert sein. Folgende Maßnahmen sind empfohlen:
- Starke Passwörter setzen: Nutz einzigartige, komplexe Passwörter für deinen Strapi Admin-Account und die PostgreSQL-Datenbank.
- HTTPS ist bereits aktiv: Caddy kümmert sich automatisch darum via Let's Encrypt.
- Alles aktuell halten: Installier regelmäßig System-Updates, Docker-Image-Updates und Strapi-Updates.
- Firewall-Regeln prüfen: Kontrollier regelmäßig deine UFW-Konfiguration und achte drauf, dass nur nötige Ports offen sind.
- Daten sichern: Richte regelmäßige Backups für deine PostgreSQL-Datenbank und hochgeladene Dateien ein. Schau dir unseren Guide zum Backup und Restore von Postgres via SSH Tunnel an.
- Logs überwachen: Beobachte Server- und Container-Logs auf verdächtige Aktivitäten. Installier Tools wie Fail2ban für zusätzliche Sicherheit.
Strapi-Installation aktualisieren
Wenn du deine Strapi-Instanz updaten willst, prüf zuerst die neueste Version auf Docker Hub, aktualisier dann die Image-Version in deiner compose.yml und führ aus:
cd ~/strapi
docker compose pull
docker compose up -d
Docker lädt die aktualisierten Images herunter und ersetzt deine aktuellen Container. Deine Daten bleiben sicher in den Named Volumes.
Kostenvergleich mit anderen Anbietern
Strapi selbst zu hosten ist in der Regel günstiger als Managed Hosting:
| Anbieter | vCPU Cores | RAM | Disk | Geschätzte monatliche Kosten | Hinweise |
|---|---|---|---|---|---|
| Sliplane | 2 | 2 GB | 40 GB | €9 | Preis pro Server |
| Render | 1 | 2 GB | 40 GB | ~$35–$45 | VM Small |
| Fly.io | 2 | 2 GB | 40 GB | ~$20–$25 | VM + Volume |
| Railway | 2 | 2 GB | 40 GB | ~$15–$66 | Nutzungsbasiert |
Fazit
Du hast jetzt eine selbst gehostete Strapi-Instanz auf Hetzner mit Docker, PostgreSQL und automatischem HTTPS via Caddy. Dieses Setup gibt dir volle Kontrolle über dein Headless CMS zu einem Bruchteil der Kosten von Managed Services. Falls du auch andere Headless CMS Optionen in Betracht ziehst, schau dir unsere Tutorials zu Directus selbst hosten oder Payload CMS mit Docker an.