Handbuch · 16

Betrieb

Startoptionen

Option Umgebungsvariable Standard
-addr IC_ADDR :8080 Adresse und Port
-data IC_DATA ./data Datenordner
-cache-mb IC_CACHE_MB 128 Seiten-Cache in MB, 0 = aus
-secure-cookies IC_SECURE_COOKIES=1 aus Session-Cookie nur über HTTPS – hinter HTTPS unbedingt aktivieren
-rate-limit IC_RATE_LIMIT 120 API-Anfragen pro Minute und IP ohne Anmeldung (mit Token/Session das Zehnfache), 0 = aus – siehe API-Doku
-headless IC_HEADLESS=1 aus Ohne Admin-App, Anmeldung und Sitzungen erzwingen – siehe Headless-Server
– IC_MASTER_TOKEN – Token mit Schreibrecht ohne Benutzerkonto (mindestens 32 Zeichen) – siehe Headless-Server
– IC_SETUP_TOKEN – Optional: Geheimnis, das die erste Einrichtung (erstes Admin-Konto) verlangt – schützt eine frisch veröffentlichte, noch leere Instanz davor, dass ein Fremder zuerst ist. Wird in der Einrichtungsmaske abgefragt
-media-cache-mb IC_MEDIA_CACHE_MB 512 Plattencache für Medien in S3 in MB, 0 = aus – siehe Medien in S3 speichern
– IC_ENCRYPTION_KEY – Schlüssel für verschlüsselte Zugangsdaten in den Einstellungen (mindestens 32 Zeichen); ohne ihn legt IllusionCMS data/secret.key an – siehe Medien in S3 speichern

Umgebungsvariablen für REST-Quellen ({env.NAME}) setzt du beim Start mit. Variablen mit dem Präfix IC_ (Konfiguration des CMS, z. B. IC_MASTER_TOKEN) sind dort nie lesbar. Workflows haben keinen Zugriff auf Umgebungsvariablen.

Außerdem: -version gibt die Version aus, -create-token "Name" legt einen API-Token mit Schreibrecht an, gibt ihn aus und beendet sich, -enable-admin schaltet ein in den Einstellungen abgeschaltetes Admin wieder ein, -healthcheck fragt /healthz des laufenden Servers ab und endet mit Exit-Code 0 bzw. 1 – gedacht für den HEALTHCHECK eines Docker-Containers.

Docker und Coolify: Fertige Compose-Dateien (Standalone hinter einem Reverse Proxy wie Apache, und für Coolify) liegen in jedem Release als illusioncms-vX.Y.Z-deploy.zip (samt Linux-Binaries, Anleitung in der enthaltenen README.md) und im Deployment-Repo IllusionCMS-Deployment. Hinter einem Proxy wichtig: Der Proxy muss den Host-Header durchreichen (bei Apache ProxyPreserveHost On) – sonst kann IllusionCMS die Website nicht der Domain zuordnen – und X-Forwarded-Proto setzen, damit Sitemap und robots.txt https:// verwenden.

Datenordner und Backup

data/
  illusion.db        Datenbank (Seiten, Snippets, CSS/JS, Collections, Einstellungen …)
  illusion.db-wal    Schreibprotokoll der Datenbank (gehört dazu!)
  media/2026/10/…    hochgeladene und importierte Dateien
  backups/           automatische Backups: nächtlich ohne Medien (die letzten 7)
                     und vor dem Einspielen eines Bundles samt Medien (die letzten 3)
  cache/media/       Plattencache für Medien aus S3 (nur mit S3)
  secret.key         Schlüssel für verschlüsselte Zugangsdaten (ohne IC_ENCRYPTION_KEY)

Automatische Backups: Jede Nacht ab 3 Uhr (Serverzeit) sichert IllusionCMS den kompletten Inhalt – Seiten, CSS/JS, Snippets, Collections, Einstellungen der Dateien … – ohne die Mediendateien selbst, aber nur, wenn sich seit dem letzten nächtlichen Backup etwas geändert hat. Die letzten 7 bleiben liegen. Wiederherstellen: unter Einstellungen → Synchronisation das Backup herunterladen und wieder einspielen; der Medienordner bleibt dabei unverändert. Sollen auch die Einträge von Collections mit Live-Daten auf den Stand des Backups zurück, beim Einspielen Auch die Einträge von Collections mit Live-Daten aus dem Bundle übernehmen anhaken. Die Mediendateien sicherst du am besten zusätzlich mit dem Datenordner (sie ändern sich selten und werden nur gelöscht, wenn du sie ausdrücklich löschst).

