Администрирование
Today

Nginx Reverse Proxy + Let's Encrypt + Authelia 2FA

Nginx Reverse Proxy + Let's Encrypt + Authelia 2FA

Руководство по развёртыванию и настройке

1. Обзор и архитектура

Данное руководство описывает развёртывание единой точки входа для публикации внутренних веб-сервисов в интернет с двухфакторной аутентификацией (2FA) через корпоративный Active Directory.

Стек технологий:

  • Nginx — reverse proxy, SSL termination
  • Certbot — автоматическое получение и обновление сертификатов Let's Encrypt
  • Authelia — портал 2FA (TOTP / Email OTP)
  • Redis — хранение сессий Authelia
  • Docker Compose — оркестрация контейнеров

2. Структура файлов проекта

3. Предварительные требования

3.1 DNS записи

До получения сертификатов оба домена должны резолвиться в IP прокси-сервера:

service1.company.ru    A    →    <IP прокси-сервера>

service2.company.ru    A    →    <IP прокси-сервера>

Проверка: nslookup service1.company.ru 8.8.8.8

3.2 Порты на файрволе хоста

  • 80/tcp — для ACME challenge и редиректа HTTP→HTTPS
  • 443/tcp — основной HTTPS
  • Прямой доступ к портам внутренних сервисов должен быть закрыт

ufw allow 80/tcp

ufw allow 443/tcp

3.3 Служебная учётная запись AD

Для LDAP bind нужна read-only учётка в Active Directory:

New-ADUser `

-Name                 "svc-authelia" `

-SamAccountName       "svc-authelia" `

-UserPrincipalName    "svc-authelia@company.local" `

-Description          "Authelia LDAP bind read-only" `

-Path                 "CN=Users,DC=company,DC=local" `

-AccountPassword      (Read-Host -AsSecureString "Password") `

-Enabled              $true `

