Deployment

Auf dieser Seite

Deployment

site/ ist eine reine statische Website - hoste sie überall, wo statische Dateien ausgeliefert werden können. bxSites deploy bringt sie mit einem einzigen Befehl direkt dorthin: S3 (und jeder S3-kompatible Dienst - DigitalOcean Spaces, Cloudflare R2, Backblaze B2, MinIO), Azure Blob Storage, Google Cloud Storage, Firebase Hosting, FTP, SFTP, rsync über SSH, Netlify, Vercel, Cloudflare Pages, ein lokales Verzeichnis oder GitHub Pages.

Der Befehl deploy

Jedes Ziel außer den beiden einfachsten (local/github-pages, die allein mit Flags auskommen - siehe CLI-Referenz) wird über eine deployments/<name>.json-Datei im Projekt-Wurzelverzeichnis konfiguriert - eine Datei pro tatsächlich genutztem Deploy-Ziel, jede benennt, welches target es ist, plus die eigenen Felder dieses Ziels:

bxSites deploy --entry=production
{ "target": "s3", "bucket": "my-docs-site", "accessKeyIdEnvVar": "AWS_ACCESS_KEY_ID", "secretAccessKeyEnvVar": "AWS_SECRET_ACCESS_KEY" }

Secrets kommen immer aus einer Umgebungsvariable, nie aus einem literalen Wert in deployments/*.json. Jedes Feld, das auf EnvVar endet, benennt die Umgebungsvariable, die das eigentliche Secret enthält (ein Access Key, ein Passwort, ein API-Token) - zur Deploy-Zeit live aufgelöst, sodass deployments/*.json selbst immer gefahrlos committet werden kann. Ein Feld, das ein Pfad zu einer Credential-Datei ist, die du bereits selbst verwaltest (ein privater SSH-Schlüssel, ein heruntergeladener GCP-Service-Account-JSON-Key), ist die eine Ausnahme - ein einfaches Feld, da die Datei selbst aus der Versionskontrolle herausgehalten wird, nicht ihr Pfad. Lokal können diese Umgebungsvariablen auch aus einer .env-Datei stammen (BoxLang lädt automatisch eine, und getSystemSetting() - was jedes Ziel zu ihrer Auflösung nutzt - prüft sie transparent), statt sie von Hand in deine Shell zu exportieren; in CI werden sie als echte Secrets auf dem Runner gesetzt.

Alle Ziele auf einmal deployen

bxSites deploy ohne --entry und ohne --target ausgeführt, deployt jeden deployments/*.json-Eintrag der Reihe nach, ausgehend von einem einzigen gemeinsamen Build:

bxSites deploy

Die Website wird nur einmal gebaut, egal wie viele Einträge du hast. Schlägt ein Ziel fehl, stoppt das die übrigen nicht - jeder Eintrag wird versucht, und der Befehl liefert nur dann einen von null verschiedenen Exit-Code, wenn mindestens einer davon fehlgeschlagen ist; die Zusammenfassung meldet, wie viele erfolgreich waren (z. B. Deployed to 2/3 target(s) (1 failed)). Mit --verbose (funktioniert auch mit --entry/--target) wird eine Fortschrittszeile ausgegeben, wenn der Build und jedes Ziel starten und enden, statt nur der abschließenden Zusammenfassung.

local

Kopiert die gebaute Website in ein beliebiges Verzeichnis - ein Netzlaufwerk, einen Staging-Ordner, egal wohin. Das einzige Ziel, das überhaupt keinen deployments/-Eintrag braucht.

bxSites deploy --target=local --destination=/path/to/somewhere

github-pages

Derselbe Push, den gh-deploy macht, auch über diesen einheitlichen Befehl erreichbar - braucht ebenfalls keinen deployments/-Eintrag:

bxSites deploy --target=github-pages [--branch=gh-pages] [--remote=origin] [--message="..."]

s3

Echtes AWS S3, oder jeder S3-kompatible Dienst - setze endpoint für alles außer AWS selbst, und forcePathStyle: true für die meisten Nicht-AWS-Provider.

{
  "target": "s3",
  "bucket": "my-docs-site",
  "region": "us-east-1",
  "prefix": "",
  "accessKeyIdEnvVar": "AWS_ACCESS_KEY_ID",
  "secretAccessKeyEnvVar": "AWS_SECRET_ACCESS_KEY"
}
{
  "target": "s3",
  "bucket": "my-docs-site",
  "endpoint": "https://nyc3.digitaloceanspaces.com",
  "forcePathStyle": true,
  "accessKeyIdEnvVar": "SPACES_KEY",
  "secretAccessKeyEnvVar": "SPACES_SECRET"
}

Dieselbe Form (eigener endpoint + forcePathStyle: true) deckt auch Cloudflare R2 (https://<accountid>.r2.cloudflarestorage.com), Backblaze B2 und MinIO/Wasabi ab.

azure

Azure Blob Storage, authentifiziert mit einem SAS-Token, einem Account-Key oder einem vollständigen Connection String - genau eines der drei.

{
  "target": "azure",
  "account": "mystorageaccount",
  "container": "site",
  "accountKeyEnvVar": "AZURE_STORAGE_KEY"
}

gcs

Google Cloud Storage, authentifiziert mit einem heruntergeladenen Service-Account-JSON-Key (Google Cloud Console -> IAM & Admin -> Service Accounts -> Keys).

{
  "target": "gcs",
  "bucket": "my-docs-site",
  "serviceAccountKeyPath": "/path/to/service-account.json"
}

firebase

Firebase Hosting, mit derselben Art von Service-Account-Key wie gcs.

{
  "target": "firebase",
  "siteId": "my-firebase-site",
  "serviceAccountKeyPath": "/path/to/service-account.json"
}

ftp / sftp

Lädt die gesamte Website per FTP oder SFTP auf einen entfernten Server hoch, unter Beibehaltung ihrer Ordnerstruktur. SFTP akzeptiert ein Passwort oder einen SSH-Schlüssel.

{
  "target": "sftp",
  "host": "example.com",
  "username": "deploy",
  "remotePath": "/var/www/html",
  "key": "/home/me/.ssh/id_rsa"
}

rsync

Synchronisiert die Website per SSH mit der echten rsync-Binary auf einen entfernten Server - schneller als FTP/SFTP bei einem vollständigen Rebuild, da nur die Änderungen übertragen werden. Erfordert rsync und ssh auf der Maschine, die bxSites ausführt.

{
  "target": "rsync",
  "host": "example.com",
  "username": "deploy",
  "remotePath": "/var/www/html",
  "identityFile": "/home/me/.ssh/id_rsa"
}

netlify

{
  "target": "netlify",
  "siteId": "my-site-id-or-name.netlify.app",
  "authTokenEnvVar": "NETLIFY_AUTH_TOKEN"
}

vercel

{
  "target": "vercel",
  "projectId": "my-project",
  "authTokenEnvVar": "VERCEL_TOKEN"
}

cloudflare-pages

Cloudflare hat keine offiziell dokumentierte REST-API für Direct-Upload-Deploys - nur seine wrangler-CLI. Dieses Ziel reverse-engineert Wranglers eigenen Upload-Flow und braucht eine BLAKE3-Hash-Implementierung auf dem JVM-Classpath, die die meisten Standard-Java-Installationen nicht mitbringen - siehe CLI-Referenz und den eigenen Quellcode dieses Ziels für das vollständige, ehrliche Detail zu diesen rauen Kanten.

{
  "target": "cloudflare-pages",
  "accountId": "your-account-id",
  "projectName": "my-project",
  "apiTokenEnvVar": "CLOUDFLARE_API_TOKEN"
}

Der Befehl package

Bevorzugst du ein reines Archiv gegenüber einem der obigen Ziele - einen Build an ein GitHub-Release anhängen, ihn an einen Host übergeben, der nur einen Zip-Upload akzeptiert, oder ihn irgendwohin ausliefern, wo keines der anbindbaren Ziele hinreicht? bxSites package baut die Website und packt sie dann in eine einzige Datei, deren Wurzel der Inhalt der gebauten Website selbst ist (kein umschließender site/-Ordner):

bxSites package
bxSites package --output=dist/my-site.zip

--output ist standardmäßig <projectRoot>/site.zip; ein relativer Wert wird gegenüber dem Projekt-Root aufgelöst, und seine übergeordneten Verzeichnisse werden automatisch angelegt, falls sie noch nicht existieren.

GitHub Actions (Multi-Versions-Veröffentlichung)

Für eine automatische Veröffentlichung bei jedem Push, statt eines manuell ausgeführten bxSites deploy/gh-deploy, bringt dieses Modul einen einsatzbereiten GitHub-Actions-Workflow mit (.github/workflows/pages.yml), der main und development als zwei unabhängig live geschaltete Versionen derselben Website auf GitHub Pages veröffentlicht. Der Rest dieser Anleitung behandelt diesen Workflow, den die eigenen Docs dieses Repos verwenden.

Was er tut

Bei jedem Push nach main oder development, der docs/, bxsites.yaml oder die eigene Quelle des Moduls (Theme-/Pipeline-Änderungen) berührt, macht der Workflow Folgendes:

  1. Installiert BoxLang + bx-markdown
  2. Registriert dieses Repo als Modul, damit boxlang bxSites build aufgelöst werden kann
  3. Setzt auf jedem Branch außer main baseURL auf .../<branch-name>/ nur für diesen einen Build (siehe unten)
  4. Führt boxlang bxSites build aus
  5. Pusht site/ in den gh-pages-Branch - main in die Wurzel der Website, development nach /development/ - ohne die jeweils andere Version anzurühren

Er ist außerdem als manueller Auslöser (workflow_dispatch) über den Reiter Actions verfügbar, für eine einmalige Neuveröffentlichung ohne neuen Commit.

Einmalige Einrichtung

GitHub Pages muss auf den gh-pages-Branch verweisen, bevor der Workflow etwas veröffentlichen kann - das ist eine Repository-Einstellung, kein Schalter, den eine Workflow-Datei von selbst umlegen kann. Der erste erfolgreiche Lauf erstellt gh-pages für dich, tu dies also, nachdem der Workflow mindestens einmal gelaufen ist:

  1. Settings -> Pages
  2. Unter Build and deployment -> Source wähle Deploy from a branch
  3. Unter Branch wähle gh-pages und / (root)

Danach wird jeder passende Push automatisch gebaut und veröffentlicht. Die veröffentlichte URL erscheint unter Settings -> Pages, sobald das erste Deploy abgeschlossen ist.

Zwei Versionen gleichzeitig veröffentlichen

main wird in die Wurzel der Website veröffentlicht (https://<user>.github.io/<repo>/) - betrachte das als die stabilen/veröffentlichten Docs. development wird nach /development/ veröffentlicht (https://<user>.github.io/<repo>/development/) - die neuesten, unveröffentlichten Docs. Beide bleiben gleichzeitig live: der Job jedes Branches pusht nur mit keep_files: true und seinem eigenen destination_dir nach gh-pages, sodass ein development-Deploy nie den Inhalt von main überschreibt und umgekehrt.

Die eigene bxsites.yaml von main sollte baseURL auf die Wurzel der Website gesetzt haben (https://<user>.github.io/<repo>/); der Workflow überschreibt das für jeden anderen Branch zur Build-Zeit, sodass die bxsites.yaml von development dafür keinen eigenen baseURL-Eintrag braucht.

Um einen dritten Branch hinzuzufügen (z. B. eine release/2.0-Vorschau), füge ihn zur on.push.branches-Liste hinzu und gib ihm einen eigenen if: github.ref_name == '...'-Deploy-Schritt mit destination_dir: release-2.0 (oder ähnlich) - das Muster ist dasselbe wie bei development.

Für dein eigenes Projekt verwenden

Kopiere .github/workflows/pages.yml in dein eigenes Projekt (passe die modules:-Zeile an, falls dein Projekt mehr als bx-markdown braucht), aktiviere Pages wie oben, und Pushes nach main/development werden auf dieselbe Weise veröffentlicht. Willst du nur eine einzige veröffentlichte Version, lösche den nicht benötigten Branch aus on.push.branches und seinen passenden Deploy-Schritt.

Aus einem Projekt-Pages-Unterpfad ausliefern

Eine GitHub-Projekt-Pages-Website (im Gegensatz zu einer <user>.github.io-Benutzer-Website) wird unter https://<user>.github.io/<repo>/ ausgeliefert, nicht von der Domain-Wurzel. Setze baseURL in bxsites.yaml auf diese vollständige URL, damit jeder interne Link, jedes Asset und jeder Navigationseintrag das nötige /<repo>/-Präfix bekommt - und damit auch eine echte sitemap.xml erzeugt wird:

baseURL: "https://<user>.github.io/<repo>/"
{ "baseURL": "https://<user>.github.io/<repo>/" }

Siehe Konfiguration für die vollständige Aufschlüsselung dessen, was baseURL bewirkt. Eine <user>.github.io-Benutzer-Website, oder jede eigene Domain, die auf die Wurzel der Website zeigt, kann baseURL bei seinem Standardwert (/) belassen.

Zugriff auf deine Website einschränken

Eine eingebaute Zugriffskontrolle gibt es hier nicht - bx-sites erzeugt immer nur ein schlichtes statisches site/, und eine statische Datei hat kein Konzept von "wer fragt hier gerade an". Das robots: false von bxsites.json sagt wohlerzogenen Crawlern, ein Build nicht zu indexieren (nützlich für ein Staging-/Vorschau-Deploy, das nicht in Suchergebnissen auftauchen soll), aber das ist eine höfliche Bitte, kein Schloss - die URL funktioniert weiterhin für jeden, der sie hat. Musst du den Zugriff tatsächlich sperren, muss das vor den statischen Dateien passieren, bei welchem Host auch immer sie ausliefert - ein paar gängige, für statische Websites geeignete Optionen:

  • Cloudflare Pages/Access - stelle die veröffentlichte Website hinter eine Cloudflare-Access-Richtlinie (E-Mail-Allowlist, SSO oder eine Einmal-PIN) - ohne eigenen Anwendungscode.
  • Netlify - eingebauter Passwortschutz pro Website oder pro Deploy, allein aus den Website-Einstellungen heraus.
  • Ein kleiner Reverse-Proxy (beliebiger Host) - HTTP-Basic-Auth vor den statischen Dateien (eine .htpasswd-artige Regel, oder ein Ein-Datei-Cloudflare-Worker/Netlify-Edge-Function) reicht, um Suchmaschinen und Zufallsbesucher fernzuhalten, auch wenn das keine echte Pro-Benutzer-Identität ist, wie sie eine eingeloggte Anwendung hätte.

Nichts davon sind bx-sites-Funktionen - es sind Host-Einstellungen, die du dort einschaltest, wo site/ am Ende ausgeliefert wird.

Diese Seite bearbeiten Markdown herunterladen Zuletzt aktualisiert Aug 28, 2026, 3:16:38 AM