MAATRIX / Блог / Authelia в Docker Compose: готовый файл

Authelia в Docker Compose: готовый файл

MAATRIX

Если у вас уже крутится десяток сервисов за Nginx или Traefik — Grafana, Portainer, какая-нибудь внутренняя админка — и каждый из них либо вообще без пароля торчит в интернет, либо у каждого свой логин, который вы забываете, — знакомая боль. Ставить ради этого полноценный Keycloak с базой данных и Java внутри часто избыточно. Authelia решает именно эту задачу: единая точка входа с 2FA перед уже существующими сервисами, без переписывания их кода — через forward-auth на уровне прокси. Ниже — рабочий docker-compose.yml, конфиг и разбор, где эта схема ломается на практике.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Authelia и когда она уместна

Authelia — это не полноценный identity provider вроде Keycloak или Authentik. Она не умеет OAuth2/OIDC для приложений, которые сами по себе не поддерживают SSO (хотя с версии 4.38 добавили OpenID Connect provider, и это меняет расклад — об этом ниже). Её основной режим работы — forward-auth: прокси (Nginx, Traefik, Caddy) перед тем как пустить запрос к защищаемому сервису, спрашивает у Authelia «этот пользователь авторизован?». Если нет — редиректит на страницу логина Authelia. Если да — пропускает запрос дальше.

Это идеально ложится на сценарий «у меня за Traefik висит 15 сервисов без встроенной аутентификации (Portainer, Prometheus, cAdvisor, какой-нибудь дашборд), и я хочу закрыть их одним логином с TOTP-кодом». Один процесс на Go, минимум зависимостей, конфиг в YAML, база пользователей — тоже YAML-файл (или LDAP/PostgreSQL для больших команд).

Когда Authelia не подходит: если нужен централизованный SSO с ролями и группами для десятков внешних сервисов через OIDC — там разумнее Keycloak, он тяжелее, но полнее закрывает корпоративный SSO. Authelia — про быстро закрыть периметр вокруг уже работающих сервисов минимальными силами.

Docker Compose: минимальный рабочий стек

Authelia требует хранилище сессий. Для одного инстанса подойдёт встроенный SQLite + файловый session store, но на практике удобнее сразу поднять Redis — тогда перезапуск контейнера Authelia не разлогинивает всех пользователей.

# docker-compose.yml
services:
  authelia:
    image: authelia/authelia:4.38
    container_name: authelia
    restart: unless-stopped
    volumes:
      - ./config:/config
    networks:
      - proxy
    environment:
      - TZ=Europe/Moscow
    depends_on:
      - redis
    healthcheck:
      test: ["CMD", "wget", "--spider", "-q", "http://localhost:9091/api/health"]
      interval: 30s
      timeout: 5s
      retries: 3

  redis:
    image: redis:7-alpine
    container_name: authelia-redis
    restart: unless-stopped
    command: redis-server --save 60 1 --loglevel warning
    volumes:
      - redis-data:/data
    networks:
      - proxy

networks:
  proxy:
    external: true

volumes:
  redis-data:

Сеть proxy — та же внешняя сеть, в которой у вас уже сидят Traefik или Nginx и защищаемые сервисы. Порт Authelia (9091) наружу не публикуется — к ней обращается только прокси внутри docker-сети.

Каталог ./config должен содержать configuration.yml и файлы с секретами до первого запуска — Authelia падает при старте, если конфиг невалиден или не хватает обязательных полей, так что готовьте файлы заранее, а не «на живую».

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Конфигурация: configuration.yml

Это ядро настройки. Ниже — рабочий пример под сценарий «один домен, поддомены для сервисов, TOTP как второй фактор».

# config/configuration.yml
theme: dark

server:
  address: 'tcp://0.0.0.0:9091'

log:
  level: info

totp:
  issuer: authelia.example.com

authentication_backend:
  file:
    path: /config/users_database.yml
    password:
      algorithm: argon2id
      iterations: 3
      memory: 65536
      parallelism: 4

access_control:
  default_policy: deny
  rules:
    - domain: 'public.example.com'
      policy: bypass
    - domain: '*.example.com'
      policy: two_factor

session:
  name: authelia_session
  secret: '{{ SESSION_SECRET_FROM_FILE }}'
  expiration: 1h
  inactivity: 15m
  domain: example.com
  redis:
    host: redis
    port: 6379

regulation:
  max_retries: 3
  find_time: 2m
  ban_time: 5m

storage:
  encryption_key: '{{ STORAGE_KEY_FROM_FILE }}'
  local:
    path: /config/db.sqlite3

notifier:
  smtp:
    address: 'submission://smtp.yourmail.example:587'
    username: authelia@example.com
    sender: 'Authelia <authelia@example.com>'

Секреты (session.secret, storage.encryption_key, пароль SMTP, JWT-секрет для сброса паролей) в реальном конфиге не пишутся текстом — используйте суффикс _FILE для переменных окружения, указывающих на файлы:

# добавить в сервис authelia в docker-compose.yml
    environment:
      - AUTHELIA_SESSION_SECRET_FILE=/config/secrets/session_secret
      - AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE=/config/secrets/storage_key
      - AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/config/secrets/smtp_password
mkdir -p config/secrets
openssl rand -hex 32 > config/secrets/session_secret
openssl rand -hex 32 > config/secrets/storage_key
chmod 600 config/secrets/*

При таком подходе строки secret: / encryption_key: из configuration.yml убираются — Authelia подхватит значения из файлов.

Пользователи и второй фактор

Для небольшой команды хватает файлового бэкенда — users_database.yml:

# config/users_database.yml
users:
  admin:
    disabled: false
    displayname: "Admin"
    password: "$argon2id$v=19$m=65536,t=3,p=4$..."
    email: admin@example.com
    groups:
      - admins
  devops:
    disabled: false
    displayname: "DevOps"
    password: "$argon2id$v=19$m=65536,t=3,p=4$..."
    email: devops@example.com
    groups:
      - devops

Хэш пароля argon2id генерируется прямо через сам контейнер, без сторонних утилит:

docker run --rm authelia/authelia:4.38 authelia crypto hash generate argon2 --password 'ваш-пароль'

Первый вход попросит настроить TOTP: Authelia покажет QR-код, вы сканируете его в Google Authenticator, Aegis или любом другом TOTP-приложении — дальше на каждый логин запрашивается 6-значный код. Поддерживается и WebAuthn (аппаратные ключи, Passkeys), но для небольшой команды TOTP обычно достаточно и проще в поддержке.

Для команд от полутора десятков человек файловый бэкенд становится неудобным — разумнее LDAP-бэкенд вместо ручного редактирования YAML при каждом увольнении сотрудника.

Интеграция с Traefik

Если прокси — Traefik, всё сводится к middleware forward-auth и лейблам на защищаемых сервисах.

Роутер для самой Authelia:

# добавить лейблы к сервису authelia
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.authelia.rule=Host(`auth.example.com`)"
      - "traefik.http.routers.authelia.entrypoints=websecure"
      - "traefik.http.routers.authelia.tls.certresolver=letsencrypt"
      - "traefik.http.services.authelia.loadbalancer.server.port=9091"
      - "traefik.http.middlewares.authelia.forwardauth.address=http://authelia:9091/api/verify?rd=https://auth.example.com"
      - "traefik.http.middlewares.authelia.forwardauth.trustForwardHeader=true"
      - "traefik.http.middlewares.authelia.forwardauth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email"

И на защищаемом сервисе (например, Portainer) достаточно одной строки:

    labels:
      - "traefik.http.routers.portainer.middlewares=authelia@docker"

Всё — Portainer теперь недоступен без логина через Authelia. Если у вас Traefik ещё не настроен, порядок установки описан в пошаговой установке Traefik на Ubuntu 24.04 и отдельно — Traefik как reverse proxy для Docker.

Интеграция с Nginx

Через auth_request схема немного многословнее, но работает так же надёжно. В конфиге виртуального хоста защищаемого сервиса:

server {
    listen 443 ssl;
    server_name portainer.example.com;

    location /authelia {
        internal;
        proxy_pass http://authelia:9091/api/verify;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    }

    location / {
        auth_request /authelia;
        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;

        proxy_pass http://portainer:9000;
    }
}

Разница с Traefik принципиальная: Nginx нужно прописывать этот блок в каждом виртуальном хосте вручную, тогда как в Traefik middleware навешивается одной лейбл-строкой на сервис. При 15+ сервисах за Nginx это ощутимо больше рутины при добавлении нового хоста — сравнение прокси под такие сценарии в статье Traefik или Nginx Proxy Manager — что выбрать для сервера.

Правила доступа и группы

access_control.rules — это список правил сверху вниз, первое совпадение побеждает. Практичный пример с разграничением по группам:

access_control:
  default_policy: deny
  rules:
    - domain: 'status.example.com'
      policy: bypass
    - domain: 'grafana.example.com'
      policy: one_factor
      subject: 'group:devops'
    - domain: 'portainer.example.com'
      policy: two_factor
      subject: 'group:admins'
    - domain: '*.example.com'
      policy: two_factor
ПолитикаЧто означает
bypassДоступ без аутентификации
one_factorДостаточно логина и пароля
two_factorОбязателен второй фактор (TOTP/WebAuthn)
denyДоступ запрещён всем

default_policy: deny — правильная настройка по умолчанию: всё, что не попало под явное правило, закрыто.

Частые проблемы на практике

Редирект на логин зацикливается. Обычно причина — session.domain в конфиге не совпадает с реальным доменом, под которым живут защищаемые сервисы, либо cookie блокируется браузером из-за отсутствия Secure/корректного SameSite при работе без HTTPS. Authelia в проде без TLS работать не должна — cookie сессии просто не выставится.

Redis недоступен — теряются сессии при рестарте контейнера. Если убрать Redis, оставив файловый провайдер сессий, каждый docker compose restart authelia разлогинит всех пользователей. Для одного администратора это не страшно, для команды — раздражает. Redis в связке — это буквально 10 строк в compose-файле, экономить на нём смысла нет.

OIDC-провайдер путают с forward-auth. С версии 4.38 Authelia умеет быть полноценным OpenID Connect provider для приложений, которые сами поддерживают OIDC-клиент. Это отдельный, более сложный конфиг (identity_providers.oidc) — не путайте его с простым forward-auth сценарием из этой статьи; если нужен именно OIDC для стороннего приложения, конфиг там существенно объёмнее.

Права на файлы конфига. Authelia в контейнере часто запускается не от root, и если смонтированный ./config принадлежит другому UID на хосте, чтение users_database.yml может падать с невнятной ошибкой доступа. Проверяйте docker logs authelia при любом «не стартует» — там обычно прямо указана проблемная строка конфига.

Ресурсы и куда ставить

Authelia — лёгкий процесс: на практике ей достаточно 128–256 МБ RAM и минимума CPU даже под нагрузкой в десятки одновременных пользователей, Redis добавляет ещё немного. Для связки Authelia + Redis + Traefik + пяток защищаемых сервисов хватает начального VPS на 2 ГБ RAM — узкое место здесь обычно сами защищаемые приложения, а не forward-auth слой. Если сервер уже развёрнут под Docker Compose в проде, порядок базовой настройки такого хоста — в статье Docker Compose для продакшена на Ubuntu 24.04.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Authelia бесплатна?

Да, полностью open source (Apache 2.0), без урезанной «community» версии — все функции, включая WebAuthn и OIDC provider, доступны без оплаты.

Можно ли использовать Authelia без Redis?

Технически да — файловый или SQLite-провайдер сессий работает, но при перезапуске контейнера все пользователи будут разлогинены.

Чем Authelia отличается от Authentik?

Authentik тяжелее: полноценный веб-интерфейс администрирования и обязательная БД PostgreSQL. Authelia проще, легче по ресурсам и конфигурируется YAML-файлами без UI.

Нужен ли отдельный поддомен для Authelia?

Да, стандартная практика — выделить поддомен вида auth.example.com, на который редиректят неаутентифицированных пользователей со всех защищаемых сервисов на том же родительском домене.

Работает ли Authelia с сервисами на разных доменах?

Из коробки — нет, cookie сессии привязан к одному session.domain. Для нескольких независимых доменов нужно либо несколько инстансов Authelia, либо OIDC-сценарий.

Как сбросить забытый пароль пользователя?

Через файловый бэкенд — вручную сгенерировать новый argon2id-хэш командой authelia crypto hash generate и вписать в users_database.yml.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →