0

Unlike other questions related to nginx not executing PHP files, mine does, the problem comes when I use SEO like urls instead and redirect to a php script, then instead of executing the code it sends the script as plain text to the browser.

Basically what I want is that every request send to the HTTP server for which there's no an actual file, index.php script will be executed and its output returned to the browser. But what is happening is that I'm getting the code inside index.php instead.

This is the section of my configuration file where the redirection is done. It's been actually translated from a former Apache's .htaccess file:

    location / {
        if (!-e $request_filename){
            rewrite ^(.*)$ /index.php break;
        }
    }

These are the PHP related directives, actually these are before the previous one in the configuration file:

    location ~ \.php$ {
        try_files /dd05cf208ebd3d4559f3af75016a1e3d.htm @php;
    }

    location @php {
        try_files $uri =404;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass unix:/var/lib/php7.0-fpm/web4.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
    }

I've been using Apache with mod_php for decades and the equivalent directives just worked out of the box, but I'm new with Nginx and I don't know where to start debugging this.

Fran Marzoa
  • 101
  • 3

3 Answers3

1

The correct way to implement front-controller pattern in nginx is the following:

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

Your PHP location blocks look a bit odd. I guess that your objective with the configuration is to enable nginx to show a maintenance notice in /dd05cf208ebd3d4559f3af75016a1e3d.htm if the file exists.

This configuration looks correct to me, except that the try_files inside your @php block makes requests fail, since it makes nginx look for files with names specified in the URI, and with friendly URLs those files simply do not exist.

There is no reason to include that, so your PHP configuration should look like the following.

location ~ \.php$ {
    try_files /dd05cf208ebd3d4559f3af75016a1e3d.htm @php;
}

location @php {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass unix:/var/lib/php7.0-fpm/web4.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_intercept_errors on;
}
Tero Kilkanen
  • 36,796
  • 3
  • 41
  • 63
0

Your SEO solution is using non-recommended if directive inside location. If Is Evil:

Directive if has problems when used in location context, in some cases it doesn’t do what you expect but something completely different instead. In some cases it even segfaults. It’s generally a good idea to avoid it if possible.

The correct way to achieve what I believe you want would be try_files, e.g.:

location / {
    try_files $uri $uri/ @missing;
}

location @missing {
    rewrite ^(.*)$ /index.php break;
}
Esa Jokinen
  • 46,944
  • 3
  • 83
  • 129
  • 1
    If you want to go with the `rewrite` way, you can use `rewrite ^ /index.php break;`, it does the same as `^(.*)$`. I don't know if that makes any real difference performance-wise though. At least there is no variable created... – Tero Kilkanen Jun 21 '17 at 13:57
  • Your answer is the most straight-forward way of doing this. This only keeps the flexibility, if more complex rewrite pattern is required later, or if a redirect is needed instead. But as we shouldn't predict that, I'll upvote for your answer. – Esa Jokinen Jun 21 '17 at 14:10
0

Into the server location put

error_page 404 =200 /index.php;

to redirect all 404 (not found) pages to your index.php

You don't need all the rewrite and location stuff, if you just want to catch all missing pages.

Federico Galli
  • 918
  • 6
  • 16