359

This is a Canonical Question about File Permissions on a Linux web server.

I have a Linux web server running Apache2 that hosts several websites. Each website has its own folder in /var/www/.

/var/www/contoso.com/
/var/www/contoso.net/
/var/www/fabrikam.com/

The base directory /var/www/ is owned by root:root. Apache is running as www-data:www-data. The Fabrikam website is maintained by two developers, Alice and Bob. Both Contoso websites are maintained by one developer, Eve. All websites allow users to upload images. If a website is compromised, the impact should be as limited as possible.

I want to know the best way to set up permissions so that Apache can serve the content, the website is secure from attacks, and the developers can still make changes. One of the websites is structured like this:

/var/www/fabrikam.com
    /cache
    /modules
    /styles
    /uploads
    /index.php

How should the permissions be set on these directories and files? I read somewhere that you should never use 777 permissions on a website, but I don't understand what problems that could cause. During busy periods, the website automatically caches some pages and stores the results in the cache folder. All of the content submitted by website visitors is saved to the uploads folder.

Chris S
  • 77,337
  • 11
  • 120
  • 212
Nic
  • 13,025
  • 16
  • 59
  • 102
  • 7
    This is intended to be a [canonical](http://meta.serverfault.com/questions/1986/what-are-the-canonical-answers-weve-discovered-over-the-years) answer for all the questions we get about website permissions. – Nic Feb 06 '12 at 01:52
  • 1
    "I read somewhere that you should never use 777 permissions on a website, but I don't understand..." - then will the reader be able to understand or at least be able to compare the merits of answers here? Any solution should be based on specific requirements - the requirements here are not specific enough (what's the threat model) – symcbean Feb 06 '12 at 10:17
  • 8
    I love that you're asking about Apache, but are using the domains Microsoft typically uses as examples. – gWaldo Sep 09 '12 at 21:12
  • Also see [What's the best way of handling permissions for apache2's user www-data in /var/www?](http://serverfault.com/questions/6895/whats-the-best-way-of-handling-permissions-for-apache2s-user-www-data-in-var#comment614312_6895) – Gareth Oct 16 '13 at 12:13
  • You can refer here for complete details about the permission that are required to be put on website files and folders in linux http://serverfault.com/questions/124800/how-to-setup-linux-permissions-for-the-www-folder –  Jun 02 '15 at 05:08

6 Answers6

386

When deciding what permissions to use, you need to know exactly who your users are and what they need. A webserver interacts with two types of user.

Authenticated users have a user account on the server and can be provided with specific privileges. This usually includes system administrators, developers, and service accounts. They usually make changes to the system using SSH or SFTP.

Anonymous users are the visitors to your website. Although they don't have permissions to access files directly, they can request a web page and the web server acts on their behalf. You can limit the access of anonymous users by being careful about what permissions the web server process has. On many Linux distributions, Apache runs as the www-data user but it can be different. Use ps aux | grep httpd or ps aux | grep apache to see what user Apache is using on your system.


Notes on linux permissions

Linux and other POSIX-compliant systems use traditional unix permissions. There is an excellent article on Wikipedia about Filesystem permissions so I won't repeat everything here. But there are a few things you should be aware of.

The execute bit
Interpreted scripts (eg. Ruby, PHP) work just fine without the execute permission. Only binaries and shell scripts need the execute bit. In order to traverse (enter) a directory, you need to have execute permission on that directory. The webserver needs this permission to list a directory or serve any files inside of it.

Default new file permissions
When a file is created, it normally inherits the group id of whoever created it. But sometimes you want new files to inherit the group id of the folder where they are created, so you would enable the SGID bit on the parent folder.

Default permission values depend on your umask. The umask subtracts permissions from newly created files, so the common value of 022 results in files being created with 755. When collaborating with a group, it's useful to change your umask to 002 so that files you create can be modified by group members. And if you want to customize the permissions of uploaded files, you either need to change the umask for apache or run chmod after the file has been uploaded.


The problem with 777

When you chmod 777 your website, you have no security whatsoever. Any user on the system can change or delete any file in your website. But more seriously, remember that the web server acts on behalf of visitors to your website, and now the web server is able to change the same files that it's executing. If there are any programming vulnerabilities in your website, they can be exploited to deface your website, insert phishing attacks, or steal information from your server without you ever knowing.

Additionally, if your server runs on a well-known port (which it should to prevent non-root users from spawning listening services that are world-accessible), that means your server must be started by root (although any sane server will immediately drop to a less-privileged account once the port is bound). In other words, if you're running a webserver where the main executable is part of the version control (e.g. a CGI app), leaving its permissions (or, for that matter, the permissions of the containing directory, since the user could rename the executable) at 777 allows any user to run any executable as root.


Define the requirements

  • Developers need read/write access to files so they can update the website
  • Developers need read/write/execute on directories so they can browse around
  • Apache needs read access to files and interpreted scripts
  • Apache needs read/execute access to serveable directories
  • Apache needs read/write/execute access to directories for uploaded content

Maintained by a single user

If only one user is responsible for maintaining the site, set them as the user owner on the website directory and give the user full rwx permissions. Apache still needs access so that it can serve the files, so set www-data as the group owner and give the group r-x permissions.

In your case, Eve, whose username might be eve, is the only user who maintains contoso.com :

chown -R eve contoso.com/
chgrp -R www-data contoso.com/
chmod -R 750 contoso.com/
chmod g+s contoso.com/

ls -l
drwxr-s--- 2 eve      www-data   4096 Feb  5 22:52 contoso.com

If you have folders that need to be writable by Apache, you can just modify the permission values for the group owner so that www-data has write access.

chmod g+w uploads

ls -l
drwxrws--- 2 eve      www-data   4096 Feb  5 22:52 uploads

The benefit of this configuration is that it becomes harder (but not impossible*) for other users on the system to snoop around, since only the user and group owners can browse your website directory. This is useful if you have secret data in your configuration files. Be careful about your umask! If you create a new file here, the permission values will probably default to 755. You can run umask 027 so that new files default to 640 (rw- r-- ---).


Maintained by a group of users

If more than one user is responsible for maintaining the site, you will need to create a group to use for assigning permissions. It's good practice to create a separate group for each website, and name the group after that website.

groupadd dev-fabrikam
usermod -a -G dev-fabrikam alice
usermod -a -G dev-fabrikam bob

In the previous example, we used the group owner to give privileges to Apache, but now that is used for the developers group. Since the user owner isn't useful to us any more, setting it to root is a simple way to ensure that no privileges are leaked. Apache still needs access, so we give read access to the rest of the world.

chown -R root fabrikam.com
chgrp -R dev-fabrikam fabrikam.com
chmod -R 775 fabrikam.com
chmod g+s fabrikam.com

ls -l
drwxrwsr-x 2 root     dev-fabrikam   4096 Feb  5 22:52 fabrikam.com

If you have folders that need to be writable by Apache, you can make Apache either the user owner or the group owner. Either way, it will have all the access it needs. Personally, I prefer to make it the user owner so that the developers can still browse and modify the contents of upload folders.

chown -R www-data uploads

ls -l
drwxrwxr-x 2 www-data     dev-fabrikam   4096 Feb  5 22:52 uploads

Although this is a common approach, there is a downside. Since every other user on the system has the same privileges to your website as Apache does, it's easy for other users to browse your site and read files that may contain secret data, such as your configuration files.

You can have your cake and eat it too

This can be futher improved upon. It's perfectly legal for the owner to have less privileges than the group, so instead of wasting the user owner by assigning it to root, we can make Apache the user owner on the directories and files in your website. This is a reversal of the single maintainer scenario, but it works equally well.

chown -R www-data fabrikam.com
chgrp -R dev-fabrikam fabrikam.com
chmod -R 570 fabrikam.com
chmod g+s fabrikam.com

ls -l
dr-xrwx--- 2 www-data  dev-fabrikam   4096 Feb  5 22:52 fabrikam.com

If you have folders that need to be writable by Apache, you can just modify the permission values for the user owner so that www-data has write access.

chmod u+w uploads

ls -l
drwxrwx--- 2 www-data  dev-fabrikam   4096 Feb  5 22:52 fabrikam.com

One thing to be careful about with this solution is that the user owner of new files will match the creator instead of being set to www-data. So any new files you create won't be readable by Apache until you chown them.


*Apache privilege separation

I mentioned earlier that it's actually possible for other users to snoop around your website no matter what kind of privileges you're using. By default, all Apache processes run as the same www-data user, so any Apache process can read files from all other websites configured on the same server, and sometimes even make changes. Any user who can get Apache to run a script can gain the same access that Apache itself has.

To combat this problem, there are various approaches to privilege separation in Apache. However, each approach comes with various performance and security drawbacks. In my opinion, any site with higher security requirements should be run on a dedicated server instead of using VirtualHosts on a shared server.


Additional considerations

I didn't mention it before, but it's usually a bad practice to have developers editing the website directly. For larger sites, you're much better off having some kind of release system that updates the webserver from the contents of a version control system. The single maintainer approach is probably ideal, but instead of a person you have automated software.

If your website allows uploads that don't need to be served out, those uploads should be stored somewhere outside the web root. Otherwise, you might find that people are downloading files that were intended to be secret. For example, if you allow students to submit assignments, they should be saved into a directory that isn't served by Apache. This is also a good approach for configuration files that contain secrets.

For a website with more complex requirements, you may want to look into the use of Access Control Lists. These enable much more sophisticated control of privileges.

If your website has complex requirements, you may want to write a script that sets up all of the permissions. Test it thoroughly, then keep it safe. It could be worth its weight in gold if you ever find yourself needing to rebuild your website for some reason.

4wk_
  • 292
  • 2
  • 14
Nic
  • 13,025
  • 16
  • 59
  • 102
  • 14
    "chmod -R 775 fabrikam.com". Very few files inside most websites have to be executable; eg php script can be 0640 as long as the web server can read them. chmod -R a+X fabrikam.com would give executable rights to everyone only on directories. –  Aug 18 '12 at 20:47
  • 8
    Note well that Apache runs as user `apache` on Red Hat derived systems. – Michael Hampton Nov 18 '12 at 03:55
  • This is excellent, but there was one thing I didn't understand: I don't understand the goal or advantage of the strategy of making apache the user/owner of a directory of file if it already has group ownership over the file. – idiotprogrammer Apr 21 '13 at 19:41
  • 1
    This answer, whilst comprehensive, only deals with DAC permissions. I think MAC permissions should be considered as well. – dawud May 01 '13 at 23:00
  • One thing I feel you should call out explicitly for new users: does the user eve need to be in the www-data group for your single-developer approach? – Patrick M Jan 03 '14 at 17:35
  • @PatrickM - In the single-developer approach, I don't think `eve` needs to be a part of `www-data`, because `eve` is already the owner of all the files anyway. – Andrew Cheong Apr 29 '14 at 09:15
  • 1
    This is an excellent post. Here's my contribution: The downside of using www-data as owner and dev-fabrikam as group (mentioned in **You can have your cake and eat it too** also applies (in reverse) to the scenario offered in **Maintained by a single user**. In that scenario, whenever Apache creates a folder or file, the user won't have access to it so the files need to be chowned back to the original user. I haven't updated the answer as I'm not 100% sure about my statement. I'd rather have others confirm it before patching the answer. –  Jul 14 '13 at 00:43
  • 2
    @PatrickM - Actually, I disagree with my comment from last month. `eve` doesn't have to be in `www-data` _to edit files_, however `eve` _does_ need to be in `www-data` if you'd like `eve` to be able to edit files _created by Apache_, _e.g._ uploads. – Andrew Cheong May 20 '14 at 18:14
  • Why do you add sticky bit for group? – Atiq Rahman Apr 04 '15 at 04:38
  • Thank you for this! Question: Why are you setting the `setuid` flag (`chmod g+s contoso.com`, etc.)? – T.J. Crowder Jun 09 '16 at 16:01
  • At the **you can have your cake and eat it too** you mentioned using www-data as an owner. now if an attacker somehow uses some vulnerability, he can run any command. for example he can changes all directories permission to 777 because apache is the owner and it is able to do this. Am I wrong? – Ravexina Jul 11 '16 at 17:21
  • @user181503 You are entirely correct. I usually create a script to reset them every night. – ZaxLofful Oct 03 '16 at 18:25
  • Regarding single user setup. I am the only user on the server and I belong to the sudo group. Do I need to create a seperate user that is not part of the sudo group to manage www/contoso.com? As in the example is it ok for eve to be in the sudo group? – dan Nov 21 '16 at 20:37
  • For nginx applications that are symlinked and installed as root, such as phpMyAdmin. Do I need to change the phpMyAdmin folder to match the above "maintained by single user" solution, or just leave the owner and permissions as set by the default install , ie root:rooot? – dan Nov 21 '16 at 20:50
  • newbie alert! When you write `chown -R eve contoso.com` , it's contoso.com a directory or a group of users. If it's a directory it wouldn't be more clear and pedagogical `contoso.com/` ? – João Pimentel Ferreira Jul 16 '17 at 10:40
  • What's the benefit of `chmod g+s contoso.com/`?? – kittygirl Nov 11 '18 at 13:00
  • @kittygirl The sticky bit (+s) for directories makes the group is inherited to newly created files. So any file added to a folder will the sticky bit set, will belong to the group `www-data` and will inherit the sticky bit too, no matter who created the new file. – Peregring-lk Mar 23 '19 at 19:58
  • @Nic you mention in your **can have your cake and eat it too** that newly created files won't be readable by `www-data`. That's not true, since other users will have read access unless you have changed the umask (which almost nobody will do). – Peregring-lk Mar 23 '19 at 20:00
  • What’s the benefit of giving Apache read access to directories? As far as I can tell, that just enables HTTP users to browse your website folders if there is no default page (index.htm, etc.) in the folder. Apache needs execute, but not read, to traverse folders, so why use 750 and 570 instead of 710 and 170, respectively? Will that break anything? – Janus Bahs Jacquet Jan 14 '20 at 21:43
  • So how does ActiveDirectory come into play here? Im trying all these commands you've laid out but no luck on being able to access them and also edit through a dev user. All I know is that my user comes from ActiveDirectory. – Kevin Hernandez May 04 '22 at 17:40
19

I'm wondering why so many people use (or recommend) the "other" (o) part of the Linux rights to control what can do Apache (and/or PHP). By setting this right part to something else than "0", you just allow the whole world to do something on the file/directory.

My approach is following:

  • I create two separated users. One for the SSH/SFTP access (if needed), which will own all the files, and one for the PHP FastCGI user (the user the website will run as). Let's call these users respectively bob and bob-www.
  • bob will have full rights (rwx on folders, rw- on files), so that he/she can read and edit the whole website.
  • The PHP FastCGI process needs r-x rights on folders and r-- rights on files, except for very specific folders like cache/ or uploads/, where the "write" permission is also needed. To give PHP FastCGI this ability, it will run as bob-www, and bob-www will be added to the automatically created bob group.
  • We now make sure the owner and group of all directories and files are bob bob.
  • Something is missing : even we use FastCGI, but Apache still needs read access, for static content, or .htaccess files that it will try to read if AllowOverride is set to something else than None. To avoid using the o part of the rights, I add the www-data user to the bob group.

Now:

  • To control what the developer can do, we can play with the u part of the rights (but this the note below).
  • To control what Apache and PHP can do, we can play with the g part of the rights.
  • The o part is always set to 0, so nobody else on the server can read or edit the website.
  • There is no problem when bob user creates new files, since it will automatically belong to its main group (bob).

This is a recap, but in this situation, bob is allowed to SSH. If there shouldn't be any user allowed to modify the website (eg. customer only modifies the website through a CMS admin panel and doesn't have Linux knowledge), create two users anyway, but give /bin/false as shell for bob as well, and disable its login.

    adduser --home /var/www/bobwebsite --shell /bin/bash bob
    adduser --no-create-home --shell /bin/false --disabled-login --ingroup bob bob-www
    adduser www-data bob
    cd /var/www/bobwebsite
    chown -R bob:bob .
    find -type d -exec chmod 750 {} \;
    find -type f -exec chmod 640 {} \;

Note : people tend to forget that limiting the u (owner) rights is most of the time useless and insecure, since the owner of a file can run the chmod command, even the rights are 000.

Tell me if my approach has some security issues, because I'm not 100% sure, but it is what I'm using.

I think this config has a problem : when PHP/Apache creates a new file (eg. upload), it will belong to bob-www:bob, and bob will only be able to read it. Maybe setuid on the directory can solve the problem.

Fox
  • 952
  • 2
  • 12
  • 21
  • Linux ignores `setuid`. New files are always owned by the creator. – Paul Aug 20 '13 at 02:35
  • I don't understand something. This doesn't seem to incorporate the situation when more developers work simultaniously on the website, since the only user is `bob`. How do you deal with that? Eg. through ssh, both users log in as bob. bob (1) feels he/she cannot remember the password and changes it to another but still secure. bob (2) tries to log in next time, and he/she can't. – n611x007 Oct 23 '13 at 07:50
  • 2
    @naxa Any marginally good system should never have any of the developers directly modifying the website. Ideally, the website is under version control such that the user account 'bob' pulls and deploys each (stable) release automatically. So, the developers do the development offsite, and changes get deployed once they're pushed to the deployment server. 'bob' is a system user who should have very limited network permissions, which don't include remote login; iptables actually allows you to filter by UID for stuff like this. – Parthian Shot Jul 15 '14 at 03:16
  • "I'm wondering why so many people use (or recommend) the "other" (o) part" - then maybe you should have posted this as a question rather than answer. It's not uncommon to deliberately run the webserver (as the most exposed part of the system) with the lowest level of privilege while support, development, admin accounts also need different access – symcbean Jan 24 '18 at 23:59
  • @ParthianShot you cannot force that to third parties (when the site is not maintained by you, but the folder exists in your server). Sometimes the only thing they know what to do is by using ftp. – Peregring-lk Mar 23 '19 at 20:03
9

Given the google rank on the above excellent answer, I think there is one thing that should be noted, and I can't seem to leave a note after the answer.

Continuing with the example, if you plan on using www-data as owner and dev-fabrikam as group with 570 permissions on the directory (or file), it is important to note that Linux ignores setuid, so all new files will be owned by the user that created them. This means that after creating new directories and files you will have to use something similar to:

chown -R www-data /newdirectory/
chmod -R 570 /newdirectory/

In Ubuntu 12.04 for Rackspace OpenStack, I had an odd issue where I could not get permissions 570 to work until I rebooted the server, which magically fixed the issue. Was losing hairs at an increasing rate over that seemingly simple issue....

Paul
  • 2,755
  • 6
  • 24
  • 35
  • Please let this be googled: In Raspbian (aka on a raspberry pi, if you want to change the ownership of /var/www under lighttpd (or another web browser), you MUST reboot. – gbronner Jan 09 '15 at 23:30
  • @gbronner If that is a difficult issue to find the resolution for, you might consider posting it as a question and providing an answer to the question. However, it is probably more appropriate in a different SE Q&A site. My guess is [Unix & Linux](http://unix.stackexchange.com/) might be a good place to do that. – Paul Jan 09 '15 at 23:44
  • 1
    There's also raspberrypi.stackexchange.com; it seems that the SE sites are fragmenting the knowledge a bit. – gbronner Jan 10 '15 at 00:05
  • @gbronner lol. I didn't know about that one! The Raspbian tag on U&L has something like 120 questions. – Paul Jan 10 '15 at 00:06
3

I going with this configuration:

  1. All directories except uploads one set to owner root and group root, permissions to 0755.
  2. All files set to owner root and group root, permissions to 0644.
  3. Uploads directory set to owner root, group www-data, permissions to 1770. The sticky bit doesn't let group owner to remove or rename the directory and files inside.
  4. Inside uploads folder a new directory with www-data owner user and group, and 0700 permissions for each www-data user that upload files.
  5. Apache configuration:

Deny AllowOverride and Index in uploads directory, so that Apache doesn't read .htaccess files, and Apache user can't index the content of uploads folder:

<Directory /siteDir>
   Options -Indexes
</Directory>

<Directory /siteDir/uploadDir>
   AllowOverride none
</Directory>

6. php.ini configuration:

open_basedir = /siteDir:/tmp:/usr/share/phpmyadmin
post_max_size = 5M
file_uploads = On
upload_max_filesize = 3M
max_file_uploads = 20

With this configuration, the www-data user won't be able to get inside directories other than siteDir/ /tmp and /usr/share/phpmyadmin. Also you can control the maximum file size, the maximum post size and the maximum files to upload in the same request.

Manolo
  • 512
  • 2
  • 8
  • 22
3

When you have a FTP user called "leo" need to upload files to example.com web directory and you also require your "apache" user to be able to create uploa-files/sessions/cache files in cache directory then do as follows:

This command assigns leo as owner and group as apache to example.com, apache user is a part of group apache so it will inherit the permissions of apache group

chown -R leo:apache example.com

Another command which insures right permission and fulfill security concerns as well.

chmod -R 2774 example.com

Here first number 2 is for directory and insures each new file created will be remain in same group and owner permissions. 77 is for owner and group means they have full access. 4 is for others mean they can only read trough.

following is helpful to understand permission numbers

Number  Octal Permission Representation
0   No permission
1   Execute permission
2   Write permission
3   Execute and write permission: 1 (execute) + 2 (write) = 3
4   Read permission
5   Read and execute permission: 4 (read) + 1 (execute) = 5
6   Read and write permission: 4 (read) + 2 (write) = 6
7   All permissions: 4 (read) + 2 (write) + 1 (execute) = 7
1

IMO one has to take into account:

  • do you trust a process which reads your files? eg. PHP?

Let's assume you have a server which various data under user 'test'.

The 'test' user has there:

  • his data in $HOMEDIR
  • his mail in $MAIL
  • his data for web in /var/www/test

Now let's think about:

  • a web app runs under test user (PHP-FPM) - it can delete any of his files!
  • a web app runs under test group (PHP-FPM) - it can delete any of his files where directory has 'w' for the group and can modify any file which has 'r' for the group; and it could still read them - your ssh keys for example!

Let's assume PHP is buggy, and it is, do you trust its open_basedir? Do you chroot your PHP process? What is you don't, do you want it does crawls through all filesystem?

Your web app process, eg. PHP-FPM, then should:

  • be restricted to specific path via chroot
  • should not run under data owner's primary user or primary group permission

Thus you can do:

  • test user is: test:test
  • test user is in a secondary group eg. test-www
  • a web app (PHP-FPM) runs under test-www:test-www
  • test user if he wants that the web app can read his files will do: chmod u=rwX,g=rX,o= /var/www/test/public
  • test user if he wants that the web app can write into his web data path: chmod u=rwX,g=rwXs,o= /var/www/test/public/upload (thus the app will create new files as: test-www:test-www - it will have test-www group because of setgid on the directory!)

Thus, if the web app process would be bogus it would just read specific files which would have group read, and it would be able to write to upload dir only. I would strongly recommend to have that upload dir on a filesystem with noexec,nodev,nosuid mount options and have constant monitoring for any new bizzare files in that directory, plus also monitor any new processes under test-www uid.

On Linux one could use ACL to better tune permissions. If more than one human should be to upload web data, it would be better to split human account from the account used to upload web data files, ie. to create new account eg. test-upload, and test user would manage ssh keys to restrict which human could ssh/sftp there. sshd_config knows ExposeAuthInfo options thus it can be configured to log which ssh key was used to upload the data.

I really doubt most webhosting services care about privileges separation, when they write 'secure' without any info what you get, I would say they lie.

Jiri B
  • 497
  • 2
  • 11
  • php-fpm allow `chroot` and `user`, `group` to be set for a pool. but I would not trust `php_admin_value[open_basedir]` option. I also read it's better to have a separate PHP-FPM master per user, see https://ma.ttias.be/a-better-way-to-run-php-fpm/ To instantiate a daemon is easy on most Linux and *BSD distros. – Jiri B Feb 17 '19 at 17:40