When configuring PHP-FPM, many developers encounter this perplexing behavior: while listen.mode
changes take effect immediately, the listen.owner
and listen.group
directives seem completely ignored. The socket stubbornly remains owned by root:
$ ls -l /run/php-fpm/www.sock
srw-rw---- 1 root root 0 Jan 1 12:00 /run/php-fpm/www.sock
The root cause (pun intended) lies in systemd's interaction with PHP-FPM. Since most modern distributions use systemd to manage PHP-FPM, the service unit file overrides our socket permissions. Here's how to verify:
$ systemctl cat php-fpm.service
# Look for these critical directives:
[Service]
...
PrivateTmp=true
ProtectSystem=full
User=root
Group=root
1. Modify the systemd service file (Recommended)
Create an override file:
$ sudo systemctl edit php-fpm.service
Add these directives:
[Service]
User=ben
Group=ben
UMask=0007
2. Alternative: Change socket creation location
Move the socket to a directory where 'ben' has write permissions:
[www]
listen = /var/lib/php-fpm/www.sock
listen.owner = ben
listen.group = ben
listen.mode = 0660
3. Using a tmpfiles.d configuration
Create /etc/tmpfiles.d/php-fpm.conf
:
d /run/php-fpm 0770 ben ben -
Then apply changes:
$ sudo systemd-tmpfiles --create
After implementing any solution:
$ sudo systemctl restart php-fpm
$ ls -l /run/php-fpm/www.sock
srw-rw---- 1 ben ben 0 Jan 1 12:00 /run/php-fpm/www.sock
Systemd enforces strict security by default. The root ownership prevents privilege escalation vulnerabilities. While inconvenient for development, this design protects production systems where PHP-FPM might run multiple pools with different users.
When configuring PHP-FPM's socket file permissions, many developers encounter a puzzling situation where listen.owner
and listen.group
directives in www.conf
appear to have no effect. Despite explicit configuration:
[www]
listen = /run/php-fpm/www.sock
listen.owner = ben
listen.group = ben
listen.mode = 0660
The socket file stubbornly remains owned by root:root
after service restart.
Through testing, we can confirm these behaviors:
- Working:
listen.mode
changes take effect immediately - Working: Modifying
listen
path creates new socket with correct permissions - Not Working: Owner/group changes through config file alone
This occurs because PHP-FPM must be started as root to bind to privileged ports (<1024). The master process runs as root, while worker processes drop privileges. The socket file inherits ownership from the master process.
Three solutions exist:
Solution 1: Use systemd tmpfiles
# /etc/tmpfiles.d/php-fpm.conf
z /run/php-fpm/www.sock 0660 ben ben -
This ensures proper ownership before PHP-FPM starts.
Solution 2: Post-start chown
# In your systemd service unit
[Service]
ExecStartPost=/bin/chown ben:ben /run/php-fpm/www.sock
Solution 3: Run master as target user
Modify systemd unit (not recommended for production):
[Service]
User=ben
Group=ben
For production systems, the tmpfiles approach is most reliable. Here's complete implementation:
- Create tmpfiles configuration:
- Apply configuration:
- Restart PHP-FPM:
echo "z /run/php-fpm/www.sock 0660 ben ben -" | sudo tee /etc/tmpfiles.d/php-fpm.conf
sudo systemd-tmpfiles --create
sudo systemctl restart php-fpm
After this, your socket file should maintain correct ownership across reboots and service restarts.
Confirm the settings took effect:
$ ls -l /run/php-fpm/www.sock
srw-rw---- 1 ben ben 0 Jul 15 10:30 /run/php-fpm/www.sock