Полное руководство: Traefik + CrowdSec с AppSec WAF в LXC-контейнере на Proxmox и вишенка на торте.

Это подробное, пошаговое руководство, основанное на реальном опыте. Вы развернёте полноценный стек безопасности для домашних сервисов: Traefik как обратный прокси с автоматическим HTTPS, CrowdSec как систему обнаружения вторжений и AppSec WAF для защиты на уровне веб-приложений. Всё будет работать в изолированном LXC-контейнере под управлением Debian 12 на платформе Proxmox 9.1.x

Оглавление

  1. Цели и используемые технологии

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

  3. Часть 1: Создание и подготовка LXC-контейнера

  4. Часть 2: Установка Traefik

  5. Часть 3: Установка и настройка CrowdSec

  6. Часть 4: Интеграция Traefik с CrowdSec через плагин

  7. Часть 5: Включение AppSec WAF

  8. Часть 6: Настройка middleware и цепочек для сервисов

  9. Часть 7: Примеры конфигураций для реальных сервисов

  10. Часть 8: Финальные штрихи – права доступа, logrotate, автоматические обновления

  11. Вишенка на торте

Цели и используемые технологии

  • Traefik – современный обратный прокси с автоматическим получением SSL-сертификатов от Let’s Encrypt. Мы будем использовать его как единую точку входа для всех наших внутренних сервисов (Seafile, OnlyOffice, Immich, Home Assistant, Proxmox VE, qBittorrent и др.).

  • CrowdSec – open-source IPS/IDS, который анализирует логи и блокирует вредоносные IP. В отличии от Fail2ban, он использует глобальные списки угроз и поведенческий анализ.

  • AppSec WAF – встроенный в CrowdSec модуль для анализа содержимого HTTP-запросов (SQL-инъекции, XSS, эксплуатация уязвимостей). Работает как дополнительный уровень защиты поверх блокировки по IP.

  • LXC-контейнер на Proxmox – легковесная изоляция, простота управления.

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

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

  1. Рабочая установка Proxmox VE (версия 8+).

  2. Зарегистрированное доменное имя (например, example.ru) и возможность управлять его DNS-записями (для получения сертификатов Let’s Encrypt через HTTP-01 challenge требуется доступ к порту 80 из интернета; если домен используется только локально, потребуется DNS-01 challenge - “Вишенка на торте“).

  3. Свободный IP-адрес в вашей локальной сети (мы будем использовать 192.168.1.100 как пример).

  4. Базовое знакомство с командной строкой Linux и редактором nano (или vim).

Часть 1: Создание и подготовка LXC-контейнера

1.1. Загрузка шаблона Debian 12

В веб-интерфейсе Proxmox:

  1. Выберите хранилище (например, local).

  2. Перейдите на вкладку Content (Содержимое).

  3. Нажмите Templates.

  4. Найдите debian-12-standard... и скачайте его.

1.2. Создание контейнера

Нажмите Create CT и заполните поля:

  • General:

    • CT ID: 100 (или любой свободный).

    • Hostname: traefik-crowdsec.

    • Unprivileged container: :white_check_mark: (включено).

    • Password: установите надёжный пароль для root.

  • Template:

    • Storage: local.

    • Template: выберите скачанный Debian 12.

  • Disks:

    • Storage: local-lvm.

    • Disk size (GiB): 8.

  • CPU: Cores: 1.

  • Memory: Memory (MiB): 1024, Swap (MiB): 512.

  • Network:

    • Bridge: vmbr0.

    • IPv4/CIDR: 192.168.1.100/24 (замените на свой IP).

    • Gateway (IPv4): 192.168.1.1 (ваш шлюз).

  • DNS: можно оставить пустым (будут использованы настройки хоста) или указать ваш локальный DNS (например, 192.168.1.1).

Проверьте параметры и нажмите Finish. Запустите контейнер.

1.3. Вход и базовая настройка

Войдите в контейнер с хоста:

bash

pct enter 100

Обновите систему и установите необходимые пакеты:

bash

apt update && apt upgrade -y
apt install -y curl wget sudo nano gnupg htop lsb-release apache2-utils

1.4. Настройка локали (UTF-8)

bash

apt install -y locales
dpkg-reconfigure locales

В меню выберите ru_RU.UTF-8 UTF-8 и en_US.UTF-8 UTF-8. Затем выберите локаль по умолчанию, например ru_RU.UTF-8. Перезапустите контейнер для применения:

bash

exit
pct restart 100
pct enter 100

Проверьте:

bash

locale
echo "Привет, мир"

1.5. Создание административного пользователя

Создайте пользователя, от которого будете работать (замените username на своё имя):

bash

useradd -m -s /bin/bash -G sudo username
passwd username

Для удобства можно разрешить sudo без пароля:

bash

echo "username ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/username

1.6. Настройка SSH (опционально, но рекомендуется)

Установите SSH-сервер, если его нет:

bash

apt install -y openssh-server

Отредактируйте /etc/ssh/sshd_config, добавив в конец:

text

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers username

Перезапустите SSH:

bash

systemctl restart ssh

Скопируйте свой публичный ключ в /home/username/.ssh/authorized_keys. Теперь можно подключаться по SSH под пользователем username.

Часть 2: Установка Traefik

Мы установим Traefik версии 3.6.9 как бинарный файл и запустим через systemd.

2.1. Скачивание и проверка

bash

cd /tmp
TRAEFIK_VERSION="v3.6.9"
ARCH="amd64"
wget "https://github.com/traefik/traefik/releases/download/${TRAEFIK_VERSION}/traefik_${TRAEFIK_VERSION}_linux_${ARCH}.tar.gz"
wget "https://github.com/traefik/traefik/releases/download/${TRAEFIK_VERSION}/traefik_${TRAEFIK_VERSION}_checksums.txt"
grep "traefik_${TRAEFIK_VERSION}_linux_${ARCH}.tar.gz" traefik_${TRAEFIK_VERSION}_checksums.txt | sha256sum -c -

Ожидаемый вывод: traefik_v3.6.9_linux_amd64.tar.gz: OK.

2.2. Установка бинарного файла

bash

tar -xzf "traefik_${TRAEFIK_VERSION}_linux_${ARCH}.tar.gz"
sudo mv traefik /usr/local/bin/
sudo chmod +x /usr/local/bin/traefik
traefik version   # должно показать 3.6.9

2.3. Создание системного пользователя для Traefik

bash

sudo groupadd --system traefik
sudo useradd --system --no-create-home --home-dir / --shell /bin/false -g traefik traefik

2.4. Подготовка структуры директорий

bash

sudo mkdir -p /etc/traefik/{conf.d,plugins-storage,ssl}
sudo mkdir -p /var/log/traefik
sudo chown -R traefik:traefik /var/log/traefik
sudo chmod 755 /var/log/traefik

2.5. Минимальная статическая конфигурация (/etc/traefik/traefik.yml)

На этом этапе мы создадим базовую конфигурацию, чтобы убедиться, что Traefik работает и панель управления доступна. Позже мы её расширим.

bash

sudo tee /etc/traefik/traefik.yml > /dev/null <<'EOF'
entryPoints:
  web:
    address: ":80"
  traefik:
    address: ":8080"

providers:
  file:
    directory: /etc/traefik/conf.d
    watch: true

api:
  dashboard: true
  insecure: true   # временно, только для отладки

log:
  level: INFO
  filePath: /var/log/traefik/traefik.log

accessLog:
  filePath: /var/log/traefik/access.log
EOF

2.6. Динамическая конфигурация для панели управления

Создайте файл /etc/traefik/conf.d/10-traefik-dashboard.yml:

bash

sudo tee /etc/traefik/conf.d/10-traefik-dashboard.yml > /dev/null <<'EOF'
http:
  routers:
    dashboard:
      rule: "Host(`traefik.local`) || PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
      entryPoints:
        - traefik
      service: api@internal
      middlewares: []
EOF

2.7. Файл окружения (обязателен, даже пустой)

bash

sudo touch /etc/traefik/traefik.env
sudo chown traefik:traefik /etc/traefik/traefik.env
sudo chmod 600 /etc/traefik/traefik.env

2.8. Systemd unit для Traefik

Важно: В unit-файле обязательно должна быть указана рабочая директория WorkingDirectory=/etc/traefik, иначе плагин CrowdSec будет работать некорректно. Также добавим --pidfile для корректной ротации логов.

bash

sudo tee /etc/systemd/system/traefik.service > /dev/null <<'EOF'
[Unit]
Description=Traefik Proxy
Documentation=https://doc.traefik.io/traefik/
After=network.target

[Service]
User=traefik
Group=traefik
WorkingDirectory=/etc/traefik
Type=simple
EnvironmentFile=/etc/traefik/traefik.env
ExecStart=/usr/local/bin/traefik --pidfile=/run/traefik.pid --configFile=/etc/traefik/traefik.yml
Restart=on-failure
RestartSec=5
LimitNOFILE=65535
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes

[Install]
WantedBy=multi-user.target
EOF

2.9. Запуск Traefik

bash

sudo systemctl daemon-reload
sudo systemctl enable --now traefik
sudo systemctl status traefik

Проверьте доступность панели: http://<IP-контейнера>:8080/dashboard/ (если вы ещё не пробросили порты, панель будет доступна только изнутри контейнера или с хоста Proxmox).

Примечание: Если вы планируете выпускать SSL-сертификаты через HTTP-01 challenge, необходимо, чтобы порт 80 был доступен из интернета. На этом этапе можно не беспокоиться, мы настроим HTTPS позже.

Часть 3: Установка и настройка CrowdSec

3.1. Добавление репозитория и установка

bash

curl -s https://install.crowdsec.net | sudo sh
sudo apt update
sudo apt install crowdsec -y

3.2. Разрешение конфликта портов

Traefik уже слушает порт 8080, а CrowdSec по умолчанию пытается запустить LAPI на том же порту. Изменим порт LAPI на 8081.

