Skip to main content

SafeLine WAF: Полное руководство по развёртыванию в Production

Для команды DevOps | Production-Ready Deployment Guide
Дата: 27 января 2026


📖 О чём эта статья

Это полное практическое руководство по развёртыванию SafeLine WAF (Web Application Firewall) в production среде на базе Docker. Материал основан на реальном опыте, включая разбор критических ошибок, которые были найдены и исправлены в процессе peer review.

Для кого эта статья:

  • ✅ DevOps инженеров, внедряющих WAF
  • ✅ System администраторов, отвечающих за безопасность
  • ✅ Команд, мигрирующих с NPM/Traefik на SafeLine
  • ✅ Всех, кто хочет понять production deployment от А до Я

Что вы получите:

  • 🎯 Пошаговые инструкции (каждый шаг объяснён)
  • 🔍 Разбор критических ошибок и их решений
  • 📊 Архитектурные решения с обоснованием
  • 🛡️ Production-grade security best practices
  • 🔧 Готовые скрипты автоматизации
  • 🆘 Troubleshooting guide для типовых проблем

💭 Личное вступление: Почему важен peer review

Честность: Первоначальная версия этого deployment содержала 8 критических ошибок, включая 1 фатальную, которая бы полностью сломала production.

Эти ошибки были найдены благодаря критическому вопросу коллеги: "Стоять... почему два reverse proxy? SafeLine же сам reverse proxy!"

Этот момент стал поворотным. Вместо защиты своего первоначального решения, я провёл полный аудит, изучил 20+ источников, и переделал всё с нуля.

Вывод: Ошибаются все. Важно не скрывать ошибки, а учиться на них и делиться опытом.

Эта статья - результат этого обучения. Здесь собрано всё, что нужно знать, чтобы не повторить те же ошибки.


