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.
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.)
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
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
# 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-group not being defined:
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 !