LAMP development in your home directory with suPHP module

suPHP Logo In my first article for Inchoo.net last week I've described how to easily manage LAMP name based virtual hosts using bash script that simplifies virtual hosts management on a Debian based Linux operating systems. While I was coding the script in question, I have assumed that most people develop from default document root /var/www and using Apache's mod_php5. In this article I'll show you how to setup your LAMP environment to develop in your home directory using another Apache module suPHP.

Developing from your home directory is a no-brainer using mod_userdir or virtual hosts (more about this later in the article). The only problem is that mod_php5 powered PHP is running as Apache's www-data user and that any file created by PHP during your code execution will be owned by www-data user. I don't want to be forced to do stuff like changing file ownership or starting Apache process as another user just to be able to delete my Magento project's /var/cache when necessary.

Here's where suPHP comes in. According to suPHP web site, suPHP Apache module comes with setuid root binary (suphp) that is called by the Apache module to change the uid of the process executing the PHP interpreter. This means that if we use mod_suphp to handle PHP scripts in our document root, we have control over created files and directories ownership and permissions. So let's proceed to configuration.

First things first, we need mod_suphp installed and enabled to play with its configuration:

sudo apt-get install libapache2-mod-suphp
sudo a2enmod suphp

The only mod_suphp gotcha is that distribution provided packages like phpMyAdmin are installed inside /usr/share and owned by root user with user and group id 0. Since it's ludicrous to allow PHP to run as root user due to security, we will leave mod_php5 active and configure it to handle only PHP code in /usr/share. We will also set minimum user and group id for mod_suphp to 33 (default user and group id for www-data user) and exclude /usr/share from it's configuration.

Now let's open suPHP configuration file (I'll use nano editor):

sudo nano /etc/suphp/suphp.conf

In one way or the other, I usually place my document root to $HOME/public_html so default suPHP docroot directive suites me just fine. Also I like to match file permissions for files created by PHP to my home directory defaults so I configure umask directive to 0002. I also disable some security checks to match home directory default umask. Here's the contents of my suphp.conf (I've commented-out default configuration, and marked my changes):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
[global]
;Path to logfile
logfile=/var/log/suphp/suphp.log
 
;Loglevel
loglevel=info
 
;User Apache is running as
webserver_user=www-data
 
;Path all scripts have to be in
docroot=/var/www:${HOME}/public_html
 
;Path to chroot() to before executing script
;chroot=/mychroot
 
; Security options
 
; Marko: Allow serving group writable files to match $HOME
; default 664 permissions due to 0002 $HOME default umask
;allow_file_group_writeable=false
allow_file_group_writeable=true
 
allow_file_others_writeable=false
 
; Marko: Allow serving from group writable directories to match $HOME
; default 775 permissions due to 0002 $HOME default umask
;allow_directory_group_writeable=false
allow_directory_group_writeable=true
 
allow_directory_others_writeable=false
 
;Check wheter script is within DOCUMENT_ROOT
; Marko: Do not check
;check_vhost_docroot=true
check_vhost_docroot=false
 
;Send minor error messages to browser
errors_to_browser=false
 
;PATH environment variable
env_path="/bin:/usr/bin"
 
;Umask to set, specify in octal notation
; Marko: To match $HOME default umask of 0002
;umask=0077
umask=0002
 
; Minimum UID
; Marko: www-data is by default uid 33
;min_uid=100
min_uid=33
 
; Minimum GID
; Marko: www-data is by default gid 33
;min_gid=100
min_gid=33
 
 
[handlers]
;Handler for php-scripts
application/x-httpd-suphp="php:/usr/bin/php-cgi"
 
;Handler for CGI-scripts
x-suphp-cgi="execute:!self"

Next thing to is to disable mod_suphp for /usr/share/ and let mod_php handle PHP code inside this directory. If you look at /etc/apache2/mods-available/suphp.conf you will notice that suPHP Apache module by default doesn't handle /usr/share directory but we do need to make changes to php5 Apache module configuration file.

sudo nano /etc/apache2/mods-available/php5.conf

We need to change this file into something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<IfModule mod_php5.c>
    # Out by Marko: We use mod_suphp to handle PHP code in general.
    #<FilesMatch ".+\.ph(p[345]?|t|tml)$">
    #    SetHandler application/x-httpd-php
    #</FilesMatch>
    #<FilesMatch ".+\.phps$">
    #    SetHandler application/x-httpd-php-source
    #    # Deny access to raw php sources by default
    #    # To re-enable it's recommended to enable access to the files
    #    # only in specific virtual host or directory
    #    # Apache <= 2.2:
    #    Order Deny,Allow
    #    Deny from all
    #    # Apache >= 2.4:
    #    #Require all denied
    #</FilesMatch>
 
    # In by Marko: PHP code running from /usr/share is uid and gid 0 thus
    # mod_suphp shouldn't handle it. We use mod_php5 for that code:
    <Directory /usr/share>
        <FilesMatch "\.ph(p3?|tml)$">
        SetHandler application/x-httpd-php
        </FilesMatch>
        <FilesMatch "\.phps$">
        SetHandler application/x-httpd-php-source
        </FilesMatch>
    </Directory>
 
    # Deny access to files without filename (e.g. '.php')
    <FilesMatch "^\.ph(p[345]?|t|tml|ps)$">
        # Apache <= 2.2
        Order Deny,Allow
        Deny from all
 
        # Apache >= 2.4:
        #Require all denied
    </FilesMatch>
 
    # Running PHP scripts in user directories is disabled by default
    # 
    # To re-enable PHP in user directories comment the following lines
    # (from <IfModule ...> to </IfModule>.) Do NOT set it to On as it
    # prevents .htaccess files from disabling it.
    #<IfModule mod_userdir.c>
    #    <Directory /home/*/public_html>
    #        php_admin_value engine Off
    #    </Directory>
    #</IfModule>
</IfModule>

This configuration will let mod_suphp handle PHP code from /var/www and $HOME/public_html and mod_php5 to handle PHP code from /usr/share. Projects placed inside /var/www won't notice any difference because mod_suphp will run them with proper user id. On the other hand if you place any project inside $HOME/public_html you will notice that files created by PHP will be owned by user owning $HOME and have proper permissions in place.

One thing to note, for PHP code handled by mod_php5, php.ini file is at it's standard /etc/php5/apache2/php.ini location. On the other hand if you need to adjust your php.ini for code under mod_suphp you need to adjust one at /etc/php5/cgi/php.ini location since mod_suphp runs your script trough CGI.

Now to actually develop from home you can enable mod_userdir, create virtual host manually or using my script, and point the document root directive to your $HOME/public_html directory. If you decide to use my script, you'll find that it is mod_suphp compliant and that you can use the -d switch to control document root where virtual host directory is to be created like this:

sudo /usr/bin/lamp-vhost-manager.sh -m add -n vhost1.loc -d $HOME/public_html

All that's left is to restart Apache2 service and you're good to go:

sudo service apache2 restart

Happy coding!

DevGenii

E-commerce is a breeze with Magento Certified Developer Plus & Zend Certified PHP Engineer nearby. Get in touch!

4 thoughts on “LAMP development in your home directory with suPHP module

    1. Marko Author

      Bok,
      nema na čemu, drago mi je da si našao svrhu LAMP Vhost Manager-u. Restart Apache 2 servisa radim čisto zbog toga što se radi o development machine-u tako da mi manji downtime koji donosi reload nije bitan.

      Poz!

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *