Skip to content

Provider relay cannot reach loopback-bound published endpoints on a standalone Linux engine #14257

Description

@ndeloof

Description

The provider extension lets a provider announce service endpoints with publish-endpoint messages; Compose then deploys a relay container carrying the service's name on the project networks, so dependent services reach the provider's resource at the compose-native address (http://<service>:<port>).

The relay rewrites host-relative upstreams (localhost, loopback or unspecified addresses) to host.docker.internal (pkg/compose/relay.go, relayUpstream), provisioned through ExtraHosts: host.docker.internal:host-gateway on engines that do not resolve it natively.

This transport is not equivalent across platforms when the provider's endpoint is bound to the host's loopback interface:

  • On Docker Desktop (all OSes), host.docker.internal traffic is proxied by the VM through the host's own loopback, so a 127.0.0.1-bound endpoint is reachable from the relay.
  • On a standalone Linux engine, host-gateway resolves to the bridge gateway address. A connection from the relay container arrives on the bridge interface with that destination address, which a listener bound only to 127.0.0.1 (or ::1) cannot accept. The endpoint publishes successfully, the relay deploys, and dependent services then get connection failures at the compose-native address.

The consequence for provider authors: a published endpoint must be bound to an address reachable from the bridge (in practice the wildcard) to work on standalone Linux engines, which exposes the port on every host interface — or bound to loopback to stay off the LAN, which limits the provider to Docker Desktop. The bundled example provider documents and works around this by binding 0.0.0.0 (docs/examples/provider.go):

// All interfaces, not loopback: on a plain Linux engine host-gateway
// is the bridge IP, which cannot reach a host loopback bind.
server := exec.Command(os.Args[0], "serve-demo", "0.0.0.0:0")

Reproduction

On a standalone Linux engine (not Docker Desktop), run a provider that binds its endpoint to 127.0.0.1:<port> and publishes it, with a dependent service consuming http://<provider-service>:<port>:

  1. docker compose up succeeds — the endpoint is published and the relay starts.
  2. The dependent service's requests to the compose-native address fail to connect.

The e2e suite does not cover this case: TestProviderPublishEndpoint (pkg/e2e/providers_test.go) exercises the full relay path on Linux CI, but with the example provider's wildcard bind. A variant with a loopback-bound endpoint fails on a standalone Linux engine today.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions