I am giving my first steps to install a VPS web server (Debian 8 + Apache 2 + PHP 5.6) and need some help with files/folders permissions, please.

I already found some similar topics about this subject (not exactly the same), and all from 4 or 5 years old. Some of them point to solutions using deprecated PHP methods. Maybe today there are some new methods or solutions.

Well, there is Apache 2 that runs in www-data user/group. So I created a user called webadmin, put it in the www-data group and configured it as the owner of the main web site folder:

adduser webadmin
usermod -a -G www-data webadmin
chown -R webadmin:www-data /var/www/website.com

I also changed the permissions of the public_html folder like this:

find /var/www/website.com/public_html -type f -exec chmod 644 {} +
find /var/www/website.com/public_html -type d -exec chmod 755 {} +
find /var/www/website.com/public_html -type d -exec chmod g+s {} +

And created the folder that will receive the uploaded files (only static files - images):

mkdir /var/www/website.com/public_html/uploads
chown webadmin:www-data /var/www/website.com/public_html/uploads
chmod 774 /var/www/website.com/public_html/uploads

Now, what is happening: all the folders and PHP/Html files that I upload using SFTP (logged as webadmin) of course get webadmin as owner. When I use PHP to create subfolders and upload the images, they get the www-data user as owner. In this scenario I am having some permission issues, like to delete files throught SFTP.

