Search code examples
apachereverse-proxymod-proxy

How to forward subdomain host to proxypass with Apache?


My node server is listening at 127.0.0.1:7676. However, it responds differently depending on the subdomain. With a standard ProxyPass config (below), the subdomain is stripped.

How can I forward the subdomain to the node server?

Example 1: Basic Proxy Config:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias *.example.com

    ProxyPass / http://localhost:7676/

</VirtualHost>

Example 2: An Attempt to pass a simply "test" subdomain for all requests

<VirtualHost *:80>
    ServerName example.com
    ServerAlias *.example.com

    RequestHeader set "Host" "test.example.com"
    ProxyPass / http://localhost:7676/

</VirtualHost>

My attempt (example 2) doesn't work. The node server still sees no subdomains. And even if it did work, I need it to be dynamic (take whatever subdomain is requested and pass it to the node server).

Please note, there can be multiple subdomains (test2.test1.example.com).


Solution

  • After some trial and error I figured it out.

    The issue with Example 2, is that instead of setting the "Host" header, Apache decides to implicitly set the "X-Forwarded-Host" header. Honestly, I would have rather it error instead of silently setting a different header, but alright.

    However, in order to forward the host (take whatever subdomain is requested and pass it to the node server), we can use Apache's handy dandy ProxyPreserveHost On, documented here.

    This will set the "X-Forwarded-Host" to the requested host.


    The following is implmentation dependent. I used Node with Express.

    The following is how I implemented the check:

    function getSubDomains(host, offset = 2) {
        const split = host.split(".").reverse();
        return split.slice(2);
    }
    
    router.all('*', function (req, res, next) {
        const subdomains = getSubDomains(req.get("X-Forwarded-Host"));
        // code to use subdomains
    

    Are you asking why I didn't just overwrite req.subdomains? For some reason it didn't work so I just went with this.

    Lastly, I added a quick check to make sure the domain is mine. This probably isn't necessary tho.

    function getSubDomains(host, offset = 2) {
        const split = host.split(".").reverse();
        if (split[0] !== "com" || split[1] !== "example") { // for *.example.com
            return false;
        }
        return split.slice(2);
    }
    
    
    router.all('*', function (req, res, next) {
        const subdomains = getSubDomains(req.get("X-Forwarded-Host"));
        if (!subdomains) {
            res.send("Huh?");
            return;
        }