11

I am trying to implement a proxy using the nginx configuration

The idea is to have a http server hosting my website (my SPA). and having one route on my http server pointing to another api.

this is my nginw configuration file below

client_max_body_size 100M;

server {
    listen       80;
    server_name  localhost;

    root   /usr/share/nginx/html;
    index  index.html index.htm;

    location ^~ /proxyapi/ {
        proxy_read_timeout 180s;
        proxy_send_timeout 180s;
        proxy_pass http://localhost:5000/;
    }

    location ~* /static/* {
      try_files $uri =404;
      expires 1y;
      access_log off;
      add_header Cache-Control "public";
    }

    # Any route that doesn't have a file extension (e.g. /devices)
    location / {
        try_files $uri $uri/ /index.html;
    }

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

it works fine most of the time

when I call http://my-nginx-host/proxyapi/search/login, it works...

unless there is a dot in the login

http://my-nginx-host/proxyapi/search/login => works fine

http://my-nginx-host/proxyapi/search/log.in => fails with a "404 resource not found"

is there any way to make it work? I couldn't find any solution

netlyonel
  • 155
  • 1
  • 2
  • 8

2 Answers2

5

Matching any dot in URI can be done with this:

location ~* \..*$ {
 # try_files $uri $uri/ =404;
 # ...
}

Let's take the regex apart:

  • ~* Tells nginx to do case-insensitive regex matching (~ for case-sensitive)
  • \. Matches to literal dot symbol .
  • .* The dot here equals to any symbol except whitespace, asterisk modifies the preceding symbol to "match as many of this as possible"
  • $ Matches end of line

You can use this regex if you want to match even "malformed" uris like log.in

EDIT: In your situation, you would have to place this regex after your location ~* /static/* so it won't match uris with dots like /static/image.png. See notes for explanation.


Notes

Take in mind this location block will match any dot anywhere in passed URI. So it will match URIs like these /a.ssets/images/, /assets/favicon.ico too. Any non-terminating locations (ones without ^~ or =) will not be used even if they should match, if the dot regex matches and it's first matching regex location it takes precedence over anything else.

Important snippet from nginx's docs about matching preference of location:

Regular expressions are specified with the preceding “~*” modifier (for case-insensitive matching), or the “~” modifier (for case-sensitive matching). To find location matching a given request, nginx first checks locations defined using the prefix strings (prefix locations). Among them, the location with the longest matching prefix is selected and remembered. Then regular expressions are checked, in the order of their appearance in the configuration file. The search of regular expressions terminates on the first match, and the corresponding configuration is used. If no match with a regular expression is found then the configuration of the prefix location remembered earlier is used.

Wereii
  • 330
  • 5
  • 16
  • just a note about the case sensitivity, although useful to know the difference, in this particular case it's irrelevant as we match both upper and lowercase with the dot .* – ptrk Oct 13 '21 at 12:41
  • If you want to match two dots, e.g. "/hello/../xyz", you have to use an if instead of location. See https://stackoverflow.com/a/52294234/5099059 – KeKru Nov 05 '21 at 08:27
2

I was trying your solution but no luck. My problem is that context root location has a dot https://example.com/something.else/test/me

I tried to match but no luck, I got 404 every time.

These are just some regex variation that I tried:

#location  ~ /[\w.]+ {
#location  ^~ ^/[\w.]+/[\w]+.* {
#location  ^~ /[\w.]+/[\w]+.* {
#location  ^~ [\w.]+/[\w]+.* {
#location  ~* [\w.]+/[\w]+.* {
#location  ~ ^[\w.]+/[\w]+.* {
location  ^~ /something\.else {