Solving the web file permissions problem once and for all

If like us you develop Web applications and deploy them on Linux servers (development or production environments), you might have wondered how to handle file permissions on the application files in a simple and fool-proof way.

Some facts

Developers operating on the server require specific file permissions on the application files to be able to read and write them (for obvious reasons).

The web server (Apache, nginx, Lighttpd, etc.) also requires specific file permissions on the application files to be able to read them, and for some files (but not all files), to be able to write them (like for instance, when uploading a file, or creating a thumbnail, etc.)

The problem

Both the web server and the developpers require file permissions on the same files to operate properly, but they might need different permissions on the same files.

Developers require the ability to read and write every file, while the web server might require only write permissions only on some files.

This constrained shared-resource problem can quickly become a nightmare for the person in charge of the server.

The user~group (flawed) solution

One common solution is to give developers the same user group as the web server (something like www-data), and then to juggle on with ownership on files

While this works in some ways, it's flawed in others:

  • concurrency problem: when a developer creates a file, the file is owned by the developer, and might not be readable (nor writable if needed) properly by the web server process (granted, one could use some ACL system on the FS, but who ever got this to work properly ?)

  • impermeability problem: if you have several web applications running side-by-side on your web server, you'll have to juggle a lot more with groups and sub-groups just to prevent Developer A to be able to see and modify Application B.

  • stability problem over time, and accordingly with the principle of increase of entropy, file permissions will become a mess and perms related bugs will occur.

Our (awesome) solution

Wouldn't it be great if a developer could read and write files of an application with its own unshared user / group, while allowing the web server to have it's own and developer-unscrewable permissions on the files of the said application ?

Well yes, it would, and that's exactly what bindfs is meant for.

With bindfs, developers access applications via dedicated filesystem mountpoints (placed in their home dir), acting as file-permission filters, presenting files like they're owned by themselves, whereas the files are really owned by the web server user (like www-data).

Advantages:

  • it solves the concurrency problem, as every user in the equation (every developers and the web server) sees the permissions that he requires to operate properly and safely;

  • it solves the impermeability problem, as if you need one developer to access a particular application, you have to add a mountpoint in its home directory, but on the contrary, if the you need one developer to not access a particular application, you just have to not add such a mountpoint in it's home directory.

  • it solves the stability problem, as developers will never be able to change the file permissions set on the application files, as required by the web server to operate properly and safely.

  • best of all, it's simple to understand and to setup !

How to use this

For Ubuntu / Debian systems

In the next example, we assume that the developer user is devone, the web server user is www-data and the application is stored at /var/www/application1.

# Installing bindfs (just the first time)
root@netgusto $ apt-get update  
root@netgusto $ apt-get -y install bindfs

# Creating the application mountpoint
root@netgusto $ mkdir -p /home/devone/websites/application1  
root@netgusto $ chown -Rf devone:devone /home/devone/websites  
root@netgusto $ chmod -Rf 770 /home/devone/websites

Then, edit the content of /etc/fstab and add this line (just one line, without line wraps):

bindfs#/var/www/application1 /home/devone/websites/application1 fuse force-user=devone,force-group=devone,create-for-user=www-data,create-for-group=www-data,create-with-perms=0770,chgrp-ignore,chown-ignore,chmod-ignore 0 0  

Save the file, and proceed with mounting application (will mount automatically at system load):

root@netgusto $ mount /home/devone/websites/application1

If your system yells about force-user or force-group not being defined:

  • replace force-user by owner
  • replace force-group by group

Testing the solution

Once the application is mounted, you can test it by creating a file in the application mountpoint using the devone account, and verifying the file perms:

# as root
root@netgusto $ su - devone

# as devone
devone@netgusto $ cd ~/websites/application1  
devone@netgusto $ touch helloworld.txt  
devone@netgusto $ ls -l helloworld.txt  
-rwxrwx--- 1 devone devone 0 sept. 10 17:15 helloworld.txt
devone@netgusto $ exit

# as root again
root@netgusto $ cd /var/www/application1  
root@netgusto $ ls -l helloworld.txt  
-rwxrwx--- 1 www-data www-data 0 sept. 10 17:15 helloworld.txt

The file is owned by www-data:www-data whereas we created it as devone:devone ! It worked !

One more thing

If you want to prevent developers to access /var/www/application1 directly, you just have to execute this:

# Attribute the /var/www root dir to www-data:www-data
root@netgusto $ chown www-data:www-data /var/www

# Change the permissions so that only the web server can enter this dir
root@netgusto $ chmod 770 /var/www

Note that the web served directory /var/www/application1 has nothing to do with bindfs, so it should not impact at all your web server.

How cool is that ? Tell us what you think !

comments powered by Disqus