Skip to content

Profiler write failure (500 on every request) when var/ is root-owned — breaks non-root/Swarm deployments #282

Description

@Ahson-Shaikh

Summary

Deploying the official ghcr.io/tchapi/davis image in a Docker Swarm setup (specifically via a named/managed volume rather than a plain docker compose bind mount on a single host) results in a 500 Internal Server Error on every request, including the login page.

Root cause

  • The Dockerfile's final image has /var/www/davis/var and /var/www/davis/vendor owned by root (composer install / cache warmup run as root during the build, after the initial COPY --chown=${FPM_USER} step).
  • The container itself correctly runs as the non-root www-data user at runtime (confirmed via php-fpm's own log: NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root).
  • config/packages/framework.yaml registers profiler: collect_serializer_data: true unconditionally — not wrapped in a when@dev: block — so Symfony's profiler is active even with APP_ENV=prod.
  • On the first request, FileProfilerStorage tries to create var/cache/prod/profiler/, which fails because www-data cannot create new directories/files under the root-owned, mode-755 var/cache/prod/.
  • Result: RuntimeException: Unable to create the storage directory (/var/www/davis/var/cache/prod/profiler). on every single request, confirmed via the app's own log:
[...] request.CRITICAL: Uncaught PHP Exception RuntimeException: "Unable to create the storage directory (/var/www/davis/var/cache/prod/profiler)." at FileProfilerStorage.php line 41

This doesn't surface in a typical single-host docker compose up because the named volume there is usually created fresh with different default ownership/timing than in a Swarm-orchestrated deployment where a managed volume mount populates from the image's baked-in ownership.

Suggested fixes (any one of these would resolve it)

  1. Wrap the profiler: key in config/packages/framework.yaml under when@dev: (the standard Symfony convention — profiler generally shouldn't run in prod anyway), or add enabled: false for the prod environment explicitly.
  2. In the Dockerfile, chown -R ${FPM_USER} /var/www/davis as the very last step (after composer install), so www-data actually owns everything it needs to write to at runtime, regardless of how the deployment orchestrator manages volumes.

Environment

  • Image: ghcr.io/tchapi/davis:5.4.3
  • Deployed via Docker Swarm (Easypanel), Postgres backend, nginx in front proxying to php-fpm over the network
  • APP_ENV=prod, APP_DEBUG unset (defaults to false)

Happy to provide more logs/repro details if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions