Required Caddy directories when running FrankenPHP inside Docker
This PR adds missing documentation about two Caddy directories required when running FrankenPHP inside Docker:
/data/caddy/config/caddy(used to store autosave.json)
These directories are not created by the official image. When `/config/caddy`` is absent or not writable, Caddy cannot autosave its adapted configuration and silently falls back to “serving initial configuration”, even with a valid Caddyfile.
What this PR adds
- A Dockerfile snippet to create the required directories with proper permissions.
- A note for Docker Compose users explaining why mounting the application over
/appcan overwrite internal Caddy files.- A recommended alternative layout using
/srv/appwhen bind-mounting the code.
This should make the Docker setup more reliable for developers using FrankenPHP.
Hi, thanks for the PR. Can you share how to trigger this issue and what it causes?
Hi @henderkes, sure here is how to reproduce it and what happens.
How to trigger the issue
- Use the official image with a custom Caddyfile:
FROM dunglas/frankenphp:php8.4-alpine
COPY Caddyfile /etc/caddy/Caddyfile
CMD ["frankenphp", "run", "--config=/etc/caddy/Caddyfile"]
- Run it in Docker Compose with a bind-mounted application directory:
volumes:
- .:/app
- Start the container.
Since
/config/caddydoes not exist in the base image, Caddy cannot write its autosave file (autosave.json).
What it causes
Depending on the user running Caddy, the log shows either:
open /config/caddy/autosave.json: permission denied or open /config/caddy/autosave.json: no such file or directory
In both cases, Caddy discards the adapted configuration and falls back to:
serving initial configuration
even though the provided Caddyfile is valid.
Creating /config/caddy (and /data/caddy for TLS/locks) resolves the issue.
Thank you! This sounds a lot like something that we should resolve internally, rather than depending on our users to jump through those hoops. I'll give it a shot reproducing it after SymfonyCon to figure out how to fix it.
I think this is partly explained in the Running as non-root user section. /config/caddy and /data/caddy are owned by root. I'd not be against giving them to www-data by default though. We could also add a frankenphp/caddy user (id:1000) and recommend running the server as that user.
I'd not be against giving them to www-data by default though. We could also add a frankenphp/caddy user (id:1000) and recommend running the server as that user.
The problem with that approach is that it doesn't work in Kubernetes and can't be run. We used to do this back in the day and flipped flopped between different configurations until we landed on the one we have. There's some really old issues about it that could probably be dug up from when we had very simple Dockerfiles.
Did you encounter other issues with Kubernetes? From my experience it should be enough that the user running supervisor/caddy/php owns all the directories that it will be writing to. Also, the 80/443 ports need to be accessible to the server process (RUN setcap CAP_NET_BIND_SERVICE=+eip name-of-binary).
The same logic applies when hardening the image with a read-only root filesystem or so.