Learn about Centmin Mod LEMP Stack today
Register Now

PHP-FPM How to tell Nginx to call a different PHP-FPM pool for each php app?

Discussion in 'Nginx, PHP-FPM & MariaDB MySQL' started by jeffwidman, May 11, 2015.

Tags:
  1. jeffwidman

    jeffwidman Active Member

    152
    27
    28
    Dec 3, 2014
    Ratings:
    +51
    Local Time:
    8:07 PM
    Despite taking careful security precautions, I've been hacked before and I expect it will happen again. I run multiple Wordpress blogs and PHP-based forums on the same VPS, so I want each app isolated as much as possible so if/when it gets hacked, it's isolated to just that particular app instance.

    I already run each in a separate database with a db user dedicated to only that particular db, now I'd like them each to run as a separate linux user that can only access files for that particular app. I looked into this, and it looks like this can be accomplished with separate PHP-FPM pools, one for each app.

    But I'm unclear how to tell Nginx to pass PHP requests to the proper pool.

    It looks like the handoff currently happens in this file: centminmod/php.conf at 123.08centos7beta02 · centminmod/centminmod · GitHub
    Each domain's vhost file includes the same php.conf file, so everything hands off to the same pool.


    Is there an easy way to override the following line?
    Code:
     fastcgi_pass  127.0.0.1:9000;
    Currently, I've got a single vhost file for each domain. Although most domains only have one php app, a few have more than one, so I want to specify the port of the php-fpm pool within the location block for the app, not just within the vhost file for the entire domain.

    So how to best tell Nginx within the location blocks for each app to pass php requests (and only php requests) onto the correct port for the php-fpm pool for that app?

    I could just create a copy of the entire php.conf file for each domain, but this feels really kludgy when I'm only changing the port, and leaving everything else alone. It also won't allow sending different apps to different php-fpm pools--all apps on the same domain would go to the same pool, which isn't what I want.

    I could move the php include directive in the vhost to be within the location block of the app--that should accomplish what I want--but it still feels kludgy to duplicate the entire config file when only one line is changing.

    Is there an easier way to override just that one line on a per-app basis within the nginx Vhost file?

    Once I get Nginx sending requests to the different port, it looks like it's pretty simple to configure each php-fpm pool and which port they should listen on thanks to @eva2000 's handy example here:
    centminmod/php-fpm-2pools.conf at 123.08centos7beta02 · centminmod/centminmod · GitHub

    Two other questions:

    Will each FPM pool have it's own Zend OPCache instance or do they share the same cache?

    When updating Nginx or Php using centmin.sh script, will it clobber any of my customizations to either the php.conf or php-fpm-2pools.conf file?

    Very aware that Centminmod is provided as-is (and grateful that it's provided), but hoping that others in the community might be able to help--I suspect I'm not the only one who's tried to do this. Or at least I won't be the only one once folks realize the security benefits of isolating each app so it runs under a separate linux user preventing a hacked app from messing with other apps.
     
    Last edited: May 11, 2015
  2. eva2000

    eva2000 Administrator Staff Member

    53,461
    12,128
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,668
    Local Time:
    1:07 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    Unfortunately, Centmin Mod structure as it is now doesn't support fully isolated php-fpm pools. Only way to do it is fully isolated jailed/chrooted at account user level to start with ie. Previews - Jailed / chrooted SFTP & SSH user Nginx vhost menu | Centmin Mod Community + multiple php-fpm pools and if you need separate php opcode cache memory for each php-fpm pool, you would need separate php-fpm master processes too i.e. more than one php-fpm init.d/systemd start up script

    Also see PHP-FPM - Problem with PHP-FPM multiple pool - only 1 master php-fpm so php opcache memory is shared across all php-fpm pools and PHP-FPM - Multiple PHP-FPM Pools Generator Script testing and PHP-FPM - php hacking shell jailed?
     
  3. jeffwidman

    jeffwidman Active Member

    152
    27
    28
    Dec 3, 2014
    Ratings:
    +51
    Local Time:
    8:07 PM
    I feel like jailed/chrooted is probably overkill. My understanding is one master process can run multiple php-fpm pools under different users/groups. From the docs, it looks like this provides reasonable isolation as the child processes shouldn't be able to reach into the master process to switch their user/group.

    Am I misunderstanding something from a security perspective?

    Also, I'm not too worried about someone reaching across the opcache, it's certainly possible, but if someone is sophisticated enough to do that I'm probably already p0wned. Just wanted to confirm I properly understood what was happening under the covers.

    The problem I'm still having though is how to tell Nginx within the location block for a single app to pass php requests to a specific TCP port?

    It looks like I can do it at the domain level by including different php.conf nginx files, but since all I'm changing is the TCP port number, and everything else on the Nginx side stays the same, I'd prefer to reuse the same php.conf file and include all variables except the TCP port number.

    So how to specify just the TCP port number at the app/location block level?
     
  4. eva2000

    eva2000 Administrator Staff Member

    53,461
    12,128
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,668
    Local Time:
    1:07 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    with current Centmin Mod and nginx in general, that is the way to do it = separate php.conf include files with different port for each nginx vhost or specifying different port specifically in each nginx vhost (if not using include file for php).
     
  5. jeffwidman

    jeffwidman Active Member

    152
    27
    28
    Dec 3, 2014
    Ratings:
    +51
    Local Time:
    8:07 PM
    It'd be handy if php-fpm had a "pool.d" directory where you could just add more php-fpm pool conf files and they'd be picked up by php-fpm to create new pools.

    The default php-fpm package on Ubuntu is setup this way and it feels cleaner than the current way of appending all the pools to the end of php-fpm.conf...
     
  6. eva2000

    eva2000 Administrator Staff Member

    53,461
    12,128
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,668
    Local Time:
    1:07 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    already does centminmod/php-fpm.conf at 123.08centos7beta02 · centminmod/centminmod · GitHub

    in php-fpm.conf
    Code:
    ; Log level
    ; Possible Values: alert, error, warning, notice, debug
    ; Default Value: notice
    log_level = warning
    pid = /var/run/php-fpm/php-fpm.pid
    error_log = /var/log/php-fpm/www-error.log
    emergency_restart_threshold = 10
    emergency_restart_interval = 1m
    process_control_timeout = 10s
    ;include=/usr/local/nginx/conf/phpfpmd/*.conf
    just uncomment line and restart php-fpm
    Code:
    ;include=/usr/local/nginx/conf/phpfpmd/*.conf
    it is what makes the multiple php-fpm pool generator possible PHP-FPM - Multiple PHP-FPM Pools Generator Script testing | Centmin Mod Community :)

    maybe we misunderstood each other ? php.conf include needs separate ones for each nginx vhost, but php-fpm.conf only needs 1 as it supports include=/usr/local/nginx/conf/phpfpmd/*.conf for the actual php-fpm pool config

    php.conf != php-fpm.conf

    php.conf as in include for each vhost
    Code:
    include /usr/local/nginx/conf/php.conf;
    vs

    php-fpm.conf that defines each php-fpm pool
     
    Last edited: May 19, 2015
  7. jeffwidman

    jeffwidman Active Member

    152
    27
    28
    Dec 3, 2014
    Ratings:
    +51
    Local Time:
    8:07 PM
    Hmm... That's a bit of an unintuitive location--I saw that folder and assumed since it was under /nginx/ and there's just nginx conf files in there, that that was where I put all my Nginx conf files for specifying how to pass requests off to different php-fpm pools. (ie, copy php.conf and edit appropriately)

    Since the php-fpm pool conf is in /etc/local/etc, I would expect the folder that includes conf files for the php-fpm side of the house to be located adjacent to that.

    Would you be open to moving the php-fpm pool configs to /usr/local/php-fpm/ ?
    It'd just make more sense for the fpm-configuration to happen there and not within the nginx conf files since it's a totally different service
     
  8. eva2000

    eva2000 Administrator Staff Member

    53,461
    12,128
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,668
    Local Time:
    1:07 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    well you can move to whether you want by changing php-fpm.conf line :)

    I set it to /usr/local/nginx/conf/phpfpmd/ and none default for a few reasons

    1. to not conflict with any distro php-fpm locations in case someone does manage to install rpm package for php-fpm on centmin mod system
    2. /usr/local/nginx/conf/phpfpmd/ is auto backed up along with everything in /usr/local/nginx/conf/ on each nginx upgrade/recompile
     
  9. jeffwidman

    jeffwidman Active Member

    152
    27
    28
    Dec 3, 2014
    Ratings:
    +51
    Local Time:
    8:07 PM
    Yeah, I understood that. One handles nginx, one php-fpm. I just (still) think it's unintuitive that conf files for php-fpm are under the nginx conf folder.

    Those are somewhat valid reasons. I'm not convinced #1 matters, because default rpm package I would expect to install under /etc/ not under /usr/local/ but I haven't played much with them.

    It's not a big deal.
     
  10. jeffwidman

    jeffwidman Active Member

    152
    27
    28
    Dec 3, 2014
    Ratings:
    +51
    Local Time:
    8:07 PM
    @eva2000 heads up potential bug in your example of php-fpm 2nd pool configuration: centminmod/php-fpm-2pools.conf at master · centminmod/centminmod · GitHub and centminmod/php-fpm-min-2pools.conf at master · centminmod/centminmod · GitHub

    The /phpstatus and /phpping for pool "www2" should be amended because currently they are occupied by pool "www".

    May also want to edit the nginx phpstatus directive as well so it's locked down to local ip, I don't know how you want to handle.

    Also, what is the purpose of php-fpm-min conf files?
     
  11. eva2000

    eva2000 Administrator Staff Member

    53,461
    12,128
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,668
    Local Time:
    1:07 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    thanks updated the files at update example 2nd php-fpm pool templates · centminmod/centminmod@338f56f · GitHub

    The min conf are for servers with lower memory amounts installed. Previously Centmin Mod prompted you if you had <2048MB memory but now .08 beta 02 auto detects how much memory you have. If you have <2048MB installed memory, the min php-fpm conf files get used. If you have >2048MB memory, the non-min php-fpm conf files get used.

    normal (left) vs min php-fpm.conf (right)

    upload_2015-5-19_15-20-53.png

    /phpstatus is left open for folks to tighten as instructions are on web site at PHP PHP-FPM - Centmin Mod - Menu based Nginx installer for CentOS servers
     
  12. jeffwidman

    jeffwidman Active Member

    152
    27
    28
    Dec 3, 2014
    Ratings:
    +51
    Local Time:
    8:07 PM
    Alright, finally got this all put together...

    I created two templates--one for nginx fast cgi params, and one for the phpfpm pool settings. I spent a lot of time playing with includes because most of the fastcgi params are the same for all my pools, but in the end was afraid that if I veer too much from stock centminmod php.conf file, it'll be too hard to diff when new changes happen. So I just created full copies of php.conf except with different port numbers.

    Using Ansible, it was really easy to create a playbook that I could pass in a pool name and port and it would create the pool. I also added variables for the type of pool (static/dynamic/ondemand), max servers, etc and gave them sane defaults so they're optional.

    I already have playbooks for each of my domains, so I just told the domain playbooks to call the php-fpm_pools playbook as many times as needed (one for each wordpress/xenforo install), passing in the pool name and port number.

    Thanks again @eva2000 for all your help. If anyone's interested, happy to share my code.

    And again, I can't recommend Ansible highly enough... it was very fast to get productive initially, and the deeper I go, the more I realize all the ways it lets you reuse deploy code across multiple apps/domains without repeating yourself. Plus having everyone scripted is so much better than having it written down in a "notes on building a new server" file. :-D
     
  13. eva2000

    eva2000 Administrator Staff Member

    53,461
    12,128
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,668
    Local Time:
    1:07 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
  14. jeffwidman

    jeffwidman Active Member

    152
    27
    28
    Dec 3, 2014
    Ratings:
    +51
    Local Time:
    8:07 PM
    Thanks for the heads up @eva2000. Much obliged.