Score:0

What is the proper value of "fastcgi_split_path_info" in Nginx virtual host when using php 7.4 with "cgi.fix_pathinfo = 1" on Nginx v1.25.1 Mainline?

mx flag

BACKGROUND: I am running a LEMP server with Ubuntu Server 20.04 with Nginx v1.25.1 Mainline and php7.4-fpm. In my virtual hosts file I am trying to set the proper and working fastcgi_split_path_info in the location ~ \.php$ { directive, but I'm not sure exactly what to put as the value, and I don't think my current fastcgi_split_path_info is correct.

NOTE: Instead of using "try_files $fastcgi_script_name =404", I am using the "if" statement

if (!-f $document_root$fastcgi_script_name) {
    return 404;
}

recommended by Nginx.org. I'm not sure if this matters when splitting fastcgi path info, but it should be noted just in case.

NOTE2: I am using cgi.fix_pathinfo = 1 (which is the default for PHP 7.4) in my php.ini file.

QUESTION: Could someone please take a look at my Nginx Virtual host and tell me the correct value that I should put for fastcgi_split_path_info in location ~\.php$?

Below is my Nginx virtual host example.com.conf

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen *:443 ssl;
    http2 on;
    server_name example.com www.example.com;
    root /var/www/example.com/;

    ##
    # SECURITY HEADERS
    ##

    # Strict Transport Security Response Header
    # Use "always" Paramater to help prevent MITM attacks.
    # ADMIN Note: Including the Preload Paramerter will cause web browsers to cache this header
    # permanently in their browser code for about two months. Use only if you want to permanently
    # commit this header to your site. If you change it, it will take a long time for changes to
    # be reflected in the web browsers.
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;

    # Content Security Policy (CSP)
    #add_header Content-Security-Policy "frame-ancestors 'self';";
    # https://gabriel.nu/tutorials/Ubuntu-20.04-NGINX-LEMP-secure-web-server-for-WordPress-DIY.html
    add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
    #add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'";
    # https://walterebert.com/blog/using-csp-wordpress/
    #add_header Content-Security-Policy "default-src 'self'; img-src 'self' data: http: https: *.gravatar.com; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline' http: https: fonts.googleapis.com; font-src 'self' data: http: https: fonts.googleapis.com themes.googleusercontent.com;" always;
    # https://nowherelan.com/2018/12/27/secure-your-wordpress-site-with-the-content-security-policy-csp-http-header-in-apache/
    #add_header Content-Security-Policy "default-src 'self'; img-src 'self' data: http: https: *.gravatar.com *.wp.com *.wordpress.com; script-src 'self' 'unsafe-inline' 'unsafe-eval' http: https: *.wp.com *.wordpress.com; style-src 'self' 'unsafe-inline' http: https: fonts.googleapis.com *.wp.com *.wordpress.com; font-src 'self' data: http: https: fonts.googleapis.com themes.googleusercontent.com *.wp.com *.wordpress.com; frame-src 'self' 'unsafe-inline' 'unsafe-eval' http: https: *.wp.com *.wordpress.com"

    # Secure MIME Types with X-Content-Type-Options. Below line adds the X-Frame-Options header in Nginx.
    add_header X-Content-Type-Options "nosniff" always;

    # Referrer Policy
    #add_header Referrer-Policy "strict-origin";
    # https://gabriel.nu/tutorials/Ubuntu-20.04-NGINX-LEMP-secure-web-server-for-WordPress-DIY.html
    add_header Referrer-Policy "no-referrer-when-downgrade" always;

    # Permissions Policy
    add_header Permissions-Policy "geolocation=(), autoplay=(), encrypted-media=(), midi=(), usb=(), sync-xhr=(), microphone=(), camera=(), magnetometer=(), gyroscope=(), fullscreen=(self), payment=(self)";

    # X-FastCGI-Cache
    # This line adds the X-FastCGI-Cache header in the HTTP response. It can be used to validate whether
    # the request has been served from the FastCGI cache or not.
    # ADMIN Note: Linuxbabe originally had this directive in "location ~ \.php$ {", however, we don't use it
    # there because it invalidates any other currently used headers and only implements itself.
    add_header X-FastCGI-Cache $upstream_cache_status always;

    # Clear Site Data
    # When we use a webpage, we can leave various pieces of data in the browser that we’d like to clear
    # out if the user logs out or deletes their account. Clear Site Data gives us a reliable way to do
    # that.
    # ADMIN Note: We decided to enable it globally on all pages via:
    add_header Clear-Site-Data "*";

    # X-Frame Options
    # Prevent click jacking by adding an X-Frame-Options header
    add_header x-frame-options "SAMEORIGIN" always;

    # X-SSS Protections
    # Enable X-XSS-Protection header in Nginx
    add_header X-XSS-Protection "1; mode=block" always;

    # LINUXBABE
    # If you allow people to upload files, or are concerned about intruders using a different flaw to get
    # files onto your server AND the content on your domain should not be accessed via other websites
    # possibly trying to impersonate you, then yes X-Permitted-Cross-Domain-Policies "none" will provide a
    # security benefit. The attack is less relevant these days, as any user of modern software first
    # needs to be tricked into allowing Flash or active PDF content.
    # If your website is just a regular website with nothing that requires a login to access, then you don't need it.
    # https://www.linuxbabe.com/ubuntu/install-wordpress-ubuntu-20-04-nginx-mariadb-php7-4-lemp
    # https://security.stackexchange.com/questions/166024/does-the-x-permitted-cross-domain-policies-header-have-any-benefit-for-my-websit
    add_header X-Permitted-Cross-Domain-Policies none;

    # LINUXBABE (User recommendation)
    # Ignore Cache Control
    # Keep fastcgi working if it's not getting hits
    # ADMIN Note: Only use this if fastcgi cache status is not getting hits
    #fastcgi_ignore_headers Cache-Control Expires Set-Cookie;

    ##
    # SSL
    ##

    # Certificate Path (signed)
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # Managed by ADMIN
    # Certificate Path (intermediate)
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # Managed by ADMIN
    # Certificate Path (Chain of trust of OCSP response using Root CA and intermediate certificates)
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem; # Managed by ADMIN
    # Perfect Forward Secrecy (Diffie Hellman 4096) Path
    ssl_dhparam /etc/ssl/private/dhparams4096.pem; # Managed by ADMIN

    # Mozilla Modern Compatibilty
    # Strict Settings with OCSP stapling turned on for A+ Rating at ssllabs.com
    ssl_protocols TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLERequires nginx >= 1.13.0 else use TLSv1.2 # Dropping TLSv1.1 for modern compatability.
    ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
    ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
    ssl_prefer_server_ciphers on;
    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m; # About 40000 sessions
    ssl_session_tickets off;

    # OCSP stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 1.0.0.1;

    ##
    # LOGS
    ##

    # ADMIN Note: Adding "if=$log_ip" to the end of access log lines will exclude your own ip address from access logs to prevent skewing data

    # Access Log (Netdata)
    access_log /var/log/nginx/example.com.access.log netdata if=$log_ip;
    # Access Log (Amplify)
    access_log /var/log/nginx/example.com.access.log apm if=$log_ip;
    # Error Log
    error_log /var/log/nginx/example.com.error.log warn;

    ##
    # PAGESPEED
    ##

    # ADMIN Note: Pagespeed is broken on Nginx v1.25.1 and up, so we should comment all of it out here and in the "nginx.conf" file

    # Settings per this virtual host
    # Enable Pagespeed module
    #pagespeed on;
    #pagespeed Domain http*://*.example.com;

    # Settings per all virtual hosts
    #include /etc/nginx/pagespeed.conf;

    ##
    # LOCATION DIRECTIVES 1
    ##

    index index.php index.html index.htm index.nginx-debian.html;

    # ADMIN
    # https://serverfault.com/questions/1137324/difference-between-3-similar-nginx-location-directives-provided-in-three-separat/1137342#1137342
    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    ### BEGIN: "Converter for Media" Wordpress Plugin
    set $ext_avif ".avif";
    if ($http_accept !~* "image/avif") {
        set $ext_avif "";
    }

    set $ext_webp ".webp";
    if ($http_accept !~* "image/webp") {
        set $ext_webp "";
    }

    location ~ /wp-content/(?<path>.+)\.(?<ext>jpe?g|png|gif|webp)$ {
        add_header Vary Accept;
        expires 365d;
        try_files
            /wp-content/uploads-webpc/$path.$ext$ext_avif
            /wp-content/uploads-webpc/$path.$ext$ext_webp
            $uri =404;
    }
    ### END: "Converter for Media" Wordpress Plugin

    # ADMIN
    # https://serverfault.com/questions/755662/nginx-disable-htaccess-and-hidden-files-but-allow-well-known-directory
    # location ~ /.well-known {
    location ~ /\.well-known {
        allow all;
    }

    # ADMIN
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    # ADMIN
    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    # LINUXBABE
    location ~ ^/wp-json/ {
        rewrite ^/wp-json/(.*?)$ /?rest_route=/$1 last;
    }

    # LINUXBABE
    location ~ /wp-sitemap.*\.xml {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # LINUXBABE
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    # LINUXBABE
    location = /50x.html {
        root /var/www/html;
    }

    # ADMIN
    # DISALLOW ACCESS of /xmlrpc.php
    # EXCEPT FROM internal IP's and Home & Apartment IP's.
    #location ^~ /xmlrpc.php$ {
        #allow xxx.xxx.xx.x/24; #   LAN IP Address
        #allow xxx.xxx.xx.x/32; # Home IP address
        #allow xxx.xxx.xx.x/32; # Apt. IP Address
        #deny all;
    #}

    # ADMIN
    # DISALLOW ACCESS of /admin
    # EXCEPT FROM internal IP's and Home & Apartment IP's
    location ^~ /admin/ {
        #satify all;
        allow xxx.xxx.xx.x/24; #   LAN IP Address
        allow xxx.xxx.xx.x/32; # Home IP address
        allow xxx.xxx.xx.x/32; # Apt. IP Address
        deny all;
        # Require basic auth login for allowed IP's
        auth_basic "You Don't belong here. Get out!";
        auth_basic_user_file /etc/nginx/basic_auth/auth.admin;
    }

    # ADMIN
    # DISALLOW ACCESS of /wp-login.php
    # EXCEPT FROM internal IP's and Home & Apartment IP's.
    #location ^~ /wp-login.php {
        #allow xxx.xxx.xx.x/24; #   LAN IP Address
        #allow xxx.xxx.xx.x; # Home IP address
        #allow xxx.xxx.xx.x; # Apt. IP Address
        #deny all;
        # Require basic auth login for allowed IP's
        #auth_basic "You Don't belong here. Get out!";
        #auth_basic_user_file /etc/nginx/basic_auth/auth.wp-login;
    #}

    # ADMIN
    # DISALLOW ACCESS of PHP In Upload Folder
    location /wp-content/uploads/ {
        location ~ \.php$ {
            deny all;
        }
    }

    # ADMIN
    # DISALLOW ACCESS of hidden files
    location ~ /\. {
        access_log off;
        log_not_found off;
        deny all;
    }

    ##
    # BEGIN: CACHE / SKIP CACHE
    ##

    # LINUXBABE
    # https://www.linuxbabe.com/nginx/setup-nginx-fastcgi-cache
    # Don't Skip Cache by Default
    set $skip_cache 0;

    # LINUXBABE
    # https://www.linuxbabe.com/nginx/setup-nginx-fastcgi-cache
    # POST requests should always go to PHP
    if ($request_method = POST) {
        set $skip_cache 1;
    }

    # LINUXBABE
    # URLs containing query strings should always go to PHP
    # ADMIN Note: You might want to be sure to turn off query strings in H-code wordpress theme, and other themes
    # https://www.linuxbabe.com/nginx/setup-nginx-fastcgi-cache
    if ($query_string != "") {
        set $skip_cache 1;
    }

    # LINUXBABE
    # Don't cache uris containing the following segments
    # https://www.linuxbabe.com/nginx/setup-nginx-fastcgi-cache
    # https://easyengine.io/wordpress-nginx/tutorials/plugins/woocommerce/
    # https://docs.cleavr.io/guides/woocommerce/
    if ($request_uri ~* "/wp-admin/|/wp-json/|/login/|/register/|/shopping-cart.*|.*add-to-cart.*|.*empty-cart.*|/cart.*|/checkout.*|/addons.*|/my-account.*|/wishlist.*|/xmlrpc.php|wp-.*.php|^/feed/*|/tag/.*/feed/*|index.php|/.*sitemap.*\.(xml|xsl)") {
        set $skip_cache 1;
    }

    # LINUXBABE
    # Don't use the cache for logged in users or recent commenters
    # https://www.linuxbabe.com/nginx/setup-nginx-fastcgi-cache
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
        set $skip_cache 1;
    }

    # LINUXBABE
    # Cache Bypass for specified IP's
    # Test the upstream (PHP-FPM and MariaDB) response time. By adding the following
    # lines we tell Nginx to bypass the FastCGI cache for our own public and local IP addresses.
    # Skip the fastCGI Cache for "Apartment Public IP|Work Public IP|Apartment LAN Subdomain".
    # https://www.linuxbabe.com/nginx/setup-nginx-fastcgi-cache
    #if ($remote_addr ~* "xxx.xxx.xx.x|108.231.125.254|xxx.xxx.xx.x|192.168.25..*") {
    #    set $skip_cache 1;
    #}

    ##
    # END: CACHE / SKIP CACHE
    ##

    # LINUXBABE
    # Google Sitemaps / Yoast SEO Rules:
    # If you use the Yoast SEO or Google XML Sitemap plugins to generate sitemap, then
    # you need to move the Yoast/Google XML rewrite rules here, below the skip cache rules (below this line).
    # https://www.linuxbabe.com/nginx/setup-nginx-fastcgi-cache
    # Rules:

    ##
    # LOCATION DIRECTIVES 2
    ##

    # LINUXBABE
    # Pass Fastcgi to PHP
    location ~ \.php$ {
        # Pass FastCGI to PHP 7.4
        fastcgi_pass unix:/run/php/php7.4-fpm.sock;

        # Add to SCRIPT_FILENAME to fastcgi params file
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        # FastCGI Split Path Info (Possibly Incorrect, need help from serverfault.com)
        # There are a couple of options for fastcgi_split_path_info, but we don't know which one, if any, are correct (Question for serverfault.com)
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        #fastcgi_split_path_info ^(.+\.php)(.*)$;
        #fastcgi_split_path_info ^(.+\.php)(/.+)$;

        # Check that the PHP script exists before passing it by using an "if" statement instead of using "try_files $fastcgi_script_name =404"
        # The if lets NGINX check whether the *.php does indeed exist,
        # to prevent NGINX from feeding PHP FPM non php script files (like uploaded images).
        # see https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/
        if (!-f $document_root$fastcgi_script_name) {
            return 404;
        }

        # Mitigate https://httpoxy.org/ vulnerabilities
        # Note: see https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/
        # also see https://www.digitalocean.com/community/tutorials/how-to-protect-your-server-against-the-httpoxy-vulnerability
        # if configuring Nginx for conventional HTTP proxying
        fastcgi_param HTTP_PROXY "";

        # Fastcgi index
        fastcgi_index index.php

        # Include fastcgi_params file
        include fastcgi_params;

        fastcgi_buffers 1024 4k;
        fastcgi_buffer_size 128k;

        # FastCGI Cache
        #fastcgi_cache off;
        fastcgi_cache example.com;
        fastcgi_cache_valid 200 301 302 12h;
        fastcgi_cache_use_stale error timeout updating invalid_header http_500 http_503;
        fastcgi_cache_min_uses 1;
        fastcgi_cache_lock on;
        # Tell Nginx to send requests to upstream PHP-FPM server, instead of trying to find files in the
        # cache. If the value of $skip_cache is 1, then the first directive tells Nginx to send request
        # to upstream PHP-FPM server, instead of trying to find files in the cache.
        # ADMIN Note: fastcgi_cache_bypass $skip_cache and fastcgi_no_cache $skip_cache should be
        # uncommented if using google XML sitemap plugin, or Yoast SEO Plugin, or if you want to
        # enable the skip cache rules above.
        fastcgi_cache_bypass $skip_cache;
        # This directive tells Nginx not to cache the response.
        fastcgi_no_cache $skip_cache;
    }

    # LINUXBABE (+ ADMIN Extra Extensions)
    # Speed up repeat visits to your page with a long browser cache lifetime
    location ~ \.(txt|flv|pdf|avi|mov|ppt|wmv|mp3|ogg|webm|aac|jpg|ogg|ogv|svgz|eot|otf|mp4|rss|atom|zip|tgz|gz|rar|bz2|doc|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|jpeg|gif|png|swf|jpeg|webp|svg|woff|woff2|ttf|css|js|ico|xml|otf|woff|woff2)$ {
        access_log off;
        log_not_found off;
        expires 1y;
    }
}
Richard Smith avatar
jp flag
`fastcgi_split_path_info` is not required in `location ~ \.php$` as there is no path info to split. Path info is for URLs that have a `/` after the `.php`. [This page](https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/) gives an example of a `location` that matches URLs with path info. But as I said, your configuration does not need or use it.
DanRan avatar
mx flag
I have other virtual hosts like postfixadmin.conf and netdata.conf as well. Is path_info excluded in those as well or would I have to make a seperate post with those specific virtual hosts? If they aren't excluded what should I use for path_info in those?
Richard Smith avatar
jp flag
In PHP, path info is that part of the URL that comes after the `.php` and before the `?`, for example: `/index.php/path/info` - If your application only uses PHP URLs that match `\.php$` - then you are not using path info.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.