Nginx serve static files directly if not matched by rewrite rules

apache-2.2nginxrewritestatic-content

I just moved from apache to nginx and I'm struggling with some configuration settings that doesn't seem to work. I have these rules from my previous .htaccess file that I'm trying to convert to nginx rules:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(js|css)/([a-z0-9\.]+)\.(js|css)$ $1/index.php?hash=$2 [L,QSA]

RewriteCond %{REQUEST_URI} !\.(gif|jpe?g|s?html|css|js|cgi)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L,QSA]

As you can tell, this says that each file that do not exist but follow the specified pattern has to be served by a php script. No further processing. Then, for each file that are not static and does not exist on the disk, send them to the main index.php file.

I know how to serve static files directly and I know how to make the first rule. The thing that I don't know how to solve is having these both conditions work together. Here is what I have so far:

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

location /js/ { 
    rewrite ^/js/([a-z0-9.]+).js$ /js/index.php?hash=$1 break; 
} 

location /css/ { 
    rewrite ^/css/([a-z0-9.]+).css$ /css/index.php?hash=$1 break; 
}

# serve static files directly
location ~* \.(?:jpg|jpeg|gif|css|png|js|ico)$ {
    access_log        off;
    expires           30d;
    add_header Pragma public;  
    add_header Cache-Control "public"; 
} 

location ~ \.php$ {
    # basic settings for php files
}

As I said, if I leave all those three location directives enabled, static files will be served directly, but styles or js files that follow the specified pattern will return 404 error (as in they are not found at that specific location). If I comment the static files directive and enable the rewrite rules for css/js that have to be served by a script, static files inside css/js directories will not be served (a blank page is returned) but all other static files will be served normally.

I really don't know what to do anymore. I've spent hours looking up on the internet on how to solve this, but everything I tried didn't work.

Best Answer

Solution:

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

# serve static files directly
location ~* \.(?:jpg|jpeg|gif|css|png|js|ico)$ {
    access_log        off;
    expires           30d;
    add_header Pragma public;
    add_header Cache-Control "public";
    try_files $uri @fallback;
}

location @fallback {
    rewrite ^/(js|css)/([a-z0-9.]+)\.(js|css)$ /$1/index.php?hash=$2;
}

location ~ \.php$ {
    # basic settings for php files
}