Add server locations based on feature flag in an OpenResty nginx.conf file

39 Views Asked by At

In an openresty nginx.conf I would like be able to add locations conditionally based on a feature flag value, like as it follows

env ENABLE_UPSTREAMS;
env UPSTREAM_HOST;


http {  
    upstream upstream1 {
        server ${UPSTREAM_HOST1};
    }

    upstream upstream2 {
        server ${UPSTREAM_HOST2};
    }

    map $ENABLE_UPSTREAMS $enable_upstreams {
        "on" 1;
        default 0;
    }

    server {
        listen 80 default_server;
        listen [::]:80 default_server;

        if ($enable_upstreams = 1) {
            location /some-path {
                proxy_pass http://upstream1;
            }

            location /some-path-2 {
                proxy_pass http://upstream2;
            }

        }
    } 
}

but this does not work. I get as error "location" directive is not allowed here in /usr/local/.

I tried to include as a separate *.conf file but still the same error.

than I tried

location /some-path {
     if ($enable_aws_upstreams = 1) {
         proxy_set_header Host $UPSTREAM_HOST;
         proxy_set_header X-Forwarded-For $remote_addr;
         proxy_pass http://upstream2;
     }
} 

but this end in another error "proxy_set_header" directive is not allowed here in and on other side I do not want to expose any path if is disabled by feature flag

What is the right way in this case?

1

There are 1 best solutions below

0
Dmitry Meyer On BEST ANSWER

Only handful of directives are allowed inside if block (mosty ngx_http_rewrite_module directives since if itself is a part of this module); neither location nor proxy_* is allowed, hence the error.

Assuming (from the tag) that you use OpenResty, we can use the power of ngx_http_lua_module.

Here is a rough example:

env ENABLE_UPSTREAMS;

http {
    upstream disabled {
        server 127.0.0.1:8001;
    }

    upstream upstream1 {
        # upstream1 mock address for demo purposes
        server 127.0.0.1:9001;
    }

    upstream upstream2 {
        # upstream2 mock address for demo purposes
        server 127.0.0.1:9002;
    }

    server {
        listen 8000;

        location /path-1 {
            # we have to predefine the variable
            set $upstream '';
            # set the actual value depending of the environment variable value 
            set_by_lua_block $upstream {
                if os.getenv('ENABLE_UPSTREAMS') == 'on' then
                    return 'upstream1'
                else
                    return 'disabled'
                end
            }
            proxy_pass http://$upstream;
        }

        location /path-2 {
            set $upstream '';
            set_by_lua_block $upstream {
                if os.getenv('ENABLE_UPSTREAMS') == 'on' then
                    return 'upstream2'
                else
                    return 'disabled'
                end
            }
            proxy_pass http://$upstream;
        }
    }

    # dummy "disabled" upstream, just returns 404
    server {
        listen 127.0.0.1:8001;
        return 404;
    }

    # upstream1 mock for demo purposes
    server {
        listen 127.0.0.1:9001;
        return 200 'response from upstream1';
    }

    # upstream2 mock for demo purposes
    server {
        listen 127.0.0.1:9002;
        return 200 'response from upstream2';
    }
}

Without the env variable:

$ openresty -p . -c nginx_if.conf

$ curl http://localhost:8000/path-1/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>openresty</center>
</body>
</html>

$ curl http://localhost:8000/path-2/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>openresty</center>
</body>
</html>

With the env variable:

$ env ENABLE_UPSTREAMS=on openresty -p . -c nginx_if.conf

$ curl http://localhost:8000/path-1/
response from upstream1

$ curl http://localhost:8000/path-2/
response from upstream2