Search code examples
perlvue.jsnginxreverse-proxymojolicious

Nginx reverse proxy configuration makes Mojolicious $self->req->url->to_abs discard the port number


Stuck on in the implementation of a "quick and dirty" web resource link sharing functionality, which should work according to the following scenario:

  • user lists items from db, clicks on edit
  • system opens edit modal dialog with selected app
  • the system presents the link to this item in this application instance, so that with couple of tabs the user can Ctrl + C or Cmd + C it ...

So I have the following code in the mojolicious template, which Mojolicious perfectly translates into the correct absolute url, while running without nginx reverse proxy:

 <input id="modal-dia-share-lnk" @focus="this.document.execCommand('selectAll',false,null)"
 :value="'<%=  $self->req->url->to_abs =%>?&'+'with=id-eq-'+this.$attrs.id.replace('dia-','')" readonly>

which translates to something like:

http://host-name:8082/qto/list/monthly_issues_202004?&with=id-eq-200327122837 which HAS the port

but, while running behind reverse proxy it omits the port, so even if I am running on port 441 the generated url is does NOT have the port http://qto.fi/qto/list/monthly_issues_202004?&with=id-eq-200325163720

Which is kind of unacceptable in this setup, because the Mojo app layer for dev must be listening to port 441 and the Mojo app layer for prd must be listening to port 443

You can actually get the scenario in both the:

  • the qto app layer instance in dev
  • the qto app layer instance in prd

by just clicking ok to be logged on with the default anonymous user ...

I could build the url based on the existing configuration of the app, but I guess there should be quick nginx hack to actually include the port as well by some regex in the location directive or something ...

This is the reverse proxy conf:

server {

  listen 443 ssl;
  server_name qto.fi;
  server_tokens off;

  ssl_certificate /etc/letsencrypt/live/qto.fi/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/qto.fi/privkey.pem;

  location / {
    proxy_pass http://localhost:8080/;
    proxy_http_version 1.1;
    proxy_pass_header Authorization;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    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 $scheme;
    proxy_read_timeout 10s;
  }
}

there is also the following http conf for the dev site:

server {
    listen 78;
    listen [::]:78;

    server_name qto.fi;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;

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

         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection "upgrade";
         proxy_set_header Host $host;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_set_header X-Real-IP        $remote_addr;
         proxy_set_header X-Forwarded-For
         $proxy_add_x_forwarded_for;
         # ....

    }
}

Solution

  • Add the port to the Host header in the nginx reverse proxy conf:

    proxy_set_header Host $host:443;
    

    OR

    proxy_set_header Host $host:$server_port;