Search code examples
regexurlnginxurl-rewritingmasking

NGINX rewrite rule with exclusions


I'm new to NGINX and horrible with regular expressions. This is what I need:
A rewrite rule that:

  • Masks mysite.com/SOMETHING over mysite.com/profile.html?id=SOMETHING
  • EXCLUDES mysite.com/images/ (and anything in that directory) from this rewrite
  • EXCLUDES mysite.com/ (the root directory) from rewriting
  • EXCLUDES mysite.com/ANOTHERFILE.html (or .php) from rewriting
  • I've done a lot of googling and can't seem to find what I need. Not even a support article that tells me more about the regex's nginx uses. This was my best guess:

     location / {
        rewrite ^(?!(/images/))(.*)$ profile.html?id=$2 break;
        return   403;
    }
    

    I put that in my nginx.conf file. It sort of worked. It would rewrite any request such as mysite.com/SOMETHING to mysite.com/profile.html?id=SOMETHING, however, it would also rewrite mysite.com/ to mysite.com/profile.html?id=. The /images/ exclusion seemed to work (as my images loaded properly), however, even going to mysite.com/index.html would rewrite to mysite.com/profile.html?=id=index.html.

    Any help would be greatly appreciated.


    Solution

  • I found a solution that works, but I suspect that the regex matching is eating up some CPU time and possibly slowing the performance of my site. I'm going to keep looking for improved solutions, but here's how I ended up solving the problem:

    #Location routing for user accounts
    location = / {
    break;
    }
    
    location / {
        rewrite ^(?!(/images/|(.*\..*)))(.*)$ /profile.html?id=$2 break;
        rewrite ^(.*)$ $1 break;
        return   403;
    }
    #end location routing for user accounts
    

    I put that inside of the server { } block of my nginx.conf file. The first block, location =/ { }, checks if the location is / (web root directory) and ONLY /, then do nothing different than normal server operation, and then that should escape all location handling/url rewriting.

    Next, the location / { block matches any URI in the webroot. Here's where the rewrite and regex matching comes in. First, the rewrite engine tries to match the URI to the regex ^(?!(/images/|(.*\..*)))(.*)$, which requires the URI not to start with /images/ OR file.ext (anything in that format), and then takes any word, (.*), and throws it into the rewritten url then all url rewriting breaks and the server serves the page.

    If there's no match in the URI to the regex, for example, URI = /images/arrow.png or URI = /folder/ or URI = /profile.php, then, it moves on to the next rule. The next rule just takes your URI and rewrites the same URI. I can't speak for the efficiency of this tactic, especially since you will never reach the return 403; statement, I feel like maybe there's a better way to do this. I tried using try_files but I had little success with that. This is working for now, and meets my criteria. Seems to be lacking in performance a bit, but I'll have to live with it until I can make improvements.