diff --git a/README.md b/README.md index d1dce01..03c4046 100644 --- a/README.md +++ b/README.md @@ -4,133 +4,7 @@ TLS: на целевых серверах в основном **wildcard-сертификаты GlobalSign**; **Git** (`git.kalinamall.ru`) использует **свой** сертификат на **192.168.160.129**. HAProxy на **443** работает в режиме **TCP + SNI** и **не терминирует** TLS — сертификаты остаются на бэкендах. -Репозиторий: [https://github.com/PTah/reverse-proxy](https://github.com/PTah/reverse-proxy) - -## Клонирование на Ubuntu, обновление и доступ без постоянного ввода пароля - -### Установка Git - -```bash -sudo apt update -sudo apt install -y git -``` - -### Первое клонирование - -**Публичный** репозиторий можно клонировать **без логина и пароля**: - -```bash -cd ~ -git clone https://github.com/PTah/reverse-proxy.git -cd reverse-proxy -``` - -Если репозиторий станет **приватным** или понадобятся **push**-правки с сервера, используйте один из способов ниже. - -### Обновление локальной копии - -```bash -cd ~/reverse-proxy -git pull origin main -``` - -После `git pull` снова скопируйте при необходимости файлы в `/etc/haproxy/` (см. раздел «Установка конфигурации»). - -### Как не вводить логин и пароль при каждом `git pull` / `git push` - -#### Способ 1: SSH-ключ (предпочтительно) - -1. Создайте ключ (имя файла можно своё): - - ```bash - ssh-keygen -t ed25519 -C "ubuntu-haproxy" -f ~/.ssh/id_ed25519_github - ``` - - Парольную фразу можно задать или оставить пустой (на сервере оцените риски). - -2. Покажите **публичный** ключ и добавьте его в GitHub: **Settings → SSH and GPG keys → New SSH key**. - - ```bash - cat ~/.ssh/id_ed25519_github.pub - ``` - -3. Проверьте доступ: - - ```bash - ssh -T git@github.com - ``` - -4. Клонируйте по **SSH** (или смените URL у уже существующего клона): - - ```bash - 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 tokens** → **Tokens (classic)**. -5. Нажмите **Generate new token** → **Generate 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. Те же **Settings** → **Developer settings** → **Personal access tokens** → **Fine-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: - -```bash -git clone https://github.com/PTah/reverse-proxy.git -# при запросе: Username = ваш_логин_github -# Password = вставить PAT -``` - -##### Чтобы не вводить PAT каждый раз - -Токен хранится **в открытом виде** в `~/.git-credentials` — используйте только на **доверенных** машинах: - -```bash -git config --global credential.helper store -cd ~/reverse-proxy -git pull origin main -# один раз ввести Username + PAT — дальше подставятся из файла -``` - -Кеш в памяти на заданное время (секунды), без постоянной записи в файл: - -```bash -git config --global credential.helper 'cache --timeout=28800' -``` - -После истечения срока кеша или срока действия токена на GitHub снова создайте новый PAT и при необходимости обновите сохранённые учётные данные (удалите строчку с `github.com` из `~/.git-credentials` или снова выполните `git pull` и введите новый токен). - -#### Способ 3: только чтение, репозиторий публичный - -Для **публичного** репозитория `git clone` и `git pull` по HTTPS **учётные данные не нужны** — отдельная настройка не требуется. +Репозиторий: [https://git.kalinamall.ru/PapaTramp/reverse-proxy](https://git.kalinamall.ru/PapaTramp/reverse-proxy) ## Соответствие имён и адресов @@ -142,256 +16,15 @@ git config --global credential.helper 'cache --timeout=28800' | 1С | `erp.kalinamall.ru` | hp-serv.b26.kalinamall.ru — **192.168.160.150** | 443 | | Git (HTTPS) | `git.kalinamall.ru` | git.kalinamall.ru — **192.168.160.129** (свой TLS-сертификат; снаружи HAProxy пускает только **5.100.81.121**) | 443 (TCP/SNI) | | Почтовый шлюз (KSMG) | `ksmg.kalinamall.ru` | ksmg.kalinamall.ru — **192.168.160.57** | 25 | + DNS: записи **A** для `ext`, **`autodiscover`**, `rds`, `erp`, **`git`**, `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) - -Обычно этого достаточно для данного конфига: - -```bash -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](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-3.3) (номер микроверсии может обновляться; см. страницу PPA). Не подключайте одновременно несколько PPA с разными ветками HAProxy. - -```bash -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](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-3.2), [haproxy-3.1](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-3.1), [haproxy-3.0](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-3.0), а также [haproxy-2.8](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-2.8) — всегда выбирайте **одну** строку версии. - -### Проверка синтаксиса конфига - -```bash -sudo haproxy -c -f /etc/haproxy/haproxy.cfg -``` - -## Установка конфигурации из репозитория - -1. Убедитесь, что установлен HAProxy **2.4+** (см. раздел выше). - -2. Скопируйте `haproxy.cfg` в `/etc/haproxy/haproxy.cfg`. Пример, если репозиторий лежит в домашнем каталоге: - - ```bash - sudo cp ~/reverse-proxy/haproxy.cfg /etc/haproxy/haproxy.cfg - ``` - -3. Проверка и перезапуск: - ```bash - 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 и Let’s Encrypt / ACME (на будущее) - -Сейчас в `haproxy.cfg` **порт 80 не используется**. Ниже — что иметь в виду, если появится, например, **Ubuntu** во внутренней сети, на которую нужно выпускать сертификаты **Let’s Encrypt** с автообновлением. - -### Нужен ли для ACME именно порт 80? - -**Не всегда.** У Let’s 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** - ```bash - sudo apt update - sudo apt install -y nginx certbot - ``` - -2. **Каталог для challenge** (Certbot будет писать сюда файлы, nginx — отдавать): - ```bash - 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_name` — `ubuntu1.kalinamall.ru`, на другой — `ubuntu2.kalinamall.ru`): - - ```nginx - 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** - ```bash - 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: - ```bash - 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`), подставив своё имя и корень сайта: - -```nginx -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; - } -} -``` - -Проверка и применение: - -```bash -sudo nginx -t && sudo systemctl reload nginx -``` - -Если **443** с интернета идёт **на эту же** Ubuntu (напрямую или отдельным пробросом с маршрутизатора), снаружи откройте **TCP 443** до неё. Если HTTPS терминирует только **HAProxy**, а до Ubuntu — снова прокси, то сертификат Let’s 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://**. - -6. **Проверка автообновления** - ```bash - sudo systemctl enable --now certbot.timer - sudo certbot renew --dry-run - ``` - -7. **Перезагрузка nginx после успешного renew** - Создайте скрипт и сделайте его исполняемым: - ```bash - 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** для вашего `ServerName` — `Alias /.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 на разные бэкенды: - -```text -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 -``` - -Let’s 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`. - -## Лицензия - -Конфигурация поставляется как есть, без гарантий. Используйте на свой риск. +- [Установка HAProxy и развёртывание конфигурации](docs/haproxy-install.md) +- [Работа с Git: clone, pull, push, ключи и PAT](docs/git.md) +- [Let's Encrypt / ACME через HAProxy (порт 80)](docs/letsencrypt-acme.md) diff --git a/docs/git.md b/docs/git.md new file mode 100644 index 0000000..0dcbf8a --- /dev/null +++ b/docs/git.md @@ -0,0 +1,109 @@ +# Работа с Git на Ubuntu + +Репозиторий: [https://git.kalinamall.ru/PapaTramp/reverse-proxy](https://git.kalinamall.ru/PapaTramp/reverse-proxy) + +## Установка Git + +```bash +sudo apt update +sudo apt install -y git +``` + +## Первое клонирование + +```bash +cd ~ +git clone https://git.kalinamall.ru/PapaTramp/reverse-proxy.git +cd reverse-proxy +``` + +Для **push** с сервера настройте SSH-ключ или PAT (см. ниже). + +## Обновление локальной копии + +```bash +cd ~/reverse-proxy +git pull origin main +``` + +После `git pull` снова скопируйте при необходимости файлы в `/etc/haproxy/` (см. [haproxy-install.md](haproxy-install.md)). + +## Как не вводить логин и пароль при каждом `git pull` / `git push` + +### Способ 1: SSH-ключ (предпочтительно) + +1. Создайте ключ (имя файла можно своё): + + ```bash + ssh-keygen -t ed25519 -C "ubuntu-haproxy" -f ~/.ssh/id_ed25519_kalinamall + ``` + + Парольную фразу можно задать или оставить пустой (на сервере оцените риски). + +2. Покажите **публичный** ключ и добавьте его на **git.kalinamall.ru**: профиль → **Settings** → **SSH / GPG Keys** → **Add Key**. + + ```bash + cat ~/.ssh/id_ed25519_kalinamall.pub + ``` + +3. Проверьте доступ: + + ```bash + ssh -T git@git.kalinamall.ru + ``` + +4. Клонируйте по **SSH** (или смените URL у уже существующего клона): + + ```bash + git clone git@git.kalinamall.ru:PapaTramp/reverse-proxy.git + # уже склонировано по HTTPS — переключение: + # git remote set-url origin git@git.kalinamall.ru:PapaTramp/reverse-proxy.git + ``` + +Дальше `git pull` / `git push` идут по SSH **без пароля** (при необходимости один раз вводится только passphrase ключа, если вы её задали; её можно кешировать через `ssh-agent`). + +### Способ 2: HTTPS + Personal Access Token (PAT) + +**git.kalinamall.ru** не принимает обычный пароль от аккаунта для операций `git clone` / `git pull` / `git push` по **HTTPS**. Вместо пароля нужно создать **Personal Access Token (PAT)** и вводить его там, где Git спрашивает пароль. + +#### Создание токена + +1. Войдите на **git.kalinamall.ru** под нужным аккаунтом. +2. Откройте **Settings** (Настройки) → **Applications** (или **Access Tokens**). +3. Создайте новый токен: + - **Name** — произвольное имя (например `ubuntu-haproxy-pull`), чтобы потом понимать, зачем токен. + - **Expiration** — срок действия (чем короче, тем безопаснее; для сервера часто выбирают ограниченный срок и потом перевыпускают). + - **Scopes** — для `pull`/`push` включите минимум **`read:repository`** и **`write:repository`** (или эквивалентные права на репозиторий). +4. **Сразу скопируйте** строку токена — сервер покажет её **один раз**; после ухода со страницы повторно не отобразит. + +#### Использование PAT в Git на Ubuntu + +- **Username** (логин): ваш **логин** на git.kalinamall.ru, не e-mail, если Git явно просит username. +- **Password**: вставьте **целиком PAT** (не пароль от сайта). + +Пример первого клонирования по HTTPS: + +```bash +git clone https://git.kalinamall.ru/PapaTramp/reverse-proxy.git +# при запросе: Username = ваш_логин +# Password = вставить PAT +``` + +#### Чтобы не вводить PAT каждый раз + +Токен хранится **в открытом виде** в `~/.git-credentials` — используйте только на **доверенных** машинах: + +```bash +git config --global credential.helper store +cd ~/reverse-proxy +git pull origin main +# один раз ввести Username + PAT — дальше подставятся из файла +``` + +Кеш в памяти на заданное время (секунды), без постоянной записи в файл: + +```bash +git config --global credential.helper 'cache --timeout=28800' +``` + +После истечения срока кеша или срока действия токена снова создайте новый PAT и при необходимости обновите сохранённые учётные данные (удалите строчку с `git.kalinamall.ru` из `~/.git-credentials` или снова выполните `git pull` и введите новый токен). diff --git a/docs/haproxy-install.md b/docs/haproxy-install.md new file mode 100644 index 0000000..28f4cd5 --- /dev/null +++ b/docs/haproxy-install.md @@ -0,0 +1,64 @@ +# Установка HAProxy и развёртывание конфигурации + +Для этого репозитория нужен 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) + +Обычно этого достаточно для данного конфига: + +```bash +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](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-3.3) (номер микроверсии может обновляться; см. страницу PPA). Не подключайте одновременно несколько PPA с разными ветками HAProxy. + +```bash +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](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-3.2), [haproxy-3.1](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-3.1), [haproxy-3.0](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-3.0), а также [haproxy-2.8](https://launchpad.net/~vbernat/+archive/ubuntu/haproxy-2.8) — всегда выбирайте **одну** строку версии. + +## Проверка синтаксиса конфига + +```bash +sudo haproxy -c -f /etc/haproxy/haproxy.cfg +``` + +## Установка конфигурации из репозитория + +1. Убедитесь, что установлен HAProxy **2.4+** (см. разделы выше). + +2. Скопируйте `haproxy.cfg` в `/etc/haproxy/haproxy.cfg`. Пример, если репозиторий лежит в домашнем каталоге: + + ```bash + sudo cp ~/reverse-proxy/haproxy.cfg /etc/haproxy/haproxy.cfg + ``` + +3. Проверка и перезапуск: + + ```bash + 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** для ACME (см. [letsencrypt-acme.md](letsencrypt-acme.md)), откройте и **TCP 80**. diff --git a/docs/letsencrypt-acme.md b/docs/letsencrypt-acme.md new file mode 100644 index 0000000..4d0cbaf --- /dev/null +++ b/docs/letsencrypt-acme.md @@ -0,0 +1,192 @@ +# Порт 80 и Let's Encrypt / ACME + +Сейчас в `haproxy.cfg` **порт 80 не используется**. Ниже — что иметь в виду, если появится, например, **Ubuntu** во внутренней сети, на которую нужно выпускать сертификаты **Let's Encrypt** с автообновлением. + +## Нужен ли для ACME именно порт 80? + +**Не всегда.** У Let's 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** + + ```bash + sudo apt update + sudo apt install -y nginx certbot + ``` + +2. **Каталог для challenge** (Certbot будет писать сюда файлы, nginx — отдавать): + + ```bash + 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_name` — `ubuntu1.kalinamall.ru`, на другой — `ubuntu2.kalinamall.ru`): + + ```nginx + 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** + + ```bash + 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: + + ```bash + 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`), подставив своё имя и корень сайта: + +```nginx +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; + } +} +``` + +Проверка и применение: + +```bash +sudo nginx -t && sudo systemctl reload nginx +``` + +Если **443** с интернета идёт **на эту же** Ubuntu (напрямую или отдельным пробросом с маршрутизатора), снаружи откройте **TCP 443** до неё. Если HTTPS терминирует только **HAProxy**, а до Ubuntu — снова прокси, то сертификат Let's 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://**. + +6. **Проверка автообновления** + + ```bash + sudo systemctl enable --now certbot.timer + sudo certbot renew --dry-run + ``` + +7. **Перезагрузка nginx после успешного renew** + Создайте скрипт и сделайте его исполняемым: + + ```bash + 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** для вашего `ServerName` — `Alias /.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 для маршрутизации ACME + +На HAProxy — один фронтенд на **80**, маршрутизация по заголовку **Host** + путь ACME на разные бэкенды: + +```text +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 +``` + +Let's 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` откройте **TCP 80** на фаерволе (см. [haproxy-install.md](haproxy-install.md)) и выполните `sudo haproxy -c -f /etc/haproxy/haproxy.cfg`.