Отредактируйте /etc/crowdsec/config.yaml:

bash

sudo nano /etc/crowdsec/config.yaml

Найдите строку listen_uri: и измените:

yaml

api:
  server:
    listen_uri: 127.0.0.1:8081   # было 8080

Сохраните. Затем отредактируйте /etc/crowdsec/local_api_credentials.yaml:

bash

sudo nano /etc/crowdsec/local_api_credentials.yaml

Измените url на http://127.0.0.1:8081.

Запустите CrowdSec и проверьте статус:

bash

sudo systemctl start crowdsec
sudo systemctl status crowdsec
sudo ss -tlnp | grep 8081   # должен быть LISTEN

3.3. Настройка сбора логов Traefik (acquisition)

CrowdSec должен читать логи Traefik. Создайте /etc/crowdsec/acquis.d/traefik.yaml:

bash

sudo tee /etc/crowdsec/acquis.d/traefik.yaml > /dev/null <<EOF
filenames:
  - /var/log/traefik/access.log
  - /var/log/traefik/traefik.log
labels:
  type: traefik
EOF

sudo systemctl reload crowdsec

3.4. Подключение к CrowdSec Console (рекомендуется)

CrowdSec Console позволяет получать глобальные списки угроз и управлять инстансами.

  1. Зарегистрируйтесь на https://app.crowdsec.net.

  2. В разделе Instances нажмите Enroll Your First Instance и скопируйте команду вида:

    bash

    sudo cscli console enroll clXXXXXXXXXX --name "traefik-crowdsec"
    
  3. Выполните её в контейнере.

  4. Вернитесь в консоль и примите инстанс.

  5. Перезапустите CrowdSec и проверьте статус:

bash

sudo systemctl restart crowdsec
sudo cscli console status

Все опции, кроме console_management, должны быть активны.

3.5. Создание белого списка для локальных сетей

Чтобы CrowdSec не блокировал IP из вашей внутренней сети, создадим парсер-whitelist. Файл /etc/crowdsec/parsers/s02-enrich/my-whitelist.yaml:

bash

sudo tee /etc/crowdsec/parsers/s02-enrich/my-whitelist.yaml > /dev/null <<'EOF'
name: crowdsecurity/my-whitelists
description: "Whitelist events from local ipv4 networks"
filter: "1 == 1"
whitelist:
  reason: "local network ranges"
  ip:
    - "127.0.0.1"
  cidr:
    - "192.168.1.0/24"    # замените на вашу сеть
    - "10.0.0.0/8"
    - "172.16.0.0/12"
EOF

sudo systemctl reload crowdsec
sudo cscli parsers list | grep my-whitelists   # должен быть enabled,local

3.6. Установка необходимых коллекций

Коллекции содержат парсеры и сценарии для конкретных типов логов.

bash

sudo cscli collections install crowdsecurity/traefik crowdsecurity/base-http-scenarios crowdsecurity/http-cve
sudo cscli collections upgrade crowdsecurity/sshd crowdsecurity/linux
sudo systemctl reload crowdsec

Проверьте список коллекций:

bash

sudo cscli collections list

Часть 4: Интеграция Traefik с CrowdSec через плагин

Используем официальный плагин crowdsec-bouncer-traefik-plugin версии 1.5.1. Он работает непосредственно внутри Traefik, без внешнего bouncer-сервиса.

4.1. Добавление секции experimental в статическую конфигурацию Traefik

Отредактируйте /etc/traefik/traefik.yml и добавьте в конец:

yaml

experimental:
  plugins:
    crowdsec-bouncer:
      moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
      version: v1.5.1

4.2. Генерация API-ключа для плагина

bash

sudo cscli bouncers add traefik-plugin -o raw
# скопируйте длинный ключ (например, aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd)

4.3. Создание middleware для плагина

Создайте файл /etc/traefik/conf.d/01-crowdsec.yml. Внимание: замените 192.168.1.0/24 на свою подсеть и вставьте скопированный ключ.

bash

sudo tee /etc/traefik/conf.d/01-crowdsec.yml > /dev/null <<EOF
http:
  middlewares:
    crowdsec-bouncer:
      plugin:
        crowdsec-bouncer:
          CrowdsecMode: "stream"
          CrowdsecLapiHost: "127.0.0.1:8081"
          CrowdsecLapiPath: "/"
          CrowdsecLapiKey: "aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
          LogLevel: "INFO"
          ClientTrustedIPs:
            - "192.168.1.0/24"
            - "10.0.0.0/8"
            - "172.16.0.0/12"
            - "127.0.0.1/32"
EOF

Пояснение параметров:

  • CrowdsecMode: "stream" – самый производительный режим: Traefik раз в минуту запрашивает список забаненных IP и кэширует его.

  • ClientTrustedIPs – IP-адреса, для которых проверка CrowdSec не выполняется (ваша локальная сеть).

4.4. Создание тестового маршрута (опционально)

Для проверки можно создать простой маршрут с заглушкой, например /etc/traefik/conf.d/00-test.yml:

yaml

http:
  routers:
    test:
      rule: "Host(`test.example.ru`)"
      middlewares:
        - crowdsec-bouncer
      service: test
  services:
    test:
      loadBalancer:
        servers:
          - url: "http://127.0.0.1:8080"

4.5. Перезапуск Traefik

bash

sudo systemctl restart traefik

Проверьте, что плагин загрузился:

bash

sudo journalctl -u traefik -f | grep plugin

4.6. Проверка доступности LAPI

bash

curl http://127.0.0.1:8081/health
# должен вернуть {"status":"up"}

Часть 5: Включение AppSec WAF

AppSec WAF анализирует содержимое запросов. Для его работы нужны дополнительные коллекции и настройка acquisition.

5.1. Установка AppSec-коллекций

bash

sudo cscli collections install crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules

5.2. Создание acquisition для AppSec

Создайте файл /etc/crowdsec/acquis.d/appsec.yaml:

bash

sudo tee /etc/crowdsec/acquis.d/appsec.yaml > /dev/null <<'EOF'
appsec_config: crowdsecurity/appsec-default
labels:
  type: appsec
listen_addr: 127.0.0.1:7422
source: appsec
EOF

Пояснение: listen_addr: 127.0.0.1:7422 – AppSec Component будет слушать только на локальном интерфейсе.

5.3. Перезагрузка CrowdSec

bash

sudo systemctl reload crowdsec

Проверьте, что AppSec запустился:

bash

sudo ss -tlnp | grep 7422
sudo journalctl -u crowdsec -f | grep appsec   # не должно быть ошибок

5.4. Настройка плагина Traefik для использования AppSec

Отредактируйте /etc/traefik/conf.d/01-crowdsec.yml, добавив параметры AppSec (выделены +):

yaml

http:
  middlewares:
    crowdsec-bouncer:
      plugin:
        crowdsec-bouncer:
          CrowdsecMode: "stream"
          CrowdsecLapiHost: "127.0.0.1:8081"
          CrowdsecLapiPath: "/"
          CrowdsecLapiKey: "aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
          # --- AppSec WAF ---
          crowdsecAppsecEnabled: true
          crowdsecAppsecHost: "127.0.0.1:7422"
          crowdsecAppsecFailureBlock: true
          crowdsecAppsecUnreachableBlock: true
          # -----------------
          LogLevel: "INFO"
          ClientTrustedIPs:
            - "192.168.1.0/24"
            - "10.0.0.0/8"
            - "172.16.0.0/12"
            - "127.0.0.1/32"

5.5. Перезапуск Traefik

bash

sudo systemctl restart traefik

Проверьте логи на наличие сообщений об AppSec:

bash

sudo journalctl -u traefik -f | grep appsec

5.6. Проверка работы AppSec

Сделайте тестовый вредоносный запрос к любому защищённому маршруту (например, к панели Traefik, если она защищена middleware crowdsec-bouncer):

bash

curl -k -H "Host: traefik.example.ru" "https://192.168.1.100/?q=%27%20OR%201=1--"

Ожидаемый ответ: 403 Forbidden (если AppSec сработает). Также можно посмотреть метрики CrowdSec:

bash

sudo cscli metrics

В секциях Appsec Metrics и Bouncer Metrics должны появиться счётчики.


Часть 6: Настройка middleware и цепочек для сервисов

Для удобства и переиспользования создадим набор стандартных middleware (аутентификация, rate limit, заголовки безопасности) и объединим их в цепочки (chains). Это позволит легко применять одинаковые политики к разным сервисам.

6.1. Основные middleware (/etc/traefik/conf.d/00-core.yml)

bash

sudo tee /etc/traefik/conf.d/00-core.yml > /dev/null <<'EOF'
http:
  middlewares:
    # Аутентификация (basic auth)
    auth-basic:
      basicAuth:
        users:
          - "username:$apr1$jkae0qdh$LJVQSVKCe0ZfYbJ/p6wK6/"   # замените на свой хеш

    # Rate limit (защита от перебора)
    rate-limit:
      rateLimit:
        average: 50
        burst: 100

    # Ограничение по IP (только локальная сеть)
    ip-whitelist-lan:
      ipWhiteList:
        sourceRange:
          - "192.168.1.0/24"        # замените на вашу сеть
          - "127.0.0.1/32"

    # Заголовки безопасности (строгие)
    headers-default:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        forceSTSHeader: true
        browserXssFilter: true
        contentTypeNosniff: true
        frameDeny: true
        referrerPolicy: "strict-origin-when-cross-origin"
        permissionsPolicy: "geolocation=(), camera=(), microphone=()"

    # Заголовки для приложений, которым нужны камера/микрофон (например, VoIP)
    headers-media:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        forceSTSHeader: true
        browserXssFilter: true
        contentTypeNosniff: true
        frameDeny: true
        referrerPolicy: "strict-origin-when-cross-origin"
        permissionsPolicy: "geolocation=(self), camera=(self), microphone=(self)"

    # Заголовки для приложений, которым нужен iframe (например, Proxmox, OnlyOffice)
    headers-allow-iframe:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true
        forceSTSHeader: true
        browserXssFilter: true
        contentTypeNosniff: true
        frameDeny: false
        customFrameOptionsValue: "SAMEORIGIN"
        referrerPolicy: "strict-origin-when-cross-origin"
        permissionsPolicy: "geolocation=(self), camera=(self), microphone=(self)"

    # --- Цепочки (chains) ---
    # Для административных интерфейсов (CrowdSec + auth + rate-limit + строгие заголовки)
    chain-admin:
      chain:
        middlewares:
          - crowdsec-bouncer@file
          - auth-basic@file
          - rate-limit@file
          - headers-default@file

    # Для административных интерфейсов, которым нужен iframe
    chain-admin-iframe:
      chain:
        middlewares:
          - crowdsec-bouncer@file
          - auth-basic@file
          - rate-limit@file
          - headers-allow-iframe@file

    # Для публичных сервисов (CrowdSec + rate-limit + строгие заголовки, без аутентификации)
    chain-public:
      chain:
        middlewares:
          - crowdsec-bouncer@file
          - rate-limit@file
          - headers-default@file

    # Для публичных сервисов с медиа-доступом
    chain-public-media:
      chain:
        middlewares:
          - crowdsec-bouncer@file
          - rate-limit@file
          - headers-media@file

    # Для публичных сервисов с iframe
    chain-public-iframe:
      chain:
        middlewares:
          - crowdsec-bouncer@file
          - rate-limit@file
          - headers-allow-iframe@file

    # Для внутренних сервисов (только LAN, CrowdSec не нужен, так как IP доверенные)
    chain-lan:
      chain:
        middlewares:
          - ip-whitelist-lan@file
          - rate-limit@file
          - headers-default@file

    # Для внутренних сервисов с iframe
    chain-lan-iframe:
      chain:
        middlewares:
          - ip-whitelist-lan@file
          - rate-limit@file
          - headers-allow-iframe@file
EOF

Примечание: Хеш пароля можно сгенерировать командой htpasswd -nB username. Если у вас ещё не установлен apache2-utils, выполните sudo apt install apache2-utils.

6.2. TLS-опции (/etc/traefik/conf.d/03-tls.yml)

Зададим минимальную версию TLS:

bash

sudo tee /etc/traefik/conf.d/03-tls.yml > /dev/null <<'EOF'
tls:
  options:
    modern:
      minVersion: VersionTLS12
EOF

6.3. Маршрут для панели Traefik (с HTTPS и аутентификацией)

Обновим файл /etc/traefik/conf.d/10-traefik-dashboard.yml для работы через HTTPS с использованием цепочки chain-admin:

bash

sudo tee /etc/traefik/conf.d/10-traefik-dashboard.yml > /dev/null <<'EOF'
http:
  routers:
    traefik-dashboard:
      rule: "Host(`traefik.example.ru`)"   # замените на ваш домен
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-admin@file
      service: "api@internal"
EOF

6.4. Обновление статической конфигурации для HTTPS

Теперь нужно дополнить /etc/traefik/traefik.yml точками входа для HTTPS и резолвером Let’s Encrypt. Приведём файл к окончательному виду (замените your-email@example.com на свой email):

bash

sudo tee /etc/traefik/traefik.yml > /dev/null <<'EOF'
providers:
  file:
    directory: /etc/traefik/conf.d/
    watch: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https

  websecure:
    address: ":443"
    transport:
      respondingTimeouts:
        readTimeout: 600s
        idleTimeout: 600s
        writeTimeout: 600s

certificatesResolvers:
  letsencrypt:
    acme:
      email: "your-email@example.com"
      storage: /etc/traefik/ssl/acme.json
      httpChallenge:
        entryPoint: web

api:
  dashboard: true
  insecure: false

log:
  filePath: /var/log/traefik/traefik.log
  format: json
  level: INFO

accessLog:
  filePath: /var/log/traefik/traefik-access.log
  format: json
  filters:
    statusCodes:
      - "400-599"
    retryAttempts: true
    minDuration: "10ms"
  bufferingSize: 0
  fields:
    headers:
      defaultMode: drop
      names:
        User-Agent: keep

experimental:
  plugins:
    crowdsec-bouncer:
      moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
      version: v1.5.1
EOF

6.5. Перезапуск Traefik

bash

sudo systemctl restart traefik

Если вы ещё не пробросили порты 80 и 443 на контейнер, Traefik будет пытаться их слушать, но извне они будут недоступны. Это нормально на этапе локальной настройки.


Часть 7: Примеры конфигураций для реальных сервисов

Ниже приведены примеры файлов для популярных self-hosted приложений. Все они используют созданные ранее middleware и цепочки. Не забудьте заменить домены и IP-адреса на свои.

7.1. Proxmox VE

Файл /etc/traefik/conf.d/20-proxmox.yml:

yaml

http:
  routers:
    proxmox:
      rule: "Host(`pve.example.ru`)"
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-admin-iframe@file   # используем iframe для консоли
      service: proxmox

  services:
    proxmox:
      loadBalancer:
        serversTransport: proxmox-transport
        passHostHeader: true
        servers:
          - url: "https://192.168.1.99:8006"

  serversTransports:
    proxmox-transport:
      insecureSkipVerify: true   # игнорируем самоподписанный сертификат Proxmox

7.2. Seafile + OnlyOffice

Seafile часто требует отдельного эндпоинта для уведомлений. Файл /etc/traefik/conf.d/30-seafile.yml:

yaml

http:
  routers:
    seafile-main:
      rule: "Host(`drive.example.ru`) && !PathPrefix(`/notification`)"
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-public@file
        - seafile-headers@file
      service: seafile-main

    seafile-notification:
      rule: "Host(`drive.example.ru`) && PathPrefix(`/notification`)"
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-public@file
        - notification-headers@file
      service: seafile-notification

    onlyoffice:
      rule: "Host(`office.example.ru`)"
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-public@file
        - onlyoffice-headers@file
      service: onlyoffice

  services:
    seafile-main:
      loadBalancer:
        servers:
          - url: "http://192.168.1.30:8080"

    seafile-notification:
      loadBalancer:
        servers:
          - url: "http://192.168.1.30:8083"
        healthCheck:
          path: /ping
          interval: 10s
          timeout: 3s

    onlyoffice:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://192.168.1.30:6233"

  middlewares:
    seafile-headers:
      headers:
        customRequestHeaders:
          X-Forwarded-Proto: "https"
          X-Forwarded-Host: "drive.example.ru"
        customResponseHeaders:
          X-Frame-Options: "SAMEORIGIN"
          Content-Security-Policy: "frame-ancestors 'self' https://drive.example.ru"

    notification-headers:
      headers:
        customRequestHeaders:
          X-Forwarded-Proto: "https"
          X-Forwarded-Host: "drive.example.ru"

    onlyoffice-headers:
      headers:
        customRequestHeaders:
          X-Forwarded-Proto: "https"
          X-Forwarded-Host: "office.example.ru"
        customResponseHeaders:
          X-Frame-Options: ""
          Content-Security-Policy: "frame-ancestors 'self' https://drive.example.ru"

7.3. Immich

Файл /etc/traefik/conf.d/40-immich.yml:

yaml

http:
  routers:
    immich:
      rule: "Host(`photos.example.ru`)"
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-public-media@file
      service: immich

  services:
    immich:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://192.168.1.102:2283"

7.4. Matrix (Synapse)

Файл /etc/traefik/conf.d/50-matrix.yml:

yaml

http:
  routers:
    matrix-web:
      rule: "Host(`matrix.example.ru`)"
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-public@file
      service: matrix-nginx

  services:
    matrix-nginx:
      loadBalancer:
        servers:
          - url: "http://192.168.1.108:80"

7.5. Home Assistant

Файл /etc/traefik/conf.d/60-homeassistant.yml:

yaml

http:
  routers:
    homeassistant:
      rule: "Host(`ha.example.ru`)"
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-public-iframe@file
      service: homeassistant

  services:
    homeassistant:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://192.168.1.200:8123"

7.6. qBittorrent

Файл /etc/traefik/conf.d/70-qbittorrent.yml:

yaml

http:
  routers:
    qbittorrent:
      rule: "Host(`qb.example.ru`)"
      entryPoints: ["websecure"]
      tls:
        certResolver: letsencrypt
        options: modern@file
      middlewares:
        - chain-admin@file
      service: qbittorrent

  services:
    qbittorrent:
      loadBalancer:
        passHostHeader: true
        servers:
          - url: "http://192.168.1.103:8090"
        healthCheck:
          path: /
          interval: 10s
          timeout: 3s

Часть 8: Финальные штрихи – права доступа, logrotate, автоматические обновления

8.1. Установка правильных прав доступа

После того как все конфигурационные файлы созданы, необходимо установить корректные владельца и права, чтобы Traefik мог их читать, а другие пользователи (например, вы) – при необходимости просматривать.

bash

# Владелец всех файлов в /etc/traefik – traefik, группа – traefik
sudo chown -R traefik:traefik /etc/traefik

# Директории: права 750 (владелец всё, группа чтение+выполнение)
sudo find /etc/traefik -type d -exec chmod 750 {} \;

# Файлы конфигурации (кроме .env и acme.json): права 640
sudo find /etc/traefik -type f -not -name "*.env" -not -name "acme.json" -exec chmod 640 {} \;

# Файл .env: права 600
sudo chmod 600 /etc/traefik/traefik.env

# Папка plugins-storage и её содержимое
sudo chown -R traefik:traefik /etc/traefik/plugins-storage
sudo find /etc/traefik/plugins-storage -type d -exec chmod 755 {} \;
sudo find /etc/traefik/plugins-storage -type f -exec chmod 644 {} \;

# Логи
sudo chown -R traefik:traefik /var/log/traefik
sudo chmod 755 /var/log/traefik

Важно: Если вы добавили своего административного пользователя в группу traefik, то после изменения прав вы сможете просматривать файлы без sudo. Для этого выполните:

bash

sudo usermod -aG traefik username

Выйдите и зайдите заново (или выполните newgrp traefik в текущей сессии).

8.2. Настройка ротации логов (logrotate) для Traefik

CrowdSec имеет встроенную ротацию логов, а Traefik – нет. Настроим logrotate для файлов в /var/log/traefik.

Создайте файл /etc/logrotate.d/traefik:

bash

sudo tee /etc/logrotate.d/traefik > /dev/null <<'EOF'
/var/log/traefik/*.log {
    daily
    rotate 7
    maxsize 50M
    compress
    delaycompress
    missingok
    notifempty
    create 640 traefik traefik
    sharedscripts
    postrotate
        if [ -f /run/traefik.pid ]; then
            kill -USR1 `cat /run/traefik.pid`
        else
            PID=$(pidof traefik)
            if [ -n "$PID" ]; then
                kill -USR1 $PID
            fi
        fi
    endscript
}
EOF

Проверьте синтаксис:

bash

sudo logrotate -d /etc/logrotate.d/traefik

8.3. Настройка автоматических обновлений безопасности (unattended-upgrades)

Это гарантирует, что система будет получать критические обновления без вашего участия.

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

bash

sudo apt install unattended-upgrades apt-listchanges -y

Настройте его:

bash

sudo dpkg-reconfigure -plow unattended-upgrades

При запросе выберите Yes.

Отредактируйте /etc/apt/apt.conf.d/50unattended-upgrades, чтобы разрешить только обновления безопасности (обычно настройки по умолчанию уже корректны). Убедитесь, что активны строки:

text

"origin=Debian,codename=${distro_codename},label=Debian";
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";

По умолчанию обновления запускаются ежедневно в случайное время (6:00 + случайная задержка до 60 минут). Чтобы изменить интервал, например, на 5:00–7:00, создайте override для таймера:

bash

sudo mkdir -p /etc/systemd/system/apt-daily-upgrade.timer.d
sudo tee /etc/systemd/system/apt-daily-upgrade.timer.d/override.conf <<EOF
[Timer]
OnCalendar=
OnCalendar=*-*-* 5:00
RandomizedDelaySec=2h
Persistent=true
EOF

sudo systemctl daemon-reload

Проверьте статус таймера:

bash

systemctl status apt-daily-upgrade.timer

В строке Trigger должно быть время в интервале 5:00–7:00.

Заключение и полезные советы

Таким образом Вы развернули полноценный, безопасный и современный стек для управления домашними сервисами. Подведём итог того, что у вас теперь есть:

  • Единая точка входа – Traefik принимает все запросы по HTTPS, автоматически перенаправляет HTTP на HTTPS, управляет сертификатами.

  • Защита на уровне IP – CrowdSec анализирует логи и блокирует подозрительные IP как на основе локальных правил, так и на основе глобальных списков (CAPI).

  • Защита на уровне приложений – AppSec WAF анализирует содержимое запросов и блокирует сложные атаки (SQLi, XSS, эксплуатацию уязвимостей).

  • Гибкая маршрутизация – через цепочки middleware вы можете легко применять единые политики безопасности к разным сервисам.

  • Автоматическое обслуживание – logrotate для логов и unattended-upgrades для системных обновлений.

P.S. Надеюсь я смог создать максимально подробное руководство по разворачиванию Traefik и Crowdsec с почти всеми возможностями, которые могут понадобится самохостеру, которое не займет у Вас много времени в отличии от меня.

Естественно текст был отредактирован с помощью Ai, за что ему спасибо!

P.P.S. У меня домен на sweb.ru (не реклама), и я смог настроить получение wildcard-сертификата для домена типа *.lan.example.ru. Это и есть та сама “Вишенка на торте“ если она будет кому интересна, я постараюсь так же подробно все описать.

Если вы обнаружили ошибки, нестыковки или в процессе у вас возникли какие либо трудности обязательно пишите. Мы попробуем решить Вашу проблему и исправим неточности в статье.

Спасибо за внимание!

6 лайков

Место под “Вишенку на торте“ :wink:

1 лайк

Огромное Вам спасибо за такое подробное руководство. Я как раз хочу перейти на Traefik с Nginx proxy manager. И основная причина этому - IaC. Я недавно развернул Homepage и кайфанул. Не от самого сервиса. А от того, что я могу сделать бекап нескольких конфигов и развернуть его потом за считанные минуты. Насколько я понимаю Traefik позволяет сделать также

Сами файлы конфигурации безусловно можно скопипастить, но процесс установки и настройки никто не отменял.

Жду отклик о проделанной работе.

Работа проделана огромная, тут однозначно лайк.
Но я бы сказал, что такой огромный объем полезен когда еще ничего нет и надо развернуть все с нуля.
В моем случае интересны были пункты с appsec т.к. пока не добрался до добавления waf. но тут проема в том, что я хочу развернуть 2 линейки crowdsec

  1. Анализатор логов и просто crowdsec, тут логи собираются и агрегируются при помощи victoria logs (есть проблема с анализаторами), а bouncer у меня не на уровне traefik, а сразу на роутере. Тут есть цепочка из services → victoria logs → crowdsec → crowdsec bgp bouncer
  2. Отдельный WAF для traefik, но поскольку у меня 5 основных инстансов traefik и несколько вспомогательных, то видится, что мне надо будет как минимум 5 инстансов crowdsec с выключением функционала bouncer и настройкой только appsec

Для 2, скорее всего, буду создавать отдельный git репозиторий с настройками т.к. по комментариям, там надо тюнить еще appsec, чтобы он сильно не лютовал, потом как-то разносить по инстансам с crowdsec

Ну и еще бы интересно рассмотреть в контексте данной статьи мониторинг этого самого crowdsec, т.к. он не дает бесплатно нормальных дашбордов. Из того, что я нашел и пробовал

  1. Облачный - во первых облако, во вторых управление только за деньги
  2. Дашборд на основе metabase - красиво, но очень ресурсоемко, я особо не тюнил, но сожрало 4ГБ оперативки прям на ровном месте, ну и вообще проект тяжелый очень, на java и вообще заточен под другие задачи, насколько я понял, то только на чтение работает. Анализирует внутренюю БД самого crowdsec
  3. Набор дашбордов на основе prometheus и grafana, по ощущениям, примерно можно получить, что и в предыдущем пункте, но меньшими трудозатратами и интегрированно в общую инфраструктуру

Каких-то визуализаторов cscli с возможностью управления я не нашел.

Я пытался описать использование в быту, а не в где-то на предприятии :upside_down_face:

В качестве мониторинга пока юзаю сайт, там конечно лимит в 500 IP месяц, который у меня однажды закончился за 10 минут :grinning_face: где-то попадалась информация что можно свою панель поставить, но пока не вникал.

Возможно есть варианты прикрутить всеми любимую Графана, но я не пользую ее, в принципе как и остальное ПО такого типа. Возможно пока не использую.

Crowdsec только в режиме appsec

  crowdsec:
    image: crowdsecurity/crowdsec:latest
    container_name: crowdsec
    restart: unless-stopped
    network_mode: host
    environment:
      TZ: Europe/Moscow
      COLLECTIONS: "crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules" 
    volumes:
      - ./db:/var/lib/crowdsec/data/
      - ./config:/etc/crowdsec/

И middleware

http:
  middlewares:
    waf-middleware:
      plugin:    
        crowdsec-bouncer:
          enabled: "true"
          CrowdsecLapiHost: "127.0.0.1:8081"
          CrowdsecLapiPath: "/"
          CrowdsecLapiKey: "aaaaaaaaaabbbbbbbbbbccccccccccdddddddddd"
          crowdsecMode: "appsec"
          crowdsecAppsecEnabled: "true"
          crowdsecAppsecHost: "127.0.0.1:7422"
          appsecFailureBlock: "true"
          appsecUnreachableBlock: "true"
      
          logLevel: "ERROR"
          clientTrustedIPs:
            - "192.168.1.0/24"
            - "10.0.0.0/8"
            - "172.16.0.0/12"
            - "127.0.0.1/32"

Памяти потребляет в таком режиме порядка 30МБ, по процессору не заметил особого роста потребления.но надо будет еще потестить

Это много/мало в сравнении с чем?

Это очень мало в сравнении с современными решениями.
Тот же Authentik при старте съедает 1.5ГБ оперативки
Сейчас проверил, crowdsec waf потребляет 67МБ, Authentik Proxy Outpost - 34.4МБ

“Большой” crowdsec LXC контейнера потребляет 181МБ

Получается, что crowdsec для хоумлабы не будет напряжным от слова совсем.

Вставлю свои пять копеек, если не возражаете.
Вы используете Traefik, как systemd service, но при этом у вас довольно громоздкая и неудобная конструкция в logrotate.
postrotate
if [ -f /run/traefik.pid ]; then
kill -USR1 `cat /run/traefik.pid`
else
PID=$(pidof traefik)
if [ -n "$PID" ]; then
kill -USR1 $PID
fi
fi

Несколько удобнее и писать просто
postrotate
/usr/bin/systemctl kill -s USR1 traefik-proxy.service
При этом отпадет и необходимость использования pidfile при запуске Traefik.
Возможно вы знаете об этом, но выбрали такую конструкцию по каким-то особым соображениям? Буду признателен, если поделитесь.

Особых соображений небыло, была задача ужимать логи. Я на их форуме нашел такой вариант, загнал его в Ai и она допилила.

Мой вариант более общий, не привязан к systemd, работает даже если Traefik запущен иначе. Ваш вариант направлен конкретно на systemd. И мне кажется, он будет более правильный в данном случае. Но т.к. у меня уже все настроено и работает - пусть работает. Остальные пользователи могу использовать ваш вариант.

1 лайк