curiousdev
curiousdev

Reputation: 636

NGINX regexp at the end of location path

I'm trying to set up a location such that suffix /reset_password/any_text would load index.html from the directory specified in the alias. Unfortunately, with no luck...

#   location /reset_password {
#       alias /var/www/grades-ui;
#   }

    location /reset_password/([0-9a-z]*) {
        alias /var/www/grades-ui;
    } 

The commented out code works fine to load exact path /reset_password, however my goal is to serve /reset_password/any_text_or_number.

Any ideas why my regular expression wouldn't work? Or maybe I'm doing something else completely wrong?

Edit: the complete conf file

server {
    listen 443 ssl; # managed by Certbot

    root /var/www/grades-ui;
    server_name www.mygrades.co.uk mygrades.co.uk;

    ssl_certificate /etc/letsencrypt/live/mygrades.co.uk/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/mygrades.co.uk/privkey.pem; # managed by Certbot

    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    location / {
        index index.html;
        add_header X-debug-message "Location / reached" always;
    }

    location ^~ /reset_password/(.*)[a-z]/ {
        alias /var/www/grades-ui;
        add_header X-debug-message "Location /reset_password/$1 reached" always;
    }

    location ^~ /reset_password {
        alias /var/www/grades-ui;
        add_header X-debug-message "Location /reset_password reached" always;
    }

#    location /reset_password/([0-9a-z]*) {
#       root /var/www/grades-ui;
#       try_files /index.html =404;
#    }
}

server {
    listen 80;

    if ($host = mygrades.co.uk) {
        return 301 $host$request_uri;
    } # managed by Certbot

    server_name www.mygrades.co.uk mygrades.co.uk;

#    return 301 https://$host$request_uri; # managed by Certbot

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header REMOTE-HOST $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

Upvotes: 2

Views: 5355

Answers (2)

Richard Smith
Richard Smith

Reputation: 49692

You are confusing your location syntax. The regular expression location is introduced with the ~ or ~* modifiers. The ^~ modifier means something else entirely. See this document for details.

The location ^~ /reset_password { ... } block already matches any URI that begins with /reset_password, including /reset_password/foo. You do not need a regular expression to match the trailing part of the URI.

You could use an alias directive with a regular expression location, but in that case, alias requires the entire pathname to be provided. See this document for details. For example, this should work:

location ~* ^/reset_password {
    alias /var/www/grades-ui/index.html;
}

But the solution I would suggest is a prefix location with a root and try_files directive. See this document for details. For example:

location ^~ /reset_password {
    root /var/www/grades-ui;
    try_files /index.html =404;
}

Upvotes: 2

Cole Tierney
Cole Tierney

Reputation: 10314

The ^~ string is a prefix location modifier which tells nginx to skip processing of regular expression locations if the prefix location is matched. A regular expression location uses just ~ or ~* to ignore case. Check the documentation for more details.

That said, if you don't need to capture any regex pattern matches, just go with a simple prefix location. Regex locations are expensive and they interfere with the natural flow of nginx. The author of nginx, Igor Sysoev, explains in this video.

A good way to use a regex location is to wrap it in a prefix location. This isolates it from the rest of the configuration and makes it easier to debug. Your config will also scale more smoothly. Here's an example:

location /reset_password/ {
    location ~ /reset_password/([0-9a-z]*) {
        # ...
    }
}

Upvotes: 1

Related Questions