Chris Moutray
Chris Moutray

Reputation: 18399

How setup location block to strip port from url

I'm trying to setup nginx to reverse proxy to a port dynamically based on port found in path.

So https://my-nginx.uksouth.cloudapp.azure.com/58585/some/route goes to https://localhost:58585/some/route

And https://my-nginx.uksouth.cloudapp.azure.com/59595/some/route goes to https://localhost:59595/some/route

I can hard code the config like this

server {
  server_tokens off;
  server_name my-nginx.uksouth.cloudapp.azure.com;

  listen [::]:443 ssl ipv6only=on; # managed by Certbot
  listen 443 ssl; # managed by Certbot
  ssl_certificate /etc/letsencrypt/live/my-nginx.uksouth.cloudapp.azure.com/fullchain.pem; # managed by Certbot
  ssl_certificate_key /etc/letsencrypt/live/my-nginx.uksouth.cloudapp.azure.com/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 /58585 {
    proxy_pass http://localhost:58585/;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;
  }

  location /59595 {
    proxy_pass http://localhost:59595/;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;
  }

}

server {
  if ($host = my-nginx.uksouth.cloudapp.azure.com) {
    return 301 https://$host$request_uri;
  } # managed by Certbot

  listen 80 default_server;
  listen [::]:80 default_server;

  server_name my-nginx.uksouth.cloudapp.azure.com;

  return 404; # managed by Certbot
}

and reverse proxy like this

ssh -R 58585:localhost:58585 [email protected]
ssh -R 59595:localhost:59595 [email protected]

This works as expected; then I've tried to make this dynamic

So https://my-nginx.uksouth.cloudapp.azure.com/targetPort/some/route goes to https://localhost:$targetPort/some/route

The best I can come up with is the following but this keeps failing and with a 502 bad gateway.

location ~ /([0-9]+) {
    set $targetPort $1;
    proxy_pass http://localhost:$targetPort/;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
    proxy_redirect off;
}

Can someone guide me with the correct way to do this ? Thanks!

Upvotes: 0

Views: 431

Answers (1)

Ivan Shatsky
Ivan Shatsky

Reputation: 15697

According to documentation:

In some cases, the part of a request URI to be replaced cannot be determined:

  • When location is specified using a regular expression, and also inside named locations.

    In these cases, proxy_pass should be specified without a URI.

I think you can try to use rewrite here to specify an URI:

location ~ ^/(\d+) {
    set $targetPort $1;
    rewrite /\d+(.*) $1 break;
    proxy_pass http://localhost:$targetPort;
    ...
}

Maybe this can be optimized for one regex matching instead of two:

location ~ ^/(\d+)(.*) {
    set $targetPort $1;
    set $newuri $2;
    rewrite . $newuri break;
    proxy_pass http://localhost:$targetPort;
    ...
}

But it needs to be tested, nginx behavior is unpredictable sometimes.

Update

This is definitely can be optimized to

location ~ ^/(?<targetPort>\d+)(?<newURI>.*) {
    rewrite . $newURI break;
    proxy_pass http://localhost:$targetPort;
    ...
}

Upvotes: 1

Related Questions