Skip to content

Instantly share code, notes, and snippets.

@jasonk
Last active September 19, 2023 15:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jasonk/a80bed70a45ae314a86f9716dae30bd7 to your computer and use it in GitHub Desktop.
Save jasonk/a80bed70a45ae314a86f9716dae30bd7 to your computer and use it in GitHub Desktop.
Nginx Reverse Proxy Configurations for Hashicorp Consul

I wanted to be able to put the Consul UI behind a reverse proxy, and be able to access it as https://example.com/consul, but it doesn't seem to support that out of the box.

According to hashicorp/consul#14342 it's supportd and you can set a variable to tell the UI what prefix to add to the front of API requests, but after a couple of days of trying I could not figure out how to set that variable (and comments on the PR suggest that nobody else has figured it out either, and Hashicorp hasn't responded to any of those).

I did manage to get it working, but it needed a little kludge. Since I couldn't figure out how to get Consul to set the right variable in the UI, I made Nginx do it instead.

This is the configuration I ended up with. As a bonus this config also includes a map that makes the UI default to read-only even if the UI is running on the consul servers.

References:

http {
# Upstream configuration for the Consul servers to proxy to.
upstream consul_servers {
server consul-a:8500;
server consul-b:8500;
server consul-c:8500;
}
# This map produces a variable named $consul_token.
# If the client provided an "X-Consul-Token" header, then it'll contain that.
# If the client didn't provide a token it defaults to the global read-only token.
map $http_x_consul_token $consul_token {
"" 00000000-0000-0000-0000-000000000002;
default $http_x_consul_token;
}
server {
# Redirect /consul to /consul/
location = /consul { return 302 /consul/ui/; }
# Proxy /consul/ui/ requests to the consul servers /ui/
location /consul/ui/ {
proxy_pass http://consul_servers/ui/;
# Include either the client-supplied token or the global read-only fallback token
proxy_set_header X-Consul-Token $consul_token;
# This is the kludgy part. When sending the HTML of the UI response we look for a chunk of URL-encoded JSON config
# that would decode to `"APIPrefix":""` and replace it with an encoded representation of `"APIPrefix":"/consul"`.
sub_filter '%22APIPrefix%22%3A%22%22' '%22APIPrefix%22%3A%22%2Fconsul%22'
sub_filter_once on;
}
location /consul/v1/ {
proxy_pass http://consul_servers/v1/;
proxy_set_header X-Consul-Token $consul_token;
}
location /consul/ {
proxy_pass http://consul_servers/;
proxy_set_header X-Consul-Token $consul_token;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment