# Proxy methods

<https://habr.com/ru/articles/244027/>

Недавно пришлось разбираться с проксированием доступа к веб-серверам с помощью HAProxy. Основная проблема оказалась в шифрованном доступе. Кому интересна эта тема, добро пожаловать под кат.

Есть в нашей компании ряд веб-серверов. Для экономии адресов доступ к ним организован через HAProxy. Примерно вот так:

![](/files/r4Y66ANIj6FViArNCZet)

При этом конфигурация самого HAProxy крайне простая (пример №1):

\*frontend http\_frontend bind *:80 mode http option httpclose acl is\_mytest1 hdr\_end(host) -i mytest1.loc use\_backend mytest1\_web if is\_mytest1 acl is\_mytest2 hdr\_end(host) -i mytest2.loc use\_backend mytest2\_web if is\_mytest2 backend mytest1\_web mode http cookie SERVERID insert indirect nocache server mytestweb1 192.168.1.5:80 check cookie mytestweb1 backend mytest2\_web mode http cookie SERVERID insert indirect nocache server mytestweb2 192.168.1.10:80 check cookie mytestweb2*

Здесь и далее я буду приводить не полные примеры конфиг-файла, а только интересующие нас куски.

Предельно просто — слушаем 80 порт и разбираем весь входящий траффик. Если запрашивается mytest1.loc, то он попадает в access-list is\_mytest1, в этом случае используется бэкенд mytest1\_web, в котором мы перенаправляем траффик на внутренний хост 192.168.1.5, где у нас и находится данный сайт. Аналогично и для mytest2.loc. Все предельно просто и при этом мы экономим реальные IP адреса.

Встал вопрос отказоустойчивости, тем более что в соседнем городе у нас тоже есть сервера, где мы можем поднять данные веб-сайты. Ну и есть виртуалка с линуксом в облаке Amazon, которая делает тоже самое, но для сайтов, расположенных в облаке. Можем ли мы использовать 2 HAProxy подряд? Поднимаем примерно такую тестовую схему и смотрим:

![](https://gitlab.com/johnmkane/tech-recipe-book/-/blob/main/Book/Architect/Load%20Balance/HAProxy/Proxy%20methods/Untitled)

Конфигурации HAProxy2 и HAProxy3 не изменились, однако в HAProxy1 добавился параметр балансировки (пример №2):

\*frontend http\_frontend bind *:80 mode http option httpclose acl is\_mytest1 hdr\_end(host) -i mytest1.loc use\_backend mytest1\_web if is\_mytest1 acl is\_mytest2 hdr\_end(host) -i mytest2.loc use\_backend mytest2\_web if is\_mytest2 backend mytest1\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server HAProxy1 1.1.1.1:80 check cookie haproxy1\_1 server HAProxy2 3.3.3.3:80 check cookie haproxy2\_1 backend mytest2\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server HAProxy1 1.1.1.1:80 check cookie haproxy1\_3 server HAProxy2 3.3.3.3:80 check cookie haproxy2\_3*

Все отлично заработало. Казалось бы, можно радоваться, но тут сайты решено было переделать под работу через SSL. И начались проблемы.

Вернемся к началу и рассмотрим все с начала. Первое допущение — нам не нужно шифровать траффик между прокси-сервером и самим сайтом. Второе — нам не нужно заботиться о привязке сертификата к сайту, то есть у нас везде используются самоподписанные сертификаты.

![](/files/YAdM6FGPyGBXbd3lOGU6)

Что нам нужно сделать? Сгенерировать и установить на нашем HAProxy сервере самоподписанный сертификат, тогда клиент, обращаясь на сайт, будет попадать на наш прокси-сервер, брать его сертификат, устанавливать защищенное соединение с сервером и дальше перенаправляться на веб-сайт. Причем для всех сайтов, находящихся за прокси-сервером, будет использоваться один сертификат.

Итак, приступим. Генерируем:

*openssl req -new -x509 -nodes -out server.crt -keyout server.key*

Записываем в один файл:

*cat server.key > /etc/ssl/mytest.loc.pem cat server.crt >> /etc/ssl/mytest.loc.pem*

И редактируем конфигурацию HAProxy(пример №3):

\*frontend http\_frontend bind \*:80 mode http option httpclose acl is\_mytest1 hdr\_end(host) -i mytest1.loc use\_backend mytest1\_web if is\_mytest1 acl is\_mytest2 hdr\_end(host) -i mytest2.loc use\_backend mytest2\_web if is\_mytest2 backend mytest1\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server mytestweb1 192.168.1.5:80 check cookie mytestweb1 backend mytest2\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server mytestweb2 192.168.1.10:80 check cookie mytestweb2 frontend https\_frontend bind *:443 ssl crt /etc/ssl/mytest.loc.pem mode http option httpclose acl is\_mytest1 hdr\_end(host) -i mytest1.loc use\_backend mytest1\_web if is\_mytest1 acl is\_mytest2 hdr\_end(host) -i mytest2.loc use\_backend mytest2\_web if is\_mytest2*

Кстати, проверять конфигурацию перед перезапуском — это очень полезная привычка:

*haproxy -c -f /etc/haproxy/haproxy.cfg Configuration file is valid*

Проверяем и видим, что все отлично работает.

Что ж, а теперь возьмем случай, когда на каждом сайте свой сертификат, причем не самоподписанный, а купленный. И в нем есть строгая привязка к имени сайта. В этом случае мы можем решить вопрос двумя способами: разместить сертификаты для сайтов на HAProxy сервере или проксировать TCP вместо HTTP. Но в обоих случаях мы не сможем обойтись одним IP адресом для двух наших сайтов.

Рассмотрим первый случай:

![](/files/LxDWjMXlBFz2sKFk6Eet)

Все отличие данного случая от предыдущего(с самоподписанными сертификатами) только в том, что здесь нам придется слушать отдельные интерфейсы и выдавать сертификат в зависимости от интерфейса (пример №4):

\*frontend http\_frontend bind *:80 mode http option httpclose acl is\_mytest1 hdr\_end(host) -i mytest1.loc use\_backend mytest1\_web if is\_mytest1 acl is\_mytest2 hdr\_end(host) -i mytest2.loc use\_backend mytest2\_web if is\_mytest2 backend mytest1\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server mytestweb1 192.168.1.5:80 check cookie mytestweb1 backend mytest2\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server mytestweb2 192.168.1.10:80 check cookie mytestweb2 frontend https\_frontend\_site1 bind 1.1.1.1:443 ssl crt /etc/ssl/mytest.loc1.pem mode http option httpclose acl is\_mytest1 hdr\_end(host) -i mytest1.loc use\_backend mytest1\_web if is\_mytest1 frontend https\_frontend\_site2 bind 9.9.9.9:443 ssl crt /etc/ssl/mytest.loc2.pem mode http option httpclose acl is\_mytest2 hdr\_end(host) -i mytest2.loc use\_backend mytest2\_web if is\_mytest2*

Вроде все понятно, если траффик пришел на интерфейс с адресом 1.1.1.1, значит, клиент запрашивает сайт mytest1.loc. Значит, мы выдаем ему сертификат этого сайта и дальше проксируем на *backend mytest1\_web*.

Во-втором случае мы пробрасываем полностью весь TCP-траффик, который пришел к нам на 443 порт. Это стоит сделать, например, тогда, когда вы по каким-либо причинам не хотите, чтоб сертификаты сайтов хранились на прокси сервере. Или, например, не доверяете внутренней сети между прокси и веб серверами.

![](/files/mVmaxyQUH3J1AxDSM21V)

Конфигурация HAProxy будет примерно следующая(пример №5):

*frontend mytest1\_frontend bind 1.1.1.1:443 mode tcp use\_backend mytest1\_webssl backend mytest1\_webssl mode tcp option ssl-hello-chk server mytestweb 192.168.1.5:443 frontend mytest2\_frontend bind 9.9.9.9:443 mode tcp use\_backend mytest2\_webssl backend mytest2\_webssl mode tcp option ssl-hello-chk server mytestweb 192.168.1.10:443*

Вроде вполне понятная конфигурация. Наверно, стоит сказать, что поскольку мы прокидываем весь TCP траффик, мы не можем анализировать его, и поэтому наличие любых access-lists в frontend части будет выдавать ошибку.

Настало время вернуться к нашей задаче с разделением web сайтов по разным городам. Для начала рассмотрим более простой случай:

![](https://gitlab.com/johnmkane/tech-recipe-book/-/blob/main/Book/Architect/Load%20Balance/HAProxy/Proxy%20methods/Untitled)

Поскольку между HAProxy1 и HAProxy2 у нас интернет, то даже при использовании самоподписанных сертификатов мы не можем использовать HTTP PROXY MODE на HAProxy1, иначе теряется весь смысл в шифровании такого соединения. Будем использовать на HAProxy1 tcp mode, а на HAProxy2 http mode.

Конфигурация для HAProxy1 (пример №6):

\*frontend https\_frontend bind *:443 mode tcp use\_backend https\_web backend https\_web mode tcp option ssl-hello-chk server haproxy2 1.1.1.1:443*

Конфигурация для HAProxy2 будет идентична конфигурации в примере №3ю

Настало время добавить вторую часть серверов:

![](https://gitlab.com/johnmkane/tech-recipe-book/-/blob/main/Book/Architect/Load%20Balance/HAProxy/Proxy%20methods/Untitled)

Конфигурация для HAProxy1 (пример №7):

\*frontend https\_frontend bind *:443 mode tcp use\_backend https\_web backend https\_web mode tcp balance roundrobin option ssl-hello-chk server haproxy2 1.1.1.1:443 check server haproxy3 3.3.3.3:443 check*

Все отличие данного примера от предыдущего — наличие балансировки и отказоустойчивости между HAProxy2 и HAProxy3, которые по нашему условию должны находиться в разных городах.

Что ж, последний пример будет в случае наличия несамоподписанных сертификатов. Предположим, что они установлены на HAProxy серверах — как в примере №4:

![](https://gitlab.com/johnmkane/tech-recipe-book/-/blob/main/Book/Architect/Load%20Balance/HAProxy/Proxy%20methods/Untitled)

Конфигурация для HAProxy1 будет как в предыдущем примере, а для HAProxy2 — как в примере №4. Такая же для HAProxy3 с небольшими изменениями реальных адресов а *frontend* части.

Также стоит сказать, что можно все 3 HAProxy сервера настроить в TCP MODE — и это тоже будет работоспособное решение.

Ну и напоследок хотелось бы сказать: если кто-то знает какие-то принципиально отличающиеся решения для данной задачи, буду признателен, если вы поделитесь ими.

Небольшой апдейт. Мне тут подумалось, что если мы пробрасываем трафик, то нам незачем использовать на HAProxy2 и HAProxy3 набор различных IP адресов, гораздо проще просто использовать разные порты.

Давайте рассмотрим вот такую схему:

![](https://gitlab.com/johnmkane/tech-recipe-book/-/blob/main/Book/Architect/Load%20Balance/HAProxy/Proxy%20methods/Untitled)

У нас есть две разные хост площадки в разных городах. Одна находится за HAProxy2 и вторая за HAProxy3. И центральный прокси сервер, на котором лежит задача балансировки, при этом сайты [www.mytest1.loc](http://www.mytest1.loc/) и [www.mytest2.loc](http://www.mytest2.loc/) должны балансироваться, а сайт [www.mytest3.loc](http://www.mytest3.loc/) существует только лишь на одной площадке, поэтому доступ к нему должен только пробрасываться через прокси сервер.Все сайты должны быть доступны как по HTTP, так и по HTTPS с несамоподписанными сертификатами.

Конфигурация HAProxy1:

\*frontend http\_frontend bind *:80 mode http option httpclose acl is\_mytest1 hdr\_end(host) -i mytest1.loc use\_backend mytest1\_web if is\_mytest1 acl is\_mytest2 hdr\_end(host) -i mytest2.loc use\_backend mytest2\_web if is\_mytest2 acl is\_mytest3 hdr\_end(host) -i mytest3.loc use\_backend mytest3\_web if is\_mytest3 backend mytest1\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server mytestweb1 1.1.1.1:80 check cookie mytestweb1 server mytestweb1 2.2.2.2:80 check cookie mytestweb1 backend mytest2\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server mytestweb2 1.1.1.1:80 check cookie mytestweb2 server mytestweb2 2.2.2.2:80 check cookie mytestweb2 backend mytest3\_web mode http balance roundrobin cookie SERVERID insert indirect nocache server mytestweb3 2.2.2.2:80 check cookie mytestweb3 frontend mytest1\_frontend bind 3.3.3.3:443 mode tcp use\_backend mytest\_webssl1 backend mytest\_webssl1 mode tcp balance roundrobin option ssl-hello-chk server mytestweb1 1.1.1.1:55551 server mytestweb2 2.2.2.2:55551 frontend mytest2\_frontend bind 4.4.4.4:443 mode tcp use\_backend mytest\_webssl2 backend mytest\_webssl2 mode tcp balance roundrobin option ssl-hello-chk server mytestweb1 1.1.1.1:55552 server mytestweb2 2.2.2.2:55552 frontend mytest3\_frontend bind 5.5.5.5:443 mode tcp use\_backend mytest\_webssl3 backend mytest\_webssl3 mode tcp balance roundrobin option ssl-hello-chk server mytestweb2 2.2.2.2:55553* И конфигурация HAProxy3:

\*frontend http\_frontend bind *:80 mode http option httpclose acl is\_mytest1 hdr\_end(host) -i mytest1.loc use\_backend mytest1\_web if is\_mytest1 acl is\_mytest2 hdr\_end(host) -i mytest2.loc use\_backend mytest2\_web if is\_mytest2 acl is\_mytest3 hdr\_end(host) -i mytest3.loc use\_backend mytest3\_web if is\_mytest3 frontend mytest1\_frontend bind 2.2.2.2:55551 ssl crt /etc/ssl/mytest1.loc.pem mode http option httpclose option forwardfor reqadd X-Forwarded-Proto:\ https use\_backend mytest1\_web frontend mytest2\_frontend bind 2.2.2.2:55552 ssl crt /etc/ssl/mytest2.loc.pem mode http option httpclose option forwardfor reqadd X-Forwarded-Proto:\ https use\_backend mytest2\_web frontend mytest3\_frontend bind 2.2.2.2:55553 ssl crt /etc/ssl/mytest3.loc.pem mode http option httpclose option forwardfor reqadd X-Forwarded-Proto:\ https use\_backend mytest3\_web backend mytest1\_web mode http balance roundrobin stats enable cookie SERVERID insert indirect nocache server mytestweb1 192.168.1.5:80 check cookie mytestweb1 backend mytest2\_web mode http balance roundrobin stats enable cookie SERVERID insert indirect nocache server mytestweb2 192.168.1.10:80 check cookie mytestweb2 backend mytest3\_web mode http balance roundrobin stats enable cookie SERVERID insert indirect nocache server mytestweb3 192.168.1.15:80 check cookie mytestweb3*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://book.konstantinsecurity.com/readme/architect/load-balance/haproxy/proxy-methods.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
