Question

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.

    Was it helpful?

    Solution 2

    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.

    OTHER TIPS

    Well i think one rule could handle all of this, but I'll assume a couple of things and you need to confirm it.

    for root location there's an index.php for /images and /file.html I'll assume that those files exist with the exact path and serve them, I'll explain more after i write the rules

    server {
        server_name mydomain.com; # maybe www.mydomain.com too
        index index.php; # or index.html, depending on ur app structure
        location ~ /(.*) {
            try_files $uri $uri/ /index.html?profile=$1;
        }
    }
    

    /images/image.png and file.php/file.html will all be matched by the first rule $uri, root will serve index.php (not very sure though) and when all fails (like your /something URL, it will try the /index.html?profile=something

    ps: I would have used $request_uri instead of $1 but it includes the first / so it would evaluate to /index.html?profile=/something and I assume that would not work with your code.

    Licensed under: CC-BY-SA with attribution
    Not affiliated with StackOverflow
    scroll top