📚 Содержание

  1. Введение и архитектура
  2. Критические ошибки и их разбор
  3. Системные требования
  4. Подготовка инфраструктуры
  5. Установка и конфигурация
  6. SSL сертификаты (Let's Encrypt)
  7. Добавление backend сервисов
  8. Мониторинг и логирование
  9. Backup и disaster recovery
  10. Troubleshooting
  11. Production checklist

1. Введение и архитектура

1.1 Что такое SafeLine WAF?

SafeLine - это self-hosted WAF (Web Application Firewall) с встроенным reverse proxy на базе Tengine (форк Nginx).

Ключевые возможности:

┌─────────────────────────────────────────────┐
│         SafeLine WAF Capabilities           │
├─────────────────────────────────────────────┤
│                                             │
│  🛡️  WAF Protection:                       │
│      • SQL Injection blocking              │
│      • XSS (Cross-Site Scripting)          │
│      • CSRF protection                     │
│      • RCE (Remote Code Execution)         │
│      • Path Traversal                      │
│      • 0-day detection (AI/ML)             │
│                                             │
│  🔄  Reverse Proxy:                        │
│      • SSL/TLS termination                 │
│      • Load balancing                      │
│      • HTTP/2, WebSocket support           │
│      • Caching (proxy_cache)               │
│                                             │
│  🤖  Bot Protection:                       │
│      • CAPTCHA challenges                  │
│      • Rate limiting (advanced)            │
│      • User-Agent filtering                │
│      • IP reputation                       │
│                                             │
│  📊  Monitoring:                           │
│      • Real-time attack dashboard          │
│      • Detailed logs                       │
│      • Attack visualization                │
│      • Alerts & notifications              │
│                                             │
└─────────────────────────────────────────────┘

❓ Почему SafeLine, а не Nginx/NPM?

Критерий Nginx/NPM SafeLine
Reverse Proxy
SSL Management
Web UI ✅ NPM
WAF Protection ✅ ⭐
AI Threat Detection ✅ ⭐
Attack Visualization ✅ ⭐
Zero-day Protection ✅ ⭐

Вывод: SafeLine = NPM + Enterprise WAF в одном решении


1.2 Архитектура решения

Правильная архитектура (Version 2.0):

┌────────────────────────────────────────────────────────┐
│                      INTERNET                          │
│                   (Port 80/443)                        │
└───────────────────┬────────────────────────────────────┘
                    │
                    │ HTTP/HTTPS Traffic
                    ↓
        ┌───────────────────────────┐
        │   SafeLine Tengine        │
        │   (Reverse Proxy + WAF)   │
        │                           │
        │   • SSL Termination       │
        │   • Attack Detection      │
        │   • Request Filtering     │
        │   • Load Balancing        │
        └───────────┬───────────────┘
                    │
                    │ Docker Network: kodalinet (172.20.0.0/24)
                    │
        ┌───────────┴───────────────────────────────────┐
        │                                               │
        ↓                                               ↓
┌──────────────────┐                          ┌──────────────────┐
│ SafeLine Detector│                          │ Backend Services │
│ (AI/ML Engine)   │                          │                  │
│                  │                          │ • Web App 1      │
│ 172.20.0.5:8000  │                          │ • API Server     │
└──────────────────┘                          │ • Database       │
        │                                     │ • etc...         │
        │                                     │                  │
        ↓                                     │ (expose only!)   │
┌──────────────────┐                          └──────────────────┘
│ SafeLine MGT     │
│ (Web UI)         │
│                  │
│ 172.20.0.4:1443  │
│ (internal only!) │
└──────────────────┘
        │
        ↓
┌──────────────────┐
│ PostgreSQL       │
│ (Configuration   │
│  & Logs)         │
│                  │
│ 172.20.0.2:5432  │
└──────────────────┘

Принципы архитектуры:

  1. Single Entry Point: Только SafeLine на портах 80/443
  2. Internal Services: Все backend сервисы в одной сети, без expose наружу
  3. Defense in Depth: WAF проверяет ВСЕ входящие запросы
  4. Least Privilege: MGT UI доступен только через VPN/SSH tunnel

1.3 Компоненты SafeLine

Контейнеры и их роли:

SafeLine Stack (7 контейнеров):

┌─ safeline-tengine ──────────────────────────────────┐
│  Роль: Reverse Proxy + WAF                         │
│  Порты: 80, 443 (ЕДИНСТВЕННЫЕ открытые наружу!)    │
│  CPU: 4 cores | RAM: 4GB                           │
│  Критичность: ⭐⭐⭐⭐⭐                              │
└─────────────────────────────────────────────────────┘

┌─ safeline-detector ─────────────────────────────────┐
│  Роль: AI/ML движок для детекции атак              │
│  Технология: Semantic analysis, 0-day detection    │
│  CPU: 2 cores | RAM: 2GB                           │
│  Критичность: ⭐⭐⭐⭐⭐                              │
└─────────────────────────────────────────────────────┘

┌─ safeline-mgt ──────────────────────────────────────┐
│  Роль: Web UI для управления                       │
│  Порт: 1443 (INTERNAL, через SSH tunnel!)          │
│  CPU: 1 core | RAM: 1GB                            │
│  Критичность: ⭐⭐⭐⭐                                │
└─────────────────────────────────────────────────────┘

┌─ safeline-pg ───────────────────────────────────────┐
│  Роль: PostgreSQL база данных                      │
│  Хранит: Конфиги, логи атак, статистику            │
│  CPU: 2 cores | RAM: 2GB                           │
│  Критичность: ⭐⭐⭐⭐⭐ (БЭКАПИТЬ!)                 │
└─────────────────────────────────────────────────────┘

┌─ safeline-luigi ────────────────────────────────────┐
│  Роль: Обработчик и анализатор логов               │
│  CPU: 1 core | RAM: 1GB                            │
│  Критичность: ⭐⭐⭐                                 │
└─────────────────────────────────────────────────────┘

┌─ safeline-fvm ──────────────────────────────────────┐
│  Роль: Feature Version Manager                     │
│  CPU: 0.5 core | RAM: 512MB                        │
│  Критичность: ⭐⭐                                   │
└─────────────────────────────────────────────────────┘

┌─ safeline-chaos ────────────────────────────────────┐
│  Роль: Дополнительный модуль безопасности          │
│  CPU: 0.5 core | RAM: 512MB                        │
│  Критичность: ⭐⭐                                   │
└─────────────────────────────────────────────────────┘

ИТОГО: ~11 CPU cores, ~12GB RAM (пиковая нагрузка)

2. Критические ошибки и их разбор

⚠️ ВАЖНО: Этот раздел - самый ценный. Здесь разобраны реальные ошибки которые могли сломать production. Изучите внимательно!

2.1 ОШИБКА #1: Host Mode vs Docker Network (ФАТАЛЬНАЯ!)

❌ Что было неправильно (Version 1.0):

# docker-compose.yml (НЕПРАВИЛЬНО!)
services:
  tengine:
    network_mode: host  # ← ФАТАЛЬНАЯ ОШИБКА!
    
networks:
  kodalinet:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/24

🔥 Почему это фатально:

  1. Docker не запустится:

    $ docker compose up -d
    ERROR: network_mode and networks cannot be used together
    
  2. Tengine НЕ будет в сети kodalinet:

    • Host mode ИЗОЛИРУЕТ контейнер от Docker networks
    • Tengine видит ТОЛЬКО host network stack
    • Не может резолвить container names (my-app:8080)
  3. Требование клиента НЕ выполнено:

    • Клиент: "всё в одной сети kodalinet"
    • Реальность: tengine в host network, остальные в kodalinet

✅ Правильное решение (Version 2.0):

# docker-compose.yml (ПРАВИЛЬНО!)
services:
  tengine:
    # Убираем network_mode: host
    
    ports:
      - "80:80"    # HTTP
      - "443:443"  # HTTPS
    
    networks:
      kodalinet:
        ipv4_address: 172.20.0.3
    
networks:
  kodalinet:
    external: true  # Сеть создана заранее!

📊 Сравнение подходов:

Аспект Host Mode Bridge Mode (правильно)
Совместимость с networks ❌ НЕТ ✅ ДА
Docker DNS (container names) ❌ НЕ работает ✅ Работает
Port mapping Не нужен Нужен (80:80, 443:443)
Производительность 100% ~95% (минимальный overhead)
Изоляция Нет Есть
Best Practice ⚠️ Редко ✅ Стандарт

🎓 Урок:

Host mode и custom networks - НЕСОВМЕСТИМЫ!

Если видите network_mode: host в примере - это НЕ значит что это единственный способ. В нашем случае bridge mode лучше потому что:

  • Совместим с kodalinet
  • Позволяет использовать container names
  • Изолирует tengine от хоста

2.2 ОШИБКА #2: Отсутствие Resource Limits (КРИТИЧНО!)

❌ Что было неправильно:

# НЕТ resource limits = production катастрофа!
postgres:
  image: postgres:15.2
  # ... БЕЗ deploy.resources

🔥 Что может пойти не так:

Сценарий 1: PostgreSQL runaway query

-- Кто-то запустил тяжёлый запрос
SELECT * FROM attack_logs 
  JOIN sites ON ... 
  WHERE date > '2020-01-01';

-- PostgreSQL начинает жрать RAM...
-- 1GB... 2GB... 4GB... 8GB... 16GB...
-- Host OOM Killer: "Убиваю случайный процесс!"
-- *убивает Docker daemon*
-- ВСЕ контейнеры падают! 💥

Сценарий 2: DDoS атака

-- 10,000 req/sec на сервер
-- Tengine пытается обработать все
-- CPU usage: 100% на всех cores
-- Другие контейнеры не получают CPU
-- Весь сервер тормозит
-- SSH не отвечает!

✅ Правильное решение:

postgres:
  deploy:
    resources:
      limits:
        cpus: '2.0'      # Максимум 2 CPU cores
        memory: 2G       # Максимум 2GB RAM
      reservations:
        cpus: '0.5'      # Гарантированно 0.5 CPU
        memory: 512M     # Гарантированно 512MB

📊 Рекомендуемые limits:

Сервис CPU Limit RAM Limit Обоснование
tengine 4.0 4G Обрабатывает ВСЕ HTTP
detector 2.0 2G ML анализ = CPU intensive
postgres 2.0 2G 600 connections * 10MB
mgt 1.0 1G Web UI, средняя нагрузка
luigi 1.0 1G Обработка логов
fvm 0.5 512M Лёгкий сервис
chaos 0.5 512M Лёгкий сервис

ИТОГО: ~11 CPU, ~12GB RAM (пик)
Сервер: Минимум 16 CPU, 32GB RAM

🎓 Урок:

В production БЕЗ resource limits = тикающая бомба!

Один runaway процесс может убить весь хост. Всегда устанавливайте limits.


2.3 ОШИБКА #3: Ulimits для Tengine (КРИТИЧНО!)

❌ Что было неправильно:

tengine:
  # ... БЕЗ ulimits

🔥 Что происходит под нагрузкой:

# 1000 requests/second приходит на сервер
# Каждый request = открытый TCP socket = file descriptor

# Linux по умолчанию: ulimit -n = 1024
# Tengine открывает:
# - 1000 connections = 1000 files
# - Nginx logs = 2 files
# - Config files = ~10 files
# ИТОГО: 1012 открытых файлов

# При 1013-м соединении:
$ curl https://your-site.com
curl: (56) Recv failure: Connection reset by peer

# В логах tengine:
[error] accept() failed (24: Too many open files)

# Сайт НЕДОСТУПЕН! 💥

✅ Правильное решение:

tengine:
  ulimits:
    nofile:
      soft: 65536
      hard: 131072

📊 Как выбрать значение:

Формула: ulimit >= (max_connections * 2) + buffer

Пример расчёта:
- Ожидаемая нагрузка: 5000 req/sec
- Среднее время обработки: 100ms
- Одновременных соединений: 5000 * 0.1 = 500
- С запасом x2: 500 * 2 = 1000
- Nginx служебные файлы: +100
- Буфер безопасности x10: (1000 + 100) * 10 = 11,000
- Округляем до степени 2: 16,384

Но проще использовать стандартные значения:
- 65,536 (64K) - для большинства случаев
- 131,072 (128K) - для высоконагруженных систем

🎓 Урок:

"Too many open files" - частая причина production инцидентов!

Проверьте ulimits ПЕРЕД деплоем, не после падения сайта в 3 часа ночи.


2.4 ОШИБКА #4: MGT порт открыт наружу (SECURITY!)

❌ Что было неправильно:

mgt:
  ports:
    - "9443:1443"  # Доступен из интернета! 😱

🔥 Последствия:

# Атакующий сканирует порты:
$ nmap your-server.com
PORT     STATE SERVICE
80/tcp   open  http
443/tcp  open  https
9443/tcp open  unknown  # ← Нашли админку!

# Пробует дефолтные пароли:
$ curl -k https://your-server.com:9443/api/login \
  -d '{"username":"admin","password":"admin"}'

# Или эксплойты:
$ searchsploit "SafeLine"
$ metasploit> use exploit/safeline_rce_2024

# Результат: ПОЛНАЯ КОМПРОМЕТАЦИЯ WAF
# Атакующий может:
# - Отключить защиту
# - Добавить свои правила
# - Видеть весь траффик
# - Украсть сертификаты

✅ Правильное решение:

Вариант A: Internal only (рекомендуется)

mgt:
  expose:
    - "1443"  # Доступен ТОЛЬКО внутри Docker network
  # БЕЗ ports!

Доступ через SSH tunnel:

# На своём компьютере:
ssh -L 9443:localhost:1443 user@server

# Затем открыть: https://localhost:9443

Вариант B: Localhost only

mgt:
  ports:
    - "127.0.0.1:9443:1443"  # Только с localhost

Вариант C: С firewall (если нужен прямой доступ)

mgt:
  ports:
    - "9443:1443"
# Но ОБЯЗАТЕЛЬНО:
sudo ufw allow from YOUR_OFFICE_IP to any port 9443
sudo ufw deny 9443  # Запретить всем остальным

🎓 Урок:

Админ-панели НИКОГДА не должны быть публичными!

Клиент сказал: "порты закрыты, открыт только 80/443" - это включает и MGT порт.


2.5 ОШИБКА #5: External Network (BEST PRACTICE)

❌ Что было неправильно:

networks:
  kodalinet:
    name: kodalinet
    driver: bridge
    ipam:
      driver: default
      config:
        - gateway: 172.20.0.1
          subnet: 172.20.0.0/24

⚠️ Проблемы:

  1. Сеть пересоздаётся:

    $ docker-compose down
    # Сеть kodalinet удалена!
    
    $ docker-compose up -d
    # Сеть kodalinet создана заново
    # IP адреса могут измениться!
    
  2. Другие сервисы не могут подключиться:

    # Хочу добавить Portainer в эту же сеть
    $ docker run -d --network kodalinet portainer
    ERROR: network kodalinet not found
    
    # Приходится редактировать safeline docker-compose.yml 😞
    
  3. Не соответствует NPM best practice:

    • Клиент привёл пример из блога про NPM
    • Там используется external: true

✅ Правильное решение:

Шаг 1: Создать сеть заранее

docker network create \
  --driver bridge \
  --subnet 172.20.0.0/24 \
  --gateway 172.20.0.1 \
  --opt com.docker.network.bridge.name=kodalinet \
  kodalinet

Шаг 2: Использовать external в compose

networks:
  kodalinet:
    external: true  # Сеть уже существует!

📊 Преимущества external network:

Аспект Internal External
Создаётся При compose up Заранее вручную
Удаляется При compose down Никогда
IP стабильность ⚠️ Могут меняться ✅ Стабильные
Другие сервисы ❌ Сложно добавить ✅ Просто
NPM pattern

🎓 Урок:

Для production используйте external networks!

Это стандартный паттерн из NPM best practices. Сеть создаётся один раз и живёт независимо от compose файлов.


2.6 ОШИБКА #6: SSL Renewal не автоматизирован

❌ Что было неправильно:

Упомянул certbot, НО:

  • ❌ Нет готового скрипта
  • ❌ Нет интеграции с SafeLine
  • ❌ Нет cron настройки

🔥 Что происходит:

День 1:   Получили SSL сертификат ✅
День 30:  Всё работает ✅
День 60:  Всё работает ✅
День 89:  Всё работает ✅

День 90:  Сертификат истёк! 💥
          Браузеры блокируют сайт
          Клиенты не могут зайти
          3:00 субботы, все спят
          Убытки компании растут!

День 91:  DevOps проснулся 😴
          Обновил сертификат вручную
          Post-mortem: "Забыли настроить renewal"

✅ Правильное решение:

Полная автоматизация с 3 компонентами:

1. SafeLine file-watch (встроенный механизм)

  • SafeLine v7.2.0+ проверяет файлы каждый час
  • При изменении сертификата - автоматически применяет
  • БЕЗ рестарта контейнера!

2. Certbot renewal script

#!/bin/bash
# Обновляет сертификат через certbot
# Копирует в /app/safeline/resources/nginx/certs/
# SafeLine подхватывает автоматически

3. Cron job

# Каждый день в 3:00
0 3 * * * /usr/local/bin/safeline-ssl-renew

🎓 Урок:

SSL renewal ДОЛЖЕН быть автоматизирован на 100%!

Человеческий фактор + истечение сертификата = production outage


2.7 Итоговая таблица ошибок

# Ошибка Tier Последствия Исправлено
1 Host mode + network S НЕ ЗАПУСТИТСЯ ✅ Bridge mode
2 Нет resource limits A OOM Killer ✅ Везде добавлены
3 Нет ulimits A "Too many files" ✅ 131072 для tengine
4 MGT порт открыт B Security breach ✅ Internal only
5 Network не external B Сложность поддержки ✅ External
6 SSL не автоматизирован A Сайт упадёт через 90 дней ✅ Скрипт + cron
7 Нет healthchecks C Плохой мониторинг ✅ Везде добавлены
8 Логи не оптимизированы C Забьют диск ✅ Правильная ротация

3. Системные требования

3.1 Минимальные требования

┌─────────────────────────────────────────┐
│      Минимум для запуска (1-10 сайтов) │
├─────────────────────────────────────────┤
│  CPU:     4 cores (x86_64 or ARM64)    │
│  RAM:     8 GB                          │
│  Disk:    50 GB SSD                     │
│  Network: 100 Mbps                      │
│  OS:      Ubuntu 22.04 / Debian 12      │
├─────────────────────────────────────────┤
│  ⚠️ Под нагрузкой будет тормозить!     │
└─────────────────────────────────────────┘

3.2 Рекомендуемые требования

┌─────────────────────────────────────────┐
│   Рекомендуется для production          │
│   (10-100 сайтов, 10K req/sec)          │
├─────────────────────────────────────────┤
│  CPU:     8+ cores                      │
│  RAM:     16 GB (32 GB лучше)           │
│  Disk:    100 GB NVMe SSD               │
│  Network: 1 Gbps                        │
│  OS:      Ubuntu 24.04 / Debian 13      │
├─────────────────────────────────────────┤
│  ✅ Комфортная работа                  │
└─────────────────────────────────────────┘

3.3 High-load требования

┌─────────────────────────────────────────┐
│   High-load (100+ сайтов, 100K req/sec) │
├─────────────────────────────────────────┤
│  CPU:     16-32 cores                   │
│  RAM:     64 GB                         │
│  Disk:    500 GB NVMe SSD (RAID 1)      │
│  Network: 10 Gbps                       │
│  OS:      Ubuntu 24.04 LTS              │
├─────────────────────────────────────────┤
│  + Load Balancer (несколько серверов)  │
│  + Отдельный сервер для PostgreSQL     │
│  + Redis для кэша                       │
└─────────────────────────────────────────┘

3.4 Проверка системы

Запустите этот скрипт для проверки:

#!/bin/bash
# system-check.sh

echo "=== SafeLine System Requirements Check ==="
echo ""

# CPU
CPU_CORES=$(nproc)
echo "CPU Cores: $CPU_CORES"
if [ $CPU_CORES -ge 8 ]; then
    echo "  ✅ GOOD (8+ cores)"
elif [ $CPU_CORES -ge 4 ]; then
    echo "  ⚠️  MINIMAL (4+ cores, может тормозить)"
else
    echo "  ❌ INSUFFICIENT (нужно минимум 4 cores)"
fi

# RAM
TOTAL_RAM=$(free -g | grep Mem | awk '{print $2}')
echo ""
echo "RAM: ${TOTAL_RAM}GB"
if [ $TOTAL_RAM -ge 16 ]; then
    echo "  ✅ GOOD (16+ GB)"
elif [ $TOTAL_RAM -ge 8 ]; then
    echo "  ⚠️  MINIMAL (8+ GB, может не хватить)"
else
    echo "  ❌ INSUFFICIENT (нужно минимум 8 GB)"
fi

# Disk
DISK_AVAIL=$(df -BG / | tail -1 | awk '{print $4}' | sed 's/G//')
echo ""
echo "Available Disk: ${DISK_AVAIL}GB"
if [ $DISK_AVAIL -ge 100 ]; then
    echo "  ✅ GOOD (100+ GB)"
elif [ $DISK_AVAIL -ge 50 ]; then
    echo "  ⚠️  MINIMAL (50+ GB)"
else
    echo "  ❌ INSUFFICIENT (нужно минимум 50 GB)"
fi

# Docker
echo ""
echo "Docker:"
if command -v docker &> /dev/null; then
    DOCKER_VERSION=$(docker --version | grep -oP '\d+\.\d+\.\d+' | head -1)
    echo "  Version: $DOCKER_VERSION"
    
    if [[ $(echo -e "24.0.0\n$DOCKER_VERSION" | sort -V | head -n1) == "24.0.0" ]]; then
        echo "  ✅ GOOD (24.0+)"
    else
        echo "  ⚠️  OLD (рекомендуется >= 24.0)"
    fi
else
    echo "  ❌ NOT INSTALLED"
fi

# Docker Compose
echo ""
echo "Docker Compose:"
if docker compose version &> /dev/null; then
    COMPOSE_VERSION=$(docker compose version | grep -oP '\d+\.\d+\.\d+' | head -1)
    echo "  Version: $COMPOSE_VERSION"
    echo "  ✅ INSTALLED"
else
    echo "  ❌ NOT INSTALLED"
fi

echo ""
echo "=== Check Complete ==="

Сохраните как system-check.sh и запустите:

chmod +x system-check.sh
./system-check.sh

4. Подготовка инфраструктуры

🎯 Цель этапа: Подготовить сервер к установке SafeLine

4.1 Установка Docker и Docker Compose

Для Ubuntu 22.04/24.04:

# 1. Обновляем систему
sudo apt update && sudo apt upgrade -y

# 2. Удаляем старые версии Docker (если есть)
sudo apt remove docker docker-engine docker.io containerd runc

# 3. Устанавливаем зависимости
sudo apt install -y \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

# 4. Добавляем GPG ключ Docker
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
    sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# 5. Добавляем репозиторий Docker
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 6. Устанавливаем Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
    docker-buildx-plugin docker-compose-plugin

# 7. Добавляем пользователя в группу docker
sudo usermod -aG docker $USER

# 8. Применяем изменения (или перелогинимся)
newgrp docker

# 9. Проверяем установку
docker --version
docker compose version

Для Debian 12/13:

# Аналогично Ubuntu, но используем:
curl -fsSL https://download.docker.com/linux/debian/gpg | \
    sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Затем:
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
    docker-buildx-plugin docker-compose-plugin

4.2 Проверка портов

КРИТИЧЕСКИ ВАЖНО: Порты 80 и 443 должны быть свободны!

# Проверяем какие порты заняты
sudo netstat -tlnp | grep -E ':80|:443'

# Или с помощью ss:
sudo ss -tlnp | grep -E ':80|:443'

Если порты заняты:

Nginx:

sudo systemctl stop nginx
sudo systemctl disable nginx  # Чтобы не запускался при reboot

Apache:

sudo systemctl stop apache2
sudo systemctl disable apache2

Docker контейнер:

# Найти контейнер
docker ps | grep -E ':80|:443'

# Остановить
docker stop <container-name>

4.3 Создание Docker network

⚠️ ВАЖНО: Сеть создаётся ПЕРЕД запуском docker-compose!

# Создаём external network
docker network create \
  --driver bridge \
  --subnet 172.20.0.0/24 \
  --gateway 172.20.0.1 \
  --opt com.docker.network.bridge.name=kodalinet \
  kodalinet

Проверка создания:

# Проверяем что сеть создана
docker network ls | grep kodalinet

# Смотрим детали
docker network inspect kodalinet

Ожидаемый вывод:

[
    {
        "Name": "kodalinet",
        "Driver": "bridge",
        "Scope": "local",
        "IPAM": {
            "Config": [
                {
                    "Subnet": "172.20.0.0/24",
                    "Gateway": "172.20.0.1"
                }
            ]
        }
    }
]

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

# Создаём базовую директорию
sudo mkdir -p /app/safeline

# Создаём структуру поддиректорий
sudo mkdir -p /app/safeline/{resources,logs,backups}
sudo mkdir -p /app/safeline/resources/{postgres/data,mgt,nginx,detector,chaos,cache,sock,luigi}
sudo mkdir -p /app/safeline/resources/nginx/{certs,conf.d}
sudo mkdir -p /app/safeline/logs/{nginx,detector}

# Права доступа
sudo chown -R $USER:$USER /app/safeline
chmod -R 755 /app/safeline

# Специальные права
chmod 700 /app/safeline/resources/postgres/data
chmod 700 /app/safeline/backups

Проверка структуры:

tree -L 3 /app/safeline

Ожидаемая структура:

/app/safeline/
├── backups/
├── logs/
│   ├── detector/
│   └── nginx/
└── resources/
    ├── cache/
    ├── chaos/
    ├── detector/
    ├── luigi/
    ├── mgt/
    ├── nginx/
    │   ├── certs/
    │   └── conf.d/
    ├── postgres/
    │   └── data/
    └── sock/

4.5 Настройка Firewall (UFW)

# Установка UFW (если не установлен)
sudo apt install ufw -y

# Разрешаем SSH (КРИТИЧНО! Иначе потеряете доступ)
sudo ufw allow 22/tcp

# Разрешаем HTTP и HTTPS
sudo ufw allow 80/tcp comment 'SafeLine HTTP'
sudo ufw allow 443/tcp comment 'SafeLine HTTPS'

# Включаем UFW
sudo ufw enable

# Проверяем статус
sudo ufw status verbose

Ожидаемый вывод:

Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
80/tcp (SafeLine HTTP)     ALLOW       Anywhere
443/tcp (SafeLine HTTPS)   ALLOW       Anywhere

⚠️ MGT порт (9443) - НЕ открываем!

Доступ только через SSH tunnel (см. раздел 5.6)


[Статья продолжается... Это первая часть. Создам остальные разделы в следующих файлах]


Навигация по статье

📖 Вы здесь: Часть 1 - Введение, ошибки, требования, подготовка
📖 Далее: Часть 2 - Установка, конфигурация, SSL
📖 Далее: Часть 3 - Backend сервисы, мониторинг, troubleshooting


Следующий файл: BOOKSTACK_ARTICLE_PART2.md (установка и конфигурация)