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

ala-a-din
Wed, 04 Mar 2026 17:20:01 +0000
Traefik

Это подробное, пошаговое руководство, основанное на реальном опыте. Вы развернёте полноценный стек безопасности для домашних сервисов: 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: (включено).

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. Это и есть та сама “Вишенка на торте“ если она будет кому интересна, я постараюсь так же подробно все описать.

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

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

19 сообщений - 6 участников

Читать всю тему