2tap2b

CMS für Astro: Sveltia CMS + Forgejo

Inhaltsverzeichnis

Git-basierte Content-Verwaltung für Static Sites

Wer statische Websites mit Astro, Hugo oder Jekyll betreibt, steht früher oder später vor der Frage: Wie verwalte ich Content effizient, ohne jedes Mal manuell Markdown-Dateien in der IDE zu editieren und zu committen?

Eine Antwort findet man in Git-basierten Content Management Systemen, die eine grafische Oberfläche bieten, aber im Hintergrund weiterhin Git als Single Source of Truth nutzen.

Für mich war ein wichtiger Punkt, dass ich meinen Blog auch unterwegs vom Smartphone aus über ein schlankes, responsives CMS verwalten kann.

Dieses Tutorial beschreibt die Integration von Sveltia CMS, einem modernen und schlanken CMS, in einen Astro‑Blog. Die volle Kontrolle behalten wir durch ein selbstgehostetes Forgejo als Git‑Backend; das Deployment erfolgt über meine Coolify‑Instanz.

Warum Sveltia CMS?

Sveltia CMS ist ein Fork von Netlify CMS, der sich jedoch weiterentwickelt hat und mehrere Vorteile bietet:

  • Aktive Entwicklung: Während Netlify CMS kaum noch gepflegt wird, entwickelt sich Sveltia stetig weiter
  • Bessere Performance: Schlankerer Code, schnellere Ladezeiten
  • Moderne UI: Aufgeräumteres Interface mit Dark Mode Support
  • API-Kompatibilität: Unterstützt die gleichen Backends wie Netlify CMS (GitHub, GitLab, Gitea/Forgejo)
  • Gitea/Forgejo Support: Native Unterstützung für selbst gehostete Git-Instanzen

2. Voraussetzungen

Bevor wir starten, stellt sicher, dass folgende Voraussetzungen erfüllt sind:


Architektur-Überblick

Das System besteht aus drei Hauptkomponenten:

  1. Astro Static Site – Der Blog selbst, generiert aus Markdown-Dateien
  2. Sveltia CMS – Eine Web-UI, die direkt in die Astro-Site integriert wird (Route /admin)
  3. Forgejo – Selbst gehostete Git-Instanz als Backend
  4. Coolify - Open Source Alternative zu Vercel oder Netlify (Optional)

Der Workflow sieht folgendermaßen aus:

Editor schreibt Artikel in Sveltia CMS

Sveltia speichert Änderungen via Git API in Forgejo

Webhook triggert Build-Pipeline (z.B. Coolify, Vercel, Netlify)

Astro generiert statische Site aus aktualisierten Markdown-Dateien

Teil 1. Forgejo mit Docker und Traefik aufsetzen

Bevor wir Sveltia CMS konfigurieren können, benötigen wir eine funktionierende Forgejo-Instanz. Ich gehe davon aus, dass Traefik bereits läuft – falls nicht, schau dir meinen Traefik Setup Guide an.

1.1 Forgejo einrichten

Erstelle das Projektverzeichnis:

mkdir -p /opt/containers/forgejo
cd /opt/containers/forgejo

Erstelle die docker-compose.yaml:

---
services:
  server:
    image: codeberg.org/forgejo/forgejo:9.0.3
    container_name: forgejo
    restart: unless-stopped
    ports:
      - "2222:22"  # SSH-Port für Git-Operationen
    volumes:
      - ./forgejo:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    labels:
      # Traefik aktivieren
      - "traefik.enable=true"
      
      # HTTPS Router
      - "traefik.http.routers.forgejo.entrypoints=websecure"
      - "traefik.http.routers.forgejo.rule=Host(`git.example.com`)"
      - "traefik.http.routers.forgejo.tls=true"
      - "traefik.http.routers.forgejo.tls.certresolver=cloudflare"
      
      # Service-Konfiguration
      - "traefik.http.routers.forgejo.service=forgejo"
      - "traefik.http.services.forgejo.loadbalancer.server.port=3000"
      
      # Middleware (siehe Teil 1.3 für CORS-Konfiguration)
      - "traefik.http.routers.forgejo.middlewares=cors-forgejo@file,geoblock-de@file,crowdsec-bouncer@file"
      
      # Netzwerk
      - "traefik.docker.network=frontend"
    networks:
      - frontend

networks:
  frontend:
    external: true

Wichtig: Passe git.example.com an deine Domain an.

Starte Forgejo:

docker compose up -d

