Apache 2.2, fpm 5.3.8 w/chroot

194 views
Skip to first unread message

rafamiga

unread,
Jan 18, 2012, 8:02:58 AM1/18/12
to highload-php-en
I'm having a very strange problem with php-fpm 5.3.8 in Apache2.2.

This is my Apache config:

DocumentRoot /home/app/php/php
FastCgiExternalServer /home/httpd/html/php/php-handler -idle-timeout
300 -socket /var/run/php-fpm-php.sock

AddHandler php5-fcgi .php
Action php5-fcgi /php-handler
Alias /php-handler /home/httpd/html/php/php-handler

/home/app/php/php is a document root for the PHP application I'm
trying to run. Actually it's a link to a directory buried down there
in chroot, /home/httpd/html/php/home/httpd/html/php to be precise.
Don't ask why I use this strange, long path, but it works, and the
path might be /chroot/php as well, it doesn't matter as long chroot
(directory exists/filesystem is mounted) at /home/httpd/html/php,
doesn't it?

Anyway, I've set FastCgiExternalServer to some path other than docroot
because if I use identical paths Apache will feed every file through
the socket, even CSS and GIFs, which, basically, is not what I hope to
achieve. 8^)

This simple test works great:

$ /bin/echo -ne "GET /test0.php HTTP/1.1\r\nHost: xxxxxxxxxxxxxxxx\r\n
\r\n" | nc localhost 8080|head -15
HTTP/1.1 200 OK
Date: Wed, 18 Jan 2012 12:32:57 GMT
Server: Apache/2
Cache-Control: max-age=18000
Expires: Wed, 18 Jan 2012 17:32:57 GMT
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

2000
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/
xhtml1-transitional.dtd">
<html><head>
<style type="text/css">
body {background-color: #ffffff; color: #000000;}
body, td, th, h1, h2 {font-family: sans-serif;}

Basically, phpinfo shows up beautifuly. But when I try to run a PHP
script from a drectory under chroot I get:

$ /bin/echo -ne "GET /test2/test2.php HTTP/1.1\r\nHost:
xxxxxxxxxxxxxxxx\r\n\r\n" | nc localhost 8080
HTTP/1.1 404 Not Found
Date: Wed, 18 Jan 2012 12:34:21 GMT
Server: Apache/2
Cache-Control: max-age=18000
Expires: Wed, 18 Jan 2012 17:34:21 GMT
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

0

I've traced the FPM worker process and I see this:

a "good" call:

read(3, "\r\21DOCUMENT_ROOT/home/app/php/php", 32) = 32
read(3, "\1\4\0\1\0\"\0\0", 8) = 8
read(3, "\17\36SCRIPT_FILENAME/home/httpd/html/php/test0.php", 47) =
47
read(3, "\1\4\0\1\0\22\0\0", 8) = 8
read(3, "\v\5REMOTE_PORT41822", 18) = 18
read(3, "\1\4\0\1\0\30\0\0", 8) = 8
read(3, "\f\nREDIRECT_URL/test0.php", 24) = 24
read(3, "\1\4\0\1\0\25\0\0", 8) = 8
read(3, "\n\nSCRIPT_URL/test0.php", 22) = 22
read(3, "\1\4\0\1\0001\0\0", 8) = 8
read(3, "\n%SCRIPT_URIhttp://xxxxxxxxxxxxxxxx/test0.php", 49) = 49
read(3, "\1\4\0\1\0\32\0\0", 8) = 8
read(3, "\21\7GATEWAY_INTERFACECGI/1.1", 26) = 26
read(3, "\1\4\0\1\0\31\0\0", 8) = 8
read(3, "\17\10SERVER_PROTOCOLHTTP/1.1", 25) = 25
read(3, "\1\4\0\1\0\23\0\0", 8) = 8
read(3, "\16\3REQUEST_METHODGET", 19) = 19
read(3, "\1\4\0\1\0\16\0\0", 8) = 8
read(3, "\f\0QUERY_STRING", 14) = 14
read(3, "\1\4\0\1\0\27\0\0", 8) = 8
read(3, "\v\nREQUEST_URI/test0.php", 23) = 23
read(3, "\1\4\0\1\0#\0\0", 8) = 8
read(3, "\v\26SCRIPT_NAME/php-handler/test0.php", 35) = 35
read(3, "\1\4\0\1\0\0\0\0", 8) = 8
clock_gettime(CLOCK_MONOTONIC, {582840, 996581876}) = 0
setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={60, 0}}, NULL) =
0
rt_sigaction(SIGPROF, {0x5b0980, [PROF], SA_RESTORER|SA_RESTART,
0x2b35bb70e2d0}, {0x5b0980, [PROF], SA_RESTORER|SA_RESTART,
0x2b35bb70e2d0}, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [PROF], NULL, 8) = 0
open("/home/httpd/html/php/test0.php", O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=20, ...}) = 0
clock_gettime(CLOCK_MONOTONIC, {582840, 996842876}) = 0
getcwd("/home/httpd/html/php"..., 4095) = 21

