В этой статье рассмотрим развертывание reverse proxy (реверс-прокси) на базе nginx с автоматическим выпуском SSL-сертификатов от Let’s Encrypt. Настроим проброс HTTPS-трафика на внутренние сервисы через единую точку входа.

Зачем нужен reverse proxy

Представьте такую ситуацию: у вас дома или в офисе есть несколько сервисов — например, система мониторинга, Git-хостинг и файловый сервис. Каждый из них работает на своём порту или на своём определённом внутреннем IP внутри сети. Но вам хочется получить доступ к ним из любой точки мира через браузер, и желательно чтобы всё работало по HTTPS (защищённое соединение).

Реверс-прокси решает эту задачу. Это сервер, который принимает запросы из интернета и перенаправляет их на нужные внутренние сервисы.

Как это работает на практике:

  1. Вы открываете в браузере https://dashboard.mydomain.ru
  2. DNS указывает на ваш публичный IP
  3. Запрос приходит на reverse proxy (порт 443)
  4. Reverse proxy смотрит на запрошенный домен и видит: » dashboard.mydomain.ru — это должно идти на сервер 192.168.1.10:3000″
  5. Он перенаправляет запрос на этот внутренний сервер и возвращает ответ пользователю

При этом реверс-прокси терминирует SSL — то есть расшифровывает HTTPS-запрос на себе, а внутрь отправляет уже обычный HTTP. Это позволяет не настраивать SSL на каждом внутреннем сервисе отдельно.

Что это даёт:

  • Единая точка входа — все сервисы доступны через один публичный IP и один порт (443)
  • Автоматический выпуск сертификатов — Let’s Encrypt выпускает и продлевает SSL-сертификаты автоматически.
  • Простое добавление сервисов — для нового сервиса нужно создать только один конфигурационный файл и выполнить несколько команд.
  • Безопасность — внутренние серверы скрыты за реверс-прокси, из интернета виден только реверс-прокси.

Что мы получим в результате

К концу статьи у вас будет настроенный реверс-прокси, через который можно:

  • Открыть https://dashboard.mydomain.ru и попасть на внутренний сервис мониторинга.
  • Открыть https://git.mydomain.ru для Git-хостинга (включая SSH для push/pull)
  • Легко добавлять новые сервисы.

Все сервисы будут работать по HTTPS с автоматическим продлением сертификатов.

Требования

  • Статический (постоянный) IP на вашем роутере.
  • Rocky Linux или другой дистрибутив из линейки RHEL.
  • Виртуальная машина в вашей локальной сети для реверс-прокси: 1 CPU, 1 Гб RAM, 10 Гб HDD.
  • Домен с возможностью управления DNS-записями.

Разворачивание реверс-прокси

У вас есть в локальной сети или физический сервер или виртуальный. Установите на него Rocky Linux или аналог. После установки убедитесь, что он доступен в вашей сети. Допустим у нас реверс-прокси имеет IP = 192.168.1.100.

У хостинг-провайдера, где вы управляете DNS-записями своего основного домена вам необходимо создать поддомен и указать ему IP адрес вашего роутера. Допустим у нас роутер имеет внешний IP = 1.0.0.1. Мы хотим создать для реверс-прокси поддомен proxy.mydomain.ru, для этого в DNS-записях основного домена добавляем A-запись. Пример:

Установка nginx и certbot

Установка пакетов:

sudo dnf install -y nginx certbot python3-certbot-nginx epel-release
sudo systemctl enable nginx
sudo systemctl start nginx

Что устанавливается:

  • nginx — веб-сервер и основа нашего реверс-прокси.
  • certbot — утилита для выпуска и продления SSL-сертификатов Let’s Encrypt.
  • python3-certbot-nginx — модуль certbot для автоматической настройки nginx.
  • epel-release — репозиторий с дополнительными пакетами.

Запуск nginx:

sudo systemctl enable nginx
sudo systemctl start nginx

Команды:

  • enable — добавляет nginx в автозагрузку (запустится после перезагрузки)
  • start — запускает прямо сейчас

Убедитесь, что nginx запустился без ошибок:

sudo systemctl status nginx

В статусе должно быть active (running). Также проверьте, что nginx отвечает локально:

curl http://localhost

Откроется тестовая страница. По умолчанию реверс-прокси показывает тестовую страницу Rocky Linux. Вы можете заменить её на свою:

/usr/share/testpage/index.html

Настройка firewall

Настраиваем, если он у вас установлен.

Firewalld — это штатный файрвол Rocky Linux. По умолчанию он закрывает все порты. Нам нужно открыть 80 (для HTTP) и 443 (для HTTPS), иначе внешние запросы не смогут доходить до nginx.

# Включаем firewalld (активируем навсегда)
sudo systemctl enable firewalld
sudo systemctl start firewalld

# Открываем порты 80 и 443
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp

# Применяем изменения (без этого правила не вступят в силу)
sudo firewall-cmd --reload

# Проверяем, что порты открылись.
# В выводе `list-all` вы должны увидеть `ports: 80/tcp 443/tcp`.
sudo firewall-cmd --list-all

Настройка SELinux

# разрешить nginx соединяться с бэкендами (серверами локальной сети)
sudo setsebool -P httpd_can_network_connect 1

Настройка роутера

Роутер стоит между вашей локальной сетью и интернетом. По умолчанию он отклоняет все входящие соединения. Чтобы внешние пользователи могли попасть на реверс-прокси, нужно создать правила NAT (Network Address Translation) — пробросить порты 80 и 443 на реверс-прокси. Создайте правила проброса портов 80 и 443:

Имя правилаПротоколВнешний портВнутренний портIP
reverse-proxy-httpTCP8080192.168.1.100
reverse-proxy-httpsTCP443443192.168.1.100

Сохраните настройки. Роутер может потребовать перезагрузку — сделайте её.

После настройки можно проверить, что порты открылись снаружи. Сходите на https://canyouseeme.org и проверьте порты 80 и 443. Если всё настроено верно — сайт сообщит «Success».

Выпуск сертификата для реверс-прокси

Принцип работы ACME. Let’s Encrypt проверяет, что вы владеете доменом, с помощью протокола ACME. Сервер ACME даёт вам «задание» — создать определённый файл по адресу http://ваш_домен/.well-known/acme-challenge/токен. Если файл доступен из интернета — значит, домен ваш. Именно поэтому мы открыли порт 80 и настроили проброс на роутере. Certbot сделает всё автоматически: создаст файл, обратится к серверу Let’s Encrypt, получит сертификат.

Создайте конфигурационный файл для домена, который будет только обрабатывать ACME-challenge (это сам реверс-прокси). Создать файл и наполнить его содержимым:

# /etc/nginx/conf.d/proxy.mydomain.ru.conf

server {
    listen 80;
    server_name proxy.mydomain.ru;

    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }
}

Проверка и перезагрузка nginx:

sudo nginx -t
sudo systemctl reload nginx

Команда nginx -t проверяет синтаксис конфигурации — если есть ошибки, она сообщит. Исправьте ошибку, если есть. Перезагрузка нужна, чтобы nginx начал использовать новый конфигурационный файл.

Выпуск сертификата:

# указывайте свой домен
sudo certbot --nginx -d proxy.mydomain.ru

Certbot задачт ряд вопросов, на которые потребуется ответить.

После успешного выпуска certbot автоматически обновит конфигурационный файл, добавит SSL-директивы.

Certbot по умолчанию может добавить правило, которое перенаправляет все HTTP-запросы на HTTPS. Но для ACME-challenge это проблема — challenge должен работать и по HTTP. Удалите этот редирект. Откройте файл /etc/nginx/conf.d/proxy.mydomain.ru.conf и удалите блок:

location / {
    return 301 https://$host$request_uri;
}

Будьте внимательны, секций location несколько. Итоговый конфигурационный файл должен выглядеть примерно так:

server {
    server_name proxy.mydomain.ru;
    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/proxy.mydomain.ru/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/proxy.mydomain.ru/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    if ($host = proxy.mydomain.ru) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name proxy.mydomain.ru;
    return 404; # managed by Certbot
}

Проверка. Выполните команды:

sudo nginx -t
sudo systemctl reload nginx
curl https://proxy.mydomain.ru

