The permissions on a file are only the last check. Several other things can deny the write while the file itself looks perfectly correct, which is what makes this one so confusing.
1. A parent directory
namei -l /var/www/site/storage/logs/app.log
Every directory in the path needs execute permission for you to reach the file. namei prints the whole chain with its permissions, and the offending row is usually obvious.
2. It is the process, not you
ps aux | grep php-fpm | head -3 # which user is it running as\nsudo -u www-data test -w /var/www/site/storage && echo writable || echo NOT
Your shell is you; the web server is www-data. Testing as the right user is the difference between a five-minute fix and an afternoon.
3. SELinux, on RHEL, Alma and Rocky
ls -Z /var/www/site/storage\nsudo ausearch -m avc -ts recent | tail\nsudo chcon -R -t httpd_sys_rw_content_t /var/www/site/storage\nsudo setsebool -P httpd_can_network_connect on
SELinux denials do not appear in the application log at all. If permissions are right and the write still fails on one of those distributions, this is almost always why.
4. Immutable, or a read-only mount
lsattr /var/www/site/config.php # ----i--------- means immutable\nsudo chattr -i /var/www/site/config.php\nmount | grep " / " # ro means read-only, often after a disk error
A filesystem remounted read-only is the kernel protecting a failing disk. Check
dmesg -T | tail before doing anything else - that is a hardware problem, not a permissions one.Then set it correctly
Not 777. Ownership and the group bit are the right tools - see ownership, umask and the group trap.