
- 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.
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 undentry.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 mitprerender = truemarkiert werden, während andere serverseitig gerendert bleiben. Adapter und Nginx-Konfiguration funktionieren identisch wie im vollständigenserver-Modus.- Dateiberechtigungen: Sicherstellen, dass der PM2-Benutzer
/var/www/deine-astro-applesen 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.