-PasswordNeverExpires $true `

-CannotChangePassword $true

Учётке не нужны никакие дополнительные права — базовые права чтения Domain Users достаточны для LDAP bind.

3.4 Экспорт CA сертификата домена

Если DC использует самоподписанный сертификат для LDAPS — экспортируйте корневой CA:

$cert = Get-ChildItem Cert:\LocalMachine\Root | Where-Object { $_.Subject -like "*company*" }

$b64  = [Convert]::ToBase64String($cert.RawData, 'InsertLineBreaks')

$pem  = "-----BEGIN CERTIFICATE-----`r`n$b64`r`n-----END CERTIFICATE-----"

$pem  | Set-Content C:\Temp\company-ca.crt -Encoding ASCII

Скопируйте файл на прокси-сервер:

scp C:\Temp\company-ca.crt user@proxy-ip:~/nginx-proxy/authelia/certs/

4. Файлы конфигурации

4.1 .env — секреты

Заполнить перед запуском (не коммитить в git):

REDIS_PASSWORD=<сложный пароль для Redis>

LDAP_BIND_PASSWORD=<пароль учётки svc-authelia>

SMTP_HOST=<IP или hostname SMTP сервера>

SMTP_USER=<логин почтового ящика>

SMTP_PASSWORD=<пароль почтового ящика>

4.2 Генерация секретов Authelia

Три независимых секрета для jwt_secret, session.secret, storage.encryption_key:

openssl rand -hex 32   # jwt_secret

openssl rand -hex 32   # session.secret

openssl rand -hex 32   # storage.encryption_key

4.3 authelia/configuration.yml — ключевые секции

Сервер

server:

address: tcp://0.0.0.0:9091/

LDAP / Active Directory

authentication_backend:

ldap:

implementation: activedirectory

address: ldaps://dc.company.local:636

tls:

skip_verify: true   # если сертификат DC самоподписанный

base_dn: DC=company,DC=local

user: CN=svc-authelia,CN=Users,DC=company,DC=local

attributes:

username: sAMAccountName

Пользователи входят по доменному логину (ivanov), а не по UPN (ivanov@company.local)

Сессии (Redis)

session:

expiration: 10h       # сессия живёт 10 часов

inactivity: 2h        # сброс при бездействии

remember_me: 14d      # галочка 'запомнить меня'

cookies:

- domain: company.ru

authelia_url: https://service1.company.ru/auth/

domain: company.ru позволяет использовать одну сессию для всех поддоменов company.ru

Политики доступа

access_control:

default_policy: deny

rules:

- domain: ['service1.company.ru', 'service2.company.ru']

resources: ['^/.well-known/', '^/auth/', '^/authelia/']

policy: bypass

- domain: ['service1.company.ru', 'service2.company.ru']

policy: two_factor

4.4 Nginx vhost конфиг (на каждый домен)

Структура location блоков в порядке приоритета:

# 1. ACME challenge (Let's Encrypt)

location /.well-known/acme-challenge/ { root /var/www/certbot; }

# 2. Редирект HTTP→HTTPS (отдельный server{} на 80)

# 3. Статика Authelia

location ^~ /static/ { proxy_pass http://authelia-host:9091/static/; }

location ^~ /locales/ { proxy_pass http://authelia-host:9091/locales/; }

# 4. API Authelia

location ^~ /api/ { proxy_pass http://authelia-host:9091/api/; }

# 5. Портал Authelia (логин + 2FA)

location ^~ /auth/ { proxy_pass http://authelia-host:9091/; }

# 6. Внутренний endpoint проверки сессии

location = /authelia-verify {

internal;

proxy_pass http://authelia-host:9091/api/verify;

proxy_pass_request_body off;

}

# 7. Основной сервис (требует 2FA)

location / {

auth_request /authelia-verify;

error_page 401 =302 https://$host/auth/?rd=https://$host$request_uri;

proxy_pass http://<IP бэкенда>:<порт>;

# WebSocket поддержка:

proxy_http_version 1.1;

proxy_set_header Upgrade $http_upgrade;

proxy_set_header Connection "upgrade";

}

Rate limit зону auth_limit НЕ применять к location /auth/ — Authelia загружает десятки JS/CSS файлов одновременно и будет получать 503.

5. Порядок развёртывания

Шаг 1 — Подготовить .env

cp .env.example .env

nano .env   # заполнить все значения

Шаг 2 — Заполнить секреты в configuration.yml

openssl rand -hex 32   # вставить в jwt_secret

openssl rand -hex 32   # вставить в session.secret

openssl rand -hex 32   # вставить в storage.encryption_key

Шаг 3 — Получить SSL сертификаты (первый раз)

chmod +x init-certs.sh

./init-certs.sh

DNS должен уже указывать на сервер. Скрипт запускает временный nginx на порту 80, получает сертификаты, останавливается.

Шаг 4 — Запуск

docker compose up -d

docker compose ps                    # все контейнеры Up

docker compose logs --tail=10 authelia

docker compose logs --tail=10 nginx

Шаг 5 — Первый вход

Открыть в браузере https://service1.company.ru — появится портал Authelia. Войти с доменным логином/паролем. При первом входе система предложит:

  • Зарегистрировать TOTP — отсканировать QR в Google Authenticator / Authy
  • Или подтвердить по email (если настроен SMTP)

После регистрации TOTP все последующие входы: логин + пароль AD + 6-значный код из приложения.

6. Решение типовых проблем

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

Для публикации нового внутреннего сервиса через прокси:

1. Создать nginx vhost конфиг по образцу существующего:

cp nginx/conf.d/service1.company.ru.conf nginx/conf.d/service3.company.ru.conf

nano nginx/conf.d/service3.company.ru.conf   # изменить домен и IP:порт бэкенда

2. Получить сертификат:

docker compose exec certbot certbot certonly \

--webroot -w /var/www/certbot \

--email admin@company.ru \

--agree-tos -d service3.company.ru

3. Добавить домен в authelia/configuration.yml → access_control.rules

4. Перезагрузить nginx:

docker compose exec nginx nginx -s reload

8. Управление сессиями и 2FA

Архив со структурой файлов для настройки через docker compose.