Behind a reverse proxy
Serve the console, the explorer, the file API and the Swagger UI under
https://host/craft/, the proxy stripping the prefix or passing it through.
| Mode | The proxy | The configuration |
|---|---|---|
strip (Traefik StripPrefix, an Ingress rewrite-target, nginx proxy_pass http://up/;) | receives /craft/x, forwards /x, writes X-Forwarded-Prefix: /craft | the paths after stripping: often the defaults |
| pass-through | forwards /craft/x unchanged | base_path, prefix and [api.ui] path under /craft |
Stripping the prefix
[admin]
listen = "0.0.0.0:8080"
[admin.ban]
trusted_proxies = ["10.42.0.0/16"] # the proxy
[api]
enabled = true
openapi = true
[api.ban]
trusted_proxies = ["10.42.0.0/16"] # the same: one listener
[api.ui]
enabled = true
The browser opens the console at https://host/craft/, the explorer at
https://host/craft/files/, the Swagger UI at
https://host/craft/api/docs/; the API answers under
https://host/craft/api/v1/files/. Open the prefix with its trailing /:
nginx and the Traefik redirect below send /craft to /craft/.
nginx:
location /craft/ {
proxy_pass http://craft-file-gate:8080/;
proxy_set_header X-Forwarded-Prefix /craft;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off; # the console's streams
client_max_body_size 0; # uploads
}
Traefik (dynamic configuration; stripPrefix writes X-Forwarded-Prefix
and X-Forwarded-For):
http:
middlewares:
craft-slash:
redirectRegex:
regex: "^(https?://[^/]+/craft)$"
replacement: "${1}/"
craft-strip:
stripPrefix:
prefixes: ["/craft"]
routers:
craft:
rule: "PathPrefix(`/craft`)"
middlewares: [craft-slash, craft-strip]
service: craft
services:
craft:
loadBalancer:
servers:
- url: "http://craft-file-gate:8080"
Kubernetes, ingress-nginx, in front of the <release>-api Service of the
chart:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: craft-file-gate
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/x-forwarded-prefix: /craft
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-body-size: "0"
spec:
ingressClassName: nginx
rules:
- host: files.example.com
http:
paths:
- path: /craft/(.*)
pathType: ImplementationSpecific
backend:
service:
name: craft-file-gate-api
port:
name: admin
The proxy must set or clear X-Forwarded-Prefix, never pass the client’s on.
trusted_proxies names the proxy’s addresses: under Kubernetes, the pod
CIDR of the ingress, see Behind an ingress.
Passing the path through
[admin]
listen = "0.0.0.0:8080"
base_path = "/craft/console"
[api]
enabled = true
prefix = "/craft/api/v1/files"
[api.ui]
enabled = true
path = "/craft/files"
location /craft/ {
proxy_pass http://craft-file-gate:8080;
proxy_set_header X-Forwarded-Prefix "";
proxy_buffering off;
client_max_body_size 0;
}
The console is at https://host/craft/console/, the explorer at
https://host/craft/files/. The proxy clears X-Forwarded-Prefix: it never
passes the client’s on (ingress-nginx without the x-forwarded-prefix
annotation passes it; HAProxy: http-request del-header X-Forwarded-Prefix). The Swagger UI stays at the server’s
/api/docs: route /api/docs and /api/openapi.json on their own, or strip
the prefix.
What the server writes
| URL | Behind a proxy that strips the prefix |
|---|---|
pages, files, fonts, API calls, the console’s streams, redirects (/files to files/, /api/docs to docs/) | relative to their page: nothing to set |
a download ticket’s URL, the servers entry of the OpenAPI document | prefixed with X-Forwarded-Prefix, when the TCP peer is in trusted_proxies |
/livez, /readyz, /metrics | read on the pod by the kubelet and Prometheus, outside the prefix |
The prefix is a path of letters, digits, -, _, ., ~, on one header
line, 256 bytes at most. X-Forwarded-Host and X-Forwarded-Proto are not
read: no URL the server writes carries a host or a scheme. The server’s
routing does not change: only the URLs it writes follow the prefix.