Understanding suPHP Permissions – Why am I getting 500 Internal Server Error?

I see this topic come up a lot with users who migrate to one of our servers or to their own setup with cPanel and suPHP. The user or their customers will install a PHP script such as wordpress, concrete5, etc… Upon testing their installation they will get 500 ISE (Internal Server Error) in their web browser, served from Apache. Many less experienced users freak out and think something is wrong with the server. The reality is that permissions or file ownership is the cause of the error in the VAST majority of cases.

Often times these scripts provide documentation geared towards basic LAMP (Linux, Apache, MySQL, PHP) setups with regular mod_php. The documentation suggests that certain directories and files should be set to world writable (i.e. 777 or 666.) Often times the PHP files that are part of this script are distributed with the executable permission of 755.

On a modern server running suPHP (common with cPanel servers) Apache does not use mod_php and scripts are not executed by the ‘apache’ or ‘nobody’ user. Instead suPHP will be used and the PHP process will run as the user that the file belongs to. For security purposes there are several considerations, which are true regardless of the script’s documentation:

  • The files and directories should be owned to the proper user that they belong to. If the username is ‘robert’ the files should be owned and grouped to robert.
  • The files and directories should NOT be owned to ‘root’, ‘nobody’ or ‘apache’.
  • All directories should be set to permission level of 0755 and all files should be set to permission level of 0644.
  • You should NOT have any world writable files or directories with permission levels such as 0777, 0666, 0770, 0660, etc…
  • Your PHP script files (.php) should not be executable, such as 0755.

If you follow the above instructions. You won’t have any problems. Here is a sample of an incorrect setup:

root@server [~]# cd /home/robert/public_html/
root@server [/home/robert/public_html]# ll
total 196
drwxr-x---. 23 robert nobody   4096 Nov 12  2011 ./
drwx--x--x. 14 robert robert  4096 Mar 26  2012 ../
drwxrwxrwx.  2 robert robert  4096 Jan  6  2011 blocks/
drwxrwxrwx.  2 robert robert  4096 Jan  6  2011 config/
drwxrwxrwx.  2 robert robert  4096 Jan  6  2011 css/
-rw-rw-rw-.  1 robert robert    42 Jan  6  2011 index.php
drwxrwxrwx.  2 robert robert  4096 Jan  6  2011 js/
drwxrwxrwx.  2 robert robert  4096 Jan  6  2011 languages/
drwxrwxrwx.  2 robert robert  4096 Jan  6  2011 libraries/
drwxrwxrwx.  2 robert robert  4096 Jan  6  2011 models/
drwxrwxrwx. 13 robert robert  4096 Mar 26  2012 packages/
-rw-rw-rw-.  1 robert robert   347 Jan  6  2011 robots.txt
-rw-rw-rw-.  1 robert robert  2467 Mar  6  2012 sitemap.xml
drwxrwxrwx.  2 robert robert  4096 Jan  6  2011 themes/
root@server [/home/robert/public_html]#

As you can see the permissions are all wrong. The index.php is 666, the directories are all 777. What a mess, this won’t ever work on suPHP! At least they’re all owned to the proper user (‘robert’).

You could go through each directory and fix permissions, but we have a quicker way to do this via two bash one liners:

root@server [~]# cd /home/robert/public_html/
root@server [/home/robert/public_html]# find -type f | while read LINE; do chmod -v 644 $LINE; done
root@server [/home/robert/public_html]# find -type d | grep -v '^\.$' | while read LINE; do chmod -v 755 $LINE; done

This will change all the files inside the current directory structure (and sub-directories) to be mode 644. The second command will change each directory in the current directory (and sub-directories) to be mode 755. Make sure you’re in the proper directory, if you’re not you might change permissions on stuff you didn’t mean to, like the whole OS>