NGINX – Setting Up Reverse Proxy for Two Web Applications

nginxreverse-proxy

I have two applications.

  • Laravel Application – Being just a dynamic website. Does not have
    data-knowledge. All the data gets fetched from the second application
    using AJAX-requests. Runs on 127.0.0.1:8000.
  • Rust Application – A web-application containing all the business
    logic and data-access. Runs on 127.0.0.1:8080.

Both applications need to be accessible from the URL example.com.
For this I want to use Nginx Reverse Proxy. I am already able to reroute all requests to my Laravel Application.

events {}
http {
    server {
        listen 80;

        # Website
        location / {
            proxy_pass http://127.0.0.1:8000;
        }
        
    }
}

While the Laravel Application works, I need actually need the following Nginx configuration:

  • Specific pages like /news, /, /about,/contact,… should be redirected to 127.0.0.1:8000.
  • Note: The pages above can contain GET-parameters like e.g /news?article=abc.
  • ALL other requests need to be redirected to 127.0.0.1:8080.
  • Note: 127.0.0.1:8080 can often contain a subdomain. But this subdomain needs to act like a wildcard and is unknown at the time of configuration. Example: bussiness1.example.com, bussiness2.example.com, businnesX.example.com,…

The subdomain returns a personalized page for which an unlimited amount of businesses can request for on example.com.

How would I achieve this configuration? I was thinking something like this?

#PSEUDO
events {}
http {
    server {
        listen 80;

        # Website
        location / {
            proxy_pass http://127.0.0.1:8000;
        }
        location /news {
            proxy_pass http://127.0.0.1:8000;
        }
        location /about {
            proxy_pass http://127.0.0.1:8000;
        }

        # Application
        location * {
            proxy_pass http://127.0.0.1:8080;
        }

    }
}

Edit regarding Tero's answer:
I need a kind of wildcard for subdomains.

 # Application catch-all
    location / {
        proxy_pass http://$subdomain.$application;
    }

abc.example.com needs to go to abc.127.0.0.1:8080
def.example.com needs to go to def.127.0.0.1:8080

I know an IP can't have a subdomain but don't worry about that. I solved that with virtual hosts.

Edit 2 – Pass subdomain of request to proxy_pass:

server {
        listen 80;
        server_name *.website.com;
        server_name ~^(?<subdomain>.+)\.website\.com$;

        location / {
            proxy_pass http://$subdomain.vhost.local:8080;
        }
    }

Is this the correct way to redirect dynamicxxx.website.com to dynamicxxx.vhost.local:8080?

Best Answer

Your design is a bit complex and therefore fragile. However, you can try the following. I added upstream blocks so that the different proxy_pass destinations are more readable.

upstream website {
    server 127.0.0.1:8000;
}

upstream application {
    server 127.0.0.1:8080;
}

server {
    server_name example.com *.example.com;

    listen 80;

    # Application catch-all
    location / {
        proxy_pass http://application;
    }

    # Website
    location = / {
        proxy_pass http://website;
    }

    location /news {
        proxy_pass http://website;
    }

    location /about {
        proxy_pass http://website;
    }
}

The = character means an exact match on the URI, and is the first priority in nginx lookup process as described in nginx documentation

An alternative approach is to use regular expression:

server {
    server_name example.com *.example.com;

    listen 80;

    location / {
        proxy_pass http://application;
    }

    location ~ ^(?:/|/news|/about) {
        proxy_pass http://website;
    }
}

The server_name example.com *.example.com tells nginx to process all requests to main domain and any subdomain with these rules.

If the website request rules need to apply only to example.com, then you need to define another server block with server_name *.example.com and application rules only.

Edit

Yes, subdomain can be captured to a variable like that, and used in proxy_pass destination. You need to have all domains in single server_name line:

server_name example.com ~^(?<subdomain>[^.]+)\.example\.com;
Related Topic