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:
Jose Diaz-Gonzalez
2026-06-01 13:48:17 -04:00
parent 2cd558e102
commit ffd5248cc3
29 changed files with 1539 additions and 7 deletions

View File

@@ -14,11 +14,27 @@ trigger-caddy-vhosts-docker-args-process-deploy() {
local proxy_container_https_port proxy_container_https_port_candidate proxy_host_https_port_candidate
local STDIN=$(cat)
if [[ "$PROC_TYPE" != "web" ]]; then
if [[ "$(plugn trigger proxy-type "$APP")" != "caddy" ]]; then
return
fi
if [[ "$(plugn trigger proxy-type "$APP")" != "caddy" ]]; then
if [[ "$PROC_TYPE" != "web" ]]; then
# Non-web processes are only labeled when at least one path-based route
# targets the process. Otherwise caddy-docker-proxy should ignore the
# container entirely.
local route_proc
local has_route=false
while IFS='|' read -r route_proc _ _ _; do
if [[ "$route_proc" == "$PROC_TYPE" ]]; then
has_route=true
break
fi
done < <(plugn trigger proxy-routes-list "$APP")
if [[ "$has_route" != "true" ]]; then
echo -n "$STDIN"
return
fi
fn-caddy-route-labels "$APP" "$PROC_TYPE" "$STDIN"
return
fi

View File

@@ -4,6 +4,70 @@ source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
fn-caddy-route-labels() {
declare desc="emits per-route caddy labels for a non-web container"
declare APP="$1" PROC_TYPE="$2" STDIN="$3"
local caddy_domains app_domains output route_proc route_port route_path route_strip
local matcher_name route_index=0
app_domains="$(plugn trigger domains-list "$APP")"
if [[ -n "$app_domains" ]]; then
caddy_domains="$(echo "$app_domains" | xargs)"
caddy_domains="${caddy_domains// /, }"
fi
output=""
if [[ -n "$caddy_domains" ]]; then
# Joining the same site declared by the web container so this container's
# handler directives are merged into the existing site block by
# caddy-docker-proxy.
output="--label 'caddy=${caddy_domains}'"
fi
while IFS='|' read -r route_proc route_port route_path route_strip; do
[[ -z "$route_proc" ]] && continue
[[ "$route_proc" != "$PROC_TYPE" ]] && continue
local route_slug
route_slug="$(fn-caddy-route-slug "$route_path")"
matcher_name="@${route_slug}"
# The named matcher accepts both the bare prefix and the prefix-glob form
# so requests like /api/v0 and /api/v0/users/42 both match.
output="$output --label 'caddy.${matcher_name}.path=${route_path} ${route_path}/*'"
output="$output --label 'caddy.${route_index}_route=${matcher_name}'"
local sub_index=0
if [[ "$route_strip" == "1" ]]; then
output="$output --label 'caddy.${route_index}_route.${sub_index}_uri=strip_prefix ${route_path}'"
sub_index=$((sub_index + 1))
fi
output="$output --label \"caddy.${route_index}_route.${sub_index}_reverse_proxy={{upstreams ${route_port}}}\""
route_index=$((route_index + 1))
done < <(plugn trigger proxy-routes-list "$APP")
local proxy_labels_file_path=$(fn-proxy-get-labels-file-path "caddy" "$APP")
if [[ -f "$proxy_labels_file_path" ]]; then
while read -r line; do
[[ -z "$line" ]] && continue
output="$output --label '$line'"
done <"$proxy_labels_file_path"
fi
echo -n "$STDIN $output"
}
fn-caddy-route-slug() {
declare desc="returns a deterministic kebab-case slug for a route path"
declare ROUTE_PATH="$1"
local s="${ROUTE_PATH#/}"
s="${s%/}"
s="${s//\//-}"
s="${s,,}"
if [[ -z "$s" ]]; then
s="root"
fi
echo "$s"
}
fn-caddy-logs() {
declare desc="shows the logs for the caddy container"
declare TAIL="$1" NUM="$2"

View File

@@ -0,0 +1,18 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
trigger-caddy-vhosts-proxy-supports-routes() {
declare desc="advertises path-based routing support for caddy"
declare trigger="proxy-supports-routes"
declare APP="$1"
if [[ "$(plugn trigger proxy-type "$APP")" != "caddy" ]]; then
return
fi
echo "true"
}
trigger-caddy-vhosts-proxy-supports-routes "$@"