Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

query: Fix external prefix and add an e2e test for it #2800

Merged
merged 12 commits into from
Jul 2, 2020
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ We use *breaking* word for marking changes that are not backward compatible (rel
- [#2728](https://github.com/thanos-io/thanos/pull/2728) Query: Fixed panics when using larger number of replica labels with short series label sets.
- [#2787](https://github.com/thanos-io/thanos/pull/2787) Update Prometheus mod to pull in prometheus/prometheus#7414.
- [#2807](https://github.com/thanos-io/thanos/pull/2807) Store: decreased memory allocations while querying block's index.
- [#2800](https://github.com/thanos-io/thanos/pull/2800) Query: Fix handling of `--web.external-prefix` and `--web.route-prefix`
- [#2809](https://github.com/thanos-io/thanos/pull/2809) Query: `/api/v1/stores` now guarantees to return a string in the `lastError` field.

### Changed
Expand Down
10 changes: 9 additions & 1 deletion cmd/thanos/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func registerQuery(m map[string]setupFunc, app *kingpin.Application) {
caCert := cmd.Flag("grpc-client-tls-ca", "TLS CA Certificates to use to verify gRPC servers").Default("").String()
serverName := cmd.Flag("grpc-client-server-name", "Server name to verify the hostname on the returned gRPC certificates. See https://tools.ietf.org/html/rfc4366#section-3.1").Default("").String()

webRoutePrefix := cmd.Flag("web.route-prefix", "Prefix for API and UI endpoints. This allows thanos UI to be served on a sub-path. This option is analogous to --web.route-prefix of Promethus.").Default("").String()
webRoutePrefix := cmd.Flag("web.route-prefix", "Prefix for API and UI endpoints. This allows thanos UI to be served on a sub-path. Defaults to the value of --web.external-prefix. This option is analogous to --web.route-prefix of Promethus.").Default("").String()
webExternalPrefix := cmd.Flag("web.external-prefix", "Static prefix for all HTML links and redirect URLs in the UI query web interface. Actual endpoints are still served on / or the web.route-prefix. This allows thanos UI to be served behind a reverse proxy that strips a URL sub-path.").Default("").String()
webPrefixHeaderName := cmd.Flag("web.prefix-header", "Name of HTTP request header used for dynamic prefixing of UI links and redirects. This option is ignored if web.external-prefix argument is set. Security risk: enable this option only if a reverse proxy in front of thanos is resetting the header. The --web.prefix-header=X-Forwarded-Prefix option can be useful, for example, if Thanos UI is served via Traefik reverse proxy with PathPrefixStrip option enabled, which sends the stripped prefix value in X-Forwarded-Prefix header. This allows thanos UI to be served on a sub-path.").Default("").String()

Expand Down Expand Up @@ -139,6 +139,14 @@ func registerQuery(m map[string]setupFunc, app *kingpin.Application) {
fileSD = file.NewDiscovery(conf, logger)
}

if *webRoutePrefix == "" {
*webRoutePrefix = *webExternalPrefix
}

if *webRoutePrefix != *webExternalPrefix {
level.Warn(logger).Log("msg", "different values for --web.route-prefix and --web.external-prefix detected, web UI may not work without a reverse-proxy.")
}

promql.SetDefaultEvaluationInterval(time.Duration(*defaultEvaluationInterval))

flagsMap := map[string]string{}
Expand Down
3 changes: 2 additions & 1 deletion docs/components/query.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@ Flags:
returned gRPC certificates. See
https://tools.ietf.org/html/rfc4366#section-3.1
--web.route-prefix="" Prefix for API and UI endpoints. This allows
thanos UI to be served on a sub-path. This
thanos UI to be served on a sub-path. Defaults
to the value of --web.external-prefix. This
option is analogous to --web.route-prefix of
Promethus.
--web.external-prefix="" Static prefix for all HTML links and redirect
Expand Down
66 changes: 66 additions & 0 deletions docs/operating/reverse-proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: Running Thanos behind a reverse proxy
type: docs
menu: operating
slug: /reverse-proxy.md
---

# Running Thanos behind a reverse proxy

There are many reasons to use a [reverse proxy](https://www.nginx.com/resources/glossary/reverse-proxy-server/) in front of Thanos, for example, TLS termination (serve Thanos over HTTPS) and basic authentication. This small guide will tell you how to do that.

## External Prefix and Route Prefix

Before continuing, let's first take a look at two CLI flags provided by Thanos, `--web.external-prefix` and `--web.route-prefix`. The external prefix is useful when you want to prefix all requests from the UI with some path. Normally, the web UI would load all static assets from `/static/...`, do API calls on `/api/v1/...` etc. But if we use `--web.external-prefix="thanos"` the UI would prefix each request with `/thanos`. It would try to load all assets from `/thanos/static/...`, do API calls on `/thanos/api/v1/...` and so on. One thing to note here is that `--web.external-prefix` only prefixes the requests and redirects with the specified value, but Thanos is still listening on the root, not the specified sub-path i.e. the API is still accessible at `/api/v1/...` and not at `/thanos/api/v1`. This is where `--web.route-prefix` comes in. If you set `--web.route-prefix="thanos"` every route would get prefixed with the specified value. For example, the API will be accessible on `/thanos/api/v1`. As this is the most common use case when using the `--web.external-prefix`, the default value of `--web.route-prefix` is the value of `--web.external-prefix`.

Note: Using different values for `--web.external-prefix` and `--web.route-prefix` can lead to the web UI not working properly if it is accessed directly (without a reverse proxy).

## Examples

Let's look into some example scenarios. All examples are using nginx as a reverse proxy here.

### Serving Thanos on a subdomain

Serving a Thanos component on the root of a subdomain is pretty straight-forward. Let's say you want to run Thanos Query behind a nginx reverse proxy, accessible on domain `thanos.example.com`. A basic nginx configuration would look like this:

```
http {
server {
listen 80;
server_name thanos.example.com;

location / {
proxy_pass http://localhost:10902/;
}
}
}
```

### Serving Thanos on a sub-path

Things become a little tricky when you want to serve Thanos on a sub-path. Let's say, you want to run Thanos Query behind an nginx server, accessible on the URL `http://example.com/thanos`. The Thanos web UI depends on it being accessed on the same URL as Thanos itself is listening. This is because the UI needs to know the URL from where to load static assets and what URL to use in links or redirects. If Thanos is behind a reverse proxy, particularly one where Thanos is not at the root, this doesn't work so well.

To tackle this problem, Thanos provides a flag `--web.external-prefix`.

Let's say we have Thanos Query running on the usual port, we need nginx running with the following configuration:

```
http {
server {
listen 80;
server_name example.com;

location /thanos/ {
proxy_pass http://localhost:10902/thanos/;
}
}
}
```

With this configuration, you can access Thanos Query on `http://example.com/thanos`. Notice that because we are using `http://localhost:10902/thanos/` as the reverse proxy target, every request path will be prefixed with `/thanos`. To make this work we need to run Thanos Query like this:

```
thanos query --web.external-prefix="thanos"
```

It should be noted that now the `/thanos` path prefix would be required for all HTTP access to Thanos. For example, the `/metrics` endpoint would be accessible at `http://localhost:10902/thanos/metrics`.
Loading