refactor: drop proxy-supports-routes capability trigger

The trigger was added to refuse proxy:route:set under openresty and haproxy, but the hard refusal created an ordering dependency for declarative tools and blocked users from staging routes ahead of a backend switch. Routes are now stored regardless of the active backend and silently ignored by backends that do not render them; the docs call out the inert behavior under openresty and haproxy.
This commit is contained in:
Jose Diaz-Gonzalez
2026-06-01 14:34:15 -04:00
parent 9153bb5097
commit a4d40becd8
11 changed files with 8 additions and 167 deletions

View File

@@ -2390,27 +2390,6 @@ while IFS='|' read -r proc port path strip; do
done < <(plugn trigger proxy-routes-list "$APP")
```
### `proxy-supports-routes`
- Description: Returns `true` if the proxy backend currently selected for the app supports path-based routes (`proxy:route:set`), `false` otherwise. Implemented by each in-tree proxy plugin (nginx, traefik, caddy, and k3s return `true`; openresty and haproxy return `false`). The `proxy:route:set` command calls this trigger and refuses with a "not supported" message when the result is `false`.
- Invoked by: `proxy:route:set` in the `proxy` plugin
- Arguments: `$APP`
- Example:
```shell
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
APP="$1"
if [[ "$(plugn trigger proxy-type "$APP")" != "my-proxy" ]]; then
return
fi
echo "true"
```
### `proxy-type`
- Description: Returns the proxy type for an app

View File

@@ -196,7 +196,7 @@ See the [port management documentation](/docs/networking/port-management.md) for
By default, every HTTP/HTTPS request is routed to the `web` process declared in the app's `Procfile`. Use `proxy:route:*` to route specific path prefixes to a different process within the same app - for example, sending `/api/v0/*` to an `api` process or `/ws` to a `websocket` process. The `web` process always handles every other path as an implicit catch-all.
> [!NOTE]
> Path-based routing is supported by the `nginx`, `traefik`, `caddy`, and `k3s` proxy backends. The `openresty` and `haproxy` backends do not currently support it; `proxy:route:set` exits with a "not supported" message under those backends. Support is tracked in [dokku/openresty-docker-proxy#137](https://github.com/dokku/openresty-docker-proxy/issues/137) and the `haproxy-vhosts` sidecar.
> Path-based routing is rendered by the `nginx`, `traefik`, `caddy`, and `k3s` proxy backends. The `openresty` and `haproxy` backends accept and store route declarations, but the routes are inert (no labels are emitted) because the sidecar images do not yet support path-prefix vocabulary. Routes stored ahead of a backend switch will activate automatically once the proxy is changed to a rendering backend. Tracked at [dokku/openresty-docker-proxy#137](https://github.com/dokku/openresty-docker-proxy/issues/137) and the `haproxy-vhosts` sidecar.
#### Adding a route
@@ -273,6 +273,7 @@ dokku proxy:route:set node-js-app api /api/v0/admin
- **nginx**: route changes take effect immediately on the next `proxy-build-config` reload (which `proxy:route:*` invokes automatically).
- **traefik** and **caddy**: routes are applied via Docker labels on the target containers. Containers must be recreated for new or removed labels to take effect. The command prints a notice instructing you to run `dokku ps:rebuild <app>` to recreate containers.
- **k3s**: route changes take effect on the next deploy when the chart is re-rendered.
- **openresty** and **haproxy**: routes are stored but inert under these backends. They activate automatically if you switch to a rendering backend (`nginx`, `traefik`, `caddy`, or `k3s`).
- **WebSocket** traffic is forwarded transparently on `nginx`, `traefik`, `caddy`, and `k3s` backends - no additional configuration is required.
- A route to a process that is scaled to `0` will resolve to no upstream until the process is scaled up (`dokku ps:scale <app> <process>=1`). `proxy:route:set` warns when this is the case.

View File

@@ -1,18 +0,0 @@
#!/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 "$@"

View File

@@ -1,21 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
trigger-haproxy-vhosts-proxy-supports-routes() {
declare desc="advertises path-based routing support for haproxy (currently false)"
declare trigger="proxy-supports-routes"
declare APP="$1"
if [[ "$(plugn trigger proxy-type "$APP")" != "haproxy" ]]; then
return
fi
# The byjg/easy-haproxy sidecar image only supports host-based routing.
# Path-prefix routing requires either an upstream change to that sidecar
# or a different config-generation strategy.
echo "false"
}
trigger-haproxy-vhosts-proxy-supports-routes "$@"

View File

@@ -1,18 +0,0 @@
#!/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 "$@"

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
trigger-openresty-vhosts-proxy-supports-routes() {
declare desc="advertises path-based routing support for openresty (currently false)"
declare trigger="proxy-supports-routes"
declare APP="$1"
if [[ "$(plugn trigger proxy-type "$APP")" != "openresty" ]]; then
return
fi
# The openresty sidecar image does not yet accept path-prefix routing labels.
# Tracked upstream at dokku/openresty-docker-proxy#137.
echo "false"
}
trigger-openresty-vhosts-proxy-supports-routes "$@"

View File

@@ -23,15 +23,6 @@ func CommandRouteSet(appName string, processName string, path string, port int,
return errors.New("Usage: dokku proxy:route:set <app> <process> <path> [--port <port>] [--strip-prefix]")
}
supported, err := SupportsRoutes(appName)
if err != nil {
return err
}
if !supported {
proxyType := getComputedProxyType(appName)
return fmt.Errorf("path-based routing is not yet supported with the %s proxy backend", proxyType)
}
if port == 0 {
port = DefaultRoutePort
}

View File

@@ -171,21 +171,6 @@ func RoutedProcessTypes(appName string) ([]string, error) {
return out, nil
}
// SupportsRoutes returns true if the proxy backend selected for the app
// supports path-based routing, as declared by the proxy-supports-routes
// trigger. Backends that do not implement the trigger are treated as not
// supporting routes (conservative default).
func SupportsRoutes(appName string) (bool, error) {
result, err := common.CallPlugnTrigger(common.PlugnTriggerInput{
Trigger: "proxy-supports-routes",
Args: []string{appName},
})
if err != nil {
return false, err
}
return result.StdoutContents() == "true", nil
}
// AddRoute upserts a route. Returns whether the stored state changed.
func AddRoute(appName string, route Route) (bool, error) {
if err := ValidatePath(route.Path); err != nil {

View File

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

View File

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

View File

@@ -218,32 +218,30 @@ teardown() {
assert_output "true"
}
@test "(proxy:route:set) refuses under openresty backend" {
@test "(proxy:route:set) stores routes under openresty backend even though they are inert" {
dokku proxy:set "$TEST_APP" openresty >/dev/null 2>&1 || skip "openresty proxy not available"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "not yet supported"
assert_success
run /bin/bash -c "dokku proxy:route:report $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_output_contains "(none)"
assert_output_contains "/api/v0 -> api:5000"
}
@test "(proxy:route:set) refuses under haproxy backend" {
@test "(proxy:route:set) stores routes under haproxy backend even though they are inert" {
dokku proxy:set "$TEST_APP" haproxy >/dev/null 2>&1 || skip "haproxy proxy not available"
run /bin/bash -c "dokku proxy:route:set $TEST_APP api /api/v0"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "not yet supported"
assert_success
run /bin/bash -c "dokku proxy:route:report $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_output_contains "(none)"
assert_output_contains "/api/v0 -> api:5000"
}