Astro.js & Docker: Dein Weg zur Live-Webseite (Statisch & Dynamisch auf dem VPS)

Astro.js mit Docker auf deinem VPS: Statisch (Nginx) oder dynamisch (Node.js). Komplettes Tutorial mit aktuellen Dockerfiles, Docker Compose und Deployment-Workflow.

Astro.js & Docker: Dein Weg zur Live-Webseite (Statisch & Dynamisch auf dem VPS) hero image

Du möchtest eine moderne, schnelle Webseite mit Astro.js bauen und sie auf deinem eigenen Server bereitstellen? Docker ist dafür das passende Werkzeug, inzwischen setzen 92% der IT-Branche auf Container (Docker State of App Dev Report, 2025). In diesem Beitrag führe ich durch den gesamten Ablauf: von der Entwicklungsumgebung bis zum Live-Deployment der Astro-Anwendung mit Docker und Docker Compose auf einem VPS.

Kernpunkte auf einen Blick

  • Astro wuchs von 29 Domains (2021) auf über 38.800 (2025), das 1.340-fache (TechnologyChecker.io, 2025).
  • Statische Builds per Nginx: schlank (~25 MB Image), extrem schnell.
  • Dynamische Builds per Node.js-Adapter: flexibel, für SSR-Routen nötig.
  • Multi-Stage Dockerfiles halten die Produktions-Images klein und sicher.
  • Docker Compose orchestriert den Start mit einem Befehl.

Wie bereitest du deine Entwicklungsumgebung vor?

Drei Werkzeuge bilden das Fundament für die Astro- und Docker-Entwicklung.

  1. Text-Editor: Visual Studio Code (VS Code) ist kostenlos und bietet eine riesige Erweiterungsbibliothek. Die Astro-Erweiterung für VS Code bringt Syntax-Highlighting und IntelliSense.

  2. Node.js: Astro basiert auf Node.js. Statt einer direkten Installation empfehle ich einen Versionsmanager, um flexibel zwischen Versionen zu wechseln.

    • Windows: nvm-windows vermeidet Rechteprobleme.
    • Linux/macOS: Das originale nvm (Node Version Manager) lässt sich per curl- oder wget-Skript installieren.
    nvm install lts # Neueste LTS-Version installieren
    nvm use lts     # LTS-Version aktivieren
  3. Git: Unverzichtbar für Versionskontrolle und den einfachen Transfer zum Server. Git herunterladen.

    # Während der Installation unter Windows: VS Code als Standard-Editor wählen
    # Default Branch Name auf "main" setzen

Öffne dein Terminal (in VS Code: Strg+Shift+Ö) und prüfe die Installationen:

node -v
npm -v
git --version
nvm version

Wie erstellst du dein erstes Astro-Projekt?

Wechsle in deinen Projektordner und starte die Astro-CLI. Das Framework generiert grundlegende Dateien und installiert alle Abhängigkeiten automatisch.

# Projekt mit minimalem Template erstellen
npm create astro@latest -- --template minimal mein-astro-projekt

# In den Projektordner wechseln
cd mein-astro-projekt

# Abhängigkeiten installieren (oft schon während der Erstellung erledigt)
npm install
# oder pnpm install

# Entwicklungs-Server starten
npm run dev
# oder pnpm dev

Standardmäßig findet man nun unter http://localhost:4321 die Astro-Standardseite.

INFO

Dieser Port wird standardmäßig seit Astro 3.0 genutzt wegen der Anlehnung an einen Raketen Countdown

Änderungen in src/pages/index.astro werden per Hot Module Replacement sofort sichtbar.

Astro verstehen: Seiten, Layouts und Komponenten

Astro-Projekte folgen einer klaren Struktur. Wer diese einmal verstanden hat, kann Projekte jeder Größe aufbauen.

  • src/pages/: Jede .astro-Datei hier wird zu einer Route. index.astro wird zu /, about.astro zu /about.
  • src/layouts/: Wiederverwendbare Seitenstrukturen. Ein typisches Layout (BaseLayout.astro) enthält das HTML-Gerüst mit einem <slot />, den jede nutzende Seite füllt.
  • src/components/: Wiederverwendbare UI-Elemente wie Header, Footer oder Karten. Importierbar in Seiten und Layouts.
  • Styling: Globale CSS-Dateien importierst du in Layouts. Innerhalb einer .astro-Datei sind <style>-Tags standardmäßig scoped, gelten also nur für die jeweilige Komponente.
---
// Beispiel: src/layouts/BaseLayout.astro
import Header from "../components/Header.astro";
import Footer from "../components/Footer.astro";
import "../styles/global.css";

interface Props {
	title: string;
	description?: string;
}

const { title, description = "Meine Astro Seite" } = Astro.props;
---

<!doctype html>
<html lang="de">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta name="description" content={description} />
		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
		<title>{title} | Astro Demo</title>
	</head>
	<body>
		<Header />
		<main class="container">
			<slot />
		</main>
		<Footer />
	</body>
</html>

<style>
	.container {
		max-width: 1100px;
		margin-left: auto;
		margin-right: auto;
		padding-left: 1rem;
		padding-right: 1rem;
		flex-grow: 1;
	}
	body {
		display: flex;
		flex-direction: column;
		min-height: 100vh;
	}
</style>

Statisch oder dynamisch: Welcher Build passt zu dir?

Nginx liefert statische Dateien unter Last etwa 4.874-mal schneller aus als ein Node.js-Server, mit einer medianen Antwortzeit von 0,05 ms gegenüber 253 ms (Benchmark, Adam Jones, 2024). Für reine Auslieferung ist der Nginx-Weg also klar überlegen. Doch nicht jedes Projekt kommt mit statischen Dateien aus.

Der statische Build (Standard)

Das ist der Normalfall bei Astro. npm run build generiert reines HTML, CSS und JavaScript im dist/ Ordner. Kein Node.js-Server zur Laufzeit nötig.

npm run build

Den dist/ Ordner kannst du auf jedem statischen Webhost bereitstellen.

Dynamische Routen mit dem Node-Adapter

Braucht eine Seite dynamische Daten, die sich bei jedem Aufruf ändern (z.B. Nutzerinfos aus Request-Headern)? Dann kommt Server-Side Rendering (SSR) ins Spiel.

  1. Adapter installieren:

    npx astro add node

    Das passt deine astro.config.mjs an und installiert die nötigen Pakete.

  2. Prerendering deaktivieren: Für die dynamische Seite explizit ausschalten:

    ---
    // src/pages/request-info.astro
    export const prerender = false;
    
    const userAgent = Astro.request.headers.get("user-agent") || "Unbekannt";
    
    import BaseLayout from "../layouts/BaseLayout.astro";
    ---
    
    <BaseLayout title="Request Info">
    	<h1>Deine Request Info</h1>
    	<p>Dein User-Agent: {userAgent}</p>
    </BaseLayout>
  3. Build-Ergebnis: Der dist/ Ordner enthält jetzt neben statischen Assets (client/) auch Server-Code (server/entry.mjs), der zur Laufzeit mit Node.js ausgeführt werden muss.

Docker als Fundament deines Deployments

Docker verpackt deine Anwendung samt aller Abhängigkeiten in einen isolierten Container. Das Resultat: deine App läuft in derselben Umgebung, lokal wie auf dem Server. Docker verzeichnet in der IT-Branche eine Adoptionsrate von 92% im Jahr 2025, ein Plus von 12 Prozentpunkten gegenüber dem Vorjahr (Docker State of App Dev Report, 2025). Auch in der Self-Hosting Community wird es aus mehreren Gründen sehr gerne verwendet. Containerisierung ist kein Nischenthema, sondern Standard.

Die .dockerignore: Was nicht ins Image gehört

Ähnlich wie .gitignore teilt diese Datei Docker mit, welche Dateien nicht kopiert werden sollen. Das beschleunigt den Build und hält das Image klein.

# .dockerignore
.DS_Store
node_modules
npm-debug.log
dist
.astro
.env*
*.env
.git
.vscode
Dockerfile*
docker-compose*
compose*
README.md

