feat: route paths to non-web processes via proxy:route
Adds proxy:route:set/remove/clear/report so users can declare path-prefix routes to non-web Procfile processes without hand-writing nginx.conf.sigil. Routes are stored on the proxy plugin as a PropertyMap of path to process:port:strip, with set semantics so each invocation produces a fully-determined state and re-application is idempotent. A proxy-supports-routes capability trigger gates the command per backend - nginx-vhosts, traefik-vhosts, caddy-vhosts, and scheduler-k3s render routes today; openresty-vhosts and haproxy-vhosts refuse until their sidecar images learn a path-prefix vocabulary (tracked in dokku/openresty-docker-proxy#137 and the haproxy sidecar). Closes #8725.
This commit is contained in:
@@ -236,6 +236,33 @@ fn-nginx-vhosts-render-template() {
|
||||
PROXY_PORT_MAP="$(echo "$proxy_port_map" | xargs)" # trailing spaces mess up default template
|
||||
PROXY_UPSTREAM_PORTS="$(echo "$PROXY_UPSTREAM_PORTS" | xargs)"
|
||||
|
||||
# Path-based routes (proxy:route:set). Format the storage representation
|
||||
# into space-separated sigil variables: PROXY_ROUTES holds the route triples
|
||||
# (process|port|path|strip), PROXY_ROUTE_LISTENERS holds one
|
||||
# (process|port|listener-ip,listener-ip,...) entry per unique process+port
|
||||
# pair so the template can render per-route upstream blocks.
|
||||
local PROXY_ROUTES="" PROXY_ROUTE_LISTENERS=""
|
||||
local route_pair_seen=" "
|
||||
while IFS='|' read -r route_proc route_port route_path route_strip; do
|
||||
[[ -z "$route_proc" ]] && continue
|
||||
PROXY_ROUTES="${PROXY_ROUTES} ${route_proc}|${route_port}|${route_path}|${route_strip}"
|
||||
local route_pair="${route_proc}|${route_port}"
|
||||
if [[ "$route_pair_seen" != *" ${route_pair} "* ]]; then
|
||||
route_pair_seen="${route_pair_seen}${route_pair} "
|
||||
local route_listeners="$(plugn trigger network-get-listeners "$APP" "$route_proc" | xargs)"
|
||||
if [[ -z "$route_listeners" ]]; then
|
||||
# No live containers for this process yet; emit a stub so nginx -t
|
||||
# still passes during pre-validate and the upstream block renders
|
||||
# without a host-not-found error at reload time.
|
||||
route_listeners="127.0.0.1:${route_port}"
|
||||
fi
|
||||
local route_listener_csv="${route_listeners// /,}"
|
||||
PROXY_ROUTE_LISTENERS="${PROXY_ROUTE_LISTENERS} ${route_proc}|${route_port}|${route_listener_csv}"
|
||||
fi
|
||||
done < <(plugn trigger proxy-routes-list "$APP")
|
||||
PROXY_ROUTES="$(echo "$PROXY_ROUTES" | xargs)"
|
||||
PROXY_ROUTE_LISTENERS="$(echo "$PROXY_ROUTE_LISTENERS" | xargs)"
|
||||
|
||||
local SSL_INUSE=
|
||||
local NONSSL_VHOSTS=$(plugn trigger domains-list "$APP")
|
||||
local NOSSL_SERVER_NAME=$(echo "$NONSSL_VHOSTS" | xargs)
|
||||
@@ -352,6 +379,7 @@ fn-nginx-vhosts-render-template() {
|
||||
NGINX_PORT="$PROXY_PORT" NGINX_SSL_PORT="$PROXY_SSL_PORT"
|
||||
PROXY_PORT="$PROXY_PORT" PROXY_SSL_PORT="$PROXY_SSL_PORT"
|
||||
PROXY_PORT_MAP="$PROXY_PORT_MAP" PROXY_UPSTREAM_PORTS="$PROXY_UPSTREAM_PORTS"
|
||||
PROXY_ROUTES="$PROXY_ROUTES" PROXY_ROUTE_LISTENERS="$PROXY_ROUTE_LISTENERS"
|
||||
PROXY_X_FORWARDED_FOR="$PROXY_X_FORWARDED_FOR"
|
||||
PROXY_X_FORWARDED_PORT="$PROXY_X_FORWARDED_PORT"
|
||||
PROXY_X_FORWARDED_PROTO="$PROXY_X_FORWARDED_PROTO"
|
||||
|
||||
@@ -32,6 +32,7 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rogpeppe/go-internal v1.15.0 // indirect
|
||||
github.com/ryanuber/columnize v2.1.2+incompatible // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.58.0 // indirect
|
||||
golang.org/x/sync v0.24.0 // indirect
|
||||
golang.org/x/sys v0.49.0 // indirect
|
||||
|
||||
18
plugins/nginx-vhosts/proxy-supports-routes
Executable file
18
plugins/nginx-vhosts/proxy-supports-routes
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
[[ $DOKKU_TRACE ]] && set -x
|
||||
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
||||
|
||||
trigger-nginx-vhosts-proxy-supports-routes() {
|
||||
declare desc="advertises path-based routing support for nginx"
|
||||
declare trigger="proxy-supports-routes"
|
||||
declare APP="$1"
|
||||
|
||||
if [[ "$(plugn trigger proxy-type "$APP")" != "nginx" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo "true"
|
||||
}
|
||||
|
||||
trigger-nginx-vhosts-proxy-supports-routes "$@"
|
||||
@@ -46,6 +46,34 @@ server {
|
||||
return 301 https://$host:{{ $.PROXY_SSL_PORT }}$request_uri;
|
||||
}
|
||||
{{ else }}
|
||||
{{ range $route := $.PROXY_ROUTES | split " " }}
|
||||
{{ if $route }}
|
||||
{{ $r := $route | split "|" }}
|
||||
{{ $route_proc := index $r 0 }}
|
||||
{{ $route_port := index $r 1 }}
|
||||
{{ $route_path := index $r 2 }}
|
||||
{{ $route_strip := index $r 3 }}
|
||||
location {{ $route_path }} {
|
||||
proxy_pass http://{{ $.APP }}-{{ $route_proc }}-{{ $route_port }}{{ if eq $route_strip "1" }}/{{ end }};
|
||||
proxy_http_version 1.1;
|
||||
proxy_connect_timeout {{ $.PROXY_CONNECT_TIMEOUT }};
|
||||
proxy_read_timeout {{ $.PROXY_READ_TIMEOUT }};
|
||||
proxy_send_timeout {{ $.PROXY_SEND_TIMEOUT }};
|
||||
proxy_buffer_size {{ $.PROXY_BUFFER_SIZE }};
|
||||
proxy_buffering {{ $.PROXY_BUFFERING }};
|
||||
proxy_buffers {{ $.PROXY_BUFFERS }};
|
||||
proxy_busy_buffers_size {{ $.PROXY_BUSY_BUFFERS_SIZE }};
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $http_connection;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Forwarded-For {{ $.PROXY_X_FORWARDED_FOR }};
|
||||
proxy_set_header X-Forwarded-Port {{ $.PROXY_X_FORWARDED_PORT }};
|
||||
proxy_set_header X-Forwarded-Proto {{ $.PROXY_X_FORWARDED_PROTO }};
|
||||
proxy_set_header X-Request-Start $msec;
|
||||
{{ if $.PROXY_X_FORWARDED_SSL }}proxy_set_header X-Forwarded-Ssl {{ $.PROXY_X_FORWARDED_SSL }};{{ end }}
|
||||
}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
location / {
|
||||
{{ if $.DOKKU_APP_WEB_LISTENERS }}
|
||||
|
||||
@@ -158,3 +186,19 @@ upstream {{ $.APP }}-{{ $upstream_port }} {
|
||||
server {{ $listener_ip }}:{{ $upstream_port }};{{ end }}
|
||||
}
|
||||
{{ end }}{{ end }}
|
||||
|
||||
{{ range $entry := $.PROXY_ROUTE_LISTENERS | split " " }}
|
||||
{{ if $entry }}
|
||||
{{ $e := $entry | split "|" }}
|
||||
{{ $route_proc := index $e 0 }}
|
||||
{{ $route_port := index $e 1 }}
|
||||
{{ $route_csv := index $e 2 }}
|
||||
upstream {{ $.APP }}-{{ $route_proc }}-{{ $route_port }} {
|
||||
{{ if $.PROXY_KEEPALIVE }} keepalive {{ $.PROXY_KEEPALIVE }};{{ end }}
|
||||
{{ range $listener := $route_csv | split "," }}
|
||||
{{ $listener_list := $listener | split ":" }}
|
||||
{{ $listener_ip := index $listener_list 0 }}
|
||||
server {{ $listener_ip }}:{{ $route_port }};{{ end }}
|
||||
}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
Reference in New Issue
Block a user