Hosted Service: Sign in Get the Code GitHub Organization
4 min read Manuel Kießling
Symfony Traefik Reverse Proxy Trusted Proxies

Fixing "Moved Permanently" on MCP instance endpoints

Root cause: Symfony generated an http ForwardAuth address for Traefik due to incomplete trusted headers; Traefik then redirected (301) to https. We updated trusted headers and proxy settings to generate https.

A small configuration gap between our app and the reverse proxy caused certain instance HTTP endpoints to reply with “Moved Permanently” (HTTP 301). This post explains what happened and how we fixed it.

The short version

Some links to MCP instance endpoints unexpectedly redirected. The root cause: Symfony generated an http URL for our authentication callback (ForwardAuth) that Traefik uses to validate tokens. Traefik then redirected that address to https (301). We updated our settings so Symfony trusts the proxy and generates the correct https URL. After the change, those endpoints respond normally again—no more surprise redirects.

What changed?

The technical details

The webapp runs behind Traefik. Symfony needs to trust the proxy and consume X-Forwarded-* headers to reconstruct the original request’s scheme, host, and port. With incomplete trusted header configuration, Symfony produced an http URL when composing the ForwardAuth address used in the Traefik label traefik.http.middlewares.mcp-<slug>-auth.forwardauth.address. Traefik subsequently redirected that address to https with a 301.

We fixed this by:

# .env.prod.local.dist
TRUSTED_PROXIES=REMOTE_ADDR

# config/packages/framework.yaml (excerpt)
framework:
  trusted_proxies: '%env(TRUSTED_PROXIES)%'
  trusted_headers: ['x-forwarded-for', 'x-forwarded-host', 'x-forwarded-proto', 'x-forwarded-port', 'x-forwarded-prefix']
# Traefik label (before → after)
traefik.http.middlewares.mcp-<slug>-auth.forwardauth.address=http://app.mcp-as-a-service.com/auth/mcp-bearer-check
# becomes
traefik.http.middlewares.mcp-<slug>-auth.forwardauth.address=https://app.mcp-as-a-service.com/auth/mcp-bearer-check

For operational visibility, we also added a small runbook snippet to quickly inspect Traefik-discovered labels on an instance container when debugging routing:

docker inspect mcp-instance-<slug> | jq -r '.\[0\].Config.Labels
| to_entries[]
| select(.key|startswith("traefik.http."))
| "\(.key)=\(.value)"'

References: Issue #4, PR #5, and orchestration docs.