VPSРейтинг
Безопасность11 февраля 2026 · 14 мин чтения

Authelia на VPS: SSO и 2FA для всех self-hosted приложений

У вас на VPS работают Gitea, Grafana, n8n и Nextcloud — и у каждого свой логин. Authelia решает это: один вход для всех, плюс двухфакторная аутентификация через приложение-генератор кодов. Если злоумышленник узнает ваш пароль — без телефона он всё равно не попадёт.

1. Как это работает

Authelia — это open-source сервер аутентификации. Он стоит перед вашими приложениями и решает: пускать пользователя или нет.

Механизм называется forward auth («переадресованная аутентификация»). Работает так: когда пользователь открывает, например, grafana.ваш-сайт.ru, Nginx не отдаёт страницу сразу. Сначала он спрашивает Authelia: «Этот пользователь авторизован?»

Сценарий запроса

  1. 1Браузер открывает grafana.ваш-сайт.ru
  2. 2Nginx делает внутренний запрос к Authelia: «разрешить?»
  3. 3Authelia проверяет cookie сессии. Если нет — редирект на auth.ваш-сайт.ru
  4. 4Пользователь вводит логин + пароль + TOTP-код из приложения
  5. 5Authelia создаёт сессию и перенаправляет обратно на Grafana
  6. 6Nginx получает 200 от Authelia и открывает Grafana

После входа сессия работает для всех защищённых поддоменов сразу. Открываете Gitea — не нужно входить снова. Открываете n8n — тоже. Это и есть SSO (Single Sign-On, единый вход).

🔑 Один логин

Один аккаунт Authelia вместо десятка логинов в разных приложениях.

📱 TOTP 2FA

Код из Google Authenticator или любого TOTP-приложения. Без телефона не войти.

🛡️ Централизация

Управляете доступом в одном месте. Добавить пользователя — одна строка в файле.

2. Что понадобится

VPS с Ubuntu 22.04 или 24.04Минимум 1 ГБ RAM (Authelia — ~50 МБ, остаётся место под ваши приложения)
Docker и Docker ComposeУстановка: curl -fsSL https://get.docker.com | sh
Nginx с модулем auth_requestПакет nginx-full (Ubuntu), или стандартный nginx — модуль включён по умолчанию
Домен с поддержкой поддоменовНужны: auth.domain.ru (для Authelia) + поддомены ваших приложений
SSL-сертификатыAuthelia требует HTTPS — session cookie работает только по защищённому соединению
TOTP-приложение на телефонеGoogle Authenticator, Aegis (Android), Raivo OTP (iOS) — любое стандартное

Пример структуры доменов

Authelia работает на auth.vps-example.ru. Ваши приложения: grafana.vps-example.ru, gitea.vps-example.ru, n8n.vps-example.ru. Все они защищены одним входом. В статье используем домен example.ru — замените на свой.

3. Установка Authelia

Запустим Authelia как Docker-контейнер. Создадим рабочую директорию и файл конфигурации.

Структура файлов

Создать директорию и структуру
sudo mkdir -p /opt/authelia/config
cd /opt/authelia

Итоговая структура директории:

/opt/authelia/
├── docker-compose.yml
└── config/
    ├── configuration.yml   # главный конфиг Authelia
    └── users_database.yml  # пользователи и хэши паролей

docker-compose.yml

Authelia запускается одним контейнером. Порт 9091 привязываем только к localhost — Nginx будет обращаться к нему локально:

/opt/authelia/docker-compose.yml
services:
  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    restart: unless-stopped
    ports:
      - "127.0.0.1:9091:9091"
    volumes:
      - ./config:/config
    environment:
      - TZ=Europe/Moscow

Сгенерировать секретные ключи

Authelia требует три уникальных секрета. Генерируем их один раз и сохраняем — они пойдут в конфиг:

Генерация трёх секретных строк
# JWT-ключ (для ссылок сброса пароля)
openssl rand -hex 32

# Ключ сессии
openssl rand -hex 32

# Ключ шифрования базы данных
openssl rand -hex 32

Каждая команда выведет строку из 64 символов. Скопируйте три разные строки — они потребуются в следующем шаге.

4. Конфигурация

Создаём главный файл конфигурации. Замените example.ru на ваш домен и вставьте три сгенерированных секрета:

