Nginx + php + fpm plug'n'play configuration

Hi guys, im new to Nginx.

Im running on a ubuntu 10.04 server machine, and im trying to understand
how
to configure nginx in order to run a website with many subdomains, where
every of them must run php with a different user, without restarting
nginx
or php5-fpm.

Basically, when i need to a subdomain, i have a script that create the
server user, then his folder owned by him; for example, for the
foo.example.com subdomain i will have a foo user and a
/var/www/vhosts/subdomains/foo/htdocs folder.

So, for every requests to *.example.com, i need to:

  1. check if user and folder exists
  2. invoke fpm with the matching user/group (maybe the group will be the
    same
    for every subdomain)

Any suggestion about?

On Fri, Apr 01, 2011 at 04:14:40PM +0200, Daniele Pignedoli wrote:

Hi there,

Hi guys, im new to Nginx.

Welcome. You’ll probably want to refer to the manuals for more
information
on everything you read here; but for testing purposes, hopefully the
following will help.

Im running on a ubuntu 10.04 server machine, and im trying to understand how
to configure nginx in order to run a website with many subdomains, where
every of them must run php with a different user, without restarting nginx
or php5-fpm.

The short answer is “it’s not a problem; nginx doesn’t know or care
about php”. But that’s not what you want to hear, so…

Basically, when i need to a subdomain, i have a script that create the
server user, then his folder owned by him; for example, for the
foo.example.com subdomain i will have a foo user and a
/var/www/vhosts/subdomains/foo/htdocs folder.

On the nginx side, there are two main ways to approach this.

Run one nginx instance which can read files of all users; or run one
nginx
instance as each user which only has access to that user’s files, plus
one “main” nginx which will proxy_pass to the correct per-user instance.

The first case is probably easier. An nginx.conf with something like

===
http {
server {
root /tmp/$host/html;
}
}

will probably do most of what you want. “$host” is “whatever the client
sent in the Host: header” (approximately), so you’ll want to make sure
that nothing nasty happens in edge cases, such as “no Host: header
at all” or “Host: …” or “Host: *” and the like.

So, for every requests to *.example.com, i need to:

  1. check if user and folder exists

“error_page 404” may help here. But it may cause confusion if there are
“genuine” 404s generated.

  1. invoke fpm with the matching user/group (maybe the group will be the same
    for every subdomain)

nginx doesn’t do php. But it does “fastcgi_pass” to a fastcgi server,
which is what fpm is.

So run one fastcgi server per user, accessible at a derivable
location. And add something like

===
location ^~ /php/ {
fastcgi_pass unix:/tmp/$host/fcgi.sock;
include fastcgi.conf;
}

inside the server{} block, and all requests for /php/something will be
sent to the appropriate fastcgi server (failing if it is not there).

Any suggestion about?

In this example I use $host as the on-filesystem key. You can set that
to something else, if you prefer.

Also, if you want to run one nginx per user, then you would listen
on a unix socket, and proxy_pass to that socket in the “main” server,
similar to fastcgi_pass above. And it would probably be “error_page 502”
if the per-user server isn’t responding.

And, I have no idea if FPM has a better way of splitting things per-user
without restarting when users are changed.

And, of course, none of this is tested by me :wink:

But if I wanted to do this, I’d probably adjust my “enable user” script
to run a dedicated php fastcgi server as this user, and possibly also
a dedicated nginx server. And then turn them off in my “disable user”
script. The main nginx would run always.

Good luck with it,

f

Francis D. removed_email_address@domain.invalid

Hi francis, many thanks for your suggestion, with that i’ve been able to
setup a ‘almost-work’ enrivonment!

I have a file i my /etc/nginx/sites-available/ (softlinket do
sites-enabled)
that looks as follow:

server{

    fastcgi_pass    unix:/var/run/php5-fpm-test_$domain.sock;
    fastcgi_param    SCRIPT_FILENAME

$document_root$fastcgi_script_name;
include fastcgi_params;
}
}

All my subdomains are hosted in /var/www/test_[subdomain_name], for
example
foo.test.local => /var/www/test_foo/{htdocs,conf,private}

Then, in my /etc/php5/fpm/fpm.d/ i just create a new file for each
subdomain, for example:

[test_foo]

listen = /var/run/php5-fpm-test_foo.sock

user = test_foo
group = test_foo
pm = static
pm.max_children = 10

…obviously this after i created the unix user useradd test_foo.

This isnt the “plug’n’play” behavior i was looking for, becose in order
to
activate new domains i have to run /etc/init.d/php-fpm reload; but i
thought a solution: when i add a new domain, i first create a simple
“temp”
php-cgi process in order to have the subdomain active instantly

php5-cgi -b /var/run/php5-fpm-test_bar.sock

Then, running a cron task that every night kill all the php5-cgi
instances
and then reload the fpm configuration.

Do you think this could be a solution?

2011/4/1 Francis D. removed_email_address@domain.invalid

On Tue, Apr 05, 2011 at 11:59:43AM +0200, Daniele Pignedoli wrote:

Hi there,

Hi francis, many thanks for your suggestion, with that i’ve been able to
setup a ‘almost-work’ enrivonment!

Good stuff.

I have a file i my /etc/nginx/sites-available/ (softlinket do sites-enabled)
that looks as follow:

OK, so you’ve gone for “one nginx which can read all files”.

Your config looks to me like it should work ok.

Then, in my /etc/php5/fpm/fpm.d/ i just create a new file for each
subdomain, for example:

And this is “one fpm that runs many instances as different users”,
which,
as you have spotted, needs a restart for a changed user.

This isnt the “plug’n’play” behavior i was looking for, becose in order to
activate new domains i have to run /etc/init.d/php-fpm reload;

I think I had suggested just running one fcgi server per user, which
would
avoid the “restart” thing. That would probably be the equivalent to your

php5-cgi -b /var/run/php5-fpm-test_bar.sock

Of course, that’s all php or fpm stuff, rather than nginx stuff. So:

Then, running a cron task that every night kill all the php5-cgi instances
and then reload the fpm configuration.

…while I think that will probably work ok, you may find better
confirmation elsewhere.

Note that on the nginx side, you haven’t got anything specific relating
to

So, for every requests to *.example.com, i need to:

  1. check if user and folder exists

that. But your testing will show what response you get, and you can
decide whether that is adequate for you.

Good luck with it,

f

Francis D. removed_email_address@domain.invalid

OK, so you’ve gone for “one nginx which can read all files”.

Your config looks to me like it should work ok.

Yes, my first try is to have just 1 nginx instance, i think is easy to
mantain and manage… and im not comfortable with ports, for what i’ve
understood every nginx instance must have its own port to listen to…

I think I had suggested just running one fcgi server per user, which
would

avoid the “restart” thing. That would probably be the equivalent to your

php5-cgi -b /var/run/php5-fpm-test_bar.sock

Yep, running 1 cgi instance per user is more flexible, but will require
more
effords in maintenance… easily to fall in a headcache to administer so
mny
instances (please note that im not a sysadmin and i dont have much
experience with server administration, that’s why im using a KIS
approach)

Of course i know the cron task can not be the solution in production
mode,
but from my tests seem that fpm could reload the configuration without
restart: I haven to try this under a storm of requests, but looks pretty
nice.

Well, thanks again for your time and suggestion, i’ll play around with
the
configurations hoping to find the ‘best’ solution.

Bye!