Backup: Am sichersten den Server kurz stoppen und den ganzen Ordner kopieren. Im laufenden Betrieb: sqlite3 data/illusion.db ".backup backup.db" plus eine Kopie von media/ – oder einfach ein Bundle herunterladen (enthält allen Inhalt, aber keine Konten und Tokens).

Medien in S3 speichern

Hochgeladene und importierte Dateien liegen standardmäßig in data/media. Wahlweise legt IllusionCMS sie in einem S3-kompatiblen Speicher ab – praktisch, wenn der Server wenig Platz hat oder die Dateien getrennt vom Server gesichert sein sollen. Die Adressen ändern sich dabei nicht: Dateien bleiben unter /media/… erreichbar, IllusionCMS holt sie selbst aus dem Bucket (auch Teilbereiche für Videos und fortsetzbare Downloads). Der Bucket bleibt privat, er muss nicht öffentlich lesbar sein.

Wo: Einstellungen → Speicher (im Remote-Modus für den verbundenen Server). Oben stehen der aktive Speicher, Anzahl und Größe der Dateien und die Belegung des Plattencaches.

Felder:

  • Endpoint – Adresse des S3-Dienstes, z. B. https://s3.eu-central-1.amazonaws.com.
  • Region – z. B. eu-central-1; bei Garage meist garage, bei Cloudflare R2 auto. Leer = us-east-1.
  • Bucket – muss schon existieren. Prefix (optional) – z. B. cms/, wenn sich mehrere Anwendungen einen Bucket teilen.
  • Access Key und Secret Key – der Key braucht Rechte zum Lesen, Schreiben, Löschen und Auflisten. Das Secret wird nie wieder angezeigt; lässt du das Feld später leer, bleibt das gespeicherte.
  • Path-Style – Adressierung endpoint/bucket/datei statt bucket.endpoint/datei. Nötig für Garage und Endpoints mit IP-Adresse.
Anbieter Endpoint Region Path-Style
Garage (selbst betrieben) http://127.0.0.1:3900 bzw. deine Garage-Adresse garage an
Hetzner Object Storage https://fsn1.your-objectstorage.com (bzw. nbg1, hel1) fsn1 aus
Cloudflare R2 https://<account-id>.r2.cloudflarestorage.com auto an
AWS S3 https://s3.eu-central-1.amazonaws.com eu-central-1 aus

Verbindung testen schreibt, liest und löscht ein kleines Probe-Objekt im Bucket und meldet verständlich, was fehlt (Adresse nicht erreichbar, Key unbekannt, Secret falsch, Bucket fehlt, Rechte fehlen). Speichern merkt sich die Angaben – solange die lokale Ablage aktiv ist, nur als Entwurf.

Umziehen: Zu S3 wechseln … startet eine geführte Migration im Hintergrund: Alle Dateien werden kopiert (was am Ziel schon mit gleicher Größe liegt, wird übersprungen – ein abgebrochener Umzug setzt also dort fort), danach wird jede Kopie geprüft, erst dann schaltet IllusionCMS um und leert den Seiten-Cache. Du kannst währenddessen weiterarbeiten: Uploads und Löschungen landen zunächst in der alten Ablage, werden mitprotokolliert und beim Umschalten nachgezogen – dafür halten Schreibzugriffe nur für diesen kurzen Moment an. Mit Abbrechen oder bei einem Fehler bleibt die alte Ablage aktiv. Ist Alte Dateien danach löschen angehakt, räumt IllusionCMS die alte Ablage nach dem erfolgreichen Umschalten auf; ohne den Haken bleibt sie als Rückfall liegen. Zurück zur lokalen Ablage … funktioniert genauso in die andere Richtung. Bucket und Prefix eines aktiven S3-Speichers änderst du nur per Migration; neue Zugangsdaten für denselben Bucket gelten nach erfolgreichem Test sofort.

