Create php-fpm process for selected users

dkzr

Verified User
Joined
Oct 17, 2013
Messages
88
Location
The Netherlands
I've found that one of the best ways to improve WordPress performance is to use OPCache. I've enabled this via custombuild and this works fine.

But:

Currently there is a php-fpm process per php version with pools per user.

And OPCache settings are per process, not per pool. So multiple users may share the OPCache cache. This also makes the OPCache memory settings hard to configure and users may get insight in other users php applications.

How could I configure a separate php-fpm process for selected users, ideally keeping DA PHP settings configured for this user or otherwise at least excluding this user from the "global" DA php-fpm processes (so it does not also start a pool for this user)?

I've found posts on how to create custom systemd processes for a user, also adding them to the DA services page. But for excluding such a user from de DA php-fpm I think there must be integration with current scripts?

Love to year your ideas!

PS.
I've already posted a DA feature request for this, Plesk has an option called Dedicated FPM which seems allow for this.
 
Have you looked at Custom HTTPD Configurations?
1751561197729.png

Then select the PHP-FPM of the domain you're editing from the list of domains

1751561281212.png
 
Yes, I did experiments there for OPCache. But since the OPCache settings are per process, not per pool, any configuration for one client may interfere with the configuration of another client.

It's quite unclear what setting takes precedence than.
 
I've done some testing myself and have come to a manual solution described below:

Dedicated PHP-FPM process for user with Apache​

Create a dedicated PHPv84 FPM instance for user testuser.

You can use the same recipe for other PHP versions and other users.

It's possible to have one user with different dedicated php-fpm versions but in this setup you can only have one dedicated php-fpm per version per user.

Create service template​

Use the example file attached to create /etc/systemd/system/[email protected]. It's based on the DA default php-fpm84.service.

This will allow you to create services for multiple users based on one template.

Create user directories & configurations​

I've choosen to use /usr/local/directadmin/data/users/testuser/dedicated-php-fpm/

You can use the example files attached to create:
  • /usr/local/directadmin/data/users/testuser/dedicated-php-fpm/php-fpm84.conf
  • /usr/local/directadmin/data/users/testuser/dedicated-php-fpm/php84/user.ini`

The php-fpm socket will be in the users homedir. So create a .php directory there. DA uses the same so it might already be there.

Code:
mkdir -p /home/testuser/.php

Start user service as root​

Call

Code:
systemctl enable --now php-fpm84@testuser

There should now be a socket file /home/testuser/.php/php-fpm84.sock

Add service to DA services.status​

Open /usr/local/directadmin/data/admin/services.status and add a line for your we service:

Code:
php-fpm84@testuser=ON

Disable PHP for user or domain in DA​

In your DA controlpanel you can (should) now disable PHP for your selected domain or for the user as a whole.

DA php takes precedence over this custom config.

Add custom HTTPD configuration for selected domain​


For each user domain you need your dedicated-fpm you should add the following modification to that sites CUSTOM3 HTTPD configuration.

It's taken from the default DA php configuration (with simplified FilesMatch)

Apache config:
<FilesMatch "\.php$">
    <If "-f %{REQUEST_FILENAME}">
        AddHandler "proxy:unix:/home/testuser/.php/php-fpm84.sock|fcgi://localhost" .php
    </If>
</FilesMatch>
<FilesMatch "\.php[578]\d$">
    Order Allow,Deny
    Deny from all
</FilesMatch>

(Wait for) Apache reload.

That's all ;)

Files​

It does not seem to be possible to attach .conf files, so here the come...

[email protected]

Code:
# php-fpm startup for DirectAdmin servers
# To alter the FPM environment, drop a file with the suffix
# .conf in /etc/systemd/system/php-fpm.service.d, with
#     [Service]
#     Environment=FOO=bar
# To reload systemd daemon after changes to this file:
# systemctl --system daemon-reload

[Unit]
Description=The PHP FastCGI Process Manager for %i
After=syslog.target network.target

[Service]
Type=notify

# Set PHP_INI_SCAN_DIR Envirionment variable.
# String starts with a colon (:) to create empty entry so that php-fpm will also parse --with-config-file-scan-dir compile option location.
Environment="PHP_INI_SCAN_DIR=:/usr/local/directadmin/data/users/%i/dedicated-php-fpm/php84"

# Added --fpm-config option.
ExecStart=/usr/local/php84/sbin/php-fpm --nodaemonize --fpm-config /usr/local/directadmin/data/users/%i/dedicated-php-fpm/php-fpm84.conf

ExecReload=/bin/kill -USR2 $MAINPID
LimitMEMLOCK=infinity
LimitNOFILE=65535

# Set up a new file system namespace and mounts private /tmp and /var/tmp directories
# so this service cannot access the global directories and other processes cannot
# access this service's directories.
PrivateTmp=true

# Sets up a new /dev namespace for the executed processes and only adds API pseudo devices
# such as /dev/null, /dev/zero or /dev/random (as well as the pseudo TTY subsystem) to it,
# but no physical devices such as /dev/sda.
# CageFS does not work with php-fpm on DirectAdmin servers. The issue is caused by this directive set to true, thus, commented out
#PrivateDevices=true

# Attempts to create memory mappings that are writable and executable at the same time,
# or to change existing memory mappings to become executable are prohibited.

# Commented out, problems with PHP 7.0/7.1 reported
#MemoryDenyWriteExecute=true

# Explicit module loading will be denied. This allows to turn off module load and unload
# operations on modular kernels. It is recommended to turn this on for most services that
# do not need special file systems or extra kernel modules to work.
ProtectKernelModules=true

# Kernel variables accessible through /proc/sys, /sys, /proc/sysrq-trigger, /proc/latency_stats,
# /proc/acpi, /proc/timer_stats, /proc/fs and /proc/irq will be made read-only to all processes
# of the unit. Usually, tunable kernel variables should only be written at boot-time, with the
# sysctl.d(5) mechanism. Almost no services need to write to these at runtime; it is hence
# recommended to turn this on for most services.
ProtectKernelTunables=true

# Required for resource throttling
ProtectControlGroups=false

# Any attempts to enable realtime scheduling in a process of the unit are refused.
RestrictRealtime=true

# Restricts the set of socket address families accessible to the processes of this unit.
# Protects against vulnerabilities such as CVE-2016-8655
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX

# Takes away the ability to create or manage any kind of namespace
#RestrictNamespaces=true

[Install]
WantedBy=multi-user.target

User php-fpm84.conf​

Code:
[global]
error_log = log/php-fpm.log

; syslog_facility is used to specify what type of program is logging the
; message. This lets syslogd specify that messages from different facilities
; will be handled differently.
; See syslog(3) for possible values (ex daemon equiv LOG_DAEMON)
; Default Value: daemon
;syslog.facility = daemon

; syslog_ident is prepended to every message. If you have multiple FPM
; instances running on the same server, you can change the default value
; which must suit common needs.
; Default Value: php-fpm
;syslog.ident = php-fpm

; Log level
; Possible Values: alert, error, warning, notice, debug
; Default Value: notice
log_level = notice

;;;;;;;;;;;;;;;;;;;
; Pool Definition ;
;;;;;;;;;;;;;;;;;;;

[testuser]
; Pool settings taken from default DA user php-fpm conf
user = $pool
group = $pool
listen = /home/$pool/.php/php-fpm84.sock
listen.owner = $pool
listen.group = apache
listen.mode = 660
pm = ondemand
pm.max_children = 30
pm.process_idle_timeout = 20
pm.max_requests = 500

; Set From e-mail address
php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f [email protected]

php_admin_value[session.save_path] = /home/$pool/tmp

; Modify as needed
php_admin_value[open_basedir] = /home/$pool/:/tmp/:/var/tmp/:/opt/alt/php81/usr/share/pear/:/dev/urandom:/usr/local/php84/lib/:/usr/local/php81/lib/:/usr/local/php82/lib/:/usr/local/php83/lib/:/usr/local/php84/lib/:/usr/local/php74/lib/:/usr/local/php80/lib/:/usr/local/lib/php/

php_admin_value[mail.log] = /home/$pool/.php/php-mail.log

; Modify as needed, DA default currently is ".php .php52 .php53 .php54 .php55 .php56 .php60 .php70 .php71 .phtml .inc .php84"
security.limit_extensions = .php

; All below taken from [webapps] DA pool
;pm.status_path = /status
;ping.path = /ping
;ping.response = pong

;access.log = log/$pool.access.log
;access.format = "%R - %u %t \"%m %r%Q%q\" %s %f %{mili}d %{kilo}M %C%%"
;slowlog = log/$pool.log.slow
;request_slowlog_timeout = 0
;request_terminate_timeout = 30s
 
; Pass environment variables like LD_LIBRARY_PATH. All $VARIABLEs are taken from
; the current environment.
; Default Value: clean env
;env[HOSTNAME] = $HOSTNAME
;env[PATH] = /usr/local/bin:/usr/bin:/bin
;env[TMP] = /tmp
;env[TMPDIR] = /tmp
;env[TEMP] = /tmp

;php_flag[display_errors] = off
;php_admin_value[error_log] = /var/log/fpm-php.www.log
;php_admin_flag[log_errors] = on
;php_admin_value[memory_limit] = 32M
;php_admin_value[open_basedir] = /tmp:/var/tmp:/var/www/html:/usr/local/php84/lib/php

User php settings user.ini​

Code:
; Any php.ini directives you need for your user
; In my setup, I've disabeld opcache globally and only enable it selectively
opcache.enable=1
 
Last edited:
Glad you got that sorted @dkzr . Looks like a nice little workaround. I will have to try that above a little later on. The latest version (8.13) of WHMCS is out and PHP 8.3 ready now, but it requires opcache to be disabled as it's known to cause problems. I want to be able to turn it off for WHMCS and keep it on for Wordpress.

Quick edit: link about opcache and WHMCS problems here in case anyone's interested or affected.

 
Alternatively... and maybe this doesn't do the same thing. But you can add the opcache_ functions to PHP's disable_function list and then users can't read OpCache information.

Just a thought.
 
Glad you got that sorted @dkzr . Looks like a nice little workaround. I will have to try that above a little later on. The latest version (8.13) of WHMCS is out and PHP 8.3 ready now, but it requires opcache to be disabled as it's known to cause problems. I want to be able to turn it off for WHMCS and keep it on for Wordpress.

Quick edit: link about opcache and WHMCS problems here in case anyone's interested or affected.

Disabling OPCache selectively is easier than enabling selectively. Just add opcache.enable=0 to your .user.ini in your public_html
 
Back
Top