How to Configure Nginx for PHP-FPM on Fedora 44

Learn to configure Nginx with PHP-FPM on Fedora 44. Set up user permissions, socket connections, firewall rules, and SELinux policies.

Last updatedAuthorJoshua JamesRead time8 minGuide typeFedora

Pairing Nginx with PHP-FPM on Fedora gives PHP applications a fast front end for static files, routing, and TLS while a separate FastCGI worker pool executes PHP code. To configure Nginx with PHP-FPM on Fedora, use Fedora’s packaged socket integration first, then add a site-specific server block when the default test page is not enough.

Fedora’s PHP-FPM package keeps the default pool under an apache service account, but that does not mean Apache HTTP Server is required. The packaged socket access control list already grants the nginx user access, so most setups should verify the default integration before changing pool ownership.

Install and Verify Required Packages

If Nginx and PHP-FPM are not installed yet, install the Fedora packages with DNF. For a longer package walkthrough, use the companion guides to install Nginx on Fedora and install PHP on Fedora.

sudo dnf install nginx php-fpm

Check that both packages are present. This is the quickest answer to “check if PHP-FPM is installed” on Fedora because it confirms the RPM packages, not only a command in your shell path.

rpm -q nginx php-fpm

Relevant output includes package names and Fedora build numbers:

nginx-1.30.0-1.fc44.x86_64
php-fpm-8.5.6-1.fc44.x86_64

Confirm the service binaries respond as expected:

nginx -v
php-fpm -v

Version numbers change as Fedora publishes updates, but the output should identify Nginx and PHP-FPM:

nginx version: nginx/1.30.0
PHP 8.5.6 (fpm-fcgi)

Understand How Nginx and PHP-FPM Work Together

Nginx and PHP-FPM do different jobs. Nginx accepts HTTP requests, serves static files, and decides which requests need PHP processing. PHP-FPM listens separately and runs PHP scripts through a worker pool. The Nginx FastCGI configuration connects those two pieces by sending PHP requests to the PHP-FPM socket.

  • Nginx: Handles the client connection, static files, virtual host routing, and reverse-proxy style request handling.
  • PHP-FPM: Runs PHP code through managed worker processes instead of embedding PHP inside the web server.
  • FastCGI socket: Provides the local handoff point between Nginx and PHP-FPM, normally /run/php-fpm/www.sock on Fedora.

Inspect Fedora’s Default PHP-FPM Socket

The main PHP-FPM pool file is /etc/php-fpm.d/www.conf. Start with a read-only check so you can confirm the active pool and socket lines without changing the file. The grep command in Linux filters the file to the directives that matter for this connection.

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

A Fedora 44 package install currently reports these lines:

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

The important line is listen.acl_users = apache,nginx. It gives the nginx service account permission to connect to the PHP-FPM Unix socket while PHP scripts still run as the Fedora package’s default apache worker account.

Open the pool file only when you intentionally need to change pool settings:

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

Do not change user and group just because the account is named apache. Change the pool user only when your site’s file ownership model requires it, then update writable directories and SELinux labels to match the new worker account.

After PHP-FPM starts, verify that the socket exists and that Nginx has access through an ACL entry. If getfacl is not found, install the acl package.

sudo systemctl start php-fpm
ls -l /run/php-fpm/www.sock
getfacl -p /run/php-fpm/www.sock

In the ls output, the socket mode should end with a +, which marks extended ACLs. In the getfacl output, look for this Nginx ACL entry:

user:nginx:rw-

Inspect Fedora’s Nginx PHP-FPM Snippets

Fedora’s Nginx package includes a PHP-FPM upstream definition under /etc/nginx/conf.d/ and a reusable PHP location snippet under /etc/nginx/default.d/. The upstream definition should point at the same Unix socket that PHP-FPM creates:

sudo cat /etc/nginx/conf.d/php-fpm.conf
# PHP-FPM FastCGI server
# network or unix domain socket configuration

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

