ThisCalculator

Everyday

Laravel VPS Deployment: Folder Structure & Permissions

Updated · Standard formula, shown below

To deploy Laravel on a VPS, the correct folder structure places the application code outside the web root, with only the public directory exposed, and sets specific permissions so the web server can read and write the necessary files without compromising security. This article explains the standard layout, the exact permission commands, and common pitfalls to avoid.

Why the Default Laravel Structure Matters

Laravel’s default directory layout is designed with security and maintainability in mind. The public folder contains the front controller (index.php) and static assets (CSS, JS, images). Everything else—the application code, configuration, routes, database migrations, and the vendor directory—is kept one level above the web root. This means if someone tries to access https://yourdomain.com/.env or https://yourdomain.com/app/, the web server returns a 404 because those files are simply not reachable. The only directory that should be accessible via HTTP is public.

On a typical VPS, the web root (often /var/www/html or /var/www/yourdomain) is where you place the public folder’s contents, or you point the server’s document root directly to the public folder. The rest of the Laravel project can live in a sibling directory, such as /var/www/yourdomain-laravel.

Recommended Folder Structure for a VPS

A common, secure layout for a single domain on a VPS looks like this:

/var/www/
├── yourdomain.com/          (Laravel project root)
│   ├── app/
│   ├── bootstrap/
│   ├── config/
│   ├── database/
│   ├── public/               (web root - the only exposed folder)
│   ├── resources/
│   ├── routes/
│   ├── storage/
│   ├── tests/
│   ├── vendor/
│   ├── .env
│   └── artisan
└── (other sites)

In your Nginx or Apache configuration, set the document root to /var/www/yourdomain.com/public. This way, all Laravel files remain outside the web-accessible area, and only the front controller and assets are served.

Understanding Laravel’s Permission Requirements

Laravel needs write access to two directories at runtime:

  • storage/ – used for logs, compiled Blade templates, file-based sessions, cache files, and any file uploads.
  • bootstrap/cache/ – used for the framework’s compiled config and route caches.

The web server (e.g., www-data for Apache/Nginx on Ubuntu) must be able to write to these directories. However, you should not give the web server write access to the rest of the application files (like app/ or config/). This separation ensures that even if a vulnerability allows file upload, the attacker cannot modify your application code.

Setting Correct Permissions (Step-by-Step)

Here’s a safe, widely used approach for a Linux VPS (Ubuntu/Debian). The commands assume your user is deploy and the web server group is www-data.

  1. Set ownership – Give your user ownership of all files, and the web server group ownership of the group:
sudo chown -R deploy:www-data /var/www/yourdomain.com
  1. Set directory permissions – Directories should be 755 (read and execute for everyone, write only for the owner):
find /var/www/yourdomain.com -type d -exec chmod 755 {} \;
  1. Set file permissions – Files should be 644 (read for everyone, write only for the owner):
find /var/www/yourdomain.com -type f -exec chmod 644 {} \;
  1. Grant write access to storage and bootstrap/cache – These need to be writable by the web server:
chmod -R 775 /var/www/yourdomain.com/storage
chmod -R 775 /var/www/yourdomain.com/bootstrap/cache

If you use 775, the web server (group) can write, but only you (the owner) can change file permissions. Some prefer 775 over 777 because 777 allows any user on the system to modify files, which is a security risk.

Common Permission Mistakes and How to Fix Them

Mistake 1: Using 777 on the whole project. This is the most common error. It makes every file writable by anyone, which is dangerous. If you’ve already done this, run the commands above to tighten permissions.

Mistake 2: Forgetting to set the correct ownership. If you upload files as root and then the web server runs as www-data, you may get “Permission denied” errors. Always change ownership with chown.

Mistake 3: Ignoring SELinux (on CentOS/RHEL). If you’re on a distribution with SELinux enabled, even correct file permissions may not work. You need to set the correct SELinux context for the web root:

sudo chcon -R -t httpd_sys_content_t /var/www/yourdomain.com
sudo chcon -R -t httpd_sys_rw_content_t /var/www/yourdomain.com/storage
sudo chcon -R -t httpd_sys_rw_content_t /var/www/yourdomain.com/bootstrap/cache

This is a frequent cause of mysterious 500 errors on CentOS.

Deploying with Git and Composer

When you deploy via Git, the vendor directory and the .env file are usually not in the repository. After pulling the code, you need to:

  • Run composer install --no-dev to install production dependencies.
  • Create the .env file manually (or copy from a secure location) and run php artisan key:generate.
  • Run php artisan config:cache and php artisan route:cache to speed up the app. Note that these commands write to bootstrap/cache, so the web server needs write access at that moment.

After running these commands, it’s a good practice to set bootstrap/cache back to 755 to prevent the web server from modifying cached files, though it’s not strictly required if you trust your server’s security.

Frequently Asked Questions

Q: Should I set permissions to 777 for the storage folder?
No. Use 775 with the correct group ownership. 777 allows any user on the system to write, which is a security risk. If you have group ownership set correctly, 775 is sufficient.

Q: Why do I get a 500 error after deployment?
Often it’s because the web server cannot write to storage/logs or bootstrap/cache. Check the log file (storage/logs/laravel.log) for permission errors. Also ensure the .env file exists and has the correct APP_KEY.

Q: How do I set permissions if I use a shared hosting plan?
Shared hosting often uses suPHP or similar, where files are owned by your user. In that case, set directories to 755 and files to 644, and make storage and bootstrap/cache writable (775 or 755 depending on the host). You may need to contact support if you see permission errors.

Q: Is it safe to give the web server write access to the entire storage directory?
Yes, that’s the intended design. Laravel uses subdirectories like framework/views, framework/cache, and logs. Allowing the web server to write there is necessary for normal operation.

Q: What about the public directory permissions?
The public directory should be readable by the web server (typically 755 for directories and 644 for files). You do not need write access for the web server unless you’re uploading files directly to public (which is not recommended).

Q: Do I need to change permissions every time I deploy?
If you use the same user for deployment and the web server group is set correctly, you usually don’t. However, if you run composer install or php artisan commands as a different user, you may need to re-apply the ownership commands. It’s a good practice to include the permission commands in your deployment script.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.