Plattencache: Vor S3 liegt ein lokaler Cache in data/cache/media (Standard 512 MB, Startoption -media-cache-mb bzw. IC_MEDIA_CACHE_MB, je Instanz auch in den Speicher-Einstellungen). Er beschleunigt vor allem Bildvarianten und WebP und liefert Gecachtes weiter aus, wenn S3 kurz nicht erreichbar ist. Ein Bucket darf nur von einer IllusionCMS-Instanz benutzt werden (der Cache geht davon aus, dass alle Änderungen über sie laufen) – für eine zweite Instanz einen eigenen Bucket oder Prefix nehmen.

Verschlüsselte Zugangsdaten: Das Secret steht nur verschlüsselt in der Datenbank (AES-256-GCM). Den Schlüssel liefert die Umgebungsvariable IC_ENCRYPTION_KEY (mindestens 32 Zeichen, z. B. openssl rand -hex 32); ist sie nicht gesetzt, legt IllusionCMS beim ersten Bedarf die Datei data/secret.key an (nur für den Besitzer lesbar). Beim Umzug auf einen anderen Server den Schlüssel mitnehmen – also data/secret.key mitkopieren bzw. dieselbe IC_ENCRYPTION_KEY setzen. Fehlt der Schlüssel oder ist er ein anderer, lässt sich das Secret nicht mehr entschlüsseln: IllusionCMS startet dann mit den lokalen Dateien und zeigt den Fehler in den Speicher-Einstellungen – Secret neu eintragen und speichern, dann gilt wieder S3. Bundles enthalten die Speicher-Einstellung bewusst nicht.

Was verschlüsselt ist und was nicht: Verschlüsselt (derselbe Schlüssel) liegen S3-Secret, Webhook-Secrets, das SMTP-Passwort, die IllusionDB-Tokens und die Tokens der Verbindungen in der Datenbank; Altbestand im Klartext bleibt lesbar und wird beim nächsten Speichern verschlüsselt. Gespeicherte Geheimnisse (SMTP-Passwort, IllusionDB-Token, S3-Secret, Verbindungs-Token) werden nur für dasselbe Ziel wiederverwendet – ändert sich Host, Adresse, Endpoint oder Bucket, musst du sie neu eingeben. Nicht verschlüsselt sind die Header der REST-Quellen (Authorization …): Sie gehören zu den Inhalten und stehen deshalb in Bundles, Nacht-Backups und beim Hochladen auf eine andere Instanz – nur so lässt sich eine Instanz vollständig wiederherstellen. Behandle Bundles und Backups wie Zugangsdaten (die Ordner data/backups und der Medien-Cache sind nur für den Serverbenutzer lesbar); Zugangsdaten für Quellen lassen sich auch aus Umgebungsvariablen ({env.SHOP_TOKEN}) beziehen, dann stehen sie nirgends in der Datenbank.

Backups: Die Datenbank bleibt auch mit S3 lokal in data/illusion.db (die nächtlichen Backups ebenso). Um sie laufend in denselben Bucket zu sichern, eignet sich Litestream – ein eigenes Programm neben IllusionCMS, das die SQLite-Datenbank fortlaufend repliziert. Beispiel für litestream.yml (ein vollständiges Docker-Compose-Beispiel steht in der README.md des Deployment-Pakets):

dbs:
  - path: /data/illusion.db
    replicas:
      - type: s3
        endpoint: https://fsn1.your-objectstorage.com
        bucket: firma-media
        path: litestream/illusion.db
        access-key-id: ${LITESTREAM_ACCESS_KEY_ID}
        secret-access-key: ${LITESTREAM_SECRET_ACCESS_KEY}

Wiederherstellen bei gestopptem Server mit litestream restore -config litestream.yml /data/illusion.db. Die Mediendateien selbst sichert der S3-Anbieter nicht automatisch – Versionierung bzw. Replikation des Buckets beim Anbieter einschalten, falls verfügbar.

Lokal bauen, online veröffentlichen (Bundles)

Du kannst eine Website lokal aufbauen und dann komplett auf deinen Online-Server bringen. Ein Bundle ist eine Datei mit der Endung .icb (IllusionCMS-Bundle, technisch ein ZIP) mit dem gesamten Inhalt der Instanz: Websites, Seiten, CSS/JS, Snippets, Dateien, Collections, REST-Quellen und Weiterleitungen. Konten und API-Tokens gehören nicht dazu – auf dem Server meldest du dich weiter mit deinem dortigen Konto an.

