These examples cover various TLS and cross-site related settings of the UI server.
The Controller-UI serves plain HTTP on -http-port by default, but it assumes running behind a
TLS-terminating reverse proxy or dedicated TLS terminator such as
Hitch. As a result, the authentication cookies are set with the
Secure flag, which browsers only send over HTTPS.
If you use a plaintext connection all the way to the browser, logins will not stick unless the
Secure flag is disabled with -secure-cookies=false.
The start command of the Controller-UI should look like this:
varnish-controller-ui -api-hosts=http://api-gw:8002 -secure-cookies=false
To serve HTTPS from the UI server itself, on -https-port (default 8443), see
HTTPS.
Cross-site protection is based on the browser Origin and Sec-Fetch-Site request headers.
State-changing requests from another origin are rejected unless that origin is listed in
-trusted-origins, which also serves as the CORS allowed-origins list:
varnish-controller-ui -api-hosts=http://api-gw:8002 -trusted-origins=https://tools.example.com
A rejected request is answered with 403 cross-origin request forbidden and logged, so the origin
that has to be allowed can be read from the log:
Rejected cross-origin request: method=POST path=/api/v1/auth/login origin="https://other.example.com" sec-fetch-site="cross-site"
Origins are compared as scheme and host, plus the port if it is not the default one, so list every origin the browser actually uses.
Individual paths can be taken out of the browser protections entirely with
-browser-security-exclusions, for non-browser clients, webhooks and public endpoints. An excluded
path skips the cross-site check, CORS and the security response headers, and on /api/ it is
proxied without the UI server requiring or injecting the authentication cookie, so the request has
to carry its own credentials. Paths are matched exactly, not as prefixes:
varnish-controller-ui -api-hosts=http://api-gw:8002 -browser-security-exclusions=/healthz,/metrics
| Argument | Default | Effect |
|---|---|---|
-hsts |
false |
Sends Strict-Transport-Security: max-age=31536000. Only honored by browsers over HTTPS. |
-csp |
a restrictive policy | Sends Content-Security-Policy with the given policy. An empty value disables the header. |
-x-frame-options |
deny |
Sends X-Frame-Options. sameorigin allows framing from the same origin, an empty value disables the header and leaves framing to the CSP frame-ancestors directive. |
X-Content-Type-Options: nosniff is always sent.
Framing the UI from another origin needs that origin in -trusted-origins as well, since the
authentication cookies are SameSite=Strict and the cross-site check rejects the request otherwise.
If you run the Controller-UI behind Varnish or any other reverse proxy, make sure that the reverse
proxy does not modify the Host header, so that the origin the browser sees matches the origin the
UI server sees. Set X-Forwarded-Proto as well, which is how the UI server knows the external
scheme.
For correct client IPs in the request log behind a proxy, list the proxy addresses in
-trusted-proxy-cidrs; only then is X-Forwarded-For trusted. Without it any client could choose
the address the Controller logs, rate-limits and locks out on.
varnish-controller-ui -api-hosts=http://api-gw:8002 -trusted-proxy-cidrs=10.0.0.0/8
Host header in VarnishIn Varnish (both Varnish Enterprise and the open source Varnish Cache), do not modify the
req.http.host variable in your VCL.
Host header in nginxIf you run the Controller-UI behind nginx, add the following configuration directives behind your
proxy_pass ... entry:
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;