When developing web applications and deploying them on Linux servers (development or production environments), you often encounter problems with file permissions on the application files.
Both the web server and the developers require file permissions on the same files to operate properly, but they might need different permissions on the same files.
The developer requires 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 has always been a nightmare for me when I am in charge of a server.
I named it "the www-data struggle".
The user~group "traditional" solution
One common solution is to give the developer the same user group as the web server (something like
www-data), and then to juggle with ownership on files.
While this works in some ways, it's flawed in others:
- concurrency problem: when the 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.
- 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.
The bindfs solution
Wouldn't it be great if a developer could read and write files of an application with its own user/group, while allowing the web server to have its permissions?
Well, 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 in fact 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@entropie$ apt-get update root@entropie$ apt-get -y install bindfs # Creating the application mountpoint root@entropie$ mkdir -p /home/devone/websites/application1 root@entropie$ chown -Rf devone:devone /home/devone/websites root@entropie$ 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@entropie$ 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@entropie$ su - devone # as devone devone@entropie$ cd ~/websites/application1 devone@entropie$ touch helloworld.txt devone@entropie$ ls -l helloworld.txt -rwxrwx--- 1 devone devone 0 sept. 10 17:15 helloworld.txt devone@entropie$ exit # as root again root@entropie$ cd /var/www/application1 root@entropie$ 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!
References / external links
This article was written while listening to Eating Hooks remixed by Siriusmo and Solomun.