Jochen
Jochen

Reputation: 93

Can traefik rewrite the location header of redirect responses (302)

I am using traefik 2.0.2 as reverse proxy in front of some services. One backend services is returning a redirect response (302), where the location header contains the absolute redirected url. The url of the backend is not reachable from the outside, how can I rewrite the location to go through the reverse proxy again?

E.g. a client requests http://my-domain/foo and receives a 302 response with location header containing http://backend:8080/foo/bar/, which of course will not work.

I am looking for something similar to ProxyPassReverse of apache mod_proxy. I have read through the available middlewares of traefik, but nothing seems to fit my requirement.

My simplified configuration:

# traefik.yml
entryPoints:
  web:
    address: ":80"

providers:
  file:
    filename: "dynamic-conf.yml"

# dynamic-conf.yml
http:
  routers:
    router1:
      entryPoints:
        - web
      service: service1
      rule: "PathPrefix(`/foo`)"
  services:
    service1
      loadBalancer:
        servers:
          - url: http://backend:8080

Upvotes: 4

Views: 6917

Answers (3)

Serious Angel
Serious Angel

Reputation: 1564

Docker Traefik Provider Example


Case

For example, in case a WebDav service is behind a TLS reverse-proxy (e.g. Traefik, port 443), and the service itself is running on non-TLS protocol (i.e. port 80), and renaming a file (i.e. HTTP method MOVE) in Nginx may result in error:

..."MOVE /dav/test.txt HTTP/1.1" 400...
...[error] 39#39: *4 client sent invalid "Destination" header...

Related: Seafdav - MOVE command causing 502.


Solution

Static (i.e. traefik.yaml)

experimental:
  plugins:
    rewriteHeaders:
      modulename: 'github.com/bitrvmpd/traefik-plugin-rewrite-headers'
      version: 'v0.0.1'

Dynamic

services:

  app:
    image: php

    volumes:
      - '/var/docker/data/app/config/:/etc/nginx/conf.d/:ro'
      - '/var/docker/data/app/data/:/var/www/'

    networks:
      reverse-proxy:

    labels:
      - 'traefik.enable=true'
      - 'traefik.http.services.app.loadbalancer.server.port=80'

      # Replace 'Destination' request header: 'https://' -> 'http://'
      - 'traefik.http.middlewares.rewriteHeadersMW.plugin.traefik-plugin-rewrite-headers.rewrites.request[0].header=Destination'
      - 'traefik.http.middlewares.rewriteHeadersMW.plugin.traefik-plugin-rewrite-headers.rewrites.request[0].regex=^https://(.+)$'
      - 'traefik.http.middlewares.rewriteHeadersMW.plugin.traefik-plugin-rewrite-headers.rewrites.request[0].replacement=http://$1'

      - 'traefik.http.routers.app.rule=Host(`sub.example.com`)'
      - 'traefik.http.routers.app.entrypoints=https'
      - 'traefik.http.routers.app.priority=2'
      - 'traefik.http.routers.app.middlewares=rewriteHeadersMW'

networks:
  reverse-proxy:
    name: reverse-proxy
    external: true

Non-Traefik alternative: Nginx module headers-more-nginx-module.


Related

Upvotes: 0

XciD
XciD

Reputation: 2617

I had the same issue as you, could not resolve it with your solution, but now, with the traefik plugins, we can:

Static config:

pilot:
  token: "xxxx"

experimental:
  plugins:
    rewriteHeaders:
      modulename: "github.com/XciD/traefik-plugin-rewrite-headers"
      version: "v0.0.2"

Dynamic config:

http:
  routes:
    my-router:
      rule: "Host(`localhost`)"
      service: "my-service"
      middlewares : 
        - "rewriteHeaders"
  services:
    my-service:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1"
  middlewares:
    rewriteHeaders:
      plugin:
        rewriteHeaders:
          header: "Location"
          regex: "^http://(.+)$"
          replacement: "https://$1"

Disclaimer: I'm the author of the plugin

Upvotes: 2

Jochen
Jochen

Reputation: 93

I did not find an option to rewrite the location header of a service response using traefik. A feature request to replaceResponseHeaders exists.

My (temporary) solution is to perform the redirection in traefik using the RedirectRegex middleware, such that the backend service does not need to response with a redirect.

The updated configuration would look like this:

# dynamic-conf.yml
http:
  routers:
    router1:
      entryPoints:
        - web
      service: service1
      rule: "PathPrefix(`/foo`)"
      middlewares:
        - my-redirect
  middlewares:
    my-redirect: # Workaround for service1 redirection
      redirectRegex:
        regex: "^https?://[^/]+/foo/?$"
        replacement: "/foo/webapp/"
  services:
    service1
      loadBalancer:
        servers:
          - url: http://backend:8080

Upvotes: 2

Related Questions