Nginx часто выступает публичным шлюзом к административным панелям и критичным API, которые требуют усиленной защиты. Эта практическая инструкция объясняет интеграцию системы двухфакторной аутентификации Authelia с Nginx для создания надежного барьера. Вы получите рабочие конфигурации Nginx, шаги по настройке обратного прокси к Authelia и решения для частых проблем - например, потери сессии или конфликтов с базовой аутентификацией. Статья позволит быстро внедрить проверенный механизм безопасности, не нарушая работу текущих сервисов.
Почему Authelia и Nginx - оптимальная связка для защиты сервисов
Nginx как обратный прокси и балансировщик нагрузки выступает единой точкой входа для множества внутренних сервисов: панели управления TrueNAS или Proxmox, Grafana, API, порталы разработчиков. Без дополнительной защиты доступ к этим ресурсам часто ограничен только базовой аутентификацией или IP-адресами, что создает риски при компрометации пароля или необходимости доступа извне.
Authelia решает эту задачу, выступая централизованным шлюзом аутентификации. В отличие от простых решений вроде htpasswd, она поддерживает двухфакторную аутентификацию по TOTP (Time-based One-Time Password), резервные коды и детальные политики доступа. По сравнению с тяжеловесными системами вроде Keycloak, Authelia проще в развертывании и управлении, идеально подходит для защиты внутренних сервисов. Она работает как промежуточное ПО (middleware), интегрируясь с Nginx через стандартный модуль auth_request.
Архитектура защиты: как работает связка Nginx и Authelia
Поток запросов при включенной защите выглядит так:
- Клиент отправляет запрос к защищенному ресурсу (например,
https://panel.example.com). - Nginx перехватывает запрос и с помощью директивы
auth_requestотправляет внутренний подзапрос на эндпоинт аутентификации. - Этот подзапрос проксируется на сервис Authelia (
http://authelia:9091/api/verify). - Authelia проверяет наличие валидной сессии в cookies запроса. Если сессии нет или она истекла, возвращает код 401.
- Nginx, получив 401, перенаправляет пользователя на страницу входа Authelia (
https://auth.example.com). - После успешного ввода логина, пароля и кода из приложения-аутентификатора, Authelia устанавливает сессионную cookie и возвращает код 200.
- Nginx, получив успешный ответ 200, проксирует исходный запрос к целевому backend-сервису (TrueNAS, Grafana и т.д.).
Модуль auth_request в Nginx выступает «проверяющим». Он не обрабатывает логику входа, а только запрашивает у внешнего сервиса (Authelia) вердикт: разрешить или запретить доступ. Это позволяет добавить защиту, минимально меняя конфигурацию существующих виртуальных хостов.
Authelia против других решений: краткое сравнение для Nginx
Для защиты Nginx существуют альтернативы, каждая со своей областью применения.
- oauth2-proxy: Более простое решение для аутентификации через OAuth2-провайдеров (Google, GitHub). Подходит для быстрого добавления единого входа, но не поддерживает TOTP из коробки и имеет менее гибкие политики доступа.
- Keycloak с Gatekeeper: Полноценная система идентификации и управления доступом (IAM). Обеспечивает Single Sign-On (SSO), поддержку протоколов OIDC, SAML. Чрезмерно сложна для сценария «просто добавить 2FA к нескольким панелям», требует значительных ресурсов.
- Authelia: Занимает промежуточную позицию. Самодостаточное решение со встроенной двухфакторной аутентификацией, управлением пользователями через YAML-файл и детальными политиками доступа на основе пути, пользователя, группы и IP-адреса. Идеально для защиты внутренних сервисов в средах DevOps.
Выбор Authelia оправдан, когда нужен контроль над всей цепочкой аутентификации без зависимости от внешних провайдеров и с минимальной сложностью развертывания.
Подготовка среды: развертывание Authelia с Docker Compose
Стандартный и рекомендуемый способ запуска Authelia - в Docker-контейнерах. Это обеспечивает изоляцию, простоту обновления и переносимость конфигурации. Приведенный ниже docker-compose.yml и конфигурационные файлы образуют рабочую основу.
Готовый docker-compose.yml для запуска Authelia
Создайте директорию для проекта (например, /opt/authelia) и поместите в нее файл docker-compose.yml:
version: '3.8'
services:
authelia:
image: authelia/authelia:latest
container_name: authelia
volumes:
- ./config:/config
- ./users_database.yml:/config/users_database.yml:ro
environment:
- TZ=Europe/Moscow
ports:
- "9091:9091"
restart: unless-stopped
networks:
- authelia-network
networks:
authelia-network:
driver: bridge
Этот файл определяет сервис Authelia, монтирует директорию с конфигурацией, пробрасывает порт 9091 наружу и создает изолированную сеть. Адаптируйте параметр TZ под свой часовой пояс. Для работы в одной сети с другими сервисами (например, Nginx в другом контейнере) используйте общую Docker-сеть вместо проброса портов.
Базовая конфигурация Authelia: config.yml и users_database.yml
Перед первым запуском необходимо создать и настроить конфигурационные файлы.
1. Создайте файл /opt/authelia/config/configuration.yml с минимальными настройками:
host: 0.0.0.0
port: 9091
log:
level: info
jwt_secret: YOUR_SUPER_SECRET_JWT_KEY_HERE # Сгенерируйте случайную строку (openssl rand -hex 32)
default_redirection_url: https://auth.example.com
server:
read_buffer_size: 4096
write_buffer_size: 4096
enable_pprof: false
enable_expvars: false
disable_keepalive: false
session:
name: authelia_session
secret: YOUR_SUPER_SECRET_SESSION_KEY_HERE # Другая случайная строка
expiration: 1h
inactivity: 5m
domain: example.com # Ваш домен
storage:
local:
path: /config/db.sqlite3
notifier:
disable_startup_check: false
authentication_backend:
file:
path: /config/users_database.yml
password:
algorithm: argon2id
iterations: 1
salt_length: 16
parallelism: 8
memory: 128
access_control:
default_policy: deny
rules:
- domain:
- "auth.example.com"
policy: bypass
- domain:
- "panel.example.com"
policy: two_factor
subject: "group:admins"
Замените YOUR_SUPER_SECRET_JWT_KEY_HERE и YOUR_SUPER_SECRET_SESSION_KEY_HERE на сгенерированные строки. Укажите свой домен в секциях session.domain и правилах доступа.
2. Создайте файл пользователей /opt/authelia/users_database.yml:
users:
admin:
displayname: "Administrator"
password: "$argon2id$v=19$m=128,t=1,p=8$WXpHb2tNb1dEdzVUQW9NZw$5g7Z/7..." # Хеш пароля
email: admin@example.com
groups:
- admins
Пароль хешируется утилитой authelia crypto hash generate или можно временно задать его в открытом виде, а после первого входа Authelia предложит сменить и сгенерирует хеш.
После создания файлов запустите Authelia: docker-compose up -d. Сервис будет доступен по адресу http://ваш_сервер:9091.
Интеграция с Nginx: два практических сценария
Интеграция Authelia с Nginx сводится к настройке модуля auth_request. Рассмотрим два наиболее частых сценария.
Сценарий 1: Добавление 2FA к существующему виртуальному хосту Nginx
Предположим, у вас уже работает виртуальный хост для панели управления TrueNAS по адресу panel.example.com. Чтобы добавить перед ней двухфакторную аутентификацию, нужно модифицировать его конфигурацию в /etc/nginx/sites-available/panel.example.com.
Добавьте следующие директивы в блок server:
server {
listen 443 ssl http2;
server_name panel.example.com;
# ... ваши настройки SSL ...
# Локация для внутренних запросов аутентификации к Authelia
location = /auth_request {
internal;
proxy_pass http://127.0.0.1:9091/api/verify; # Адрес Authelia
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
# Основная локация, защищенная auth_request
location / {
auth_request /auth_request;
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
error_page 401 =302 https://auth.example.com/?rd=$scheme://$http_host$request_uri;
# Проксирование на backend (TrueNAS)
proxy_pass http://192.168.1.100:80; # IP и порт TrueNAS
# ... остальные proxy_set_header ...
}
}
Ключевые изменения:
- Создана внутренняя локация
/auth_request, которая проксирует проверку на Authelia. - Директива
auth_request /auth_request;в основной локации активирует проверку для всех запросов. auth_request_setизвлекает заголовки пользователя и групп из ответа Authelia и передает их в backend.error_page 401 =302 ...перенаправляет неаутентифицированных пользователей на страницу входа Authelia.
После внесения изменений проверьте конфигурацию (nginx -t) и перезагрузите Nginx (systemctl reload nginx). Теперь доступ к панели будет требовать двухфакторную аутентификацию. Аналогичный подход используется для защиты веб-панелей TrueNAS и Proxmox.
Сценарий 2: Создание нового защищенного серверного блока с нуля
Если вы развертываете новый сервис (например, мониторинг Grafana) и сразу хотите его защитить, используйте готовую конфигурацию.
server {
listen 443 ssl http2;
server_name grafana.example.com;
ssl_certificate /etc/letsencrypt/live/grafana.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/grafana.example.com/privkey.pem;
# ... остальные настройки SSL ...
location = /auth_request {
internal;
proxy_pass http://authelia:9091/api/verify; # Используем имя сервиса в Docker-сети
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
}
location / {
auth_request /auth_request;
auth_request_set $user $upstream_http_remote_user;
proxy_set_header X-WEBAUTH-USER $user; # Grafana принимает пользователя в этом заголовке
error_page 401 =302 https://auth.example.com/?rd=$scheme://$http_host$request_uri;
proxy_pass http://grafana:3000; # Прокси на контейнер Grafana
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;
}
}
Эта конфигурация предполагает, что Nginx и Authelia работают в одной Docker-сети, поэтому используется имя сервиса authelia вместо IP-адреса. Обратите внимание на заголовок X-WEBAUTH-USER, который передает аутентифицированного пользователя в Grafana для автоматического входа.
Ключевые директивы Nginx: auth_request, proxy_pass и обработка ошибок
Понимание назначения директив критично для отладки.
- auth_request: Активирует модуль аутентификации для location или server. В качестве аргумента принимает внутреннюю локацию, которая сделает подзапрос к сервису аутентификации.
- auth_request_set: Извлекает данные из заголовков ответа сервиса аутентификации и сохраняет их в переменные Nginx. Например,
$upstream_http_remote_userсодержит значение заголовкаRemote-User, который отправляет Authelia при успешной проверке. - proxy_pass в локации
/auth_request: Должен вести на эндпоинт проверки Authelia (/api/verify). Убедитесь, что адрес и порт верны. - error_page 401: Определяет действие при получении кода 401 (Unauthorized) от Authelia. Чаще всего это редирект 302 на страницу входа Authelia с параметром
rd(redirect), куда вернуть пользователя после успешного входа. - proxy_set_header: Корректная передача заголовков (особенно
X-Forwarded-*) важна для работы Authelia и backend-сервисов, чтобы они видели реальные IP-адреса и протоколы.
Правильная настройка этих директив - залог отсутствия бесконечных редиректов и ошибок доступа.
Настройка политик доступа и резервных кодов в Authelia
После базовой интеграции важно настроить детальный контроль и обеспечить отказоустойчивость системы.
Политики доступа: как ограничить доступ по пути, пользователю и IP
Политики доступа в Authelia задаются в секции access_control.rules файла configuration.yml. Правила обрабатываются сверху вниз, первое совпавшее правило применяется.
access_control:
default_policy: deny
rules:
- domain: "auth.example.com"
policy: bypass # Страница входа Authelia доступна всем
- domain: "panel.example.com"
resources:
- "^/api/health$"
policy: bypass # Эндпоинт healthcheck доступен без аутентификации
- domain: "panel.example.com"
policy: two_factor
subject: "group:admins" # Полный доступ только группе admins
- domain: "panel.example.com"
resources:
- "^/public/"
policy: one_factor # Доступ к публичному разделу по логину/паролю
- domain: "internal.example.com"
policy: two_factor
networks:
- "192.168.1.0/24" # Требовать 2FA только из внутренней сети
- domain: "*.example.com"
policy: deny # Запретить все для остальных поддоменов
Доступные политики: bypass (пропустить), one_factor (только пароль), two_factor (пароль + TOTP), deny (запретить). Правила могут комбинироваться по доменам (с поддержкой wildcard *), ресурсам (регулярные выражения), субъектам (пользователь или группа) и сетям.
Резервные TOTP-коды: создание и безопасное хранение
Резервные коды - это одноразовые коды, которые служат запасным методом входа при потере основного устройства с аутентификатором (телефона). В Authelia они генерируются локально в браузере пользователя при настройке двухфакторной аутентификации и никуда не передаются, что обеспечивает безопасность.
Процесс генерации:
- Пользователь входит в интерфейс Authelia (
https://auth.example.com) под своей учетной записью. - В разделе профиля переходит к настройке двухфакторной аутентификации.
- После сканирования QR-кода в приложении-аутентификаторе (Google Authenticator, Authy) Authelia отображает набор резервных кодов (обычно 10-16 штук).
- Каждый код можно использовать только один раз, после чего он становится недействительным.
Рекомендации по хранению, основанные на практике крупных сервисов (GitHub, Google):
- Сохраните коды в нескольких физически разделенных безопасных местах: зашифрованный диск (VeraCrypt), аппаратный сейф, защищенный менеджер паролей.
- Распечатайте коды на бумаге и храните в надежном месте, недоступном для посторонних.
- Не храните коды в незашифрованных файлах на рабочей станции или в облаке.
- При использовании кода вычеркивайте его из списка.
Формат кодов в Authelia обычно представляет собой строку из 16 цифр, разделенных на группы для удобства чтения (например, 1234-5678-9012-3456). Резервные коды - критически важный компонент любой системы 2FA, их наличие и безопасное хранение предотвращает полную потерю доступа к защищенным сервисам.
Отладка и решение типичных проблем
Даже с готовыми конфигурациями могут возникнуть проблемы. Вот чек-лист для диагностики.
Бесконечные редиректы и ошибки 401/500: анализ логов
Проблема: браузер попадает в цикл редиректов между защищенным ресурсом и страницей входа Authelia, либо получает ошибку 500.
Что проверять:
- Логи Authelia:
docker logs authelia. Ищите ошибки в конфигурации, проблемы с подключением к базе данных (SQLite), неверные секреты (jwt_secret,session.secret). Ошибка «Invalid JWT» указывает на неверныйjwt_secret. - Логи Nginx:
tail -f /var/log/nginx/error.log. Ищите ошибки проксирования (failed to resolve, connection refused) к Authelia. Убедитесь, что адрес вproxy_passлокации/auth_requestкорректен и сервис доступен. - Коды ответа: Включите в конфиг Nginx логирование кодов ответа от Authelia, добавив в локацию
/auth_request:proxy_intercept_errors on;и просматриваяaccess.log. - Политики доступа: Убедитесь, что для домена защищенного ресурса в Authelia задано правило с политикой
one_factorилиtwo_factor, а неdeny. Правилоbypassдля домена аутентификации (auth.example.com) должно быть первым.
Частая причина ошибок 500 - несовпадение секретов (jwt_secret) между экземплярами Authelia при обновлении или редеплое. Сгенерируйте новые секреты и обновите их во всех конфигурациях.
Конфликты с базовой аутентификацией и другими методами
Проблема: на backend-сервисе (например, старом веб-интерфейсе) уже настроена базовая HTTP-аутентификация (basic auth). Nginx, получив успешный ответ от Authelia, проксирует запрос к backend, который запрашивает свои учетные данные, создавая второй уровень аутентификации или ошибку 401.
Решение:
- Предпочтительный способ: Отключить базовую аутентификацию в backend-сервисе, если это возможно. Защита теперь обеспечивается Authelia.
- Альтернатива: Настроить Nginx на передачу заголовков базовой аутентификации через Authelia. Это сложный сценарий, требующий хранения паролей в двух системах. Добавьте в конфигурацию Nginx в локацию
/auth_requestпередачу заголовкаAuthorization:proxy_set_header Authorization $http_authorization;. Однако Authelia не будет проверять эти учетные данные.
В большинстве случаев достаточно отключить встроенную аутентификацию защищаемого сервиса, оставив Authelia единственным шлюзом. Это упрощает управление доступом и аудит.
Проблемы с сессией: cookie не устанавливаются или не передаются
Проблема: аутентификация в Authelia проходит успешно, но при переходе к защищенному ресурсу пользователь снова перенаправляется на страницу входа. Сессия не сохраняется.
Что проверять:
- Домен cookie в Authelia: В файле
configuration.ymlпараметрsession.domainдолжен быть установлен в корневой домен (например,example.com), а не в поддомен. Cookie с доменом.example.comбудут передаваться во все поддомены. - Флаги cookie: Убедитесь, что для продакшн-среды (при использовании HTTPS) в Authelia включены флаги
secureиhttp_onlyдля сессионных cookie (они включены по умолчанию при правильной настройкеX-Forwarded-Proto). - Передача заголовков: В локации
/auth_requestNginx должен передавать заголовкиCookieк Authelia и принимать их обратно. Убедитесь, что нет директив, сбрасывающих или игнорирующих эти заголовки. - Время жизни сессии: Проверьте настройки
session.expiration(общее время жизни) иsession.inactivity(время неактивности) в Authelia. Слишком короткие значения могут вызывать частые разлогинивания. - Синхронизация времени: Убедитесь, что время на сервере с Authelia, Nginx и клиентском устройстве синхронизировано (используйте NTP). Расхождение во времени влияет на валидность TOTP-кодов и сессионных cookie.
Для глубокой диагностики проблем с аутентификацией, особенно ошибок 401 и 403, полезно изучить отдельное руководство по диагностике ошибок 401/403 в стеке Nginx, Docker и Kubernetes, где разобраны команды анализа логов и проверки заголовков.
Интеграция Authelia с Nginx создает надежный барьер для ваших внутренних сервисов. Начните с тестового окружения, используя готовые конфигурации из этой статьи, проверьте работу аутентификации и политик доступа, а затем переносите решение на продакшн. Это позволит вам централизованно управлять доступом к десяткам панелей и API, значительно повысив безопасность инфраструктуры без усложнения ее архитектуры.