Forge Pages

CI/CD-agnostischer Webserver für statische Seite

Was ist Forge Pages?

Forge Pages ist ein Tool, das CI/CD-gesteuerte Bereitstellung statischer Seiten für Forgejo und Gitea bietet – also ein Pendant zu Diensten wie GitHub Pages – nur eben für Git-Forges wie Forgejo und Gitea.

Es gibt bereits andere Tools, die einen ähnlichen Ansatz haben, allerdings erfordern diese, dass der statische Website-Content im Repository selbst (z.B. in einem dedizierten Branch) abgelegt werden muss. Das ist vor allem für Single Page Applications unpraktisch: Man müsste diese entweder manuell bei jeder Änderung neu bauen, oder man automatisiert das über CI/CD, die dann wiederum ins Repository pushen muss (wer das schon mal gemacht hab, weiß, was das für ein Krampf ist, aus einer CI/CD Pipeline in ein privates Repo zu pushen), nur um dann darauf zu warten, bis der Pages-Server den Branch neu pullt, um die Seite zu deployen. Außerdem wird mit jedem Commit auf diesen Branch das Repository größer. Das will doch keiner.

Außerdem fehlte ein wichtiges Feature, das ich an GitLab Pages sehr mochte: Das Spiegeln von Repository-Berechtigungen auf das Page-Deployment. Wird ein Page-Deployment in GitLab aus einem privaten Repository erzeugt, ist auch diese Page nur mit Login und entsprechenden Leseberechtigungen zugreifbar.

Forge Pages macht genau das: Es nutzt den Identity Provider von Forgejo oder Gitea, um vor private Seiten einen Login über OAuth2 zu schalten. Nach dem Login erhält Forge Pages ein Access Token von Forgejo oder Gitea, mit dem geprüft werden kann, ob der User die korrekten Berechtigungen auf das Repository hat, aus dem das Deployment stammt.

Wie funktioniert das?

Forge Pages wird auf einem Server mit einer Domain mit Subdomain-Wildcards (z.B. *.pages.example.com) installiert. Dort wird dann der Deploy-Endpunkt pages.example.com/deploy bereitgestellt. An diesen Endpunkt kann ein .tar.gz-Archiv per HTTP POST übertragen werden, zusammen mit einem Access Token (z.B. einem CI/CD-Token) und dem Repository-Slug des Projekts (z.B. owner/repo). Forge Pages prüft dann, ob der Access Token Schreibrechte im angegeben Repo hat und erzeugt das Deployment unter <owner>.pages.example.com/<repo>. Über einen zusätzlichen Parameter kann festgelegt werden, ob das Deployment über OAuth2 abgesichert werden soll oder ob es öffentlich sein soll.

Wenn die URL dann besucht wird, sucht Forge Pages anhand der Owner-Subdomain und dem Repo-Pfad das richtige Deployment. Wenn das Deployment als privat konfiguriert ist, erzwingt Forge Pages zunächst einen OAuth2 Login beim konfigurierten Identity Provider. Dieser stellt Forge Pages dann ein Access Token für den User aus, mit dem geprüft wird, welche Rechte der Benutzer auf das zugehörige Repository hat. Hat der Benutzer mindestens Leseberechtigungen, liefert Forge Pages die Seite aus, ansonsten nicht.

Forge Pages über die Forgejo Action nutzen

Da das Erzeugen eines solchen .tar.gz-Archivs mit anschließendem HTTP-Upload in einer CI/CD-Pipeline nicht so schön aussieht, gibt es eine dazu passende Forgejo Action. Die Action nutzt eigenständig den CI/CD-Token und bestimmt den Namen des Repos. Ein Workflow zum Bauen und Deployen einer Hugo-Seite, könnte z.B. so aussehen:

on:
  push:
    branches:
      - main

jobs:
  deploy-frontend-to-pages:
    runs-on: alpine-node-lts
    steps:
      # Checkout and install dependencies
      - name: Checkout
        uses: actions/checkout@v6
      - name: Install dependencies
        run: apk add git hugo
      # Build Hugo page and adjust the pages base URL
      - name: Compile page
        run: hugo --baseURL "https://owner.pages.example.com/repo/" --gc --minify --cleanDestinationDir
      # Deploy using the Forge Pages Action
      - name: Deploy to Forge Pages
        uses: https://code.leon.wtf/leon/Forge-Pages-Action@v1
        with:
          content: public # local root folder of the static page 
          to_host: https://pages.example.com
          protect: true # enable OAuth2 protection

Hier ist ein Screenshot eines solchen Deployments mit der Forge Pages Action aus einem anderen Repository mit einem etwas komplexeren Setup:

Erfolgreiches Deployment einer statischen Seite mit der Forge Pages Action
Erfolgreiches Deployment einer statischen Seite mit der Forge Pages Action

Forge Pages ist super praktisch für Dinge wie interne Dokumentation oder Staging-Environments für Websites. Tatsächlich nutze ich Forge Pages selbst genau dafür: Pull Requests für neuen Content für leon-schmidt.dev werden über Forge Pages in unterschiedliche Unterverzeichnisse deployed, sodass ich auch parallel an unterschiedlichen Dingen arbeiten kann. Wenn ich Artikel reviewen lassen möchte, kann ich die entsprechende Person einfach mit Leserechten zum Repository hinzufügen. Forge Pages zwingt diese Person nun zum OAuth2-Login, prüft den Token und lässt die Person dann entweder rein oder nicht. Am Ende habe ich also eine vollständig integrierte Pages-Umgebung mit Login, ohne Forge Pages selbst jemals anfassen zu müssen – alles wird über Forgejo oder Gitea abgebildet.

Wenn ihr Forge Pages selbst nutzen wollt: Es ist Open-Source! Eine Anleitung zur Installation und Konfiguration liegt in der README.md im Repo. Die Action findet ihr hier. Übrigens: Da das Action-Repository öffentlich ist, kann es auch aus GitHub Actions oder von anderen Forgejo- oder Gitea-Instanzen heraus verwendet werden!