After deploying with sudo, Laravel says "Permission denied" writing to storage/logs and WordPress cannot update plugins. I have been running chmod 777 everywhere. What is the proper way?
DEV3 Developer Forum
What are the correct file ownership and permissions for a web app on Linux (www-data, 755 vs 775)?
Every post is reviewed first. Usually reviewed within 24 hours.
1 reply
chmod 777 makes files writable by every account on the server and is a security hole. Use ownership and groups instead.
Principles
- The deploy user owns the code and can write it.
- The web server user (
www-dataon Debian/Ubuntu,nginxorapacheon RHEL) only needs to read code, and write only to specific data directories. - Directories 755 (or 775 if a group must write), files 644. Never 777.
Typical setup
sudo chown -R deploy:www-data /var/www/app
sudo find /var/www/app -type d -exec chmod 755 {} \;
sudo find /var/www/app -type f -exec chmod 644 {} \;
# writable paths for the web server (Laravel)
sudo chmod -R ug+rwX storage bootstrap/cache
sudo find storage bootstrap/cache -type d -exec chmod g+s {} \; # new files inherit the group
Setting the setgid bit (g+s) on directories keeps new files in the www-data group, so both your deploy user and PHP can write them. Make sure the PHP-FPM pool and queue workers run with a umask that keeps group write (umask 002), or files created by www-data may not be writable by the deploy user.
WordPress: only wp-content/uploads (plus plugin and theme folders if you want admin installs/updates) needs to be writable by the web user. Many secure setups keep code read-only and update via WP-CLI or deployments. wp-config.php can be 640.
Debug
namei -l /var/www/app/storage/logs/laravel.log # shows permissions on each path part
sudo -u www-data test -w storage/logs && echo writable
ps aux | grep php-fpm # which user runs PHP
Pitfalls
- Running artisan or composer with
sudocreates root-owned cache and log files that the web user cannot then write. Run them as the deploy user, or fix withchown. - SELinux (RHEL, CentOS) blocks writes even with correct modes: label writable dirs with
chcon -R -t httpd_sys_rw_content_t(orsemanage fcontext). - A parent directory without execute (
x) permission blocks access to everything beneath it.