Files
reverse-proxy/README.md
T

25 KiB
Raw Blame History

reverse-proxy

Периметровая конфигурация HAProxy для сети kalinamall.ru: Exchange, RDS (веб/шлюз по HTTPS), 1С, почтовый шлюз KSMG. Прямой RDP (3389) через HAProxy не используется — клиенты идут через RDS на 443 (rds.kalinamall.ru).

TLS: на целевых серверах используются wildcard-сертификаты GlobalSign; HAProxy на 443 работает в режиме TCP + SNI и не терминирует TLS — сертификаты остаются на бэкендах.

Репозиторий: https://github.com/PTah/reverse-proxy

Клонирование на Ubuntu, обновление и доступ без постоянного ввода пароля

Установка Git

sudo apt update
sudo apt install -y git

Первое клонирование

Публичный репозиторий можно клонировать без логина и пароля:

cd ~
git clone https://github.com/PTah/reverse-proxy.git
cd reverse-proxy

Если репозиторий станет приватным или понадобятся push-правки с сервера, используйте один из способов ниже.

Обновление локальной копии

cd ~/reverse-proxy
git pull origin main

После git pull снова скопируйте при необходимости файлы в /etc/haproxy/ (см. раздел «Установка конфигурации»).

Как не вводить логин и пароль при каждом git pull / git push

Способ 1: SSH-ключ (предпочтительно)

  1. Создайте ключ (имя файла можно своё):

    ssh-keygen -t ed25519 -C "ubuntu-haproxy" -f ~/.ssh/id_ed25519_github
    

    Парольную фразу можно задать или оставить пустой (на сервере оцените риски).

  2. Покажите публичный ключ и добавьте его в GitHub: Settings → SSH and GPG keys → New SSH key.

    cat ~/.ssh/id_ed25519_github.pub
    
  3. Проверьте доступ:

    ssh -T git@github.com
    
  4. Клонируйте по SSH (или смените URL у уже существующего клона):

    git clone git@github.com:PTah/reverse-proxy.git
    # уже склонировано по HTTPS — переключение:
    # git remote set-url origin git@github.com:PTah/reverse-proxy.git
    

Дальше git pull / git push идут по SSH без пароля GitHub (при необходимости один раз вводится только passphrase ключа, если вы её задали; её можно кешировать через ssh-agent).

Способ 2: HTTPS + Personal Access Token (PAT)

GitHub не принимает обычный пароль от аккаунта для операций git clone / git pull / git push по HTTPS. Вместо пароля нужно создать Personal Access Token (PAT) и вводить его там, где Git спрашивает пароль.

Создание классического токена (Tokens classic) — проще всего для Git
  1. Войдите на github.com под нужным аккаунтом.
  2. В правом верхнем углу откройте меню аватараSettings (Настройки).
  3. В левой колонке прокрутите вниз до раздела Developer settings (Параметры разработчика) и откройте его.
  4. Выберите Personal access tokensTokens (classic).
  5. Нажмите Generate new tokenGenerate new token (classic).
  6. Заполните поля:
    • Note — произвольное имя (например ubuntu-haproxy-pull), чтобы потом понимать, зачем токен.
    • Expiration — срок действия (чем короче, тем безопаснее; для сервера часто выбирают ограниченный срок и потом перевыпускают).
    • Select scopes — для приватного репозитория и pull/push включите минимум repo (полный доступ к репозиториям). Если нужен только чтение приватного репо, в классических токенах по-прежнему часто отмечают repo, т.к. узкого «только read» в classic нет; для только pull удобнее fine-grained (ниже).
  7. Нажмите Generate token внизу страницы.
  8. Сразу скопируйте строку токена (начинается часто с ghp_…). GitHub покажет её один раз; после ухода со страницы повторно не отобразит.
Fine-grained token (по желанию, гибче по правам)
  1. Те же SettingsDeveloper settingsPersonal access tokensFine-grained tokens.
  2. Generate new token.
  3. Укажите имя, срок, в блоке Repository access выберите «только выбранный репозиторий» reverse-proxy (или «все» — по политике безопасности).
  4. В Permissions для чтения/обновления кода задайте Contents: Read-only или Read and write, при необходимости Metadata: Read.
  5. Создайте токен и скопируйте его (формат обычно github_pat_…).
Использование PAT в Git на Ubuntu
  • Username (логин): ваш логин GitHub (короткое имя пользователя), не e-mail, если Git явно просит username.
  • Password: вставьте целиком PAT (не пароль от сайта).

Пример первого клонирования по HTTPS:

git clone https://github.com/PTah/reverse-proxy.git
# при запросе: Username = ваш_логин_github
#              Password = вставить PAT
Чтобы не вводить PAT каждый раз

Токен хранится в открытом виде в ~/.git-credentials — используйте только на доверенных машинах:

git config --global credential.helper store
cd ~/reverse-proxy
git pull origin main
# один раз ввести Username + PAT — дальше подставятся из файла

Кеш в памяти на заданное время (секунды), без постоянной записи в файл:

git config --global credential.helper 'cache --timeout=28800'

После истечения срока кеша или срока действия токена на GitHub снова создайте новый PAT и при необходимости обновите сохранённые учётные данные (удалите строчку с github.com из ~/.git-credentials или снова выполните git pull и введите новый токен).

Способ 3: только чтение, репозиторий публичный

Для публичного репозитория git clone и git pull по HTTPS учётные данные не нужны — отдельная настройка не требуется.

Соответствие имён и адресов

Служба Внешнее имя (клиенты) Внутренний хост / IP Порт снаружи
Microsoft Exchange (OWA https://ext.kalinamall.ru/owa, EWS, MAPI/HTTPS и т.д.) ext.kalinamall.ru fifth.kalinamall.ru — 192.168.160.42 443 (TCP/SNI)
Autodiscover autodiscover.kalinamall.ru тот же Exchange — 192.168.160.42 443 (TCP/SNI)
RDS rds.kalinamall.ru (443 на HAProxy) k6a-dc3.b26.kalinamall.ru — 192.168.160.40, служба 4430 443 (SNI → внутр. 4430)
1С erp.kalinamall.ru hp-serv.b26.kalinamall.ru — 192.168.160.150 443
Почтовый шлюз (KSMG) ksmg.kalinamall.ru ksmg.kalinamall.ru — 192.168.160.57 25
DNS: записи A для ext, autodiscover, rds, erp, ksmg должны указывать на публичный IP хоста с HAProxy. Имя autodiscover.kalinamall.ru должно быть в SAN wildcard *.kalinamall.ru или отдельно в сертификате на Exchange.

Доступ по SSH к внутренним хостам (например Ubuntu 192.168.160.85) в этом репозитории не настраивается через HAProxy — организуйте отдельно (прямой проброс, VPN, бастион и т.д.).

В режиме TCP + SNI отдельные строки в HAProxy для путей вроде /owa не нужны: после согласования TLS клиент шлёт HTTP внутри шифрования, разбор путей делает IIS/Exchange на 192.168.160.42.

Установка HAProxy на Ubuntu 24.04 (Noble)

Для этого репозитория нужен HAProxy не ниже 2.4. Конструкции req_ssl_sni и tcp-request content accept (разбор ClientHello для SNI в TCP-режиме) входят в штатные сборки 2.8.x из Ubuntu 24.04 и во все актуальные ветки 3.x.

Вариант 1: пакет из репозитория Ubuntu (HAProxy 2.8.x)

Обычно этого достаточно для данного конфига:

sudo apt update
sudo apt install -y haproxy
haproxy -v

Проверьте, что версия 2.4+ (на Noble обычно 2.8.x).

Вариант 2: последняя ветка 3.x (PPA Vincent Bernat)

Актуальные пакеты HAProxy 3.3.x для Noble публикуются в PPA vbernat/haproxy-3.3 (номер микроверсии может обновляться; см. страницу PPA). Не подключайте одновременно несколько PPA с разными ветками HAProxy.

sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:vbernat/haproxy-3.3
sudo apt update
sudo apt install -y haproxy
haproxy -v
sudo systemctl enable --now haproxy

Другие ветки того же автора (при необходимости): haproxy-3.2, haproxy-3.1, haproxy-3.0, а также haproxy-2.8 — всегда выбирайте одну строку версии.

Проверка синтаксиса конфига

sudo haproxy -c -f /etc/haproxy/haproxy.cfg

Установка конфигурации из репозитория

  1. Убедитесь, что установлен HAProxy 2.4+ (см. раздел выше).

  2. Скопируйте haproxy.cfg в /etc/haproxy/haproxy.cfg. Пример, если репозиторий лежит в домашнем каталоге:

    sudo cp ~/reverse-proxy/haproxy.cfg /etc/haproxy/haproxy.cfg
    
  3. Проверка и перезапуск:

    sudo haproxy -c -f /etc/haproxy/haproxy.cfg
    sudo systemctl reload haproxy
    

Проверка ssl verify none на бэкендах

В backend для 443 указано ssl verify none, чтобы health-check и при необходимости установка соединения не ломались на внутренних именах/SAN. Если вы выпустите внутренние доверенные CA и зададите их в системе, можно включить проверку (verify required + ca-file).

Порты на фаерволе

На хосте с HAProxy с интернета обычно открывают только то, что слушает конфиг: 25, 443 (и при использовании — 8404 для stats). Остальной трафик — по политике безопасности.

Порт 80 и Lets Encrypt / ACME (на будущее)

Сейчас в haproxy.cfg порт 80 не используется. Ниже — что иметь в виду, если появится, например, Ubuntu во внутренней сети, на которую нужно выпускать сертификаты Lets Encrypt с автообновлением.

Нужен ли для ACME именно порт 80?

Не всегда. У Lets Encrypt (протокол ACME) есть несколько типов проверки владения доменом:

Тип Порт Комментарий
HTTP-01 80 (HTTP) Центр сертификации делает запрос вида http://ваш-домен/.well-known/acme-challenge/.... С интернета до отвечающего хоста порт 80 должен быть доступен (напрямую или через проброс на HAProxy).
DNS-01 не нужен 80/443 Запись в DNS; удобно, когда 80 снаружи открывать нельзя или сертификат для внутреннего имени.
TLS-ALPN-01 443 Проверка по TLS; порт 80 не обязателен.

Итого: при классическом Certbot + webroot/standalone с проверкой HTTP-01 порт 80 действительно участвует. При DNS-01 отдельный HTTP на 80 для выпуска не нужен.

Автообновление обычно делают certbot renew по systemd timer или cron — это на стороне машины с Certbot, не в HAProxy.

Если позже понадобится HTTP на 80 через этот HAProxy (например, HTTP-01)

  1. На пограничном роутере разрешить с интернета TCP 80 на IP хоста с HAProxy (или на тот хост, где будет отвечать ACME).
  2. В haproxy.cfg добавить отдельный HTTP-фронтенд на 80 и отправлять только путь проверки на бэкенд с ответом ACME (остальное — редирект на HTTPS, пустой ответ или отказ — по политике).

Пример: два Ubuntu в LAN и HTTP-01 через один периметровый HAProxy

Допустим, во внутренней сети два сервера Ubuntu, для обоих нужны публичные имена и периодическое обновление сертификатов Let’s Encrypt по HTTP-01:

Имя (снаружи) Внутренний IP
ubuntu1.kalinamall.ru 192.168.160.90
ubuntu2.kalinamall.ru 192.168.160.60

DNS: записи A для ubuntu1.kalinamall.ru и ubuntu2.kalinamall.ru должны указывать на тот же публичный IP, что и для остальных сервисов за HAProxy (чтобы запросы Let’s Encrypt пришли на порт 80 этого хоста).

На каждой Ubuntu: нужен HTTP на порту 80 и каталог под webroot Certbot (/.well-known/acme-challenge/…). Ниже — пошагово для nginx (типичный вариант); в конце — кратко про Apache. Если открывать 80 не хотите, используйте DNS-01 на той же машине (без этого блока).

Пошагово: nginx + Certbot webroot на Ubuntu

Выполняйте на каждой Ubuntu отдельно; подставляйте своё имя (ubuntu1.kalinamall.ru или ubuntu2.kalinamall.ru).

  1. Установите nginx и certbot

    sudo apt update
    sudo apt install -y nginx certbot
    
  2. Каталог для challenge (Certbot будет писать сюда файлы, nginx — отдавать):

    sudo mkdir -p /var/www/certbot/.well-known/acme-challenge
    sudo chown -R www-data:www-data /var/www/certbot
    
  3. Виртуальный хост только под ACME и имя сервера
    Создайте файл, например /etc/nginx/sites-available/acme-le.conf (на одной машине в server_nameubuntu1.kalinamall.ru, на другой — ubuntu2.kalinamall.ru):

    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name ubuntu1.kalinamall.ru;
    
        location ^~ /.well-known/acme-challenge/ {
            root /var/www/certbot;
            default_type "text/plain";
        }
    
        location / {
            return 404;
        }
    }
    
  4. Включите сайт и перезапустите nginx

    sudo ln -sf /etc/nginx/sites-available/acme-le.conf /etc/nginx/sites-enabled/
    sudo rm -f /etc/nginx/sites-enabled/default
    sudo nginx -t && sudo systemctl reload nginx
    

    Убедитесь, что снаружи (через HAProxy и открытый WAN 80) до этой машины доходит запрос с правильным Host — иначе Let’s Encrypt не пройдёт проверку.

  5. Первый выпуск сертификата (webroot)
    Подставьте свой домен и e-mail:

    sudo certbot certonly --webroot -w /var/www/certbot \
      -d ubuntu1.kalinamall.ru \
      --email admin@example.com --agree-tos --non-interactive
    

    При первом запуске можно убрать --non-interactive, чтобы согласиться с условиями в диалоге.

Где лежат файлы и что с ними делать (HTTPS в nginx)

После успешного certbot certonly каталог (симлинки) будет таким:

  • /etc/letsencrypt/live/ubuntu1.kalinamall.ru/ — имя совпадает с первым -d в команде certbot (на второй машине — ubuntu2...).
  • fullchain.pem — ваш сертификат и цепочка до Let’s Encrypt; его указывают в ssl_certificate (так браузеры доверяют сайту).
  • privkey.pem — закрытый ключ; в ssl_certificate_key. Файлы в archive/, в live/ — только ссылки; при certbot renew обновляются именно они, пути в nginx менять не нужно.

Добавьте второй server для HTTPS (отдельный файл или тот же acme-le.conf ниже блока :80), подставив своё имя и корень сайта:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name ubuntu1.kalinamall.ru;

    ssl_certificate     /etc/letsencrypt/live/ubuntu1.kalinamall.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ubuntu1.kalinamall.ru/privkey.pem;

    # Рекомендуемые параметры TLS (если пакет certbot их положил):
    # include /etc/letsencrypt/options-ssl-nginx.conf;
    # ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    root /var/www/html;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

Проверка и применение:

sudo nginx -t && sudo systemctl reload nginx

Если 443 с интернета идёт на эту же Ubuntu (напрямую или отдельным пробросом с маршрутизатора), снаружи откройте TCP 443 до неё. Если HTTPS терминирует только HAProxy, а до Ubuntu — снова прокси, то сертификат Lets Encrypt на Ubuntu нужен той службе, которая реально открывает TLS на этой машине (или выпускайте сертификат на том узле, где крутится HTTPS).

