I have a Wordpress site where I want to use middleware to restrict wp-admin, wp-login and xmlrpc to only certain secure IP ranges. I got that working using a combination of the following:
A middlewares.toml file for dynamic Traefik config:
[http.middlewares]
[http.middlewares.bur-whitelist.ipWhiteList]
sourceRange = ["10.10.4.0/24", "10.10.8.0/22", "10.250.10.1/24"]
[http.middlewares.csf-whitelist.ipWhiteList]
sourceRange = ["10.0.0.1/8"]
[http.middlewares.wp-ratelimit.rateLimit]
average = 10
burst = 50
[http.middlewares.bur-secured.chain]
middlewares = ["bur-whitelist", "wp-ratelimit"]
[http.middlewares.csf-secured.chain]
middlewares = ["csf-whitelist", "wp-ratelimit"]
docker-compose.yaml (particularly note the ${SERVICE}_admin rule and middleware lines:
- "traefik.enable=true"
- "traefik.http.routers.${SERVICE}.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.${SERVICE}.service=nginx-${SERVICE}"
- "traefik.http.routers.${SERVICE}.entrypoints=websecure"
- "traefik.http.routers.${SERVICE}.middlewares=wp-ratelimit@file"
- "traefik.http.routers.${SERVICE}.tls=true"
- "traefik.http.routers.${SERVICE}_admin.entrypoints=websecure"
- "traefik.http.routers.${SERVICE}_admin.rule=(Host(`${DOMAIN}`) && Path(`/{(wp-login|wp-admin|xmlrpc)}`, `/{(.*)}/{(wp-login|wp-admin|xmlrpc)}`))"
- "traefik.http.routers.${SERVICE}_admin.middlewares=bur-secured@file"
- "traefik.http.routers.${SERVICE}_admin.tls=true"
- "traefik.${SERVICE}.network=traefik"
This setup does correctly block the wp-admin, wp-login and xmlrpc routes.
Note:Because this is a multisite, I quickly discovered that hackers could enter https://domain/random_entry/wp-admin and it would reroute back to the main wp-admin. This is why I have a second entry in the admin rule with the /{(.*)}/{(wp-login|wp-admin|xmlrpc)}
) to prevent that. Perhaps there is a better way for that to be done?
More importantly, this admin route Path rule is matching more than just wp-admin, wp-login and xmlrpc, and in so doing is breaking other parts of the site. We have some static files mounted at /csf_directives_administratives_final, and for some reason Traefik is matching that path as being part of the admin route, so is applying the IP filter and blocking it. I can't figure out for the life of me why that route rule would match this extra path so I'm hoping someone can point me in the right direction.