Skip to content
Search Fedora

    Browse this documentation

    nginx plus PHP-FPM on Fedora: from the default page to a working PHP 8.5 request

    Two packages are all you need for a web server on Fedora, and both are small:

    Terminal window
    sudo dnf install nginx php-fpm
    nginx version: nginx/1.30.5
    PHP 8.5.12 (fpm-fcgi) (built: Oct 19 2026 17:02:46) (NTS gcc x86_64)

    The nginx package itself is only 126.5 KiB; php-fpm comes as part of PHP.

    nginx handing PHP to php-fpm over a Unix socket, and the SELinux port label limit

    Terminal window
    sudo systemctl enable --now nginx php-fpm
    systemctl is-active nginx php-fpm
    active
    active

    nginx listens on 80 by default:

    Terminal window
    ss -lntp | grep :80
    LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
    LISTEN 0 511 [::]:80 [::]:*

    Fetch it:

    Terminal window
    curl -s http://127.0.0.1/ | grep -oE "Fedora|nginx" | head -2
    Fedora

    That is Fedora’s welcome page; the document root is /usr/share/nginx/html.

    php-fpm does not use TCP by default; it uses a Unix socket:

    Terminal window
    ss -lx | grep php
    /run/php-fpm/www.sock

    The pool config is /etc/php-fpm.d/www.conf:

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

    listen.acl_users already includes nginx — packaging deliberately grants the nginx process read/write on that socket, so you do not need to change ownership.

    Drop a server block in /etc/nginx/conf.d/ (this is the exact config that worked):

    server {
    listen 8008;
    server_name _;
    root /usr/share/nginx/html;
    index index.php index.html;
    location ~ \.php$ {
    fastcgi_pass unix:/run/php-fpm/www.sock;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
    }
    Terminal window
    sudo nginx -t
    sudo systemctl reload nginx
    nginx: configuration file /etc/nginx/nginx.conf test is successful

    Write a test file:

    Terminal window
    printf '<?php echo "PHP " . PHP_VERSION . " OK\n"; ?>' | \
    sudo tee /usr/share/nginx/html/demo.php >/dev/null

    Request it:

    Terminal window
    curl -s http://127.0.0.1:8008/demo.php
    PHP 8.5.12 OK

    That is the whole chain working: nginx → Unix socket → php-fpm 8.5.12.

    The trap: SELinux blocks non-standard ports

    Section titled “The trap: SELinux blocks non-standard ports”

    I first ran this server on 8081 — nginx -t passed, reload succeeded, and the page simply refused to load. The error log said:

    [emerg] bind() to 0.0.0.0:8081 failed (13: Permission denied)

    This is not file permissions but SELinux: nginx may only bind ports labelled http_port_t:

    Terminal window
    sudo semanage port -l | grep '^http_port_t'
    http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
    http_port_t udp 80, 443

    8081 is not in the list; 8008 is. So either move to an allowed port (changing to 8008 worked immediately) or add the label:

    Terminal window
    sudo semanage port -a -t http_port_t -p tcp 8081

    The default root is /usr/share/nginx/html; drop files there:

    Terminal window
    sudo cp -r mysite/* /usr/share/nginx/html/

    If the site lives elsewhere (say /srv/www), two things must change together:

    Terminal window
    # 1. SELinux label
    sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
    sudo restorecon -Rv /srv/www
    # 2. root in the nginx config

    Change root without the label and nginx returns 403 Forbidden — the file exists and is readable, but the SELinux context is wrong. See SELinux.

    The firewall opens only three services by default:

    Terminal window
    sudo firewall-cmd --list-services
    dhcpv6-client mdns ssh

    Allow HTTP:

    Terminal window
    sudo firewall-cmd --add-service=http --permanent
    sudo firewall-cmd --reload

    HTTPS is the same with --add-service=https. Details in firewalld.

    Terminal window
    sudo nginx -t # test config before reloading
    sudo systemctl reload nginx # graceful reload, no dropped connections
    sudo systemctl restart php-fpm # needed after php.ini or pool changes
    tail -f /var/log/nginx/error.log # first place to look
    tail -f /var/log/php-fpm/www-error.log

    The difference matters: reload keeps existing connections, so nginx config changes only need reload; php-fpm pool changes in www.conf need a restart.

    SymptomCause
    bind() ... (13: Permission denied)SELinux forbids the port; use an http_port_t port or semanage port -a
    PHP page returns 404missing fastcgi_param SCRIPT_FILENAME
    static file returns 403wrong SELinux context, not httpd_sys_content_t
    502 Bad Gatewayphp-fpm down, or the socket path is wrong
    config change has no effectforgot systemctl reload nginx
    unreachable from outsidefirewall does not allow http
    mangled non-ASCII pathscheck charset utf-8; and filesystem encoding