Nginx Reverse Proxying to Node.js with Rewrite

2019-03-15 05:13发布

问题:

I have several apps running behind an Nginx reverse proxy, one of which is a Node server with Express.js. I'm proxying domain.com/demo/app/<path> to localhost:7003/<path> using this Nginx config:

http {

    ...

    server {

        listen 80;
        server_name domain.com;

        ...

        location /demo/app {

            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-Scheme $scheme;

            rewrite ^/demo/app/?(.*) /$1 break;
            proxy_pass http://localhost:7003;
        }

        ...
    }
}

This works great and app receives requests as if it was rooted at /. The problem is app handles its own static files and might make requests for routes such as css/app.css or images/image.jpg. But because of the reverse proxy, these actually exist at /demo/app/css/app.css and /demo/app/images/image.jpg respectively.

I've solved this by getting Nginx to pass to Node a custom header indicating the root path, which the Node server prepends to the URLs of all subsequent requests. But now my code is littered with these root path strings. For example, part of my back-end templates:

link(rel='stylesheet', href="#{basePath}/css/base.css")
link(rel='stylesheet', href="#{basePath}/css/skeleton.css")
link(rel='stylesheet', href="#{basePath}/css/layout.css")

What's a more elegant way to handle this? Isn't there a way to get Nginx to recognize requests coming from an upstream server and automatically forward them to that server?

回答1:

I have made nginx serve static files without even passing those requests to node by adding location directive to the app's nginx configuration file (which is included in nginx.conf):

location ~ /(img|js)/ {
    rewrite ^(.*)$ /public/$1 break;
}

location / {
    proxy_pass http://localhost:3000/;
    ...
}

In case request comes to /img or /js directory nginx serves files from /public/img or /public/js directory respectively. All other requests are proxied to node.

You can add more directories if you need (like /css or /views, if you store templates there that you want to use both in node and in browser) and have any directory structure inside those directories, nginx just prepends /public to them and gets files from there without your node app even knowing about it.