Search code examples
apachenginxmimephp

Proper way to configure NGINX with rewrite and valid mime types


I'm attempting to test out NGINX and potentially make a switch from Apache. Which I've read nginx is much faster, but I want to be the judge of that. I'm having issues getting the configuration of NGINX to match that of my Apache setup -- mainly rewrite rules. I'll explain how my applications works and what I want to be able to do in NGINX.

Currently I have my application handling all the REQUEST_URI's sent to the server. Even if the URI doesn't exist, my application handles processing of that URI. I'm able to do this because of a rewrite rule for Apache.

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)$ index.php?_url=$1 [QSA,NC]
</IfModule>

As you can see if the file or directory doesn't actually exist, it gets sent to index.php. I don't even check for the query string, I just handle the processing of the URI itself via the PHP variable $_SERVER['REQUEST_URI'] which is setup inside NGINX as fastcgi_param REQUEST_URI $request_uri;. I want to accomplish this exact thing with NGINX, but I've been only kind of successful with that.

So basically, if domain.com/register.php exists, then it is going to go to that url, if not it is going to be redirected to domain.com/index.php and the application handles the URI from there.

Here is my config file for my server. This is included at the bottom of nginx.conf file

server {
    listen ####:80;
    server_name ####;

    charset utf-8;

    access_log /var/www/#####/logs/access-nginx.log;
    error_log /var/www/#####/logs/error-nginx.log;

    root /var/www/######/public/;

    location / {
        index index.php index.html;
        include /etc/nginx/mime.types;
        try_files $uri /index.php?_url=$1;

        include /etc/nginx/fastcgi.conf;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_index  index.php;
        fastcgi_pass unix:/var/run/php-fpm.socket;

        autoindex on;
        autoindex_exact_size off;
        autoindex_localtime on;
        rewrite_log on;
    }
}

So this kind of works. What I mean by that is the try_files $uri /index.php?_url=$1 directive is processing the URI the way I want it to, but MIME types don't seem to work. Everything is being processed as text/html. Which means that my .css and .js files have to be turned into a .php file and a header attached in order for it to be processed correctly. image and font files seem to function correctly, but Chrome still shows the mime type as html. I have the mime.types file being included, so I can't figure out why it's doing that. I did try to use a "rewrite" directive to handle the what try_files is doing, but that didn't work.

This is the rewrite I tried inside the location / block:

if (!-e $request_filename){
    rewrite ^(.*)$ /index.php?_url=$1;
}

So my question is this: How do I properly rewrite my uri for non-existent files and directories while serving the proper mime type for the files automatically?


Solution

  • I ended up solving my own issue. What I had to do here was to process PHP files on their own and it took for a while to figure out that for sure. Here is the final .conf file that sends the correct mime types and also rewrites the way I needed it. Hopefully this helps someone else as well.

    server {
        listen #######:80;
        server_name ######;
    
        charset utf-8;
    
        access_log /var/www/######/logs/access-nginx.log;
        error_log /var/www/#######/logs/error-nginx.log;
    
        root /var/www/#########/public/;
    
        location ~ \.php$ {
            include /etc/nginx/mime.types;
            try_files $uri /index.php?_url=$1;
            include /etc/nginx/fastcgi.conf;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_index  index.php;
            fastcgi_pass unix:/var/run/php-fpm.socket;
    
        }
    
        location / {
            index index.php index.html;
            include /etc/nginx/mime.types;
            try_files $uri /index.php?_url=$1;
    
            autoindex on;
            autoindex_exact_size off;
            autoindex_localtime on;
            rewrite_log on;
        }
    }
    

    Using the location ~ .php$ section made it so that only PHP files were being sent to php-fpm. I also use the try_files directive to handle sending all the URI's that don't exist to my script, which is what my application expects. Hopefully this helps someone else out there!