Редирект HTTP → HTTPS на :80 (по желанию, после того как HTTPS завёлся): в блоке server на порту 80 оставьте location ^~ /.well-known/acme-challenge/ как есть, а вместо return 404 для location / поставьте return 301 https://$host$request_uri; — обновление сертификата по-прежнему идёт по HTTP на путь .well-known, остальное уходит на https://.

  1. Проверка автообновления

    sudo systemctl enable --now certbot.timer
    sudo certbot renew --dry-run
    
  2. Перезагрузка nginx после успешного renew
    Создайте скрипт и сделайте его исполняемым:

    sudo install -d /etc/letsencrypt/renewal-hooks/deploy
    echo 'systemctl reload nginx' | sudo tee /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx.sh
    sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/01-reload-nginx.sh
    

    Таймер certbot.timer по расписанию вызывает certbot renew; при обновлении сертификата выполняются hook’и из renewal-hooks/deploy.

Кратко: Apache вместо nginx

  1. sudo apt install -y apache2 certbot python3-certbot-apache (или только certbot и webroot без плагина apache).
  2. Корень для challenge: например sudo mkdir -p /var/www/certbot/.well-known/acme-challenge и в виртуальном хосте на :80 для вашего ServerNameAlias /.well-known/acme-challenge /var/www/certbot/.well-known/acme-challenge и доступ Require all granted для этого каталога.
  3. sudo apachectl configtest && sudo systemctl reload apache2
  4. sudo certbot certonly --webroot -w /var/www/certbot -d ubuntu1.kalinamall.ru (и аналогично для второго имени на второй машине).
  5. Таймер certbot.timer и при необходимости hook с systemctl reload apache2.

На HAProxy: один фронтенд на 80, маршрутизация по заголовку Host + путь ACME на разные бэкенды:

frontend fe_http
    bind *:80
    mode http
    option httplog
    acl path_acme path_beg /.well-known/acme-challenge/
    acl host_u1 hdr(host) -i ubuntu1.kalinamall.ru
    acl host_u2 hdr(host) -i ubuntu2.kalinamall.ru
    use_backend be_acme_u1 if path_acme host_u1
    use_backend be_acme_u2 if path_acme host_u2
    http-request deny if !path_acme

backend be_acme_u1
    mode http
    server u1 192.168.160.90:80 check

backend be_acme_u2
    mode http
    server u2 192.168.160.60:80 check

Lets Encrypt при проверке обращается к http://ubuntu1.kalinamall.ru/.well-known/... или http://ubuntu2... — HAProxy по Host пересылает запрос на нужный внутренний :80, где локальный веб-сервер отдаёт файлы challenge.

Варианты без проброса HTTP на две машины: на каждой Ubuntu DNS-01 (порт 80 на периметре тогда не обязателен для этих сертификатов); либо TLS-ALPN-01 по 443 (потребуется уже другая схема на HAProxy, не этот пример).

После добавления bind :80 допишите в раздел «Порты на фаерволе» выше порт 80 и выполните sudo haproxy -c -f /etc/haproxy/haproxy.cfg.

Лицензия

Конфигурация поставляется как есть, без гарантий. Используйте на свой риск.