Назад | Перейти на главную страницу

Перенаправление Haproxy на основе пути

Похожий на HAProxy reqrep удалить URI по бэкэнд-запросу.

К нам относятся следующие проблемы.

У нас есть приложения, которые работали с разными корнями контекста из одного домена. Однако не все клиенты URL-адресов были изменены.

Я хотел бы перенаправить с перенаправлением 301 в haproxy, если запрос соответствует устаревшему пути.

Взять к примеру http://example.com/abc и http://example.com/def

...
frontend https
  bind *:{{ proxy_port }} ssl crt /etc/haproxy/bundle_dh.pem ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4 no-sslv3
  http-request set-header X-Forwarded-Proto https if { ssl_fc }
  http-request set-header X-Forwarded-Port %[dst_port]

  acl has_legacy_abc path_beg /abc
  acl has_legacy_def path_beg /def
  redirect location 301 https://abcdomain.com/{PATH_WITHOUT_ABC} if { has_legacy_abc }
  redirect location 301 https://defdomain.com/{PATH_WITHOUT_ABC} if { has_legacy_def }

  use backend abc_backend if { hdr(Host) -i abcdomain.com }
  use backend def_backend if { hdr(Host) -i defdomain.com }
...

Проблема в том, как сохранить путь в редиректе. Я могу сделать абсолютное перенаправление.

Посмотрел и reqrep но это похоже на изменение запроса перед переходом на бэкэнд. Я хочу сказать всем посетителям, что им следует перейти в новый домен.

У меня такая же проблема, и я нашел другое решение, которое, на мой взгляд, лучше. Это другое решение хорошо работает с haproxy версии 1.6+. Оно использует http-запрос и regsub.

Если я перепишу ваш пример:

frontend https
  bind *:{{ proxy_port }} ssl crt /etc/haproxy/bundle_dh.pem ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4 no-sslv3
  acl has_legacy_abc path_beg /abc
  acl has_legacy_def path_beg /def
  http-request redirect code 301 location https://%[hdr(host)]%[url,regsub(^/abc,/newabc,)] if has_legacy_abc

Это можно сделать с помощью таких временных заголовков, вставленных между вашими acl определения и use_backend ключевые слова:

http-request set-header X-Location-Path %[capture.req.uri] if has_legacy_abc OR has_legacy_def

http-request replace-header X-Location-Path [^/]+/(.*) \1 if has_legacy_abc OR has_legacy_def

http-request redirect location https://abcdomain.com/%[hdr(X-Location-Path)] if has_legacy_abc
http-request redirect location https://defdomain.com/%[hdr(X-Location-Path)] if has_legacy_def

В зависимости от фактической конфигурации ваших доменов / путей и необходимых перенаправлений, возможно, даже удастся свернуть все это в один набор директив, например:

...
frontend https
  bind *:{{ proxy_port }} ssl crt /etc/haproxy/bundle_dh.pem ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4 no-sslv3
  http-request set-header X-Forwarded-Proto https if { ssl_fc }
  http-request set-header X-Forwarded-Port %[dst_port]

  acl has_legacy path_beg /abc /def

  http-request set-header X-Location-Path %[capture.req.uri] if has_legacy
  http-request set-header X-Location-Host %[capture.req.uri] if has_legacy

  http-request replace-header X-Location-Host /([^/]*)/ \1 if has_legacy
  http-request replace-header X-Location-Path [^/]+/(.*) \1 if has_legacy

  http-request redirect location https://%[hdr(X-Location-Host)]domain.com/%[hdr(X-Location-Path)] if has_legacy_abc

  use backend abc_backend if { hdr(Host) -i abcdomain.com }
  use backend def_backend if { hdr(Host) -i defdomain.com }
...

Если количество путей и доменов огромно, вы можете использовать карты (где ключ - это путь, а значение - целевой хост), чтобы еще больше упростить задачу.