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 writableRuntimeException: Failed to save cacheduring deploymentcache:warmupfails 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.Set up ACL for shared directory access:
- 2.```bash
- 3.# Set ACLs (requires acl package: apt install acl)
- 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.If ACL not available, use group permissions:
- 2.```bash
- 3.# Add CLI user to web server group
- 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.Fix deployment script:
- 2.```bash
- 3.#!/bin/bash
- 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.Configure cache directory for Docker:
- 2.```dockerfile
- 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.Use alternative cache storage:
- 2.```yaml
- 3.# config/packages/cache.yaml
- 4.framework:
- 5.cache:
- 6.# Use Redis instead of filesystem
- 7.app: cache.adapter.redis
- 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:warmupas 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 0002in 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
`