Wie containerisierst du eine statische Astro-Seite?

Für rein statische Seiten nutzen wir einen zweistufigen Docker Build. Die Build-Stage erzeugt die statischen Dateien mit Node.js, die Runtime-Stage serviert sie per Nginx. Das entspricht dem offiziellen Astro-Docker-Rezept.

Dockerfile (statische Seite):

# Dockerfile (statische Astro-Seite mit Nginx)

# ---- Build Stage ----
FROM node:lts AS build
WORKDIR /app
COPY package*.json ./
# RUN corepack enable
# COPY package.json pnpm-lock.yaml ./

RUN npm install
# RUN pnpm install --frozen-lockfile --ignore-scripts

COPY . .

# ENV NODE_OPTIONS="--max-old-space-size=4096"

RUN npm run build
# RUN pnpm rebuild && pnpm build

# ---- Runtime Stage ----
FROM nginx:alpine AS runtime
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80

nginx/nginx.conf:

Lege die Konfigurationsdatei im Ordner nginx/ im Projektroot ab. Sie aktiviert Gzip-Komprimierung, Caching-Header und blockiert den Zugriff auf versteckte Dateien.

# nginx/nginx.conf
worker_processes auto;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    server {
        listen 80;
        server_name _;
        root /usr/share/nginx/html;
        index index.html;

        gzip on;
        gzip_vary on;
        gzip_proxied any;
        gzip_comp_level 6;
        gzip_min_length 1000;
        gzip_types text/plain text/css text/xml application/json
                   application/javascript application/xml+rss
                   application/atom+xml image/svg+xml;

        location ~* \.(?:css|js|svg|gif|png|jpg|jpeg|webp|woff|woff2|ttf|eot)$ {
            expires 1y;
            add_header Cache-Control "public";
            access_log off;
        }

        location ~ /\. {
            deny all;
        }

        location / {
            try_files $uri $uri/ /index.html;
        }

        error_page 404 /index.html;
    }
}

Warum worker_processes auto; statt 1? Im Container hat Nginx Zugriff auf alle CPU-Kerne des Hosts. auto nutzt sie alle, was unter Last einen spürbaren Unterschied macht.

Wie containerisierst du eine dynamische Astro-Seite?

Mit dem Node-Adapter brauchst du Nginx nicht. Die Dockerfile folgt dem optimierten Multi-Stage-Pattern aus den Astro-Docs, das Produktions-Dependencies von Build-Dependencies trennt. Das beschleunigt nachfolgende Builds, wenn sich nur der Quellcode geändert hat.

Dockerfile (dynamische Seite mit Node.js):

# Dockerfile (dynamische Astro-Seite mit Node-Adapter)

# ---- Base Stage ----
FROM node:lts AS base
WORKDIR /app
COPY package.json package-lock.json ./

# ---- Production Dependencies ----
FROM base AS prod-deps
RUN npm install --omit=dev

# ---- Build Dependencies + Build ----
FROM base AS build-deps
RUN npm install

FROM build-deps AS build
COPY . .
RUN npm run build

# ---- Runtime Stage ----
FROM base AS runtime
COPY --from=prod-deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
ENV HOST=0.0.0.0
ENV PORT=4321
EXPOSE 4321
CMD ["node", "./dist/server/entry.mjs"]

Der Vorteil dieser Aufteilung: wenn sich nur dein Quellcode ändert (nicht aber package.json), überspringt Docker die npm install-Schritte und geht direkt zum Build. Das spart bei großen Projekten Minuten.

Docker Compose: Container orchestrieren

docker compose vereinfacht das Starten und Konfigurieren enorm. Auch für einen einzelnen Container lohnt es sich.

compose.yml:

services:
    astro-app:
        build:
            context: .
            dockerfile: Dockerfile
        image: mein-astro-projekt:latest
        container_name: mein-astro-container
        ports:
            # Statische Seite (Nginx auf Port 80 im Container)
            - "80:80"
            # Dynamische Seite (Node.js auf Port 4321 im Container)
            # - "80:4321"
        restart: unless-stopped