Cool, chroot path /home/httpd/html/php/test0.php does exist and FPM
gets a file from there:

# chroot /home/httpd/html/php/
bash-3.2# ls -la /home/httpd/html/php/test0.php
-rw-r--r-- 1 20114800 20114800 20 Jan 18 05:22 /home/httpd/html/php/
test0.php

But when I request a file from "test2" directory ["GET /test2/test2.php
\r\n..."] the trace looks different:

read(3, "\r\21DOCUMENT_ROOT/home/app/php/php", 32) = 32
read(3, "\1\4\0\1\0\"\0\0", 8) = 8
read(3, "\17\32SCRIPT_FILENAME/home/httpd/html/php/test2", 43) = 43
read(3, "\1\4\0\1\0\22\0\0", 8) = 8
read(3, "\v\5REMOTE_PORT41918", 18) = 18
read(3, "\1\4\0\1\0\36\0\0", 8) = 8
read(3, "\f\20REDIRECT_URL/test2/test2.php", 30) = 30
read(3, "\1\4\0\1\0\25\0\0", 8) = 8
read(3, "\n\tGEOIP_ADDR127.0.0.1", 21) = 21
read(3, "\1\4\0\1\0\34\0\0", 8) = 8
read(3, "\n\20SCRIPT_URL/test2/test2.php", 28) = 28
read(3, "\1\4\0\1\0007\0\0", 8) = 8
read(3, "\n+SCRIPT_URIhttp://xxxxxxxxxxxxxxxx/test2/test2.php", 55) =
55
read(3, "\1\4\0\1\0\32\0\0", 8) = 8
read(3, "\21\7GATEWAY_INTERFACECGI/1.1", 26) = 26
read(3, "\1\4\0\1\0\31\0\0", 8) = 8
read(3, "\17\10SERVER_PROTOCOLHTTP/1.1", 25) = 25
read(3, "\1\4\0\1\0\23\0\0", 8) = 8
read(3, "\16\3REQUEST_METHODGET", 19) = 19
read(3, "\1\4\0\1\0\16\0\0", 8) = 8
read(3, "\f\0QUERY_STRING", 14) = 14
read(3, "\1\4\0\1\0\35\0\0", 8) = 8
read(3, "\v\20REQUEST_URI/test2/test2.php", 29) = 29
read(3, "\1\4\0\1\0\37\0\0", 8) = 8
read(3, "\v\22SCRIPT_NAME/php-handler/test2", 31) = 31
read(3, "\1\4\0\1\0\25\0\0", 8) = 8
read(3, "\t\nPATH_INFO/test2.php", 21) = 21
read(3, "\1\4\0\1\0,\0\0", 8) = 8
read(3, "\17\33PATH_TRANSLATED/home/app/php/php/test2.php", 44) = 44
read(3, "\1\4\0\1\0\0\0\0", 8) = 8
lstat("/home/app/php/php/test2.php", 0x7fff36823420) = -1 ENOENT (No
such file or directory)
stat("/home/app/php/php", 0x7fff36825620) = -1 ENOENT (No such file or
directory)
stat("/home/app/php", 0x7fff36825620) = -1 ENOENT (No such file or
directory)
stat("/home/app", 0x7fff36825620) = -1 ENOENT (No such file or
directory)

I have no idea why FPM tries to get a filename from NON-chroot path
and why the directory is stripped. It seems that FPM tried to open a
filename pointed to by PATH_TRANSLATED env var. Why? And notice the
SCRIPT_FILENAME which is... a directory, not a file.

I can set Apache like this:

DocumentRoot /home/app/php/php
FastCgiExternalServer /home/httpd/html/php -idle-timeout 300 -
socket /var/run/php-fpm-php.sock

RewriteRule ^/(.*)\.php$ /home/httpd/html/php/$1.php [L]

No Action nor AddHandler nor Alias used. It works, the RewriteRule
above takes care of passing this request to a handler. Still, it works
only for top-level paths:

$ /bin/echo -ne "GET /test0.php HTTP/1.1\r\nHost: php.xxxxxxxxxxxxxxxx
\r\n\r\n" | nc localhost 8080|head -15
HTTP/1.1 200 OK
Date: Wed, 18 Jan 2012 12:43:39 GMT
Server: Apache/2
Cache-Control: max-age=18000
Expires: Wed, 18 Jan 2012 17:43:39 GMT
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

2000
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/
xhtml1-transitional.dtd">
<html><head>
<style type="text/css">
body {background-color: #ffffff; color: #000000;}
body, td, th, h1, h2 {font-family: sans-serif;}

read(3, "\r\21DOCUMENT_ROOT/home/app/php/php", 32) = 32
read(3, "\1\4\0\1\0\"\0\0", 8) = 8
read(3, "\17\36SCRIPT_FILENAME/home/httpd/html/php/test0.php", 47) =
47
read(3, "\1\4\0\1\0\22\0\0", 8) = 8
read(3, "\v\5REMOTE_PORT42110", 18) = 18
read(3, "\1\4\0\1\0\25\0\0", 8) = 8
read(3, "\n\tGEOIP_ADDR127.0.0.1", 21) = 21
read(3, "\1\4\0\1\0\26\0\0", 8) = 8
read(3, "\n\nSCRIPT_URL/test0.php", 22) = 22
read(3, "\1\4\0\1\0001\0\0", 8) = 8
read(3, "\n%SCRIPT_URIhttp://xxxxxxxxxxxxxxxx/test0.php", 49) = 49
read(3, "\1\4\0\1\0\32\0\0", 8) = 8
read(3, "\21\7GATEWAY_INTERFACECGI/1.1", 26) = 26
read(3, "\1\4\0\1\0\31\0\0", 8) = 8
read(3, "\17\10SERVER_PROTOCOLHTTP/1.1", 25) = 25
read(3, "\1\4\0\1\0\23\0\0", 8) = 8
read(3, "\16\3REQUEST_METHODGET", 19) = 19
read(3, "\1\4\0\1\0\16\0\0", 8) = 8
read(3, "\f\0QUERY_STRING", 14) = 14
read(3, "\1\4\0\1\0\27\0\0", 8) = 8
read(3, "\v\nREQUEST_URI/test0.php", 23) = 23
read(3, "\1\4\0\1\0\27\0\0", 8) = 8
read(3, "\v\nSCRIPT_NAME/test0.php", 23) = 23
read(3, "\1\4\0\1\0\0\0\0", 8) = 8
clock_gettime(CLOCK_MONOTONIC, {583395, 860114876}) = 0
setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={60, 0}}, NULL) =
0
rt_sigaction(SIGPROF, {0x5b0980, [PROF], SA_RESTORER|SA_RESTART,
0x2b35bb70e2d0}, {0x5b0980, [PROF], SA_RESTORER|SA_RESTART,
0x2b35bb70e2d0}, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [PROF], NULL, 8) = 0
open("/home/httpd/html/php/test0.php", O_RDONLY) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=20, ...}) = 0
clock_gettime(CLOCK_MONOTONIC, {583395, 860385876}) = 0
getcwd("/home/httpd/html/php"..., 4095) = 21
chdir("/home/httpd/html/php") = 0

Good, SCRIPT_FILENAME is what it should be. But with test2/test2.php
it fails but for a different cause:

$ /bin/echo -ne "GET /test2/test20.php HTTP/1.1\r\nHost:
xxxxxxxxxxxxxxxx\r\n\r\n" | nc localhost 8080
HTTP/1.1 404 Not Found
Date: Wed, 18 Jan 2012 12:44:40 GMT
Server: Apache/2
Cache-Control: max-age=18000
Expires: Wed, 18 Jan 2012 17:44:40 GMT
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

19
No input file specified.

read(3, "\r\21DOCUMENT_ROOT/home/app/php/php", 32) = 32
read(3, "\1\4\0\1\0\"\0\0", 8) = 8
read(3, "\17\32SCRIPT_FILENAME/home/httpd/html/php/test2", 43) = 43
read(3, "\1\4\0\1\0\22\0\0", 8) = 8
read(3, "\v\5REMOTE_PORT42168", 18) = 18
read(3, "\1\4\0\1\0\25\0\0", 8) = 8
read(3, "\n\tGEOIP_ADDR127.0.0.1", 21) = 21
read(3, "\1\4\0\1\0\34\0\0", 8) = 8
read(3, "\n\20SCRIPT_URL/test2/test2.php", 28) = 28
read(3, "\1\4\0\1\0007\0\0", 8) = 8
read(3, "\n+SCRIPT_URIhttp://xxxxxxxxxxxxxxxxxxxxxxxxx/test2/
test20.php", 55) = 55
read(3, "\1\4\0\1\0\32\0\0", 8) = 8
read(3, "\21\7GATEWAY_INTERFACECGI/1.1", 26) = 26
read(3, "\1\4\0\1\0\31\0\0", 8) = 8
read(3, "\17\10SERVER_PROTOCOLHTTP/1.1", 25) = 25
read(3, "\1\4\0\1\0\23\0\0", 8) = 8
read(3, "\16\3REQUEST_METHODGET", 19) = 19
read(3, "\1\4\0\1\0\16\0\0", 8) = 8
read(3, "\f\0QUERY_STRING", 14) = 14
read(3, "\1\4\0\1\0\35\0\0", 8) = 8
read(3, "\v\20REQUEST_URI/test2/test20.php", 29) = 29
read(3, "\1\4\0\1\0\23\0\0", 8) = 8
read(3, "\v\6SCRIPT_NAME/test2", 19) = 19
read(3, "\1\4\0\1\0\25\0\0", 8) = 8
read(3, "\t\nPATH_INFO/test2.php", 21) = 21
read(3, "\1\4\0\1\0/\0\0", 8) = 8
read(3, "\17\36PATH_TRANSLATED/home/httpd/html/php/test20.php", 47) =
47
read(3, "\1\4\0\1\0\0\0\0", 8) = 8
lstat("/home/httpd/html/php/test2", {st_mode=S_IFDIR|S_ISGID|0755,
st_size=4096, ...}) = 0
clock_gettime(CLOCK_MONOTONIC, {583449, 31099876}) = 0
setitimer(ITIMER_PROF, {it_interval={0, 0}, it_value={60, 0}}, NULL) =
0
rt_sigaction(SIGPROF, {0x5b0980, [PROF], SA_RESTORER|SA_RESTART,
0x2b35bb70e2d0}, {0x5b0980, [PROF], SA_RESTORER|SA_RESTART,
0x2b35bb70e2d0}, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [PROF], NULL, 8) = 0
open("/home/httpd/html/php/test2", O_RDONLY) = 4
fstat(4, {st_mode=S_IFDIR|S_ISGID|0755, st_size=4096, ...}) = 0
close(4) = 0

It seems that with this setup the PATH_TRANSLATED env var [which maps
to chrooted path perfectly] is OKAY but FPM is trying to open
SCRIPT_FILENAME which is... a directory the requested script it in!
And WHY FPM is ignoring PATH_TRANSLATED now?

I'm stuck. The later method works for me better, but WHY ON EARTH I
GET 404 or "No input file specified"?

I've tried even this:

RewriteRule ^/(.*)\.php$ /home/httpd/html/php/$1.php
[E=SCRIPT_FILENAME:/home/httpd/html/php/$1,L]

But it doesn't work, it gets overwritten by Apache.

Any help, any ideas?

This is my php-fpm chroot-revelant configuraion options in fpm config:

chroot = /home/httpd/html/php
chdir = /home/httpd/html/php

Przemysław Pawliczuk

unread,
Jan 27, 2012, 4:37:47 PM1/27/12
to highloa...@googlegroups.com
> chroot = /home/httpd/html/php
> chdir = /home/httpd/html/php

Chdir should be relative to chrooted directory.

rafamiga

unread,
Jan 24, 2012, 5:00:12 AM1/24/12
to highload-php-en
I found no explanation for this behaviour. All I know is that Apache
is doing sub-request with "broken" SCRIPT_FILENAME already set, before
passing it to FastCgiExternalServer's socket.

I've developed a patch for my problem, freely available under GPL
license at http://orfika.net/src/mod_fastcgi-chroot-patch/.

On 18 Sty, 14:02, rafamiga <rafam...@gmail.com> wrote:
> I'm having a very strange problem with php-fpm 5.3.8 in Apache2.2.
>
> This is my Apache config:
>
> DocumentRoot /home/app/php/php
> FastCgiExternalServer /home/httpd/html/php/php-handler  -idle-timeout
> 300 -socket /var/run/php-fpm-php.sock
>
> AddHandler php5-fcgi .php
> Action php5-fcgi /php-handler
> Alias /php-handler /home/httpd/html/php/php-handler

--
rafamiga

rafamiga

unread,
Jan 28, 2012, 6:00:03 AM1/28/12
to highload-php-en
On 27 Sty, 22:37, Przemysław Pawliczuk <p.pawlic...@gmail.com> wrote:
> > chroot = /home/httpd/html/php
> > chdir = /home/httpd/html/php
> Chdir should be relative to chrooted directory.

They are. The full, non-chrooted path for the later directory is /home/
httpd/html/php/home/httpd/html/php. Don't ask why. 8^)

--
rafamiga

Reply all
Reply to author
Forward
0 new messages