PHP mail() not working in chroot vhost (Could not execute mail delivery...)

Written by - 2 comments

Published on - Listed in PHP Linux Mail

In an Apache chroot environment per virtual host, one has to take special care about PHP's mail() function, as it needs more than the actual sendmail binary.
Although this installation was using mini_sendmail (due to the complexity of normal sendmail which would have to be re-installed in every chroot environment), the function didn't work.

By doing some tests of a new hosting platform I also tested the function mail() which threw an error like the following on the browser:

PHP Warning:  mail(): Could not execute mail delivery program '/opt/local/mini_sendmail -t' in /var/www/hosting1/htdocs/mailtest.php on line 2

The mail delivery program, which is defined in php.ini in the sendmail_path variable, is well available and executable in the chroot environment. So there must be another problem with the chroot (I tested the same hosting without chroot and it worked).

On the PHP documentation page for the mail() function, I found the following hint by Sven Riedel:

mail() requires /bin/sh to exist in Unix environments, next to a mail delivery program. This is very relevant when setting up apache in a chroot environment. Unfortunately this isn't anywhere in the documentation and took me several months to figure out.

This is a very important hint! I checked it and although /bin/sh was also available in the chroot environment, it was not executable. Actually /bin/sh was a symlink to /bin/ksh which threw the following error by trying to execute it in the chroot cage:

# chroot /var/www/hosting1

bash-4.1# /bin/sh
/bin/sh: getexecname() failed

To be able to run /bin/sh (or /bin/ksh in this case) /proc needed to be mounted in the chroot environment.
Note: /bin/bash was working and executable...

So once /proc was mounted and /bin/sh was executable, I tried it again, this time by simply using the php cli:

bash-4.1# php -c /opt/local/php.ini mailtest.php
PHP Warning:  mail(): Could not execute mail delivery program '/opt/local/mini_sendmail -t' in /var/www/hosting1/htdocs/mailtest.php on line 2

Same error! The only difference between the "normal" server environment and the chrooted one was the mountpoint /dev. But is /dev necessary to send an e-mail? I decided to trace it down with truss and to my big surprise the answer is yes, it is necessary.
The following files were opened after executing mailtest.php (I removed unnecessary truss-lines):

# truss /var/www/hosting1/opt/local/php -c /var/www/hosting1/opt/local/php.ini /var/www/hosting1/htdocs/mailtest.php
write(2, "\n", 1)                               = 1
stat("/var/www/hosting1/htdocs/mailtest.php", 0x00A51E48) = 0
access("/usr/bin/sh", X_OK)                     = 0
open("/dev/null", O_RDWR)                       = 4
fcntl(4, F_GETFD, 0xFFFFFF22057007E0)           = 0
pipe()                                          = 5 [6]
access("/usr/bin/sh", X_OK)                     = 0
open("/dev/dtrace/helper", O_RDWR)              = 0
ioctl(0, DTRACEHIOC_REMOVE, 0x00000000)         = 0
close(0)                                        = 0

Thanks to truss' output, I saw that /usr/bin/sh (/bin/sh symlinks to it), /dev/null and /dev/dtrace/helper were opened to send the mail.

Long story short: To be able to send e-mails in a chrooted PHP hosting environment you need to have the real /proc and /dev mounted.

Add a comment

Show form to leave a comment

Comments (newest first)

Claudio from Switzerland wrote on Aug 8th, 2012:

Hi Josh. Are you running Linux? I'd launch strace on the php file which is having dns issues. You should then see a similar output like in my article pointing you to the missing files. Just out of the blue I'd say that /proc and /dev needs to be mounted in the chroot environment.

Josh from United States wrote on Aug 8th, 2012:

I\\\'m having dns issues with php-fpm\\\'s chroot feature. Do you know what exactly needs to be in the chroot\\\'s folder for everything to function properly?