Если видите ответ и нет ошибок — сертификат работает. Можете в браузере открыть старницу https://proxy.mydomain.ru

Реверс-прокси настроен.

Автоматическое продление сертификатов

Let’s Encrypt выдаёт сертификаты на 90 дней. Certbot устанавливает таймер (certbot-renew.timer), который дважды в день проверяет сертификаты. Если до окончания осталось менее 30 дней — автоматически продлевает и перезагружает nginx.

Проверка таймера:

sudo systemctl list-timers --all | grep certbot

Если вывод пустой — таймер не активен. Включите:

sudo systemctl enable --now certbot-renew.timer

Управление сертификатами:

# Посмотреть все сертификаты
sudo certbot certificates

# Тест автопродления (без реального продления)
sudo certbot renew --dry-run

# Ручное продление
sudo certbot renew

# Принудительное продление
sudo certbot renew --force-renewal

Что происходит при автопродлении? Certbot:

  1. Проверяет срок всех сертификатов
  2. Для тех, где осталось < 30 дней — проходит ACME-challenge заново
  3. Обновляет файлы сертификатов
  4. Выполняет systemctl reload nginx

Всё это происходит автоматически, без участия администратора.

Добавление сервисов за реверс-прокси

Порядок действий:

  1. У хостинг-провайдера (доменного провадера) прописать требуемый поддомен в DNS-записи основного домена (добавить A-запись).
  2. На реверс-прокси создать конфигурационный файл с proxy_pass
  3. На реверс-прокси запустить certbot --nginx -d <subdomain>
  4. Готово — SSL + проксирование работают

Для некоторых сервисов требуется донастройка на самих серверах сервисов, о чём будет сказано ниже.

Добавление первого сервиса

Теперь добавим сервис, который будет работать за ревер-прокси. В качестве примера возьмём вымышленную систему мониторинга, который работает на внутреннем сервере с IP 192.168.1.10:3000 и мы будем систему по адресу dashboard.mydomain.ru

У провайдера прописываем требуемый поддомен в DNS-записи основного домена — dashboard.mydomain.ru. Добавьте A-запись dashboard = ваш публичный IP.

На реверс-прокси создаём отдельный конфигурационный файл содержимое которого отличается от конфигураиции самого реверс-прокси:

# файл /etc/nginx/conf.d/dashboard.mydomain.ru.conf