/opt/authelia/config/configuration.yml
theme: 'auto'

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

log:
  level: 'info'

# Секрет для подписи ссылок сброса пароля
# (вставьте первую строку из openssl rand -hex 32)
identity_validation:
  reset_password:
    jwt_secret: 'ВСТАВЬТЕ_ПЕРВЫЙ_СЕКРЕТ'

authentication_backend:
  file:
    path: '/config/users_database.yml'
    watch: true          # автоматически применять изменения в файле
    password:
      algorithm: argon2id

# Сессии — общие для всех поддоменов example.ru
session:
  # (вставьте второй секрет)
  secret: 'ВСТАВЬТЕ_ВТОРОЙ_СЕКРЕТ'
  cookies:
    - name: 'authelia_session'
      domain: 'example.ru'                        # ваш базовый домен
      authelia_url: 'https://auth.example.ru'     # URL входа в Authelia
      expiration: '12h'                           # сессия живёт 12 часов
      inactivity: '45m'                           # закрыть через 45 мин без активности

# Хранилище — SQLite (достаточно для одного VPS)
storage:
  # (вставьте третий секрет)
  encryption_key: 'ВСТАВЬТЕ_ТРЕТИЙ_СЕКРЕТ'
  local:
    path: '/config/db.sqlite3'

# Уведомления — в файл (не требует почтового сервера)
# Ссылки для сброса пароля будут записываться в этот файл
notifier:
  filesystem:
    filename: '/config/notification.txt'

# Правила доступа
access_control:
  default_policy: deny   # запрещено всё, что не разрешено явно
  rules:
    # Authelia сама должна быть доступна без авторизации
    - domain: 'auth.example.ru'
      policy: bypass

    # Все остальные поддомены — только после входа + TOTP
    - domain: '*.example.ru'
      policy: two_factor

Важно: домен в session.cookies

Указывайте базовый домен (example.ru), а не поддомен (auth.example.ru). Именно так браузер сможет отправлять сессионную cookie на все поддомены — и Authelia не будет просить авторизацию при переходе между приложениями.

Если хотите уведомления по почте

Замените блок notifier на SMTP-конфигурацию:

Notifier через SMTP (опционально)
notifier:
  smtp:
    address: 'submission://smtp.yandex.ru:587'
    username: 'вы@yandex.ru'
    password: 'пароль_приложения'
    sender: 'Authelia <вы@yandex.ru>'

5. Пользователи и пароли

Authelia хранит пользователей в простом YAML-файле. Пароли хранятся хэшированными — нельзя просто написать пароль в открытом виде. Сначала сгенерируем хэш.

Шаг 1: сгенерировать хэш пароля

Запустите команду — она спросит пароль интерактивно и выведет хэш:

Генерация хэша пароля (введите пароль когда спросит)
docker run --rm -it authelia/authelia:latest   authelia crypto hash generate argon2
Пример вывода
Enter Password:
Confirm Password:

Digest: $argon2id$v=19$m=65536,t=3,p=4$abc123...XYZ$hashed...value

Строка начиная с $argon2id$ — это хэш пароля. Скопируйте её целиком.

Шаг 2: создать файл пользователей

/opt/authelia/config/users_database.yml
users:
  admin:
    disabled: false
    displayname: 'Администратор'
    # Вставьте полный хэш из предыдущей команды:
    password: '$argon2id$v=19$m=65536,t=3,p=4$ВАШHЭШ'
    email: 'admin@example.ru'
    groups:
      - admins

Чтобы добавить второго пользователя — добавьте ещё один блок под ключом users с новым именем. Authelia увидит изменение сразу (параметр watch: true) — перезапуск не нужен.

Запустить Authelia

Запуск контейнера
cd /opt/authelia
docker compose up -d

Проверьте что Authelia запустилась и слушает порт 9091:

Проверить статус и логи
docker compose logs -f authelia

В логах должны быть строки level=info msg="Startup complete". Если есть ошибки — скорее всего опечатка в configuration.yml (YAML чувствителен к отступам).

6. Настройка Nginx

Настройка состоит из двух частей: виртуальный хост для самой Authelia, и защита ваших приложений через forward auth.

Шаг 1: виртуальный хост Authelia

Это страница входа — auth.example.ru. Сначала создайте минимальный HTTP-конфиг — он нужен certbot для прохождения ACME-проверки:

/etc/nginx/sites-available/auth.example.ru (временный HTTP-конфиг)
server {
    listen 80;
    server_name auth.example.ru;
}
Активировать и перезагрузить Nginx
sudo ln -s /etc/nginx/sites-available/auth.example.ru /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Получить SSL-сертификат
sudo certbot certonly --nginx -d auth.example.ru

Теперь замените содержимое файла на полный конфиг с HTTPS:

/etc/nginx/sites-available/auth.example.ru (полный конфиг)
server {
    listen 80;
    server_name auth.example.ru;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name auth.example.ru;

    ssl_certificate     /etc/letsencrypt/live/auth.example.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/auth.example.ru/privkey.pem;

    # Внутренний endpoint для проверки авторизации (используется другими хостами)
    location /internal/authelia/authz {
        internal;
        proxy_pass http://127.0.0.1:9091/api/authz/auth-request;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-Method  $request_method;
        proxy_set_header X-Original-URL     $scheme://$http_host$request_uri;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_set_header X-Forwarded-Host   $host;
        proxy_set_header X-Forwarded-URI    $request_uri;
        proxy_connect_timeout 5s;
        proxy_read_timeout    5s;
    }

    # Веб-интерфейс Authelia (страница входа)
    location / {
        proxy_pass http://127.0.0.1:9091;
        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 с полным конфигом
sudo nginx -t && sudo systemctl reload nginx

Шаг 2: защитить приложение

Теперь добавим защиту Authelia к любому приложению. Пример — Grafana на grafana.example.ru. Сначала создайте HTTP-конфиг и получите сертификат:

/etc/nginx/sites-available/grafana.example.ru (временный HTTP-конфиг)
server {
    listen 80;
    server_name grafana.example.ru;
}
Активировать и получить SSL-сертификат
sudo ln -s /etc/nginx/sites-available/grafana.example.ru /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot certonly --nginx -d grafana.example.ru

Замените содержимое файла на полный конфиг с forward auth:

/etc/nginx/sites-available/grafana.example.ru (полный конфиг)
server {
    listen 80;
    server_name grafana.example.ru;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name grafana.example.ru;

    ssl_certificate     /etc/letsencrypt/live/grafana.example.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/grafana.example.ru/privkey.pem;

    location / {
        # --- Authelia forward auth ---
        # Перед каждым запросом спрашиваем Authelia: можно?
        auth_request /internal/authelia/authz;

        # Сохраняем данные о пользователе из ответа Authelia
        auth_request_set $user   $upstream_http_remote_user;
        auth_request_set $groups $upstream_http_remote_groups;

        # Если Authelia вернула 401 — редирект на страницу входа
        # После входа Authelia вернёт пользователя обратно (&rd=...)
        error_page 401 = @authelia_redirect;

        # Передаём информацию о вошедшем пользователе в бэкенд
        proxy_set_header Remote-User   $user;
        proxy_set_header Remote-Groups $groups;
        # --- конец блока Authelia ---

        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host              $host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Редирект на страницу входа Authelia
    location @authelia_redirect {
        internal;
        return 302 https://auth.example.ru/?rd=$scheme://$http_host$request_uri;
    }

    # Сюда Authelia делает internal-запрос для проверки сессии
    location /internal/authelia/authz {
        internal;
        proxy_pass http://127.0.0.1:9091/api/authz/auth-request;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Original-Method  $request_method;
        proxy_set_header X-Original-URL     $scheme://$http_host$request_uri;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_set_header X-Forwarded-Host   $host;
        proxy_set_header X-Forwarded-URI    $request_uri;
        proxy_connect_timeout 5s;
        proxy_read_timeout    5s;
    }
}
Перезагрузить Nginx с полным конфигом
sudo nginx -t && sudo systemctl reload nginx

Для каждого следующего приложения

Повторите ту же схему: создайте HTTP-конфиг → ln -s → certbot → замените на полный конфиг с HTTPS. Блоки auth_request, @authelia_redirect и /internal/authelia/authz одинаковые во всех конфигах — просто скопируйте, замените server_name и порт proxy_pass.

7. Первый вход и настройка TOTP

Откройте браузер и перейдите на любой защищённый поддомен — например grafana.example.ru. Вас перенаправит на страницу входа Authelia.

Первая авторизация — пошагово

  1. 1

    Ввести логин и пароль

    Имя пользователя из users_database.yml (например: admin) и пароль, хэш которого вы сгенерировали.

  2. 2

    Зарегистрировать TOTP

    При первом входе Authelia покажет QR-код. Откройте Google Authenticator → «+» → «Сканировать QR-код». Сканируйте. QR-код показывается только один раз — сканируйте сразу!

  3. 3

    Ввести код из приложения

    Приложение покажет 6-значный код, который меняется каждые 30 секунд. Введите его для подтверждения.

  4. 4

    Authelia сохраняет сессию

    Вас перенаправит обратно на Grafana. Теперь все поддомены открываются без повторного входа до истечения сессии (12 часов по умолчанию).

QR-код показывается только один раз

Если вы закрыли страницу до сканирования — не страшно. Сбросьте TOTP и начните заново: docker exec authelia authelia storage user totp delete admin. При следующем входе QR-код появится снова.

8. Гибкие правила доступа

Правила в access_control.rules применяются по порядку — срабатывает первое совпавшее. Authelia поддерживает четыре политики:

ПолитикаЧто делаетКогда использовать
bypassПропускает без авторизацииПубличные сайты, API-эндпоинты, сама Authelia
one_factorТолько логин + парольПриложения без 2FA (если вы доверяете сети)
two_factorПароль + TOTP-кодВсе чувствительные приложения — рекомендуется
denyБлокирует запросЯвно запретить доступ (обычно не нужно при default_policy: deny)

Примеры правил

Разные уровни доступа для разных приложений
access_control:
  default_policy: deny
  rules:
    # Authelia сама — без авторизации
    - domain: 'auth.example.ru'
      policy: bypass

    # Публичный сайт — без авторизации
    - domain: 'blog.example.ru'
      policy: bypass

    # Grafana только для группы admins, и только с 2FA
    - domain: 'grafana.example.ru'
      subject: 'group:admins'
      policy: two_factor

    # n8n — достаточно одного пароля
    - domain: 'n8n.example.ru'
      policy: one_factor

    # Все остальные поддомены — два фактора
    - domain: '*.example.ru'
      policy: two_factor

Второй пользователь с ограниченным доступом

Добавьте в users_database.yml второго пользователя с другой группой:

/opt/authelia/config/users_database.yml — добавить второго пользователя
users:
  admin:
    disabled: false
    displayname: 'Администратор'
    password: '$argon2id$...'
    email: 'admin@example.ru'
    groups:
      - admins

  vasya:
    disabled: false
    displayname: 'Василий'
    password: '$argon2id$...'   # отдельный хэш пароля Василия
    email: 'vasya@example.ru'
    groups:
      - family

Теперь можно ограничить Nextcloud только группой family:

Правило только для группы family
    - domain: 'nextcloud.example.ru'
      subject: 'group:family'
      policy: two_factor

Изменения в configuration.yml применяются после перезапуска контейнера:docker compose restart authelia

9. Частые проблемы

Authelia запустилась, но при входе бесконечный редирект

Причина: неправильный домен в session.cookies.domain — указан поддомен вместо базового, или домен не совпадает с адресом сайта.

Решение:

Правильно — базовый домен без auth.
session:
  cookies:
    - domain: 'example.ru'          # НЕ auth.example.ru
      authelia_url: 'https://auth.example.ru'

Nginx выдаёт 500 при обращении к защищённому приложению

Причина: блок /internal/authelia/authz не определён в данном server-блоке. Он должен быть в каждом виртуальном хосте, который использует auth_request.

Решение:

Скопируйте блок location /internal/authelia/authz из примера выше в каждый защищённый server-блок.

Authelia не запускается: ошибка в конфиге

YAML очень требователен к отступам. Используйте только пробелы (не табуляции), и одинаковое количество пробелов на каждом уровне.

Диагностика:

Посмотреть точный текст ошибки
docker compose logs authelia | grep -i error

В логах будет указана строка с ошибкой. Проверьте отступы вокруг неё.

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

Нужен VPS для своих приложений? Смотрите лучшие варианты

Рейтинг VPS →

Смотрите также