Introduction

Symfony's cache warmup phase generates optimized PHP files (container compilation, route matching, Twig template compilation) in var/cache/. The web server user (www-data) and the CLI user (deployer) both need write access to this directory. When permissions are misconfigured, the warmup command fails, and the application cannot serve requests because the container is not compiled.

Symptoms

  • Cache directory "/var/www/html/var/cache/prod" is not writable
  • RuntimeException: Failed to save cache during deployment
  • cache:warmup fails with permission denied
  • Application returns 500 after deployment - container not compiled
  • Works after rm -rf var/cache/* but breaks on next deployment

``` $ php bin/console cache:warmup --env=prod

In Filesystem.php line 111: Failed to create "/var/www/html/var/cache/prod/pools": mkdir(): Permission denied

cache:warmup [--no-optional-warmers] [-e|--env ENV] ```

Common Causes

  • CLI user (root/deployer) owns var/cache, web server (www-data) cannot write
  • Deployment script deletes and recreates var/cache with wrong ownership
  • Docker volume mount with incorrect user mapping
  • setfacl not available on the filesystem (NFS, Docker overlay)
  • Symfony running as different user in CLI vs web context

Step-by-Step Fix

  1. 1.Set up ACL for shared directory access:
  2. 2.```bash
  3. 3.# Set ACLs (requires acl package: apt install acl)
  4. 4.HTTPDUSER=$(ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1)

sudo setfacl -R -m u:"$HTTPDUSER":rwX -m u:"$(whoami)":rwX var/cache var/log sudo setfacl -dR -m u:"$HTTPDUSER":rwX -m u:"$(whoami)":rwX var/cache var/log

# Verify getfacl var/cache ```

  1. 1.If ACL not available, use group permissions:
  2. 2.```bash
  3. 3.# Add CLI user to web server group
  4. 4.sudo usermod -a -G www-data $(whoami)

# Set group ownership and permissions sudo chown -R www-data:www-data var/cache var/log sudo chmod -R 775 var/cache var/log

# Set setgid bit so new files inherit group sudo chmod -R g+s var/cache var/log

# Verify ls -la var/ # drwxrwsr-x 4 www-data www-data 4096 Jan 15 10:30 cache ```

  1. 1.Fix deployment script:
  2. 2.```bash
  3. 3.#!/bin/bash
  4. 4.# deploy.sh

# After code is deployed, before warmup: cd /var/www/html

# Ensure correct ownership sudo chown -R www-data:www-data var/cache var/log sudo chmod -R 775 var/cache var/log

# Warm up cache php bin/console cache:warmup --env=prod --no-debug

# Fix ownership again (warmup may create new files as CLI user) sudo chown -R www-data:www-data var/cache/prod ```

  1. 1.Configure cache directory for Docker:
  2. 2.```dockerfile
  3. 3.FROM php:8.2-fpm

WORKDIR /var/www/html

# Create cache and log directories RUN mkdir -p var/cache var/log && \ chown -R www-data:www-data var

# As non-root user USER www-data

# Warm up cache during build COPY --chown=www-data:www-data . . RUN php bin/console cache:warmup --env=prod --no-debug ```

  1. 1.Use alternative cache storage:
  2. 2.```yaml
  3. 3.# config/packages/cache.yaml
  4. 4.framework:
  5. 5.cache:
  6. 6.# Use Redis instead of filesystem
  7. 7.app: cache.adapter.redis
  8. 8.default_redis_provider: 'redis://localhost:6379'

# Or use APCu (faster, per-server) app: cache.adapter.apcu ```

Prevention

  • Add permission checks to deployment scripts
  • Use ACL or group-based permissions for shared directories
  • Run bin/console cache:warmup as the same user that runs the web server
  • Include permission verification in post-deploy smoke tests
  • In Docker, build the container as the correct user
  • Use umask 0002 in deployment scripts to ensure group-writable files
  • Monitor cache directory permissions in health checks:
  • ```bash
  • #!/bin/bash
  • # health-check-cache-permissions.sh
  • if [ ! -w /var/www/html/var/cache ]; then
  • echo "CRITICAL: Cache directory is not writable"
  • exit 2
  • fi
  • echo "OK: Cache directory writable"
  • exit 0
  • `