How to Configure Nginx for PHP-FPM on Fedora

Nginx and PHP-FPM together create a high-performance stack for serving dynamic PHP content. Nginx handles static files and request routing efficiently, while PHP-FPM (FastCGI Process Manager) manages PHP script execution through a separate process pool. This separation allows each component to be optimized independently, making the combination ideal for hosting WordPress sites, Laravel applications, or any PHP-based web project.

This guide walks through configuring Nginx to communicate with PHP-FPM on Fedora. You will adjust the PHP-FPM pool settings to run under the correct user, verify the socket permissions, create a working server block, and test the complete integration. By the end, your server will be ready to process PHP requests.

Prerequisites

Before configuring the integration, you need both Nginx and PHP-FPM installed on your system. If you have not installed them yet, follow these guides first:

Once both packages are installed, verify they are available on your system:

nginx -v
php-fpm -v

Expected output confirming both are installed:

nginx version: nginx/1.x.x
PHP 8.x.x (fpm-fcgi) (built: ...)
Copyright (c) The PHP Group
Zend Engine v4.x.x, Copyright (c) Zend Technologies

Understand the Default Configuration

Fedora ships with pre-configured integration files that simplify the Nginx and PHP-FPM connection. Before making changes, it helps to understand what exists by default so you can avoid unnecessary modifications.

PHP-FPM Pool Configuration

The main PHP-FPM pool configuration file is located at /etc/php-fpm.d/www.conf. Check the current user and group settings:

grep -E '^(user|group)' /etc/php-fpm.d/www.conf

Default output on a fresh installation:

user = apache
group = apache

By default, PHP-FPM runs as the apache user because the package was historically designed for Apache HTTP Server. However, since Nginx runs as the nginx user, you need to change these settings to ensure proper file permissions and ownership.

Socket Permissions

PHP-FPM communicates with Nginx through a Unix socket. Check the socket configuration:

grep -E '^listen' /etc/php-fpm.d/www.conf

Expected output:

listen = /run/php-fpm/www.sock
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1

Fedora already includes nginx in the listen.acl_users directive, which grants Nginx permission to connect to the PHP-FPM socket. This means you do not need to modify socket ownership or permissions.

Pre-configured Nginx Integration Files

Additionally, Fedora provides ready-to-use configuration files for Nginx and PHP-FPM integration. First, check the upstream definition file:

cat /etc/nginx/conf.d/php-fpm.conf

Expected output showing the upstream definition:

# PHP-FPM FastCGI server
# network or unix domain socket configuration

upstream php-fpm {
        server unix:/run/php-fpm/www.sock;
}

This file defines a named upstream called php-fpm that points to the Unix socket. Next, examine the default PHP handler configuration:

cat /etc/nginx/default.d/php.conf

Expected output showing the location block for PHP files:

# pass the PHP scripts to FastCGI server
#
# See conf.d/php-fpm.conf for socket configuration
#
index index.php index.html index.htm;

location ~ \.(php|phar)(/.*)?$ {
    fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;

    fastcgi_intercept_errors on;
    fastcgi_index  index.php;
    include        fastcgi_params;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO $fastcgi_path_info;
    fastcgi_pass   php-fpm;
}

These pre-configured files mean the default Nginx server block already supports PHP. As a result, the only required change is updating the PHP-FPM user and group settings.

Configure PHP-FPM for Nginx

Open the PHP-FPM pool configuration file in your preferred text editor:

sudo nano /etc/php-fpm.d/www.conf

Locate the user and group directives near the top of the file (around lines 24-26) and change them from apache to nginx:

Before:

user = apache
group = apache

After:

user = nginx
group = nginx

Save the file and exit the editor. If using nano, press Ctrl+O to save, then Ctrl+X to exit.

Changing the user and group ensures PHP-FPM worker processes run with the same permissions as Nginx. This prevents ownership conflicts when PHP scripts create or modify files in your web directories.

Alternatively, use sed to make these changes without opening an editor:

sudo sed -i 's/^user = apache/user = nginx/' /etc/php-fpm.d/www.conf
sudo sed -i 's/^group = apache/group = nginx/' /etc/php-fpm.d/www.conf

Verify the changes took effect:

grep -E '^(user|group)' /etc/php-fpm.d/www.conf

Expected output confirming the new settings:

user = nginx
group = nginx

Enable and Start Services

With the configuration changes complete, enable both services to start automatically at boot and start them now:

sudo systemctl enable --now nginx php-fpm

If the services were already running, restart them to apply the configuration changes:

sudo systemctl restart nginx php-fpm

Verify both services are running:

systemctl status nginx php-fpm --no-pager

Expected output showing both services active:

● nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: disabled)
     Active: active (running) since ...; Xs ago
   Main PID: XXXX (nginx)
      Tasks: 3 (limit: 4652)
     Memory: 5.2M
        CPU: 25ms
     CGroup: /system.slice/nginx.service
             ├─XXXX "nginx: master process /usr/sbin/nginx"
             └─XXXX "nginx: worker process"

● php-fpm.service - The PHP FastCGI Process Manager
     Loaded: loaded (/usr/lib/systemd/system/php-fpm.service; enabled; preset: disabled)
     Active: active (running) since ...; Xs ago
   Main PID: XXXX (php-fpm)
     Status: "Processes active: 0, idle: 5, Requests: 0, slow: 0, Traffic: 0req/sec"
      Tasks: 6 (limit: 4652)
     Memory: 12.5M
        CPU: 45ms
     CGroup: /system.slice/php-fpm.service
             ├─XXXX "php-fpm: master process (/etc/php-fpm.conf)"
             └─XXXX "php-fpm: pool www"

Test the PHP Integration

To confirm the configuration is valid, test the Nginx syntax:

sudo nginx -t

Expected output confirming the configuration is correct:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Next, create a PHP info file to verify the complete stack is working. This file displays PHP configuration details and confirms Nginx is correctly passing requests to PHP-FPM:

echo "<?php phpinfo(); ?>" | sudo tee /usr/share/nginx/html/info.php

Test the file from the command line using curl:

curl -s http://localhost/info.php | head -20

Expected output showing PHP information (HTML formatted):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<style type="text/css">
body {background-color: #fff; color: #222; font-family: sans-serif;}
...
<title>PHP 8.x.x - phpinfo()</title>

If you see HTML output containing PHP version information, the integration is working correctly. You can also open http://your-server-ip/info.php in a web browser to see the full PHP info page.

Security note: Remove the info.php file after testing. The phpinfo() output exposes sensitive server configuration details that attackers could exploit.

sudo rm /usr/share/nginx/html/info.php

Configure Firewall Rules

If you are running firewalld (Fedora’s default firewall), you need to allow HTTP and HTTPS traffic. First, check if firewalld is active:

sudo firewall-cmd --state

If the firewall is running, add the HTTP and HTTPS services:

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Verify the rules were added:

sudo firewall-cmd --list-services

Expected output showing HTTP and HTTPS in the list:

cockpit dhcpv6-client http https ssh

SELinux Considerations

Fedora has SELinux enabled and enforcing by default, which provides an additional layer of security. In most cases, the default SELinux policies allow Nginx and PHP-FPM to work correctly. However, if your PHP application needs to perform certain actions like connecting to databases or sending emails, you may encounter permission denials.

Check if SELinux is blocking anything. If the ausearch command is not found, install the audit package first with sudo dnf install audit:

sudo ausearch -m avc -ts recent 2>/dev/null | grep -E 'nginx|php-fpm' | tail -5

If you see AVC denial messages related to Nginx or PHP-FPM, common solutions include:

Allow Nginx to connect to backend services (databases, external APIs):

sudo setsebool -P httpd_can_network_connect 1

Allow PHP to send emails:

sudo setsebool -P httpd_can_sendmail 1

Allow PHP to connect to databases:

sudo setsebool -P httpd_can_network_connect_db 1

Only enable the SELinux booleans your application actually requires. Each enabled boolean slightly reduces the security boundary that SELinux provides.

Create a Custom Server Block

While the default Nginx configuration works for testing, production sites typically use custom server blocks with their own document roots. The following example demonstrates a complete server block for hosting a PHP site:

sudo nano /etc/nginx/conf.d/example.conf

Add the following configuration, replacing example.com with your domain:

server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    root /var/www/example.com/html;

    index index.php index.html index.htm;

    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }
}

This configuration includes:

  • try_files in root location: Enables clean URLs for frameworks like WordPress and Laravel
  • try_files $uri =404 in PHP location: Returns 404 for non-existent PHP files instead of passing them to PHP-FPM
  • Deny .ht files: Blocks access to .htaccess and other Apache configuration files that may exist

Create the document root directory and set proper ownership:

sudo mkdir -p /var/www/example.com/html
sudo chown -R nginx:nginx /var/www/example.com

Set the correct SELinux context for web content. If the semanage command is not found, install it first with sudo dnf install policycoreutils-python-utils:

sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example.com(/.*)?"
sudo restorecon -Rv /var/www/example.com

Test the configuration and reload Nginx:

sudo nginx -t && sudo systemctl reload nginx

Troubleshooting Common Issues

502 Bad Gateway Error

This error typically means Nginx cannot connect to PHP-FPM. Check if PHP-FPM is running:

systemctl status php-fpm

If PHP-FPM is running, verify the socket exists and has correct permissions:

ls -la /run/php-fpm/www.sock

Expected output:

srw-rw----+ 1 root root 0 ... /run/php-fpm/www.sock

The + at the end indicates ACL permissions are set. To verify nginx is in the ACL, use getfacl (install with sudo dnf install acl if needed):

getfacl /run/php-fpm/www.sock

File Not Found or Blank Page

If PHP files return 404 or blank pages, check:

  1. Document root: Verify the root directive in your server block points to the correct directory
  2. File ownership: Ensure files are owned by the nginx user: ls -la /var/www/yoursite/
  3. PHP-FPM error log: Check for errors in /var/log/php-fpm/www-error.log
  4. Nginx error log: Check /var/log/nginx/error.log for request processing errors

Permission Denied Errors

If you see “Permission denied” in logs, SELinux may be blocking access. Check the audit log:

sudo ausearch -m avc -ts recent | tail -20

If denials appear, you can generate a policy to allow the specific action. The audit2allow command is part of the policycoreutils-python-utils package mentioned earlier:

sudo ausearch -m avc -ts recent | audit2allow -M mypolicy
sudo semodule -i mypolicy.pp

Conclusion

With PHP-FPM configured to run as the nginx user and the pre-configured integration files in place, your Fedora server can now process PHP requests through Nginx. The default configuration covers most use cases, while custom server blocks allow you to host multiple PHP sites with their own document roots and settings. For production environments, consider adding SSL certificates with Let’s Encrypt, enabling gzip compression for better performance, and configuring security headers to protect your PHP applications. If you plan to deploy containerized PHP applications, explore our guide on installing Docker on Fedora.

Leave a Comment