Review the packaged PHP handler as well:

sudo cat /etc/nginx/default.d/php.conf
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;
}

The default Fedora Nginx server includes files from /etc/nginx/default.d/*.conf, so the stock test site can process PHP after both services are running. Custom server blocks need their own PHP location block or an explicit include for the packaged snippet.

Start and Restart Nginx and PHP-FPM

Enable both services to start at boot and start them now:

sudo systemctl enable --now php-fpm nginx

Check the runtime state with the narrow service probe. A healthy pair returns one active line per service:

systemctl is-active php-fpm nginx
active
active

Restart PHP-FPM after changing pool settings or PHP extensions. Reload Nginx after a successful syntax check when only Nginx configuration changed:

sudo systemctl restart php-fpm
sudo nginx -t && sudo systemctl reload nginx

Test PHP-FPM Through the Default Nginx Site

Run the Nginx syntax check before testing a browser request:

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

Create a small PHP test file in Fedora’s default Nginx web root. The sudo tee pattern writes to a root-owned path, while > /dev/null hides the echoed file body from your terminal.

sudo tee /usr/share/nginx/html/lc-php-test.php > /dev/null <<'EOF'
<?php echo "PHP-FPM OK\n"; ?>
EOF

Probe the local response with the curl command in Linux. The -f flag fails on HTTP errors, and -sS keeps normal output quiet while still showing errors.

curl -fsS http://127.0.0.1/lc-php-test.php
PHP-FPM OK

Remove the test file after the check so the default site does not expose a leftover diagnostic endpoint:

sudo rm -f /usr/share/nginx/html/lc-php-test.php

Create a Custom Nginx Server Block for PHP-FPM

Production PHP sites usually use their own document root, access log, error log, and server name. Fedora’s Nginx package loads custom virtual host files from /etc/nginx/conf.d/*.conf, so place one file there for each site.

Create the document root and add a temporary PHP index file for the first response test:

sudo mkdir -p /var/www/example.com/html
sudo tee /var/www/example.com/html/index.php > /dev/null <<'EOF'
<?php echo "custom PHP-FPM OK\n"; ?>
EOF

Install the SELinux management tool if semanage is not already available, then label the site path as web content. The conditional keeps the command reusable: it updates the rule if it already exists and creates it when it does not.

sudo dnf install policycoreutils-python-utils
if sudo semanage fcontext -l | grep -Fq '/var/www/example.com(/.*)?'; then
    sudo semanage fcontext -m -t httpd_sys_content_t "/var/www/example.com(/.*)?"
else
    sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/example.com(/.*)?"
fi
sudo restorecon -Rv /var/www/example.com

Create the server block, replacing example.com with your real domain:

sudo nano /etc/nginx/conf.d/example.com.conf
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|phar)(/.*)?$ {
        fastcgi_split_path_info ^(.+\.(?:php|phar))(/.*)$;
        try_files $fastcgi_script_name =404;
        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;
    }

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

This server block keeps application routing in the root location, passes only existing PHP or PHAR files to PHP-FPM, and uses Fedora’s packaged php-fpm upstream. The try_files $fastcgi_script_name =404 line prevents non-existent PHP paths from being handed to PHP-FPM.

Test the configuration, reload Nginx, and probe the virtual host locally before changing DNS or public firewall rules. The --resolve option maps example.com to loopback for this one request, so the check reaches the named server block even before public DNS points at the server.

sudo nginx -t
sudo systemctl reload nginx
sleep 1
curl -fsS --resolve example.com:80:127.0.0.1 http://example.com/
custom PHP-FPM OK

Allow PHP to Write to Application Directories

Keep most web files read-only to the PHP worker. When an application needs writable directories, such as framework cache folders or upload paths, assign those specific directories to the PHP-FPM worker account shown in /etc/php-fpm.d/www.conf. With Fedora’s default pool, that account is apache.

sudo mkdir -p /var/www/example.com/html/{storage,cache}
sudo chown -R apache:apache /var/www/example.com/html/storage /var/www/example.com/html/cache
if sudo semanage fcontext -l | grep -Fq '/var/www/example.com/html/(storage|cache)(/.*)?'; then
    sudo semanage fcontext -m -t httpd_sys_rw_content_t "/var/www/example.com/html/(storage|cache)(/.*)?"
else
    sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/example.com/html/(storage|cache)(/.*)?"
fi
sudo restorecon -Rv /var/www/example.com/html/storage /var/www/example.com/html/cache

If you intentionally changed the PHP-FPM pool to run as nginx, use nginx:nginx for those writable directories instead. Keep the ownership model consistent with the worker account, not with the public-facing web server by habit.

Open Firewall Access for HTTP and HTTPS

Fedora uses firewalld by default on standard installations. If the server needs to accept traffic from other machines, confirm firewalld is running and allow the HTTP and HTTPS service definitions. For a broader firewall walkthrough, see how to install and configure firewalld on Fedora.

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

Verify that both services are allowed in the active zone:

sudo firewall-cmd --query-service=http
sudo firewall-cmd --query-service=https
yes
yes

Handle SELinux for PHP-FPM Applications

Fedora enables SELinux in enforcing mode by default. The standard Nginx and PHP-FPM package paths work with the default policy, but custom document roots, writable directories, outbound API calls, database connections, or mail delivery may require specific SELinux labels or booleans.

Check the common HTTPD booleans before enabling anything:

getsebool httpd_can_network_connect httpd_can_network_connect_db httpd_can_sendmail
httpd_can_network_connect --> off
httpd_can_network_connect_db --> off
httpd_can_sendmail --> off

Run only the command that matches the access your application actually needs:

# External APIs or other outbound network calls
sudo setsebool -P httpd_can_network_connect on

# Network database connections
sudo setsebool -P httpd_can_network_connect_db on

# Local sendmail access
sudo setsebool -P httpd_can_sendmail on

Each SELinux boolean widens what web server processes can do. Enable the network, database, or mail boolean only after the application needs that access and a log check confirms SELinux is the blocking layer.

When requests fail with permission messages, inspect recent AVC denials. Install audit first if the command is missing:

sudo dnf install audit
sudo ausearch -m avc -ts recent | grep -E 'nginx|php-fpm|httpd_t' | tail

Prefer the narrow fix first: restore the file context, label a custom path, or enable the specific boolean. Avoid generating a broad local policy until you understand the denial and have ruled out path labels and standard booleans.

Troubleshoot Nginx and PHP-FPM Errors

Fix 502 Bad Gateway from PHP-FPM

A 502 response usually means Nginx cannot reach PHP-FPM or PHP-FPM rejected the FastCGI handoff. Start with the service state and socket permissions:

systemctl is-active php-fpm nginx
ls -l /run/php-fpm/www.sock
getfacl -p /run/php-fpm/www.sock

The service check should return active for both units, and the ACL output should include user:nginx:rw-. If the socket is missing, restart PHP-FPM. If the ACL entry is missing, recheck listen.acl_users in /etc/php-fpm.d/www.conf and restart PHP-FPM after correcting it. For a wider Nginx diagnostic path, use the fix Nginx 502 Bad Gateway guide.

Fix PHP Downloading as Text

If the browser downloads PHP files or displays raw PHP source, Nginx is serving the file as static content instead of passing it to PHP-FPM. Confirm that the active configuration includes a PHP location block and the fastcgi_pass php-fpm; directive:

sudo nginx -T | grep -E 'default.d/php.conf|fastcgi_pass|php-fpm'

If your custom server block does not include the packaged snippet, copy the PHP location block from this article into that server block, then run sudo nginx -t and reload Nginx.

Fix File Not Found or Blank PHP Pages

A 404, blank page, or PHP-FPM “Primary script unknown” entry usually points to the wrong document root, missing file, or bad SCRIPT_FILENAME value. Check the site file, PHP-FPM log, and Nginx error log together. The tail command in Linux keeps each log read focused on recent entries.

sudo nginx -T | grep -E 'server_name|root |SCRIPT_FILENAME'
sudo tail -n 40 /var/log/php-fpm/www-error.log
sudo tail -n 40 /var/log/nginx/example.com.error.log

The root directive must point to the directory that contains the PHP file, and SCRIPT_FILENAME should use $document_root$fastcgi_script_name. If Nginx returns a plain 404 for every route, review the site-specific routing pattern or use the fix Nginx 404 Not Found checklist.

Fix SELinux Permission Denials

If logs show “Permission denied” and normal Unix ownership looks correct, restore labels on the document root and check recent SELinux denials:

sudo restorecon -Rv /var/www/example.com
sudo ausearch -m avc -ts recent | tail -20

For custom writable directories, use httpd_sys_rw_content_t only on the paths PHP must write to. Do not label the whole site writable unless the application truly needs that broad access.

Remove the Example Site or PHP-FPM Stack

Remove only the example virtual host when you are keeping Nginx and PHP-FPM for other sites:

The cleanup commands delete the example server block and its document root. Replace example.com with the real test path, and do not run the recursive remove command against a production site that contains data you need.

sudo rm -f /etc/nginx/conf.d/example.com.conf
sudo rm -rf /var/www/example.com
sudo semanage fcontext -d "/var/www/example.com/html/(storage|cache)(/.*)?" 2>/dev/null || true
sudo semanage fcontext -d "/var/www/example.com(/.*)?" 2>/dev/null || true
sudo nginx -t && sudo systemctl reload nginx

If this was only a temporary lab server and you want to remove the web stack as well, stop the services first, then remove the packages:

sudo systemctl disable --now nginx php-fpm
sudo dnf remove nginx php-fpm

If you opened HTTP and HTTPS only for this temporary stack, close those firewalld services after removing the site:

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

If you enabled SELinux booleans only for this application, turn those specific booleans off after confirming no other web application still needs them:

sudo setsebool -P httpd_can_network_connect off
sudo setsebool -P httpd_can_network_connect_db off
sudo setsebool -P httpd_can_sendmail off

DNF may preserve modified configuration files as RPM save files. Review any remaining files under /etc/nginx/, /etc/php-fpm.d/, and your web roots before deleting them manually.

Conclusion

Nginx now passes PHP requests to PHP-FPM through Fedora’s packaged Unix socket, with service checks, a site-specific server block, SELinux labels, and rollback commands in place. From here, harden the virtual host with configure security headers in Nginx or improve response size with enable gzip compression in Nginx before exposing the site to real traffic.

Share this guide

Help another Linux user troubleshoot faster

Share this guide with someone troubleshooting Linux systems or saving it for later.

Follow LinuxCapable

Want more LinuxCapable guides in Google?

Add LinuxCapable as a preferred source so Google can show more of our fresh Linux tutorials in Top Stories and From your sources when relevant.

Add LinuxCapable as a preferred source on Google
Search LinuxCapable

Need another guide?

Search LinuxCapable for package installs, commands, troubleshooting, and follow-up guides related to what you just read.

Found this guide useful?

Support LinuxCapable to keep tutorials free and up to date.

Buy me a coffeeBuy me a coffee
Before commenting, please review our Comments Policy.
Formatting tips for your comment

You can use basic HTML to format your comment. Useful tags currently allowed in published comments:

You type Result
<code>command</code> command
<strong>bold</strong> bold
<em>italic</em> italic
<blockquote>quote</blockquote> quote block

Got a Question or Feedback?

We read and reply to every comment - let us know how we can help or improve this guide.

Verify before posting: