moselwal/frankenphp — Worker-Mode plus Souin-Cache für TYPO3.

moselwal/frankenphp hängt TYPO3 in den FrankenPHP-Worker-Mode ein, schickt RFC-8297-konforme 103 Early Hints aus dem AssetCollector und invalidiert den vorgelagerten Caddy/Souin-HTTP-Cache automatisch über PSR-14-Events und einen DataHandler-Hook. Ein Backend-Modul macht Cache-Flushes und Key-Inspection direkt im TYPO3 verfügbar.

Fünf Bausteine

Voraussetzungen

Frontend-Worker und Request-Klassifizierung

KlasseAufgabe
Classes/Runtime/FrontendWorkerWorker-Loop mit frankenphp_handle_request(), pro Request frisches TYPO3-Bootstrap mit REQUESTTYPE_FE
Classes/Runtime/RequestClassifierPure-PHP (keine TYPO3-Dependencies), klassifiziert Requests aus $_SERVER in Frontend, Backend oder Install. Backend-Erkennung path- oder host-basiert
Resources/Private/Worker/frontend.phpWorker-Entry-Point (als worker im Caddyfile eintragen)

Classes/Runtime/ ist von der DI-Auto-Registrierung ausgenommen, weil dieser Code vor dem TYPO3-Container läuft.

Environment-Variablen

VariableBeschreibungDefault
TYPO3_BACKEND_ENTRYPOINTBackend-Entry-Point (Pfad oder URL)/typo3
MAX_REQUESTSRequests pro Worker-Lifecycle1
TYPO3_AUTOLOAD_PATHPfad zu vendor/autoload.phpAuto-Detect

EarlyHintMiddleware (103 Early Hints)

Die Middleware sammelt im PSR-15-Hook nach handler->handle() die per AssetCollector registrierten CSS- und JS-Quellen, resolved EXT:-Pfade mit PathUtility::getSystemResourceUri() (TYPO3 v14+-konform) und sendet zwei parallele Hints:

  1. 103 Early Hints via headers_send(103) — sobald FrankenPHP die Funktion bereitstellt (function_exists()-Guard für CLI- und Test-Kontexte).
  2. Link:-Header in der 200-Response — Fallback und für HTTP/2-Push-fähige Reverse-Proxies.

Beide Mechanismen liefern Browser-deduplizierbare Preload-Hints. Bei CSS- und JS-lastigen Seiten messbar bessere LCP-Werte.

Middleware-Position: vor typo3/cms-frontend/timetracker (siehe Configuration/RequestMiddlewares.php).

Cache-Invalidierung gegen Caddy/Souin

CaddyCacheService spricht die Souin-REST-API:

Auto-Invalidierung

Optional API-Key via X-API-Key-Header.

Eigene Cache-Tags

 

$this->caddyCacheService->invalidateByTags(['custom:tag', 'product:123']);

 

Eigener Event-Listener

 

# Configuration/Services.yaml
services:
  Your\Extension\EventListener\CustomCacheListener:
    tags:
      - name: event.listener
        identifier: 'custom-cache-invalidation'
        event: Your\Extension\Event\CustomEvent

Installation und Caddyfile

composer require moselwal/frankenphp

 

Caddyfile

 

your-domain.com {
    root * /app/public
    
    php_server {
        worker /app/vendor/moselwal/frankenphp/Resources/Private/Worker/frontend.php
        env TYPO3_BACKEND_ENTRYPOINT /typo3
        env MAX_REQUESTS 1000
    }
    
    route {
        cache {
            api {
                souin
            }
            ttl 1h
            default_cache_control public
        }
    }
}

 

Extension-Konfiguration

Im TYPO3-Backend unter „Admin Tools → Extension Configuration → frankenphp":

KeyBeschreibungDefault
caddyHostCaddy-Server-Host für die Cache-APIlocalhost
caddyPortCaddy-Server-Port80
caddyProtocolhttp oder httpshttp
caddyApiEndpointSouin-API-Pfad/souin/api/souin
caddyApiKeyOptional, sendet X-API-Key-Header
enableDebugLoggingDetail-Logs für Cache-Calls0
httpTimeoutHTTP-Timeout (Sekunden)5
invalidateAllSitesCache-Flush invalidiert alle Sites1
cacheTagHeaderHeader-Name für Tag-InvalidierungSurrogate-Key

Worker-Reload und Troubleshooting

Worker-Reload ohne Container-Restart

OPcache cached den Middleware-Code pro Worker-Thread. Nach Code-Änderungen reicht typo3 cache:flush --group all nicht. Worker recyclen:

 

# SIGUSR1 an FrankenPHP-PID 1
docker exec <httpd-container> kill -USR1 1

 

frankenphp reload --config /etc/caddy/Caddyfile lädt nur die Caddy-Config, nicht zwingend die PHP-Worker-Threads.

Logging

PSR-3-Logger via TYPO3:

Backend-Modul

„Admin Tools → Caddy Cache Management":

Troubleshooting

SymptomWahrscheinlich
103 sehe ich nicht im curl -vSouin-Cache schluckt 103 bei Cache-Hits. Cache-Control: no-cache plus Cache-Buster im URL. Außerdem zeigt curl < 8.10 die 103 stillschweigend nicht.
Browser-Console Refused to apply style from 'https://host/EXT:...'Pre-v4.0.3 — EXT:-Resolution war nicht implementiert. Auf v4.0.6+ updaten.
Cache wird nicht invalidiertCaddy-Host/Port/Protocol prüfen, enableDebugLogging aktivieren, Logs in /var/log/typo3 checken
API-Calls schlagen mit 401 fehlAPI-Key prüfen, X-API-Key-Header in der Caddy-Config zulassen
Nächster Schritt

TYPO3 in den Worker-Mode umstellen?

Wenn Sie TYPO3 in den FrankenPHP-Worker-Mode bringen, die Caddy-Souin-Cache-Strecke vor TYPO3 sauber invalidieren oder messbar bessere LCP-Werte über 103 Early Hints holen wollen, sprechen Sie uns an. Wir koordinieren Migration, Caddyfile, Worker-Reload-Pipeline und Backend-Setup.

Worker-Mode besprechen

Oder direkt schreiben: kontakt@moselwal.de

Setzen wir ein bei …

Dieses Paket trägt die PHP-Runtime in TYPO3 Kubernetes — Worker-Mode, geringere Startup-Cost pro Pod, bessere Auslastung. In der betreuten Variante: AI-Ready CMS as a Service.