I’m deploying multiple WordPress instances for each GitLab merge request. I cannot use subdomains; each instance lives under a unique path prefix on the same host/port.
Examples:
https://test.domain.com:18086/x/y/mr1/wordpress/
https://test.domain.com:18086/x/y/mr2/wordpress/
Stack: Docker, Traefik v2, Nginx, WordPress.
What changed / Current problem
Originally, hitting https://test.domain.com:18086/x/y/mr1/wordpress//wp-admin/ redirected to the root (https://test.domain.com:18086/wp-admin).
After adjusting my configuration, the URL stays under the correct prefix, but now the browser shows ERR_TOO_MANY_REDIRECTS.
This happens both on the test server and on localhost.
On localhost, the only working workaround is to remove Traefik completely and add this to .htaccess:
RewriteRule ^x/y/mr1/(.*) /$1 [L]
This fixes wp-admin
, but I want to solve it cleanly through Traefik.
Compose service (simplified)
wordpress:
build:
context: ../
dockerfile: ./build/wordpress/Dockerfile
args:
DIST: ./build/wordpress
TOOLS: ./tools
WP_PATH_PREFIX: ${WP_PATH_PREFIX}
container_name: ${MR_NAME}-wordpress
restart: always
depends_on:
wp_db:
condition: service_healthy
networks:
- wp_internal
- traefik_wordpress_backend
environment:
WP_PATH_PREFIX: ${WP_PATH_PREFIX}
WORDPRESS_DB_HOST: wp_db
WORDPRESS_DB_USER: ${WP_DB_USER}
WORDPRESS_DB_PASSWORD: ${WP_DB_PASS}
WORDPRESS_DB_NAME: ${WP_DB_NAME}
WORDPRESS_CONFIG_EXTRA: |
define('WP_HOME', '${WP_URL}');
define('WP_SITEURL', '${WP_CUSTOM_SITEURL}');
define('FORCE_SSL_ADMIN', ${FORCE_SSL_ADMIN});
MR_NAME: ${MR_NAME}
WP_URL: ${WP_URL}
labels:
- "traefik.enable=true"
- "traefik.docker.network=traefik_wordpress_backend"
- "traefik.http.routers.${MR_NAME}-wordpress.rule=PathPrefix(`${WP_PATH_PREFIX}`)"
- "traefik.http.routers.${MR_NAME}-wordpress.entrypoints=web"
- "traefik.http.routers.${MR_NAME}-wordpress.priority=50"
- "traefik.http.routers.${MR_NAME}-wordpress.service=${MR_NAME}-wordpress"
- "traefik.http.services.${MR_NAME}-wordpress.loadbalancer.server.port=80"
- "traefik.http.middlewares.${MR_NAME}-stripprefix.stripprefix.prefixes=${WP_PATH_PREFIX}"
- "traefik.http.middlewares.${MR_NAME}-fix-host.headers.customrequestheaders.Host=${WP_HOST}"
- "traefik.http.middlewares.${MR_NAME}-fix-host.headers.customrequestheaders.X-Forwarded-Host=${WP_HOST}"
- "traefik.http.middlewares.${MR_NAME}-fix-host.headers.customrequestheaders.X-Forwarded-Proto=http"
- "traefik.http.middlewares.${MR_NAME}-fix-host.headers.customrequestheaders.X-Forwarded-Prefix=${WP_PATH_PREFIX}"
- "traefik.http.routers.${MR_NAME}-wordpress.middlewares=${MR_NAME}-stripprefix@docker,${MR_NAME}-fix-host@docker"
volumes:
- wp_data:/var/www/html
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
My Questions
-
Is there a recommended way to configure Traefik + WordPress for path-based multi-instance deployments (not subdomains)?
-
Should I be using StripPrefix, X-Forwarded-Prefix, or a different approach to make WordPress respect the path?
-
Are there any known best practices for handling wp-admin and wp-login.php behind Traefik when WordPress lives under a path prefix?
-
Do I need additional X-Forwarded-* headers (like X-Forwarded-Port) to avoid redirect loops?
Any guidance or working examples would be very helpful!