Problems with Postback-Routing when using a Reverse Proxy (NGINX)

Hello everybody,

I am currently trying to host two web applications, both developed with DotVVM, on one server and reverse proxy them with NGINX via two different locations (frontend1 and frontend2).
The two applications are already accessible through the NGINX and with the help of sub_filters I have also been able to rewrite the resources (js,css,favicon,etc.) in the HTML files accordingly.
However, what doesn’t work and where I have already invested some hours solving it is that the postbacks are only ever directed to the “original” base url (always to http://mydns/ instead of http://mydns/frontend1 or http://mydns/frontend2) and I now have no idea left how I can get the postbacks to be routed via a reverse proxy to the right location.

Here is my current NGINX configuration file, where I have anonymised the urls, ports and so on for this forum entry. This is working fine except the POST calls for Postbacks.

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    server {
        listen 80 default_server;
        server_name  _;

        location /frontend1 {
            proxy_pass http://mydns:50000/;
            proxy_http_version 1.1;
            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;
            sub_filter_types text/html;
            sub_filter "/dotvvmResource" "/frontend1/dotvvmResource";
            sub_filter "/Resources" "/frontend1/Resources";
            sub_filter_once off;
        }

        location /frontend2 {
            proxy_pass http://mydns:50001/;
            proxy_http_version 1.1;
            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;
            sub_filter_types text/html;
            sub_filter "/dotvvmResource" "/frontend2/dotvvmResource";
            sub_filter "/Resources" "/frontend2/Resources";
            sub_filter_once off;
        }
        
		# My attempt to detect postbacks, but i am missing further information to distinguish the source of the postback between the two locations 
        # location / {
        #    if ($http_x_dotvvm_postback = "true"){
        #        rewrite ^/$ /frontend2;
        #    }
        # }

    }
}

One of the things I have already tried is to use app.UsePathBase(…) to influence the postbacks. However, this does not work with the rewriting of the paths by the NGINX locations, but only if you address the application directly. This was inspired by resource pathing behind nginix ingress · Issue #1649 · riganti/dotvvm · GitHub.

Another thing I have tried is to identify the postbacks via the X-DotVVM-Postback header and then rewrite the url accordingly, but in the postback calls I get no further indication of which application it is being called from. However, this also seemed to me to be quite a hack, which could possibly break later in other places.

Since I have not found anything about this in the documentation, in the forum and in Github (except the topic with the UsePathBase from resource pathing behind nginix ingress · Issue #1649 · riganti/dotvvm · GitHub) so far.
I am now posting here in the forum in the hope that the use of a reverse proxy could somehow be made possible in the context of two DotVVM Web Applications. Maybe someone already solved this or a similar issue and could tell me how or where i make something wrong?

Many thanks in advance for your help.

Daniel Wecker

Hello,

I think you have to use the app.UsePathBase(…) method, rewriting all kinds of response URLs in nginx is extremely fragile. The application with UsePathBase assumes that it gets requests with that base, so you should configure the proxy to keep the /frontend1 prefix. http://nginxserver:80/frontend1/something should be rewritten to http://mydns:50000/frontend1/something.

I always struggle with how to do that in nginx, I think location /frontend2/ { proxy_pass http://mydns:50001/frontend2/; } might work in your case

1 Like

Thank you for your fast reply.

That was the solution. I used “frontend1” and “frontend2” as the path bases for each frontend and then instead of rewriting it with NGINX i set it up like you suggested to let the frontends itself do the rewriting. So basically only the ports are really routed by NGINX and the rest is done by the frontends itself. This has furthermore the nice side effect that i do not need the sub_filters anymore to rewrite the paths to the different resource files.

My configuration file now looks like this:

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log notice;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    server {
        listen 80 default_server;
        server_name  _;
        large_client_header_buffers 4 32k;

        location /frontend1/ {
            proxy_pass http://mydns:50000/frontend1/;
            proxy_http_version 1.1;
            proxy_set_header    Upgrade $http_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_pass_request_headers      on;
            proxy_cache_bypass  $http_upgrade;
            # buffer sizes
            proxy_buffer_size   32k;
            proxy_buffers       8 32k;
        }

        location /frontend2/ {
            proxy_pass http://mydns:50001/frontend2/;
            proxy_http_version 1.1;
            proxy_set_header    Upgrade $http_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_pass_request_headers      on;
            proxy_cache_bypass  $http_upgrade;
            # buffer sizes
            proxy_buffer_size   32k;
            proxy_buffers       8 32k;
        }
    }
}

One important thing which maybe can be used by other people who want to use NGINX in the context of DotVVM frontends is that you have to increase the request and response header sizes as the cookies which are used by DotVVM or ASP.NET Core (I think mainly when doing cookie-authentication) are too big for the default configuration of NGINX. For that i increased the “proxy_buffer_size”, “proxy_buffers” and “large_client_header_buffers” attributes like shown above.

1 Like

Great! Thanks for posting the working configuration. Note that most of this is actually inherent to Asp.Net Core, which might be easier find answers for than DotVVM. Of course, feel free to ask if you have any further issues, it’s just that Google tends to have a lower latency than I do