I could assign Apache to run as webadmin user and www-data group, but I think I can have security issues (don't I?). Please, is there a standard and best pratice to configure the server or the PHP script that will created the folders and upload the files to avoid this issue?

  • On a multi-user system one often uses the suphp Apache module (and its shell counterpart) or something similar, to call the PHP script as the user who owns the files. Then the PHP code can read and write files. Apache still runs as apache, a separate user. This also works for a single-user setup.
    – Ned64
    Sep 23, 2017 at 22:23
  • The webserver I use at work is a read-only file system - I recently had to set up a file upload script so I'm storing them as binary blobs in a mysql database table.
    – ivanivan
    Sep 24, 2017 at 1:02
  • "on a muliti-user system one often uses suphp" - no, this is a very innefficent configuration, also not relevant to the problem here.
    – symcbean
    Sep 24, 2017 at 10:48

2 Answers 2


Your problem is that new files are not group writable. Instead of using setgid on directory to set the group, use ACLs which offer more flexibility.

The default ACL entry is inherited for new files and directories, granting permissions defined in the ACL. To set a default ACL entry for group webadmin to allow rwx:

setfacl -m default:g:webadmin:rwx /var/www/website.com/public_html/uploads

New files created in the directory will be readable and writable for group webadmin.

If ACL is not an option, you need to change the umask, which is determines the default UNIX permissions for new files. Sensible choices for new umask are 002 (world-writable bit masked) and 007 (all world permission bits masked, i.e. only group and owner have access).

To set Apache umask, copy systemd unit file to /etc:

cp /lib/systemd/system/apache2.service /etc/systemd/system/

Configure umask in /etc/systemd/system/apache2.service by appending UMask=<umask> to [Service] section. Note that this affects all files created by Apache.

Changing umask for sftp is only required if you need to change uploaded files/directories from PHP/Apache. The default umask 022 creates files group and world readable, but not group writable. Easiest way to configure default umask for sftp is with pam_umask.

To apply your custom umask only for users in a specific group and only when using sftp, append /etc/pam.d/sshd with:

session [default=1 success=ignore] pam_succeed_if.so user notingroup <yourgroup>
session optional                   pam_umask.so umask=<umask>

The first rule tells pam to skip the next rule if the user is not in group <yourgroup>, i.e. only apply the next rule if the user is in group <yourgroup>. The second rule sets the umask to <umask>.

Addendum: Note that existing files moved with mv retain their original permissions and ownership. You can apply default permissions from umask and directory setgid/ACLs by copying files with cp -d instead.

  • Advising a change of umask in the pam config file is a bit silly - its only the permissions/ownership of http uploaded content which is under discussion here. Assuming that the pam_umask setting is successful (I'm not familiar with debian but a lot of other systems change the umask later in the login cycle) this could result in files being created with more liberal permissions than they should be. It doesn't simplify the deployment process unless the deploying users default group is www-data, and you've just made all the files uploaded by sftp/this user writable by the webserver.
    – symcbean
    Sep 24, 2017 at 23:38
  • Good note about the symmetric permissions not being required, I expanded the answer with that detail. With sftp, there are no "later in the login cycle phase after pam, open ssh executes sftp-server.
    – sebasth
    Sep 25, 2017 at 8:17
  • Sebasth, thank you for answering and sorry about my delay! I heard about ACLs before but never used it. I will try to understand how it works. Please, why ACLs would not be an option?
    – Guybrush
    Sep 25, 2017 at 13:57
  • ACL might not be an option if you use some unusual/old file system, which does not support them on Linux (they are supported on common file systems, such as ext4, btrfs and xfs).
    – sebasth
    Sep 25, 2017 at 17:31
  • @sebasth, thanks, I checked and setfacl is a valid command in my Debian 8. So I removed the setgid using "find /var/www/website.com/public_html -type d -exec chmod g-s {} +", and set ACL as your tip. But now PHP is not working in any folder. Folders still have 755 permissions and files 644 permissions, all owned by webmin:www-data. Both webadmin and www-data users are members of www-data group. Please, do you know what is wrong?
    – Guybrush
    Sep 25, 2017 at 18:24

The good thing about standards is there's usually plenty to choose from.

Kudos for thinking about permissions and preventing your webserver uid from being able to write files other than uploaded content. I do hope you have completely disabled php execution in the upload directory. At the moment your model is somewhat flawed in that you are adding apache to a group with extra privilege. But that is only part of the problem - but I digress from the question you asked.

That you created a user implies you have root privileges on the box (you should have explicitly mentioned this). But you didn't say if you are using your own software or an off the shelf package. The latter creates some complications as customizing it may compromise the regular patching you should be undertaking. If apache is the only uid you intend to have highly controlled rights on the target, then you could solve the problem by provisioning apache's file access as the "other" rather than user or group.

Alternatively, in order to provision access to the upload content to other accounts, simply use a umask of 000/chmod the files to 666. Note that move_uploaded_file() actually creates a copy and deletes the original and critcally, the file creation respects the umask. Hence any properly written php can store http uploaded content as world readable and writable, without any code changes by setting an umask of 000 for the webserver.

Alternatively you could write a shell script to change the permissions of http uploaded content to something which allows you to manipulate the content with a normal user account, then give your webserver uid the right to invoke that script via sudo. This would need to be called by your code after move_uploaded_file().

Alternatively, a rather ugly solution would be to put an inotify watch on the upload directory linked to a script for fixing the permissions (e.g. using incron)

As a last resort you could run a regular cron job on the upload directory to fix the permissions.

I recommend using the umask approach.

  • thank you for answering! I did not change Apache group, I only added the new user to the same www-data group as Apache. About application, I am using my own "software" (PHP) and also taking care about security. I will try your umask tip and let you know. Thank you again!
    – Guybrush
    Sep 24, 2017 at 0:09
  • chmod 666 (rw-rw-rw-) makes files world writable and with umask 000 (no permission bits masked) new files and directories will be world writable.
    – sebasth
    Sep 24, 2017 at 11:22
  • Yes, that sebasth, that is exactly the point. Or do you have a better suggestion to make the file uploads accessible to user management and to the webserver uid? Who are the others you are trying to block access by?
    – symcbean
    Sep 24, 2017 at 23:28
  • "Who are the others you are trying to block access by" processes not running with www-data or webadmin group. If you think chmod 666 is a good idea, then there is really no need to assign any groups is there?
    – sebasth
    Sep 25, 2017 at 8:13
  • If the webserver is granted access to deployed content owned by the developer via the "other" permissions and the developer gains access to HTTP uploaded content owned by the webserver via the "other" then, no, there's no need for additional groups. OTOH if there are multiple people in the developer role, then yes, groups are required. The point of "other" is that the principle of least privilege is applied.
    – symcbean
    Sep 25, 2017 at 19:33

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .