One of the most common headaches when deploying a Laravel app is getting the file and directory permissions right. You’ve probably seen errors like:
- Permission denied
- The stream or file could not be opened
- mkdir(): Permission denied
- Unable to write in the “/public/uploads” directory.
This quick guide walks you through setting correct permissions for a Laravel site deployed to Nginx on Ubuntu, using /var/www/yourwebsite.com
as the example directory.
🧱 Why Permissions Matter
Laravel needs certain directories to be writable—specifically storage/
and bootstrap/cache/
. Everything else should not be writable to protect your app from malicious uploads or file tampering.
If your app breaks after deployment or throws obscure errors, it’s probably a permissions problem.
🔧 Step-by-Step: Set Proper Permissions
1. Set Ownership
Make sure the web server user (typically www-data
) owns the Laravel directory:
sudo chown -R www-data:www-data /var/www/yourwebsite.com
Or, if you’re developing and want to retain ownership as your user:
sudo chown -R youruser:www-data /var/www/yourwebsite.com
Replace youruser
with your Ubuntu username.
2. Set Directory and File Permissions
Set all directories to 755
:
sudo find /var/www/yourwebsite.com -type d -exec chmod 755 {} \;
Set all files to 644
:
sudo find /var/www/yourwebsite.com -type f -exec chmod 644 {} \;
3. Make Laravel Directories Writable
Give the web server access to storage
and bootstrap/cache
:
sudo chgrp -R www-data /var/www/yourwebsite.com/storage /var/www/yourwebsite.com/bootstrap/cache sudo chmod -R ug+rwx /var/www/yourwebsite.com/storage /var/www/yourwebsite.com/bootstrap/cache
To ensure group inheritance on new files, add the sticky bit:
sudo chmod g+s /var/www/yourwebsite.com/storage /var/www/yourwebsite.com/bootstrap/cache
✅ Quick Summary Table
Path | Owner/Group | Permissions | Purpose |
---|---|---|---|
/var/www/ | www-data:www-data | 755 | Web root |
storage/ & bootstrap/cache/ | www-data:www-data | 775 | Writable runtime data |
PHP, routes, config, etc. | www-data:www-data | 644 | Secure, read-only files |
Bash Script
This Bash script is designed to resolve common file and directory permission issues encountered when deploying Laravel applications on Ubuntu with Nginx. It sets the correct ownership, applies appropriate permissions to the Laravel writable directories (storage
, bootstrap/cache
, and public/uploads
), and ensures secure default permissions elsewhere in the project.
How to Use:
- Update the
PROJECT_ROOT
variable to point to your Laravel project’s root directory. - Add any additional writable directories (such as
public/uploads
) to theWRITABLE_DIRS
array as needed. - Save the script as
fix-laravel-permissions.sh
. - Make it executable:
chmod +x fix-laravel-permissions.sh
- Run the script as root or with sudo:
sudo ./fix-laravel-permissions.sh
#!/usr/bin/env bash # fix-laravel-permissions.sh # Fixes Laravel file and directory permissions on Ubuntu/Nginx # === CONFIGURATION === PROJECT_ROOT="/var/www/my-laravel-app" NGINX_USER="www-data" NGINX_GROUP="www-data" WRITABLE_DIRS=("storage" "bootstrap/cache" "public/uploads") # === SCRIPT START === set -euo pipefail echo "Fixing permissions in $PROJECT_ROOT..." # 1. Set ownership to web server user chown -R "$NGINX_USER:$NGINX_GROUP" "$PROJECT_ROOT" # 2. Ensure writable directories have proper permissions for dir in "${WRITABLE_DIRS[@]}"; do FULL_PATH="$PROJECT_ROOT/$dir" if [ -d "$FULL_PATH" ]; then chmod -R ug+rwx "$FULL_PATH" else echo "Warning: $FULL_PATH does not exist, skipping." fi done # 3. Set safe defaults for other files and directories find "$PROJECT_ROOT" -type d ! -path "$PROJECT_ROOT/storage/*" ! -path "$PROJECT_ROOT/bootstrap/cache/*" ! -path "$PROJECT_ROOT/public/uploads/*" -exec chmod 755 {} + find "$PROJECT_ROOT" -type f ! -path "$PROJECT_ROOT/storage/*" ! -path "$PROJECT_ROOT/bootstrap/cache/*" ! -path "$PROJECT_ROOT/public/uploads/*" -exec chmod 644 {} + echo "Permissions have been set successfully."
Ask ChatGPT
Pro Tip: Use umask
in Dev Environments
If you edit files alongside the server, set your shell’s umask to allow group write access:
umask 002
Still Having Issues?
Make sure Nginx is configured to use www-data
. Check this in /etc/nginx/nginx.conf
:
user www-data;
Also confirm PHP-FPM is running as www-data
by checking:
/etc/php/8.2/fpm/pool.d/www.conf
user = www-data group = www-data
Restart both services:
sudo systemctl restart php8.2-fpm sudo systemctl restart nginx
🎯 Final Thoughts
Laravel permissions can be frustrating, but once you know what’s required, it’s easy to bake into your deployment scripts. If this post helped you, share it or save it—you’ll definitely need it again.
Discover more from AJB Blog
Subscribe to get the latest posts sent to your email.