Alles Nötige steht unter Einstellungen → Synchronisation:

  • Herunterladen – das Bundle als .icb-Datei.
  • Hochladen und einspielen – auf dem Online-Server: die .icb-Datei auswählen, Einspielen und ersetzen. Bundles und Backups älterer Versionen (.zip) lassen sich weiterhin einspielen.
  • Mit einem Server abgleichen – vom lokalen Admin aus in einem Schritt, über eine gespeicherte Verbindung: Hochladen ersetzt den Inhalt des Servers durch den lokalen, Herunterholen holt den Stand des Servers samt Live-Daten hierher (z. B. auf einen neuen Rechner oder nach einem Notfall-Fix online). Der Fortschritt wird angezeigt. Hat sich auf der Seite, die ersetzt wird, seit dem letzten Abgleich etwas geändert, warnt das CMS vorher – Live-Daten zählen dabei nicht als Änderung.

Wichtig zu wissen:

  • Das Einspielen ersetzt den kompletten Inhalt des Ziels – was nur online geändert wurde, ist danach weg. Vorher sichert der Server automatisch seinen bisherigen Stand (die letzten 3 Backups stehen in derselben Ansicht zum Herunterladen; Wiederherstellen = Backup einspielen).
  • Live-Daten bleiben: Einträge von Collections mit dem Haken Live-Daten (z. B. Kontaktanfragen) bleiben auf dem Ziel immer erhalten – auch die, die eingehen, während du lokal arbeitest. Die lokalen Einträge dieser Collections werden nicht übertragen. Umgekehrt (ein Bundle vom Live-Server lokal einspielen, ein Backup wiederherstellen) übernimmst du sie mit dem Haken Auch die Einträge von Collections mit Live-Daten aus dem Bundle übernehmen.
  • Online gepflegte Inhalte behalten: Mit Collection-Einträge behalten bleiben die Einträge des Servers (z. B. Blogartikel, die online geschrieben werden) – Layout, Seiten und Code kommen trotzdem vom lokalen Stand. Zugeordnet wird über den Slug der Collection.
  • Domains: Lokal hat deine Website meist keine Domain. Dann behält die Website auf dem Server ihre eingetragenen Domains. Trägst du lokal Domains ein, werden sie übernommen.
  • Unveränderte Dateien werden nicht neu geschrieben – wiederholte Übertragungen gehen schneller. Hochgeladen wird trotzdem das ganze Bundle.
  • Beide Instanzen sollten dieselbe IllusionCMS-Version haben; ein älterer Server lehnt Bundles einer neueren Version ab.
  • Läuft der Server hinter nginx, muss client_max_body_size groß genug für das Bundle sein (Caddy: kein Limit).
  • Skriptbar: curl -H "Authorization: Bearer <token>" -H "Content-Type: application/zip" --data-binary @bundle.icb https://www.firma.de/api/v1/bundle (siehe API).

Mehrere Instanzen: live arbeiten oder abgleichen

Unter Einstellungen → Verbindungen trägst du andere IllusionCMS-Instanzen ein – Name, Adresse und einen API-Token mit Schreibrecht von dort (auf dem Server unter Einstellungen → API-Tokens, bei einem Server ohne Admin der Master-Token oder per -create-token). Der Token bleibt in der lokalen Datenbank, wird nicht angezeigt und gehört nicht ins Bundle. Prüfen zeigt, ob der Server erreichbar ist, welche Version dort läuft und ob er headless betrieben wird. Ob auf dem Server selbst das Admin läuft, ist egal – nötig ist nur der Token. So verwaltest du beliebig viele Instanzen aus einer lokalen App; headless ist eine zusätzliche Option für Server, die du ausschließlich so pflegst.

