Alle Beiträge
Astro, Nginx, and Node.js server rack with rocket launch and cloud infrastructure
  • Astro
  • Nginx
  • Deployment
  • Node.js
  • SSL
  • VPS

Astro auf einem VPS mit Nginx deployen (Node.js-Adapter)

Schritt-für-Schritt-Anleitung zum Deployment einer Astro-Site auf einem VPS mit dem Node.js-Standalone-Adapter, Nginx als Reverse-Proxy, PM2-Prozessverwaltung und Let's Encrypt SSL.

4 Min. Lesen

Diese Anleitung beschreibt das Deployment einer Astro-Site auf einem VPS (Ubuntu 22.04 / 24.04) mit dem offiziellen @astrojs/node-Standalone-Adapter. Nginx fungiert als Reverse Proxy vor dem Node.js-Prozess, den PM2 über Reboots hinweg am Laufen hält.

Voraussetzungen

  • Ein VPS mit Ubuntu 22.04 oder 24.04
  • Ein Domainname, der auf die Server-IP zeigt
  • Node.js 18.17 oder höher auf dem Server installiert
  • npm oder pnpm verfügbar

1. Node.js-Adapter konfigurieren

Adapter im Astro-Projekt installieren:

npm install @astrojs/node

astro.config.mjs aktualisieren, um ihn im standalone-Modus zu verwenden:

// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'server',       // oder 'hybrid', wenn nur manche Seiten SSR nutzen
  adapter: node({
    mode: 'standalone',   // bündelt einen Node.js-HTTP-Server mit dem Build
  }),
});

Rein statische Sites: Wenn dein Astro-Projekt keine serverseitigen Routen, API-Endpunkte oder SSR-Seiten hat, kannst du output: 'static' verwenden und den Adapter weglassen. Überspringe in diesem Fall zum statischen Abschnitt am Ende dieser Anleitung.


2. Astro-App bauen

Lokal bauen, bevor die Dateien auf den Server übertragen werden:

# Abhängigkeiten installieren
npm install

# Für Produktion bauen
npm run build

Das Build-Ergebnis enthält zwei Verzeichnisse:

  • dist/client/ — statische Assets (JS, CSS, Bilder)
  • dist/server/ — Node.js-Server-Bundle und entry.mjs

3. Dateien auf den Server übertragen

# Vom lokalen Rechner
scp -r dist package.json package-lock.json benutzername@server-ip:/var/www/deine-astro-app

Zielverzeichnis auf dem Server erstellen, falls noch nicht vorhanden:

sudo mkdir -p /var/www/deine-astro-app
sudo chown -R $USER:$USER /var/www/deine-astro-app

4. Produktionsabhängigkeiten auf dem Server installieren

Per SSH auf den Server einloggen und Abhängigkeiten installieren:

cd /var/www/deine-astro-app
npm install --omit=dev

Prüfen, ob der Server korrekt startet:

node dist/server/entry.mjs

Die Ausgabe sollte Server listening on http://0.0.0.0:4321 zeigen. Mit Strg+C beenden – PM2 übernimmt ab sofort.


5. Nginx als Reverse Proxy konfigurieren

Nginx installieren, falls noch nicht vorhanden:

sudo apt update
sudo apt install nginx

Site-Konfiguration erstellen:

sudo nano /etc/nginx/sites-available/astro

Folgendes hinzufügen (yourdomain.com und Port anpassen falls geändert):

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;

    # Gzip-Komprimierung
    gzip on;
    gzip_comp_level 5;
    gzip_min_length 256;
    gzip_proxied any;
    gzip_vary on;
    gzip_types
        application/javascript
        application/json
        application/x-javascript
        application/xml
        image/svg+xml
        text/css
        text/javascript
        text/plain
        text/xml;

    # Langzeit-Caching für Astros gehashte statische Assets
    location /_astro/ {
        proxy_pass http://localhost:4321/_astro/;
        expires 365d;
        access_log off;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    # Alles andere an den Node.js-Server weiterleiten
    location / {
        proxy_pass http://localhost:4321;
        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;
    }
}

Site aktivieren, Konfiguration testen und Nginx neu laden:

sudo ln -s /etc/nginx/sites-available/astro /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

6. App mit PM2 ausführen

PM2 hält den Node.js-Prozess am Laufen und startet ihn bei Server-Neustart automatisch neu:

# PM2 global installieren
sudo npm install -g pm2

# Astro-Server starten
cd /var/www/deine-astro-app
pm2 start dist/server/entry.mjs --name "astro-app"

# Prozessliste speichern und Startup-Skript einrichten
pm2 startup
pm2 save

pm2 startup gibt einen auszuführenden Befehl aus – diesen kopieren und ausführen, um PM2 bei systemd zu registrieren.

Nützliche PM2-Befehle:

pm2 status           # Alle laufenden Prozesse auflisten
pm2 logs astro-app   # Logs streamen
pm2 restart astro-app
pm2 stop astro-app

7. SSL mit Let’s Encrypt einrichten

Certbot installieren und Zertifikat erhalten:

sudo apt install certbot python3-certbot-nginx

sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot passt die Nginx-Konfiguration automatisch an, um HTTP auf HTTPS umzuleiten und das Zertifikat einzubinden. Automatische Erneuerung prüfen:

sudo systemctl status certbot.timer

Port ändern

Standardmäßig lauscht der Node.js-Adapter auf Port 4321. Zum Ändern vor dem Start Umgebungsvariablen PORT und HOST setzen:

# Via PM2
pm2 start dist/server/entry.mjs --name "astro-app" -- --env PORT=8080,HOST=127.0.0.1

# Oder via PM2 Ecosystem-Konfiguration (Details im PM2-Leitfaden)

Den proxy_pass-Port in der Nginx-Konfiguration entsprechend anpassen.


Statisches Deployment (ohne SSR)

Wenn das Astro-Projekt output: 'static' verwendet, erzeugt der Build nur ein dist/-Verzeichnis mit statischen Dateien. Den Node.js-Adapter weglassen und die Dateien direkt über Nginx ausliefern:

# Nur das dist-Verzeichnis übertragen
scp -r dist/* benutzername@server-ip:/var/www/yourdomain.com/html/

Nginx-Konfiguration für statische Dateien:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/yourdomain.com/html;
    index index.html;

    gzip on;
    gzip_types text/css application/javascript image/svg+xml text/plain;

    location /_astro/ {
        expires 365d;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    location / {
        try_files $uri $uri.html $uri/ =404;
    }

    error_page 404 /404.html;
}

Danach Certbot wie gewohnt ausführen. PM2 wird nicht benötigt.


Wichtige Hinweise

  • Node.js-Version: Auf dem Server muss Node.js 18.17 oder höher installiert sein.
  • Umgebungsvariablen: Produktionsgeheimnisse auf dem Server setzen, nicht im Repository. Vor PM2-Start exportieren oder eine vom Programm gelesene .env-Datei verwenden.
  • output: 'hybrid': Im Hybrid-Modus können einzelne Seiten mit prerender = true markiert werden, während andere serverseitig gerendert bleiben. Adapter und Nginx-Konfiguration funktionieren identisch wie im vollständigen server-Modus.
  • Dateiberechtigungen: Sicherstellen, dass der PM2-Benutzer /var/www/deine-astro-app lesen kann.
  • Firewall: Nur die Ports 80 und 443 müssen öffentlich erreichbar sein. Port 4321 sollte nicht direkt exponiert werden.

Häufig gestellte Fragen

Was ist der Unterschied zwischen den Adapter-Modi standalone und middleware?

Im standalone-Modus wird ein vollständiger Node.js-HTTP-Server gebündelt – du startest ihn direkt mit node dist/server/entry.mjs. Im middleware-Modus wird ein Express/Connect-kompatibler Handler exportiert, den du in deinen eigenen Server einbettest. Für die meisten VPS-Deployments ist standalone einfacher.

Muss ich node_modules auf den Server übertragen?

Nein. package.json, package-lock.json und das dist/-Verzeichnis übertragen, dann auf dem Server npm install --omit=dev ausführen. Das hält die Übertragungsgröße klein und stellt sicher, dass native Module für die Server-Architektur kompiliert werden.

Wie aktualisiere ich das Deployment nach einer Code-Änderung?

Lokal bauen, das neue dist/-Verzeichnis auf den Server übertragen und den PM2-Prozess neu starten:

pm2 restart astro-app

Kann ich Astro und Next.js auf demselben Server betreiben?

Ja. Jedem Programm einen anderen Port geben (z. B. 4321 und 3000) und für jede Domain einen separaten Nginx-Server-Block erstellen. PM2 verwaltet beide Prozesse unabhängig.

Meine API-Endpunkte funktionieren nicht. Was soll ich prüfen?

Sicherstellen, dass output auf 'server' oder 'hybrid' gesetzt ist (nicht 'static'), der Adapter installiert und in astro.config.mjs referenziert ist, und der Nginx-location /-Block auf den richtigen Port weiterleitet. Außerdem pm2 logs astro-app auf Laufzeitfehler prüfen.