Question

Laravel File Permissions with Apache: Secure Ownership and chmod

phpapachelaravellaravel-5file-permissions

Question

I am running a Laravel 5 application on Apache, where the web-server account is _www:_www. Laravel requires its writable directories to be writable by the web server. I have often used chmod -R 777 to make the application work, but I understand that this is insecure.

The documentation states that directories within storage and vendor require write access by the web server. Does the web server need write access only to existing files inside those directories, or also to the directories themselves?

Changing the ownership of the entire Laravel project to _www:_www makes the site work, but then my normal user account cannot save files from my editor or Finder without entering an administrator password.

What is the correct and secure approach? Should I change permissions, change ownership, run Apache as my operating-system user, or use another method?

Short Answer

You will learn how Unix ownership, groups, and permission bits affect a Laravel application running under Apache. You will also learn why 777 and making the entire project web-server-owned are poor defaults, and how to grant write access only to Laravel directories that genuinely need it.

Concept

Unix-like systems decide whether a process can read, modify, or enter a path by checking:

  • the file or directory owner
  • the file or directory group
  • permissions for the owner, group, and everyone else
  • the account running the process, such as Apache's _www account

A Laravel developer normally needs to edit source files as their own login user. Apache normally needs to read the application and write only to runtime-generated data, such as logs, sessions, cached files, and uploaded files.

Those are different responsibilities. The secure goal is therefore not to make every Laravel file writable by Apache. Instead:

  1. Keep application code owned by the deployment or developer user.
  2. Let Apache read the code it must execute or serve.
  3. Grant Apache group-based or ACL-based write access only to the runtime directories.

For modern Laravel releases, the usual runtime-writable locations are storage and bootstrap/cache. The vendor directory contains Composer-installed dependencies and should normally be readable by Apache but not writable at runtime. Composer may need to write vendor during installation or updates, but that operation should run as the deployment user, not as the web server.

A directory's permissions are especially important. To create, rename, or delete entries in a directory, a process needs write and execute permission on that directory. Write permission on an existing file alone is not enough to create a new log file or cache file.

Mental Model

Think of the project as an office building:

  • Your developer account is the building manager who can change plans and furniture.
  • Apache is a worker who needs to enter the building and use only a few designated work rooms.
  • storage and bootstrap/cache are the work rooms where the worker creates notes, temporary files, and logs.
  • Source files, .env, and vendor are the manager's records and should not be open for the worker to alter.

Using chmod -R 777 is like giving every person in the building a master key to every room. Changing the owner of every file to _www makes Apache the building manager, which prevents you from comfortably editing your own project. A shared group or ACL gives both the manager and worker the specific access they need.

Take Quiz

Syntax and Examples

Permission bits are commonly shown in three groups:

owner  group  others
 rwx    rwx    rwx
  • r means read.
  • w means write.
  • x means execute a file or traverse/search a directory.

For example:

chmod 775 storage

775 means:

  • owner: rwx
  • group: rwx
  • others: r-x

For a Laravel project, use a shared group rather than giving ownership of all files to Apache. Replace youruser with your login name and use the actual Apache group for your system. On the system in the question, that group may be _www.

# Keep the project owned by the developer/deployment account.
sudo chown -R youruser:_www /path/to/project

# Apache needs to read and traverse ordinary project directories.
find /path/to/project -type d -exec chmod 755 {} \;
find /path/to/project -type f -exec chmod 644 {} \;

# Allow the shared group to write only Laravel runtime directories.
chmod -R g+rwX /path/to/project/storage /path/to/project/bootstrap/cache

# Keep the shared group on newly created nested directories.
find /path/to/project/storage /path/to/project/bootstrap/cache -type d -exec chmod g+s {} \;

The uppercase X in g+rwX adds execute permission to directories and to files that are already executable. It does not make every ordinary file executable.

The exact ownership and mode policy depends on your deployment model. The important rule is scope: apply group-write permission to runtime directories, not recursively to all application code.

Step by Step Execution

Consider this layout:

project/
├── app/                  drwxr-xr-x  developer:_www
├── vendor/               drwxr-xr-x  developer:_www
├── storage/              drwxrwsr-x  developer:_www
│   └── logs/             drwxrwsr-x  developer:_www
└── bootstrap/cache/      drwxrwsr-x  developer:_www

Suppose Apache runs as user _www and belongs to group _www.

  1. Apache receives a request and traverses project/, app/, and vendor/.

    • The x bit for others lets it traverse these directories.
    • The r bit lets it read files that are world-readable, such as typical PHP source files.
  2. Laravel tries to append to storage/logs/laravel.log.

    • _www matches the directory's group _www.
    • Group rwx permits Apache to enter storage/logs and create or modify its entries.
  3. Laravel creates a new cache file in bootstrap/cache.

    • Group write and execute permissions permit creating that entry.
  4. A new directory created under storage inherits group _www because storage has the set-group-ID bit (g+s).

    • Its displayed mode includes s, such as drwxrwsr-x.
    • This prevents newly created directories from unexpectedly becoming inaccessible to the other collaborator.
  5. Your editor runs as youruser, the owner of the project.

    • It can save application code without sudo or password prompts.

The process umask can still affect permissions of newly created files. If Apache creates files too restrictively, configure an appropriate process umask or use default ACLs for the writable directories.

Real World Use Cases

  • Logging: Laravel writes application errors and diagnostic messages under storage/logs.
  • Sessions and cache: File-based session and cache drivers create runtime files under storage/framework.
  • Compiled views: Blade templates can be compiled into files in storage/framework/views.
  • Framework cache: Laravel may write route, configuration, event, or package cache files in bootstrap/cache.
  • File uploads: If uploads are stored locally, a Laravel disk may write under storage/app or a configured writable location.
  • Deployments: A CI/CD account can install Composer dependencies and publish a release, while Apache only reads the release and writes runtime state.
Take Quiz

Real Codebase Usage

In a production codebase, permissions are usually managed by deployment tooling rather than fixed manually after every change.

Common patterns include:

  • Deploy as a dedicated user: A deploy account owns each release and runs composer install. Apache has read access to the release.
  • Writable directories outside immutable releases: Applications often keep storage data in a shared location that is linked into each new release. This preserves logs and uploads while code releases remain read-only.
  • Shared Unix group: The deploy user and web-server user belong to a group that has write permission on selected runtime paths.
  • Default ACLs: Where multiple users or processes must consistently write files, ACLs can define inherited permissions more precisely than basic mode bits.
  • Least privilege: .env, deployment keys, source code, and dependencies are not made Apache-writable merely to solve a cache or log problem.
  • Correct web root: Apache should normally use Laravel's public directory as DocumentRoot, not the project root. This is separate from permissions but prevents exposing .env, vendor, and application files over HTTP.

A deployment script may clear and rebuild caches while running as the deploy user:

php artisan optimize:clear
php artisan config:cache
php artisan route:cache

If these commands write bootstrap/cache, the deploy user also needs access there. A shared group lets both the deploy user and Apache use that directory when necessary.

Common Mistakes

Using chmod -R 777

chmod -R 777 /path/to/project

This allows every local account to write every project file. It also makes source code, dependencies, and configuration writable by the web-server process. If an application vulnerability is exploited, broad write access can make the impact worse.

Avoid it: grant group write access only to storage and bootstrap/cache.

Making the entire project owned by Apache

sudo chown -R _www:_www /path/to/project

This lets Apache write code and makes normal editing inconvenient because your login user is no longer the owner.

Avoid it: keep the developer or deploy user as owner; use Apache's group only where shared access is needed.

Giving file write permission but not directory write permission

chmod 664 storage/logs/laravel.log
chmod 755 storage/logs

Apache may be able to modify the existing log file if it has the correct group, but it cannot create a new log file, rotate one, or create another file in storage/logs because the directory lacks group write permission.

Avoid it: writable directories need group w and x, commonly 775 or 2775.

Making every file executable

chmod -R 775 /path/to/project

This sets execute permission on regular files, including PHP files, JSON files, and images. It is usually unnecessary.

Avoid it: use find to handle directories and files separately, or use g+rwX.

Assuming vendor must be web-server-writable

At runtime, Laravel normally reads code from vendor; it does not need Apache to modify it. Composer writes there during install/update operations.

Avoid it: run Composer as the deploy user and keep vendor read-only to Apache unless a specific, verified workflow requires otherwise.

Forgetting new-file permissions

A directory can initially be correct, but files created later may not be group-writable because of the creating process's umask.

Avoid it: use setgid directories and, when needed, default ACLs or an appropriate service umask.

Comparisons

ApproachWhat it doesSuitable useMain concern
chmod 777Everyone can read, write, and traverseAlmost never; temporary local diagnosis onlyExcessive access
Web server owns all filesApache can modify all project filesRarely appropriateDeveloper cannot edit normally; code becomes writable
Developer owns project; Apache has read accessApache reads application codeGood baselineDoes not alone allow logs/cache writes
Shared group on selected pathsDeveloper and Apache can write runtime directoriesCommon practical solutionMust manage inherited group and umask
POSIX ACLs on selected pathsGrants named users/groups precise accessUseful for complex multi-user setupsLess portable and more complex
PermissionOn a regular fileOn a directory
rRead file contentsList directory entries
wModify file contentsCreate, remove, or rename entries when combined with x
xRun as a program/scriptTraverse or access entries inside

Basic mode bits are simple and widely supported. ACLs are useful when one owner and one group are not enough, but they should still follow least privilege.

Take Quiz

Cheat Sheet

# Inspect owner, group, and modes
ls -ld storage bootstrap/cache
ls -l storage/logs

# Replace these values for your environment
PROJECT=/path/to/project
OWNER=youruser
WEBGROUP=_www

# Developer/deployer owns the project; Apache is the shared group
sudo chown -R "$OWNER:$WEBGROUP" "$PROJECT"

# Typical read-only application code baseline
find "$PROJECT" -type d -exec chmod 755 {} \;
find "$PROJECT" -type f -exec chmod 644 {} \;

# Laravel runtime paths: shared-group write access
chmod -R g+rwX "$PROJECT/storage" "$PROJECT/bootstrap/cache"

# New nested directories inherit the group
find "$PROJECT/storage" "$PROJECT/bootstrap/cache" -type d -exec chmod g+s {} \;
  • Prefer owner = developer/deploy user.
  • Prefer group = Apache group only where collaboration is needed.
  • Runtime directories generally need group rwx: 775 or 2775 is common.
  • Normal code directories commonly use 755; normal files commonly use 644.
  • 2775 means group-write plus the setgid inheritance bit on a directory.
  • Apache needs directory x to traverse a path.
  • Apache needs directory w plus x to create/delete/rename entries.
  • Do not make .env, source code, or vendor broadly writable.
  • Confirm the actual Apache user and groups with your operating-system and Apache configuration; names differ across platforms.

FAQ

Should Laravel's vendor directory be writable by Apache?

Usually no. Apache needs to read PHP dependencies in vendor at runtime. Composer needs write access when installing or updating dependencies, and Composer should normally run as the deployment user.

Which Laravel directories should be writable?

For current Laravel applications, storage and bootstrap/cache are the usual writable locations. Check your Laravel version and configured cache, session, log, and filesystem drivers because custom configuration can add another writable path.

Does Apache need write access to a directory or only its files?

It needs write and execute permission on the directory to create, delete, rename, or replace entries. It needs write permission on an existing file to modify that file's contents.

Why does my editor ask for a password after chown -R _www?

Your account no longer owns the files and may lack write permission. Keep your user or deploy account as owner instead of making Apache the owner of the entire project.

Is chmod 775 storage enough?

It can be enough if Apache belongs to the directory's group, the relevant nested directories also permit group writes, and newly created files do not lose required group access. Setgid directories or default ACLs help preserve access for new content.

Should I run Apache as my personal login user?

This is generally not a good production default. A compromised web application would gain the same access as your personal account. Use a dedicated low-privilege web-server account and grant narrowly scoped access.

Why should Apache's document root be public?

Laravel's public directory contains assets and the front controller intended for HTTP access. Pointing Apache at the project root can expose sensitive files such as .env or application source if configuration is wrong.

Can I use ACLs instead of changing groups?

Yes. ACLs are useful when several accounts need different access rules. They can also define default permissions for files created later, but the commands and availability vary by operating system.

Take Quiz

Mini Project

Description

Configure a local Laravel project so that you can edit application code as your normal user while Apache can write logs and cache files. This demonstrates least-privilege permissions instead of using 777 or giving Apache ownership of the whole project.

Goal

Create a shared-group permission setup in which Apache can write Laravel runtime directories but cannot modify the entire application.

Requirements

Use your normal login account as the owner of the Laravel project.

Take Quiz

Keep learning

Related questions

View more