server {
    listen 80;
    server_name dashboard.mydomain.ru;

    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }

    location / {
        proxy_pass http://192.168.1.10:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Разберём по частям:

  • server_name — какой домен обрабатывать
  • location /.well-known/acme-challenge/ — для сертификатов (не трогать)
  • location / — все остальные запросы
  • proxy_pass — куда перенаправлять
  • proxy_set_header — передавать оригинальные заголовки, чтобы бэкенд знал настоящий IP и протокол

Последние три строки (Upgrade, Connection) нужны для WebSocket — если сервис их поддерживает, они будут работать корректно.

Всегда под каждый сервис создаём свой отдельный файл конфигурации в именовании которого прописан домен сервиса.

На реверс-прокси проверка и выпуск сертификата:

sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d dashboard.mydomain.ru

Certbot автоматически добавит SSL-директивы в конфиг. Ваш proxy_pass останется нетронутым.

Если забудете создать конфигурационный файл, то certbot выдаст ошибку, но сообщит как исправить проблему.

На сервере 192.168.1.10 откройте порт 3000 в firewall, если используется:

sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload

Откройте в браузере https://dashboard.mydomain.ru — должен отобразиться сервис.

При добавлении нового сервиса не забывайте на нём всегда открывать порт в firewalld, по которому он будет доступен для реверс-прокси. Без этого будете получать — 502 Bad Gateway даже если реверс-прокси настроен правильно.

Добавление Git-хостинга

Этот пример сложнее — добавим SSH-проброс для Git-операций (push/pull по SSH).

Допустим внутренний сервер: 192.168.1.11, HTTP порт 3000, SSH порт 2222.

Все предварительные операции аналогичны описанному при добавлении первого сервиса мониторинга.

На реверс-прокси правим основной конфигурационный файл nginx: /etc/nginx/nginx.conf

Найдите строку events и добавьте блок stream после неё:

events {
    # тут разное, не трогаем
}

stream {
    log_format basic '$remote_addr [$time_local] '
                     '$protocol $status $bytes_sent $bytes_received '
                     '$session_time';

    access_log /var/log/nginx/stream-access.log basic;
    error_log /var/log/nginx/stream-error.log;

    server {
        listen 2222;
        proxy_pass 192.168.1.11:2222;
    }
}

Блок stream работает на уровне TCP, не HTTP. Он принимает соединения на порту 2222 и перенаправляет их на тот же порт внутреннего сервера.

При добавлении нестандартных портов в блок stream (например SSH проброс) nginx не сможет сделать bind() — Permission denied.

Решение: Добавить порт в SELinux policy:

# Проверить текущие порты
sudo semanage port -l | grep http_port_t

# Добавить порт (пример для 2222)
sudo semanage port -a -t http_port_t -p tcp 2222

Если команда semanage не найдена:

sudo dnf install -y policycoreutils-python-utils

Важно: systemctl reload nginx НЕ покажет ошибку bind(), если она есть — нужно использовать systemctl restart nginx для проверки новых портов.

Проверка и выпуск сертификатов:

sudo nginx -t
sudo systemctl restart nginx
sudo certbot --nginx -d git.mydomain.ru

На роутере добавьте ещё одно правило:

ИмяПротоколВнешнийВнутреннийIP
git-sshTCP22222222192.168.1.100

Firewall на Git-сервере. На 192.168.1.11 откройте порты:

sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload

Откройте в браузере https://git.mydomain.ru — должен отобразиться сервис. Также можете клонировать репозитории по SSH.

Особенности добавления Nextcloud

Об установке Nextcloud на Rocky Linux писал в отдельной статье.

Все предварительные операции аналогичны описанному при добавлении первого сервиса мониторинга. Далее требуется дополнительная настройка.

Nextcloud определяет протокол по заголовку X-Forwarded-Proto. Без настройки trusted_proxies Nextcloud игнорирует этот заголовок и считает, что запрос пришёл по HTTP — возникает ошибка авторизации.

На сервере Nextcloud в config/config.php добавьте:

'trusted_proxies' => ['192.168.1.100'],
'overwrite.cli.url' => 'https://nextcloud.mydomain.ru',
'overwriteprotocol' => 'https',

Путь к config.php зависит от установки обычно /var/www/html/nextcloud/config/config.php или /opt/nextcloud/config/config.php

После добавления перезапустите PHP или веб-сервер Nextcloud:

systemctl restart httpd

Без этой настройки Nextcloud возвращает ошибку: При запросе процедуры авторизации с использованием HTTPS получен адрес сервера, не использующего HTTPS

Особенности добавления BookStack

Об установке BookStack на CentOS писал в отдельной статье.

Все предварительные операции аналогичны описанному при добавлении первого сервиса мониторинга. Далее требуется дополнительная настройка.

.env — изменить:

   APP_URL=https://wiki.mydomain.ru
   APP_PROXIES="192.168.1.100"

Без APP_PROXIES BookStack может некорректно определять IP пользователей.

Все предварительные операции аналогичны описанному при добавлении первого сервиса мониторинга.

Особенности добавления Home Assistant

Все предварительные операции аналогичны описанному при добавлении первого сервиса мониторинга. Далее требуется настройка trusted_proxies в Home Assistant. После выпуска сертификата и до проверки работы через HTTPS, нужно настроить HA.

Подключитесь к консоли Home Assistant (монитор или по SSH). Пользователь root, пароль пустой.

Отредактируйте файл конфигурации:

vi /mnt/data/supervisor/homeassistant/configuration.yaml

В конец файла добавьте:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 192.168.1.100

Или командой:

echo "
http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 192.168.1.100" >> /mnt/data/supervisor/homeassistant/configuration.yaml

Затем проверьте, что добавлено:

tail -10 /mnt/data/supervisor/homeassistant/configuration.yaml

Перезапустите Home Assistant:

ha core restart

Или через интерфейс.

Без этой настройки Home Assistant вернёт 400 Bad Request при обращении через реверс-прокси.