Kai Ole Hartwig
4 min read
By

TYPO3 on FrankenPHP: Operational Gotchas

FrankenPHP's worker model is fast and lovely — and it quietly changes your mental model for config reloads, logging, and deploys versus classic PHP-FPM. Part 4 of "The Ops Log."

TL;DR

TL;DR: The worker is frontend-only, so backend requests run as classic PHP and pick up config edits in ~2s — but a code change to a preloaded class needs the process restarted. TYPO3 file logging is effectively dead over HTTP; route logs to stderr. And /app is an emptyDir — in-pod edits vanish on recreation.

What happened

Gotcha 1 — two runtimes in one pod. The FrankenPHP worker serves the frontend; a request classifier 503s backend/install requests out of the worker, so /typo3, /login and the whole auth chain run as classic PHP with a fresh bootstrap per request. Practical upshot: with opcache.validate_timestamps=On, editing additional.php or a non-preloaded extension class takes effect within ~2s — no pod restart. Great for hotfixing config.

Gotcha 2 — preload pins classes, so some swaps need a restart. The flip side of gotcha 1: opcache.preload pins the TYPO3\CMS\* core into the process at boot. Swap the code of a preloaded class under a running worker and you get a duplicate-class TypeError — the old definition is still pinned. Those deploys must restart the FrankenPHP process, not just drop new files:

what "takes effect" depends on what changed

 

no restart  additional.php, non-preloaded ext class   (validate_timestamps=On)
restart     anything under opcache.preload (TYPO3\CMS\*)
restart     class signature swaps → duplicate-class TypeError

 

Gotcha 3 — file logging is a black hole over HTTP. The log writer config points at a path the CLI warmup can write but the HTTP worker's working directory can't, so typo3_*.log sits at zero bytes and you debug blind. The way out is to route a channel to PhpErrorLogWriter, whose error_log goes to /dev/stderr — which is exactly what kubectl logs reads:

additional.php — make logs visible

 

$GLOBALS['TYPO3_CONF_VARS']['LOG'][$vendor][$ext]['writerConfiguration']
  [\Psr\Log\LogLevel::DEBUG]
  [\TYPO3\CMS\Core\Log\Writer\PhpErrorLogWriter::class] = [];

$ kubectl -n kunde-xyz logs <pod> -c app   # ← now the channel shows up</pod>

 

Gotcha 4 — /app is ephemeral. The application directory is an emptyDir repopulated by init containers (an OCI artifact pull plus setup) on every pod start. Edit a file in the running pod to test something and it's gone the moment the pod recreates. Anything permanent goes through the build artifact and the deploy — the pod filesystem is a scratchpad, not a source of truth.

The lesson

Under FrankenPHP, "did my change take effect?" has three different answers depending on whether it's config, a preloaded class, or a file on disk. Know which one you're touching before you assume a restart is or isn't needed.

Frequently asked questions

Can I test hotfixes directly in the running pod?+

Not permanently — /app is an emptyDir repopulated by init containers on every pod restart. In-pod edits are a scratchpad for short-lived tests, not a place for permanent changes.

Why are TYPO3 log files empty?+

Because the log writer points at a path the HTTP worker can't write to, even though the CLI warmup could. The fix is to route a channel to PhpErrorLogWriter, which writes to stderr.

How do I know whether a deploy needs a restart?+

Check whether the changed class is pinned under opcache.preload (typically TYPO3\CMS\* core classes) or whether a class signature changed — in both cases a process restart is needed, not just new files.

Why do backend changes take effect faster than frontend changes?+

Because the FrankenPHP worker only serves the frontend — backend/install requests run as classic PHP with a fresh bootstrap per request, so opcache.validate_timestamps works normally.

Conclusion

FrankenPHP's worker model is a genuine operational win — faster requests, less overhead — but it splits what "needs a restart" means across three different places: config, preload, and the filesystem. If you don't keep those three cases apart, you either debug blind or restart unnecessarily.

I run and harden your TYPO3 platform on FrankenPHP — including the operational quirks classic PHP-FPM knowledge doesn't cover.

From worker architecture through preload strategy to logging and the deploy pipeline: I build TYPO3-on-FrankenPHP setups that stay predictable in production.

Platform operations, not consulting on paper: I build and maintain your TYPO3 platforms on an ongoing basis.

Book a call →

About the author

[Translate to English:] Foto von Kai Ole Hartwig.

Kai Ole Hartwig

Freelance DevSecOps consultant · OnlyOle Consulting

Programming since 2002 – self-taught, set up my own business with KO-Web in 2012. Over 100 projects, with a focus on security, performance, automation and quality. Today freelance: DevSecOps consulting, training and software development.