Sat 18 April 2020
While setting up a PHP application in a PHP-FPM chrooted environment, you may come across some difficulties with the fopen() function called for URLs. These difficulties are fairly simple to solve if one understands what is happening in and out of the chroot(), but might become burdensome otherwise.
allow_url_fopen = On
which is the first place to look at, no matter whether in chroot or not, there is a little bit more.
Prepare a simple script that will fopen() a site and print out its content.
<?php $f = fopen('http://some.site.domain', 'r') or die("fopen() fail"); while($line = fread($f, 1000)) print($line); fclose($f); ?>
Should everything be all right, you will see the content of some.site.domain.
If you get this error:
PHP Warning: fopen(http://some.site.domain): failed to open stream: php_network_getaddresses: getaddrinfo failed: Name does not resolve in /testscript.php on line 2'
this gives us a clue, that the system resolver could not find the host by name. The way the system resolver works vary from one system to another, but there are some general rules that apply to most of the popular unix-like systems.
Look at the
(...) hosts: files dns (...)
In the given case the system will look first at
then fallback to the DNS.
call is executed from within the chroot(), the resolver has no way to access the
resolv.conf files in the base system, thus does not know what
the DNS servers are. Just copy the
/etc/resolv.conf to your chroot location.
If you use
/etc/hosts, copy this one too.
# cp /etc/hosts /your/chroot/path/etc/hosts # cp /etc/resolv.conf /your/chroot/path/etc/resolv.conf
Now the unencrypted HTTP request should succeed.
Next try to access an SSL site. Modify the test script replacing
fopen('https://some.site.domain', 'r'). If the request fails, check if you have openssl extension enabled in the
Missing openssl extension will rise an error:
PHP Warning: fopen(https://some.site.domain): failed to open stream: Unable to find the socket transport "ssl" - did you forget to enable it when you configured PHP? in /testscript.php on line 2'
FreeBSD has the extension in a separate package (assuming it is not built from ports), thus
# pkg install php74-openssl
This step however is just a hint. Other systems will require a different approach.
If the openssl extension has been enabled, yet you see:
fopen(): SSL operation failed with code 1. OpenSSL Error messages:\nerror:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed in /testscript.php on line 2 PHP message: PHP Warning: fopen(): Failed to enable crypto in /testscript.php on line 2 PHP message: PHP Warning: fopen(https://some.site.domain): failed to open stream: operation failed in /testscript.php on line 2'
you have to provide the OpenSSL library with its mandatory files, eg. CA root certificates. In FreeBSD 12.1
all certificates are stored in a bundle
# cp /etc/ssl/cert.pem /your/chroot/path/etc/ssl/cert.pem
In many Linux distributions those certificates usually come as single files located in a subdirectory under
Now the fopen() function should work fine for both
If you can’t get it working, try to deduce from the PHP errors which of the base system files the PHP internal calls may require. Then copy those files to the directory that PHP-FPM chroots to (preserving paths). Understanding of the system, libraries and applications may be essential here.