Table of Contents
By default Centos 6 has Apache (2.2.x) which comes with suexec preinstalled.
The suexec module itself could be found here: /etc/httpd/modules/mod_suexec.so
There is also a suexec wrapper binary, which is by default installed here: /usr/sbin/suexec
0. What is the problem with default suexec ?
Imagine you want to activate Suexec for some of your sites, then you will probably use something like that:
<VirtualHost *:80>
ServerAdmin webmaster@dummy-host.example.com
DocumentRoot /var/www/html/example.com
ServerName example.com
ErrorLog logs/example.com-error_log
CustomLog logs/example.com-access_log combined
SuexecUserGroup modsecurity modsecurity
</VirtualHost>
After adding such snippet, I started getting the following errors:
root@localhost[]# cat /etc/httpd/logs/suexec.log [2016-05-27 21:45:23]: command not in docroot (/usr/bin/php-cgi) [2016-05-27 21:45:23]: uid: (514/some_user) gid: (514/some_user) cmd: php-cgi [2016-05-27 21:45:23]: command not in docroot (/usr/bin/php-cgi) [2016-05-27 21:45:29]: uid: (514/some_user) gid: (514/some_user) cmd: php-cgi [2016-05-27 21:45:29]: command not in docroot (/usr/bin/php-cgi) [2016-05-27 21:47:41]: uid: (514/some_user) gid: (514/some_user) cmd: php-cgi
What this error says is that your php binary “/usr/bin/php-cgi” in my case is outside your configured suexec docroot. Basically you can’t execute anythin outside the suexec docroot.
By default the suexec docroot is configured to be “/var/www”, which could be easily observed by executing the following command:
root@localhost[]# /usr/sbin/suexec -V -D AP_DOC_ROOT="/var/www" -D AP_GID_MIN=100 -D AP_HTTPD_USER="apache" -D AP_LOG_EXEC="/var/log/httpd/suexec.log" -D AP_SAFE_PATH="/usr/local/bin:/usr/bin:/bin" -D AP_UID_MIN=500 -D AP_USERDIR_SUFFIX="public_html"
Those are the options our suexec was compiled with.
1. What is the fix for this ?
Basically what you need to do in order to fix this is to recompile Suexec with some more wide open docroot.
In order to do that, you may follow the following steps:
1) Install the httpd source RPM from repo
You could find the httpd srpm for your Centos version here:
http://vault.centos.org
In my case I was using the latest Centos 6 – 6.8, and the exact URL was:
http://vault.centos.org/6.8/os/Source/SPackages/httpd-2.2.15-53.el6.centos.src.rpm
I installed this SRPM by using the following command:
# rpm -Uvh http://vault.centos.org/6.8/os/Source/SPackages/httpd-2.2.15-53.el6.centos.src.rpm
By installing the SRPM, you will get the following file accessible:
/root/rpmbuild/SOURCES/httpd-2.2.15.tar.gz
This is your apache source, which you must untar:
# cd /root/rpmbuild/SOURCES/
# tar xvzf httpd-2.2.15.tar.gz
2) Recompile Suexec binary from the Apache source
Now you have the source, so it is time to recompile your Apache with the right Suexec options:
# cd httpd-2.2.15 # ./configure \ --enable-suexec \ --with-suexec-docroot=/ \ --with-suexec-logfile=/etc/httpd/logs/suexec.log \ --with-suexec-bin=/usr/sbin/suexec \ --with-suexec-caller=apache # make -j4
If everything goes fine with the compilation, you will have new Suexec binary here:
./support/suexec
or the full path:
/root/rpmbuild/SOURCES/httpd-2.2.15/support/suexec
Now you must substitute your original suexec with the newly compiled one:
# Make backup of the original suexec # cp -a /usr/sbin/suexec{,.bak} # Copy the new suexec # cp /root/rpmbuild/SOURCES/httpd-2.2.15/support/suexec /usr/sbin/suexec # Finally fix the permissions # chown root:root /usr/sbin/suexec # chmod 4755 /usr/sbin/suexec
3. Finally restart Apache
# /etc/init.d/httpd restart
2. Errors and fixes
During the setup you may encounter some errors, here is the what I’ve got.
The following log snippets are from /etc/httpd/logs/suexec.log and were leading to different errors on the site ( usually Internal Server Error 500).
The Error:
[2016-05-27 22:04:05]: user mismatch (apache instead of nobody) [2016-05-27 22:04:43]: user mismatch (apache instead of nobody) [2016-05-27 22:04:44]: user mismatch (apache instead of nobody) [2016-05-27 22:04:44]: user mismatch (apache instead of nobody) [2016-05-27 22:04:46]: user mismatch (apache instead of nobody)
The Fix:
When you recompile Suexec, make sure you use the right user for “–with-suexec-caller=apache”
If your apache runs with user different than “apache”, then you need to correct this configuration option and recompile suexec again.
The Error:
Warning: SuexecUserGroup directive requires SUEXEC wrapper. Warning: SuexecUserGroup directive requires SUEXEC wrapper. Warning: SuexecUserGroup directive requires SUEXEC wrapper.
The Fix:
Make sure you have set correctly the suexec permissions after copying it.
The right thing to do is:
# chmod 4755 /usr/sbin/suexec
# chown root:root /usr/sbin/suexec
The Error:
[2016-05-27 23:12:41]: target uid/gid (514/514) mismatch with directory (0/0) or program (0/0) [2016-05-27 23:12:41]: uid: (514/some_user) gid: (514/modsecurity) cmd: php-fcgi [2016-05-27 23:12:41]: target uid/gid (514/514) mismatch with directory (0/0) or program (0/0) [2016-05-27 23:12:55]: uid: (514/some_user) gid: (514/modsecurity) cmd: php-fcgi
This seems to be very common issue with Suexec which people get to.
Here is what you need to understand about this errors:
The first line is telling you what you try to execute:
[2016-05-27 23:12:55]: uid: (514/some_user) gid: (514/modsecurity) cmd: php-cgi
- Your script is with uid: 514 and gid: 514
- You are trying to execute it with “php-cgi” binary
The second line is telling you the actual error about this execution:
[2016-05-27 23:12:41]: target uid/gid (514/514) mismatch with directory (0/0) or program (0/0)
Here is the biggest confusion of most people ( I was confused too), and let makes the things more clear
- target uid/gid (514/514) – These are the permissions of your php script you try to execute
- program (0/0) – These are the permissions of your php handler binary. In my case (mod_fcgid config) it is: /usr/bin/php-cgi , so only “php-cgi”
- directory(0/0) – These are the permissions of your “php-cgi” containing directory: “/usr/bin”
The Fix:
So, what you need to fix this issue ? – Make a php wrapper for the current user/group and vhost, which will be defined in your vhost.
Here is how to do it with Apache + mod_fcgid:
1) Create wrapper containing directory
mkdir /var/www/php-fcgi-scripts
2) Create sub-directory for your exact vhost / user /group config
mkdir /var/www/php-fcgi-scripts/example.com
chown my_user:my_group /var/www/php-fcgi-scripts/example.com
3) Create your php wrapper script, which will spawn the php
vim /var/www/php-fcgi-scripts/example.com/php-fcgi-starter
#!/bin/sh PHPRC=/etc export PHPRC export PHP_FCGI_MAX_REQUESTS=5000 export PHP_FCGI_CHILDREN=8 exec /usr/bin/php-cgi
This is very important step:
chmod 755 /var/www/php-fcgi-scripts/example.com/php-fcgi-starter
chown my_user:my_group /var/www/php-fcgi-scripts/example.com/php-fcgi-starter
4) Finally edit your VHOST to look like this
<VirtualHost *:80> ServerAdmin webmaster@dummy-host.example.com DocumentRoot /var/www/html/example.com ServerName example.com ErrorLog logs/example.com-error_log CustomLog logs/example.com-access_log combined <IfModule mod_suphp.c> suPHP_UserGroup my_user my_group </IfModule> SuexecUserGroup my_user my_group <Directory /var/www/html/example.com> Options +ExecCGI AllowOverride All AddHandler fcgid-script .php FCGIWrapper /var/www/php-fcgi-scripts/example.com/php-fcgi-starter .php Order allow,deny Allow from all </Directory> </VirtualHost>
Voala !
Awesome!!
Thanks a lot for neat instruction. It worked for me like a piece of cake without any errors!!
Wish you good luck!