nginxproxynginx-reverse-proxy

Nginx rules simplification for a proxy


Context

[Hiding actual project names and urls as it is an internal project.]
A group of our internal company dashboards are deployed at an internal url: console.fk.dev. It's a next-js project containing multiple dashboards. e.g.

Problem Statement:

To be able to setup a nginx proxy so that Onboarding Dashboard is accessible at onboard.fk.com.

Onboarding Dashboard currently has two pages

(more pages will be added in future)

Dashboard Url Need to be available at
dashboard.fk.dev/client/onboard onboard.fk.com
dashboard.fk.dev/client/onboard/pages/user onboard.fk.com/user
dashboard.fk.dev/client/onboard/pages/company onboard.fk.com/company

Current Solution:

We are able to currently achieve the same by following repetitive nginx rules configured for onboard.fk.com

# rule 1
location = / {
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Console-Basename "/";
    proxy_set_header X-Request-Uri $request_uri;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass "https://dashboard.fk.dev/client/onboard/pages";
}
# rule 2
location /user {
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Console-Basename "/";
    proxy_set_header X-Request-Uri $request_uri;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass "https://dashboard.fk.dev/client/onboard/pages";
}
# rule 3
location /company {
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Console-Basename "/";
    proxy_set_header X-Request-Uri $request_uri;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass "https://dashboard.fk.dev/client/onboard/pages";
}
# rule 4
location / {
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Request-Uri $request_uri;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass "https://dashboard.fk.dev";
}

Question: How to simplify or aggregate above nginx rules?

(I am a frontend developer with little idea of nginx trying to set up and expand my knowledge)

I tried using below regex rule but get the error: nginx: [emerg] "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /opt/homebrew/etc/nginx/nginx.conf:142

location ~ ^/(?:user|company) {
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Console-Basename "/";
    proxy_set_header X-Request-Uri $request_uri;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass "https://dashboard.fk.dev/client/onboard/pages";
}

Is there a way where I can aggregate and simplify the above rules either by merging location blocks or creating a function for repetitive lines (the way we create functions in high level language such as javascript). As more and more pages will be added in project, this config will become too big and repetitive and hence looking for simplification of rules.

Thanks in advance.


Solution

  • location ~ ^/(?:user|company) {
      rewrite ^/(?:user|company)/(.*)$ /client/onboard/pages/$1 break;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Console-Basename "/";
      proxy_set_header X-Request-Uri $request_uri;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_pass https://dashboard.fk.dev;
    } #quotes not necessary && make sure NO trailing slash on proxy_pass for this case
    

    This makes several assumptions else the method to execute a correct path from Requested URI => Resulting URI will vary greatly

    It is not exactly Art, but more experience which helps to understand the cascading set of rules which create efficient and robust routing in Nginx.

    Try the above, and keep in mind here is what will happen: Requested URL:

    https://example.com/user/me
    

    Proxy "Receives" this URL:

    https://dashboard.fk.dev/client/onboard/pages/me
    

    Why? Nginx cannot use Regex from original location in the Proxy Pass directive. Using rewrite beats this. Using break means request will not seek another location. I am assuming you want to avoid appending "user" when /user/ ... if that is the case and you want to retain either /user or /company then it has to be configured differently...

    Just to be explicitly clear, same result for /company as:

    https://example.com/company/widgetco/index.htm
    

    Proxies to:

    https://dashboard.fk.dev/client/onboard/pages/widgetco/index.htm
    

    IF you need or possibly need args with uri, then there is another config... keep in mind once Regex in location rules or any kind of Rewriting involved, then you are officially beyond "basic" Nginx and your knowledge base will need to increase slightly ;)