1.2 Forgejo initialisieren

Öffne https://git.example.com im Browser und führe die Ersteinrichtung durch:

initial setup forgejo

  1. Datenbank: SQLite ist ausreichend für kleine bis mittlere Instanzen
  2. Server-Domain: git.example.com
  3. SSH Server Port: 2222 (da wir im Container auf Port 22 mappen)
  4. Base URL: https://git.example.com
  5. Administrator-Account: Erstelle deinen Admin-User

Nach der Ersteinrichtung ist Forgejo einsatzbereit. Erstelle nun ein Repository für deinen Blog.

1.3 CORS-Konfiguration für Sveltia CMS

Sveltia CMS greift per JavaScript aus dem Browser auf die Forgejo API zu. Dafür benötigen wir CORS-Header (Cross-Origin Resource Sharing), sonst blockiert der Browser die Anfragen mit einem Fehler wie:

Network error when attempting to fetch resources

CORS in Forgejo aktivieren

Bearbeite die Datei /opt/containers/forgejo/forgejo/gitea/conf/app.ini und füge hinzu:

[cors]
ENABLED = true
ALLOW_DOMAIN = *
METHODS = GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
MAX_AGE = 10m
ALLOW_CREDENTIALS = true
HEADERS = Content-Type,User-Agent,Authorization,Accept,X-Requested-With
X_FRAME_OPTIONS = SAMEORIGIN

Sicherheitshinweis: ALLOW_DOMAIN = * erlaubt Zugriffe von allen Domains. In Produktionsumgebungen solltest du hier nur deine Blog-Domain(s) eintragen:

ALLOW_DOMAIN = https://blog.example.com,https://www.blog.example.com

CORS-Middleware in Traefik

Zusätzlich fügen wir eine Traefik-Middleware hinzu, um konsistente CORS-Header zu garantieren. Erstelle die Datei /opt/containers/traefik/config/conf.d/forgejo-cors.yaml:

http:
  middlewares:
    cors-forgejo:
      headers:
        accessControlAllowMethods:
          - GET
          - HEAD
          - POST
          - PUT
          - PATCH
          - DELETE
          - OPTIONS
        accessControlAllowOriginList:
          - "*"  # In Produktion: spezifische Domains nutzen
        accessControlAllowCredentials: true
        accessControlAllowHeaders:
          - "*"
        accessControlExposeHeaders:
          - "*"
        accessControlMaxAge: 600
        addVaryHeader: true

Die Middleware wird bereits in der docker-compose.yaml referenziert (siehe Label oben).

Starte Forgejo und Traefik neu:

docker compose restart

Teil 2: OAuth-App in Forgejo erstellen

Sveltia CMS authentifiziert sich über OAuth 2.0 an Forgejo. Dafür benötigen wir eine OAuth-Applikation.

oauth setup forgejo

2.1 OAuth-App registrieren

  1. Melde dich bei Forgejo an (https://git.example.com)
  2. Navigiere zu Einstellungen → Anwendungen
  3. Scrolle zu OAuth2-Anwendungen verwalten
  4. Klicke auf Neue OAuth2-Anwendung erstellen

Konfiguration:

  • Anwendungsname: Sveltia CMS
  • Weiterleitungs-URI: https://blog.example.com/admin/,, http://localhost:4321/admin (deine Blog-Domain mit /admin/ am Ende!)
  • Vertraulicher Client: Abwählen

Klicke auf Anwendung erstellen.

2.2 Client ID notieren

Nach der Erstellung erhältst du eine Client ID (UUID-Format). Diese benötigen wir später für die Astro-Konfiguration.

Wichtig: Die Client ID wird nur einmal angezeigt. Notiere sie dir sicher.


Teil 3: Sveltia CMS in Astro integrieren

3.1 Paket installieren

Installiere den offiziellen Astro-Loader für Sveltia CMS:

npm install astro-loader-sveltia-cms

3.2 Content Collection konfigurieren

Astro 5 nutzt das neue Content Layer API. Definiere deine Blog-Collection in src/content.config.ts:

import { defineCollection, z } from "astro:content";
import { sveltiaLoader } from "astro-loader-sveltia-cms/loader";

const blogs = defineCollection({
  loader: sveltiaLoader("blogs"),
  schema: z.object({
    slug: z.string(),
    title: z.string(),
    description: z.string(),
    date: z.date(),
    author: z.string(),
    tags: z.array(z.string()),
    featured: z.boolean(),
    image: z.string().optional(),
    draft: z.boolean().optional(),
  }),
});

export const collections = { blogs };

3.3 Astro-Konfiguration erweitern

Bearbeite astro.config.mjs und füge die Sveltia-Integration hinzu:

import { defineConfig } from "astro/config";
import sveltia from "astro-loader-sveltia-cms";

export default defineConfig({
  integrations: [
    sveltia({
      route: "/admin",
      title: "Blog CMS",
      config: {
        backend: {
          name: "gitea",
          repo: "username/blog-content",  // Dein Forgejo-Repository
          base_url: "https://git.example.com",
          api_root: "https://git.example.com/api/v1",
          app_id: "424f35b7-a9f4-4597-bfef-38631351dd2f",  // Deine OAuth Client ID
        },
        media_folder: "public/images/posts",
        public_folder: "/images/posts",
        collections: [
          {
            name: "blogs",
            label: "Blog Posts",
            label_singular: "Blog Post",
            folder: "src/blog",
            create: true,
            path: "{{slug}}/index",
            slug: "{{slug}}",
            format: "yaml-frontmatter",
            fields: [
              { label: "Slug", name: "slug", widget: "string" },
              { label: "Titel", name: "title", widget: "string" },
              { label: "Beschreibung", name: "description", widget: "text" },
              { label: "Datum", name: "date", widget: "datetime" },
              { label: "Autor", name: "author", widget: "string", default: "Tobias" },
              { 
                label: "Tags", 
                name: "tags", 
                widget: "list",
                hint: "Drücke Enter nach jedem Tag"
              },
              { label: "Featured", name: "featured", widget: "boolean", default: false },
              { label: "Draft", name: "draft", widget: "boolean", default: false, required: false },
              { 
                label: "Hero Image", 
                name: "image", 
                widget: "string", 
                required: false,
                hint: "z.B. /images/posts/mein-post.png"
              },
              { label: "Inhalt", name: "body", widget: "markdown" },
            ],
          },
        ],
      },
    }),
  ],
  
  site: "https://blog.example.com",
  output: "static",
});

Wichtige Parameter:

  • backend.repo: Format owner/repository-name (wie auf Forgejo)
  • backend.app_id: Die OAuth Client ID aus Teil 2
  • media_folder: Wo Bilder gespeichert werden (im Repository)
  • public_folder: Öffentlicher URL-Pfad zu den Bildern

3.4 Dev-Server testen

Starte den Astro-Dev-Server:

npm run dev

Öffne http://localhost:4321/admin im Browser. Du solltest jetzt die Sveltia CMS-Oberfläche sehen.

login to sveltia

Klicke auf Login with Gitea – du wirst zu Forgejo weitergeleitet, authentifizierst dich dort, und wirst zurück zum CMS geleitet. Jetzt kannst du Blog-Posts erstellen, bearbeiten und löschen – alles wird direkt in dein Git-Repository committed.

auth to forgejo

webui sveltia


Teil 4: Deployment und CI/CD

4.1 Production Build

Für Production baue die Site:

npm run build

Die fertige Site liegt in dist/. Das Admin-Interface wird automatisch unter /admin verfügbar sein.

4.2 Webhook für Auto-Deploy (Optional)

Wenn du Coolify, Vercel oder ähnliche Plattformen nutzt, kannst du einen Webhook einrichten, der bei jedem Push automatisch ein neues Deployment triggert:

  1. In Forgejo: Repository → Einstellungen → Webhooks
  2. Webhook hinzufügenForgejo
  3. Payload URL: Deine Coolify/Vercel Webhook-URL
  4. Content Type: application/json
  5. Events: Push aktivieren
  6. Token: Dein Coolify Auth Token

Jetzt wird bei jedem gespeicherten Blog-Post automatisch die Website neu gebaut.


Mein Fazit

Wer bereit ist, etwas Betriebsaufwand zu investieren, erhält hier eine robuste, wartungsfreundliche Alternative zu cloud‑basierten Diensten. Mit Forgejo als Git‑Backend und Coolify fürs Deployment lässt sich Sveltia CMS sauber in einen Astro‑Workflow integrieren: schlankes UI, Git‑Versionierung und ein direkter Commit‑Flow sorgen für Transparenz und Kontrolle.

Weiterführende Ressourcen


Hinweis: Dieser Artikel basiert auf Astro v6, Sveltia CMS v0.146.10 und Forgejo v13.0.3 (März 2026). Bei neueren Versionen können sich Details ändern.