Der Dateiname kann compose.yml, compose.yaml oder docker-compose.yml lauten. Docker Compose v2 erkennt alle drei Varianten. Wähle das passende ports-Mapping: 80:80 für Nginx, 80:4321 für den Node-Adapter. Die linke Zahl ist der Host-Port, den du im Browser aufrufst.

Wie deployest du deine Astro-App auf den VPS?

Jetzt bringen wir alles zusammen. Voraussetzung: ein VPS mit einem Docker-komptiblem Betriebssystem (z.B. Ubuntu 24.04). Wenn du noch keinen Server hast, hilft dir mein VPS-Leitfaden fuer Anfaenger bei Auswahl und Ersteinrichtung.

1. Docker auf dem Server installieren

Verbinde dich per SSH (ssh root@DEINE_SERVER_IP) und installiere Docker inklusive Compose-Plugin. Folgendes gilt für Ubuntu:

sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo \
 "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
 $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
 sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Docker Compose ist als Plugin bereits enthalten.

Git installieren:

sudo apt update && sudo apt install git -y

2. Code auf den Server holen

Klone dein Repository (das du vorher auf GitHub gepusht hast):

git clone DEINE_REPOSITORY_URL
cd dein-projekt-ordner

Falls du Git noch nicht kennst, erklärt mein Git-Tutorial die Grundlagen.

3. Container starten

Im Projektordner auf dem Server:

sudo docker compose up --build -d

Was passiert hier? docker compose up startet die in der compose.yml definierten Services. --build erzwingt einen Neu-Bau des Images, falls sich Code oder Dockerfile geändert haben. -d startet alles im Hintergrund (detached).

Öffne nun http://DEINE_SERVER_IP in deinem Browser. Deine Astro-Webseite ist live.

4. Updates einspielen

Wenn du lokal Änderungen gemacht hast:

  1. Code committen und pushen (Git)
  2. Auf dem Server: git pull ausführen
  3. Danach: sudo docker compose up --build -d

Das war’s. Docker baut das neue Image und startet den Container automatisch neu.

FAQ
Kann ich Astro auch ohne Docker deployen?
Ja. Astro generiert statische Dateien, die auf jedem Webserver hostbar sind. Ansonsten generiert Astro mit dem Node.js Adapter auch Dateien, die auf jedem Node.js Server laufen.
Wann brauche ich Server-Side Rendering?
SSR ist nötig, wenn Seiten bei jedem Aufruf aktuelle Daten brauchen, etwa nutzerspezifische Inhalte oder Echtzeit-Abfragen. Für Blogs, Portfolios und Dokumentationsseiten reicht statisches Rendering völlig aus. Es ist performanter und braucht keinen laufenden Serverprozess.
Wie aktualisiere ich meine Webseite auf dem Server?
Lokal änderst du den Code, testest und pushst per Git. Auf dem Server loggst du dich per SSH ein, führst git pull und danach docker compose up --build -d aus. Das baut das Image neu und startet den Container.
Kann ich mehrere Astro-Projekte auf einem VPS hosten?
Ja. Verwende verschiedene Ports oder einen Reverse Proxy wie Traefik oder Nginx als Gateway. Jedes Projekt bekommt seinen eigenen Container.
Nginx oder Apache für statische Astro-Seiten?
Beide funktionieren.

Fazit

Astro.js und Docker ergänzen sich hervorragend. Astro liefert die Performance und Entwicklerfreundlichkeit, Docker sorgt für konsistente, portable Deployments. Mit den Dockerfiles und der Docker-Compose-Konfiguration aus diesem Beitrag hast du alles, was du brauchst, um dein Projekt live zu setzen.

Wenn du Fragen hast oder Feedback, schreib gern einen Kommentar. Viel Erfolg bei deinem Deployment!

Diesen Beitrag teilen:

Änderungsprotokoll

Dockerfiles aktualisiert (node:lts, optimiertes Multi-Stage-Pattern), Text ergänzt, FAQ-Sektion hinzugefügt.

Verwandte Artikel