phpsuexec
Yesterday night, my host switched over to phpsuexec.
For those that don't know, phpsuexec allows a hosting company to detatch php from the Apache server (usually php is installed as an Apache "module") and run it like a regular cgi inside the user's own account. This has many advantages for the host, chiefly, that they can track which user is eating up all the resources. As I've learned, it also has many advantages for the webmaster, too.
Firstly, of course, nothing works. Your pages will likely not load, and you will probably be greeted with a nice 500 error page instead of your beloved website. If you are still reading this, I'll assume phpsuexec is something that interests you, so here's what you need to know..
File permissions. Under phpsuexec, php scripts can no longer have their persmissions set to 777, or live in folders with those permissions, either. Folders should be set to 755, and php scripts to 644. If some script you downloaded says it needs to be set to 777 (world-writable), ignore it, and set it to 644. Your scripts are no longer run as user "nobody", but as YOU, so as long as the owner (you) can write to the file (the first 6) then all is well. Same story for log files, comment files, etc. Where they used to need to be 777, now they don't. With phpsuexec, 644 is just fine, even 600 if they are private things.
If you have shell access to your site, you can fix the whole lot in one go, like this..
for i in $( find . -name "*.php" ); do chmod 644 $i; done
for i in $( find . -type d ); do chmod 755 $i; done
and that's all your file and folder permissions fixed. But you still get 500 errors, right?
php directives. Becasue with phpsuexec, php has been disconnected from Apache, those php directives inside your .htaccess files are now completely meaningless to Apache. Hence the error. You need to remove all those php directives from your .htaccess files. Again, this is easy to do in one fell swoop..
for i in $( find . -name ".htaccess" ); do mv $i $i.old; sed 's/php_value/#php_value/g' $i.old > $i;rm -f $i.old; done
(all commmands are entered on a single line, even if it may appear split into two in your web browser) Now all php directives will be commented out in every .htaccess file, and you can at least see your page. (if you have "php_flag" directives, use a similar command for those, too). Still not working?
AddType directives. If you parse non *.php files as php, for instance generated CSS (like corz.org) then statements like this..
AddType application/x-httpd-php .css .style
will now fail dramatically. The solution is simple, use SetHandler instead, like this..
# for suexec..
<FilesMatch ".(css|style)$">
SetHandler application/x-httpd-php
</FilesMatch>
And now all *.css and *.style files covered by that particular .htaccess will be parsed by the php machine. Excellent!
Options -ExecCGI will also prevent your php script from running, of course. While we're at it, here's some other stuff you need to know..
- The user executing the wrapper must be a valid user on this system.
- The command that the request wishes to execute must not contain a /.
- The command being executed must reside under your web document root.
- The current working directory must be a directory.
- The current working directory must not be writable by group or other.
- The command being executed cannot be a symbolic link.
- The command being executed cannot be writable by group or other.
- The command being executed cannot be a setuid or setgid program.
- The target UID and GID must be a valid user and group on the system.
- The target UID and GID to execute as, must match the UID and GID of the directory the script is located within.
- The target execution UID and GID must not be the privledged ID 0 (root)
- Group access list is set to NOGROUP and the command is executed.
Only a couple of these things will likely have any impact on your site. Other things of note:
- PHP-based HTTP Authentication no longer works (good, it was crap)
- The $PATH_INFO variable within PHP does not function (good, it's a security hole)
- The PHP function getallheaders() does not work. (damn! gonna have to rewrite PDA!)
what about my php directives!?
Okay, so far so good. But what about all those php directives you deleted? How are you supposed to enable zlib compression? or change the upload size and what-not? Worry not! This is where the fun begins.
Rather than mix php directives in with apache directives, you can now create local php.ini files. In much the same way that it's smart to split code structures and content, content and style in your web pages, this enables you alter your php environment in almost any way. The more I think about this, the more I think it's a great idea.
You don't have to recreate a complete php.ini for your site, you simply specify the values you wish to override, just like you do with Apache directives in .htaccess files. Perhaps something like this..
; php directives
[php]
register_globals = Off
zlib.output_compression = 16386
zlib.output_compression_level = 7
zlib.output_handler = zlib.output_compression
default_charset = utf-8
display_errors = off
log_errors = on
error_log = /www/cor/public_html/err/php_error.log
upload_max_filesize = 10M
post_max_size = 10M
[session]
session.use_trans_sid = 0
session.save_path = /www/cor/tmp/sessions
note: you MUST use proper [sections], just like the master php.ini file. You can override any php directive in this manner, though sensible web hosts will have disabled the dangerous ones. Currently, at least on my host, the php.ini values don't cascade down through the tree, though I'm assured they are looking for a fix. placing php.in files in EVERY directory seems a daunting task, indeed, we'll see.
Now everything's setup, your site should function exactly as before. Better, in fact..
The first thing I noticed is that because my session files now live inside my user space, as opposed to the system /tmp folder, they are exempt from the server's garbage collection process. Think about it.
This has been a continual nuisance for years, at every web hosts I've been with.
Now, if I specify that a session should last twenty four hours, it does exactly that! As opposed to fifteen minutes or thereabouts, as before. This alone has made the switch to phpsuexec worthwhile.
It's tempting to think that this whole phpsuexec business is some Gestapo effort by your host to clamp down on "bad" users, it's not. It's simply a means to managing better, more robust web servers. If I have some script that is out of control and eating server resources, I WANT TO KNOW ABOUT IT! With php running as an Apache module, there is simply no way to do this.
More importantly, if some other website on my shared server has a script that is out of control, I WANT IT FIXED! There's no reason why a hundred web sites should have to suffer for one user's wonky code. In our case, it turns out that one of the hosts' server tools was eating up most of the extra resources, and this change has enabled them to locate and crucially, FIX the source of the trouble. There were a couple of users with dodgy scripts too, by the way. phpsuexec gives us all
control.
There are other advantages, too. Mail now comes from my user account as opposed to "nobody@..", which is nice, and this fine-grained control over php directives that couldn't previously be manipulated has opened up a whole lot of possibilities. And of course, other users on my shared server can no longer read my raw files. Not a small consideration.
It's all good. Sure, it takes a wee bit of effort to get your site working again (and if only you'd used proper <ifModule> conditions, nothing would have broken, but then, who does? they don't work on Windows servers anyway,
afaik, not that mine is) but it's effort well spent.
for now..
;o)