Mit einer Verbindung gibt es zwei Arbeitsweisen – du kannst beide mischen:

  • Live arbeiten: Oben im Menü steht, mit welcher Instanz das Admin gerade arbeitet (Lokal). Wählst du dort eine Verbindung, gehen alle Ansichten – Seiten, Dateien, Collections, Statistik, Workflows, 404-Protokoll … – direkt an diesen Server; Änderungen wirken sofort. Das Menü zeigt dann den Namen der Verbindung mit LIVE. So verwaltest du mehrere Websites auf verschiedenen Servern aus einer lokalen App, und Live-Daten wie Kontaktanfragen siehst du ohne Umweg. Lokal bleiben nur Konten, API-Tokens und die Verbindungen selbst. Seiten-Vorschau, Pens und Workflow-Adressen zeigen auf den Server.
  • Lokal bauen und abgleichen: Lokal ausprobieren, ohne dass Besucher etwas davon sehen, dann unter Einstellungen → Synchronisation hochladen (siehe oben). Live-Daten auf dem Server bleiben dabei erhalten.

Versionen: Die Admin-App kommt immer aus deiner lokalen Instanz. Beim Umschalten (und bei jedem Laden) prüft sie, ob der Server dieselbe IllusionCMS-Version hat. Weicht sie ab oder ist der Server nicht erreichbar, wird der Umschalter rot statt gelb, und ein Hinweis nennt beide Versionen; im Auswahlmenü stehen bei jeder Verbindung ihre Version und gegebenenfalls ein ⚠. Arbeiten geht trotzdem, aber manche Funktionen können fehlen oder fehlschlagen – am besten beide Instanzen gemeinsam aktualisieren.

Für schnelle Korrekturen eignet sich der Live-Modus, für größere Umbauten (neues Layout, viele CSS-Änderungen) die lokale Instanz – Entwürfe gibt es nur für Seiten, eine geänderte CSS-Datei oder ein Snippet wirkt live sofort überall.

Headless-Server (ohne Admin)

Wer seinen Live-Server nur noch aus der lokalen App verwaltet, braucht dort kein Admin. Ohne Admin liefert der Server die Website, die API für Tokens, die HTTP-Eingänge der Workflows und öffentliche Pens aus – aber kein /cms-admin, keine Anmeldung, keine Sitzungen und keine Konto- oder Token-Verwaltung (alles 404). Das macht die Angriffsfläche kleiner: Es gibt keine Login-Seite, die jemand durchprobieren könnte.

Am einfachsten – ganz ohne Benutzerkonto: Beim Start einen Master-Token setzen und das Admin abschalten:

IC_MASTER_TOKEN=$(openssl rand -hex 32)   # merken – das ist der Token für die Verbindung
IC_HEADLESS=1

Der Master-Token gilt wie ein API-Token mit Schreibrecht, steht aber in keiner Datenbank und braucht kein Konto (mindestens 32 Zeichen, sonst startet der Server nicht). Lokal trägst du ihn unter Einstellungen → Verbindungen ein. Im Verlauf erscheint er als Autor Master-Token. Konten und Tokens verwaltet er nicht – das bleibt dem Admin vorbehalten. Gesperrt ist er, sobald du die Variable entfernst und neu startest.

Admin per Schalter abschalten: Statt IC_HEADLESS=1 geht es auch unter Einstellungen → System → Admin abschalten – im Admin des Servers selbst oder, bequemer, aus deiner lokalen App im Remote-Modus. Das geht nur, wenn ein Token mit Schreibrecht existiert (oder ein Master-Token gesetzt ist), damit du dich nicht aussperrst. Wieder einschalten: im Remote-Modus unter Einstellungen → System, per API (PUT /api/v1/system) oder auf dem Server mit illusioncms -enable-admin. Notausgang, falls kein Token mehr bekannt ist: IC_MASTER_TOKEN setzen, neu starten, damit verbinden und das Admin einschalten. Mit IC_HEADLESS=1 ist das Admin dagegen fest aus und der Schalter gesperrt.

Statt eines Master-Tokens geht auch ein normaler API-Token: auf dem Server unter Einstellungen → API-Tokens anlegen, solange das Admin noch läuft, oder per Kommandozeile – im Docker-Container z. B. docker exec <container> illusioncms -data /data -create-token "Lokales Admin".

Als statische Website exportieren

Eine Website lässt sich komplett als statische HTML-Seiten exportieren – für einen einfachen Webspace mit Apache, ohne dass dort IllusionCMS laufen muss. Im Editor der Startseite unter Einstellungen → Website → Als statische Website exportieren:

  1. Export prüfen – rendert alle Seiten und zeigt einen Bericht: Anzahl der Seiten, Dateien und Größe, Seiten mit Template-Fehlern, interne Links ins Leere und fehlende Dateien.
  2. ZIP herunterladen und den Inhalt ins Wurzelverzeichnis der Domain entpacken (z. B. htdocs/ bzw. public_html/).

Was drin ist:

  • Jede Seite als pfad/index.html – /leistungen wird zu leistungen/index.html. Apache leitet /leistungen automatisch auf /leistungen/ um.
  • Detailseiten hinter Catch-All-Seiten (einzelne Blogartikel) kommen mit, wenn sie in der Sitemap stehen (Collections oder Sitemap-Quelle, z. B. IllusionDB) oder irgendwo verlinkt sind – z. B. von der Blog-Übersicht.
  • robots.txt wie im CMS.
  • Die 404-Seite als 404.html und eine .htaccess, die sie einbindet (ErrorDocument 404 /404.html) – mit allen Weiterleitungen der Website.
  • Alle CSS- und JS-Dateien, sitemap.xml (für die erste Domain der Website oder die angegebene Basis-URL) und die verwendeten Bilder samt srcset-Varianten. Mit Alle Dateien der Medienverwaltung mitnehmen kommt der ganze Medienordner mit – nötig, wenn JavaScript Bild-URLs selbst zusammensetzt.
  • Private Dateien fehlen immer – auch mit Alle Dateien der Medienverwaltung mitnehmen, samt ihren Varianten und WebP-Fassungen; der Bericht nennt ihre Anzahl.

Grenzen: Alles ist ein Schnappschuss zum Zeitpunkt des Exports – REST-Daten, Collections und Änderungen danach brauchen einen neuen Export. Seiten mit Query-Parametern (?seite=2) gibt es statisch nicht, ebenso keine /api/v1-Aufrufe aus JavaScript. Der Export gehört ins Wurzelverzeichnis der Domain, nicht in einen Unterordner (Links beginnen mit /).

Gesundheitscheck

GET /healthz antwortet ohne Anmeldung mit 200 und {"status":"ok", …}, solange die Datenbank erreichbar ist, sonst mit 503. Geeignet für Uptime-Monitoring, Docker-HEALTHCHECK oder Load-Balancer. Die Antwort enthält außerdem die Build-Kennung der Admin-App und den Git-Commit des Binarys – praktisch, um zu prüfen, ob ein Update wirklich läuft.

Hinter einem Reverse Proxy (HTTPS)

IllusionCMS spricht selbst nur HTTP. Für HTTPS setzt du einen Proxy davor, z. B. Caddy (holt Zertifikate automatisch):

www.firma.de, shop.firma.de {
    reverse_proxy 127.0.0.1:8080
}
firma.de {
    redir https://www.firma.de{uri}
}

Bei mehreren Websites trägst du alle Domains im Proxy ein; IllusionCMS wählt die Website anhand der aufgerufenen Domain (Host-Header, den Caddy unverändert weiterreicht).

Den Server dann mit -addr 127.0.0.1:8080 -secure-cookies starten. Die Sitemap übernimmt Domain und Schema aus X-Forwarded-Host/X-Forwarded-Proto, die Caddy automatisch setzt.

Schutz-Header wie HSTS kann IllusionCMS selbst senden (Sicherheits-Header). Die Weiterleitung von http:// auf https:// sollte der Proxy dauerhaft machen (301 oder 308, bei Caddy Standard). Bei Traefik ist dafür permanent: true an der Redirect-Middleware nötig, sonst leitet er mit 302 um. Für Coolify steht eine Anleitung im Deployment-Paket (README.md, Abschnitt Coolify).

IllusionCMS komprimiert HTML-Seiten, CSS/JS und die Sitemap selbst (gzip). Eine Komprimierung im Proxy ist deshalb nicht nötig. Schalte sie dort besser ab, sonst werden auch Bilder unnötig noch einmal gepackt.

Als Dienst (systemd)

[Unit]
Description=IllusionCMS
After=network.target

[Service]
ExecStart=/opt/illusioncms/illusioncms -addr 127.0.0.1:8080 -data /var/lib/illusioncms -secure-cookies
Environment=SHOP_TOKEN=…
Restart=on-failure
User=illusioncms

[Install]
WantedBy=multi-user.target