SafeLine WAF: Полное руководство - Часть 2
Продолжение статьи
Часть 1: Введение, ошибки, требования
Часть 2: Установка и конфигурация ← ВЫ ЗДЕСЬ
Часть 3: Backend сервисы, мониторинг
5. Установка и конфигурация
5.1 Подготовка конфигурационных файлов
Структура проекта:
# Создаём директорию для проекта
mkdir -p ~/safeline-deployment
cd ~/safeline-deployment
# Структура:
~/safeline-deployment/
├── docker-compose.yml # Главный compose файл
├── .env # Конфигурация (секреты!)
├── .gitignore # Не коммитим .env!
└── scripts/
├── init.sh # Инициализация
├── backup.sh # Бэкап
└── ssl-renew.sh # SSL renewal
5.2 Создание .env файла
🔒 SECURITY: Этот файл содержит пароли! Защитите его!
# Создаём .env
nano .env
Содержимое .env:
# ==================================================================================
# SafeLine Production Configuration
# ==================================================================================
# Базовая директория
SAFELINE_DIR=/app/safeline
# Префикс подсети
SUBNET_PREFIX=172.20.0
# PostgreSQL пароль (ОБЯЗАТЕЛЬНО СМЕНИТЕ!)
# Генерация: openssl rand -base64 32
POSTGRES_PASSWORD=ИЗМЕНИ_МЕНЯ_НА_СЛОЖНЫЙ_ПАРОЛЬ
# Порт Management UI (internal only)
MGT_PORT=9443
# Docker образы
IMAGE_TAG=latest # Или конкретная версия: 9.2.7
IMAGE_PREFIX=chaitin # Официальный registry
ARCH_SUFFIX= # Пусто для x86_64, "-arm" для ARM64
REGION=-g # -g для international
MGT_PROXY=0 # 0 = SafeLine первый reverse proxy
🔑 Генерация сложного пароля:
# Способ 1: openssl
openssl rand -base64 32
# Способ 2: pwgen (если установлен)
pwgen -sync 32 1
# Способ 3: /dev/urandom
tr -dc 'A-Za-z0-9!@#$%^&*' </dev/urandom | head -c 32; echo
Пример сильного пароля:
POSTGRES_PASSWORD=Kx9#mP2$vL8@nQ4&wR7%tY5^uI3!oE6
🔒 Защита .env файла:
# Только владелец может читать
chmod 600 .env
# Не коммитим в Git
echo ".env" >> .gitignore
5.3 Создание docker-compose.yml
📄 Используйте готовый файл из
/safeline-production-v2/docker-compose.yml
Или создайте вручную:
nano docker-compose.yml
Ключевые моменты (подробности в файле):
version: '3.8'
# СЕТЬ: external (создана заранее!)
networks:
kodalinet:
external: true
services:
# PostgreSQL - база данных
postgres:
container_name: safeline-pg
image: ${IMAGE_PREFIX}/safeline-postgres${ARCH_SUFFIX}:15.2
restart: always
volumes:
- ${SAFELINE_DIR}/resources/postgres/data:/var/lib/postgresql/data
- /etc/localtime:/etc/localtime:ro
environment:
- POSTGRES_USER=safeline-ce
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
networks:
kodalinet:
ipv4_address: ${SUBNET_PREFIX}.2
command: [postgres, -c, max_connections=600]
healthcheck:
test: pg_isready -U safeline-ce -d safeline-ce
deploy:
resources:
limits: {cpus: '2.0', memory: 2G}
reservations: {cpus: '0.5', memory: 512M}
# Management - Web UI
mgt:
container_name: safeline-mgt
image: ${IMAGE_PREFIX}/safeline-mgt${REGION}${ARCH_SUFFIX}:${IMAGE_TAG}
restart: always
volumes:
- /etc/localtime:/etc/localtime:ro
- ${SAFELINE_DIR}/resources/mgt:/app/data
- ${SAFELINE_DIR}/logs/nginx:/app/log/nginx:z
- ${SAFELINE_DIR}/resources/sock:/app/sock
- /var/run:/app/run
# SECURITY: только expose, НЕ ports!
expose:
- "1443"
environment:
- MGT_PG=postgres://safeline-ce:${POSTGRES_PASSWORD}@safeline-pg/safeline-ce?sslmode=disable
- MGT_PROXY=${MGT_PROXY}
depends_on:
postgres:
condition: service_healthy
fvm:
condition: service_started
networks:
kodalinet:
ipv4_address: ${SUBNET_PREFIX}.4
deploy:
resources:
limits: {cpus: '1.0', memory: 1G}
# Detector - AI движок
detect:
container_name: safeline-detector
image: ${IMAGE_PREFIX}/safeline-detector${REGION}${ARCH_SUFFIX}:${IMAGE_TAG}
restart: always
volumes:
- ${SAFELINE_DIR}/resources/detector:/resources/detector
- ${SAFELINE_DIR}/logs/detector:/logs/detector
- /etc/localtime:/etc/localtime:ro
environment:
- LOG_DIR=/logs/detector
networks:
kodalinet:
ipv4_address: ${SUBNET_PREFIX}.5
deploy:
resources:
limits: {cpus: '2.0', memory: 2G}
# Tengine - REVERSE PROXY + WAF (ВХОДНАЯ ТОЧКА!)
tengine:
container_name: safeline-tengine
image: ${IMAGE_PREFIX}/safeline-tengine${REGION}${ARCH_SUFFIX}:${IMAGE_TAG}
restart: always
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/resolv.conf:/etc/resolv.conf:ro
- ${SAFELINE_DIR}/resources/nginx:/etc/nginx
- ${SAFELINE_DIR}/resources/detector:/resources/detector
- ${SAFELINE_DIR}/resources/chaos:/resources/chaos
- ${SAFELINE_DIR}/logs/nginx:/var/log/nginx:z
- ${SAFELINE_DIR}/resources/cache:/usr/local/nginx/cache
- ${SAFELINE_DIR}/resources/sock:/app/sock
# ЕДИНСТВЕННЫЕ открытые порты!
ports:
- "80:80"
- "443:443"
environment:
- TCD_MGT_API=https://${SUBNET_PREFIX}.4:1443/api/open/publish/server
- TCD_SNSERVER=${SUBNET_PREFIX}.5:8000
- SNSERVER_ADDR=${SUBNET_PREFIX}.5:8000
- CHAOS_ADDR=${SUBNET_PREFIX}.10
# КРИТИЧНО для production!
ulimits:
nofile:
soft: 65536
hard: 131072
networks:
kodalinet:
ipv4_address: ${SUBNET_PREFIX}.3
depends_on:
mgt:
condition: service_healthy
detect:
condition: service_started
deploy:
resources:
limits: {cpus: '4.0', memory: 4G}
# Luigi, FVM, Chaos...
# (остальные сервисы - см. полный файл)
5.4 Запуск SafeLine
Шаг 1: Проверка конфигурации
# Проверяем что .env правильный
cat .env | grep POSTGRES_PASSWORD
# НЕ должно быть "ИЗМЕНИ_МЕНЯ"!
# Проверяем compose
docker compose config
Если есть ошибки - исправьте перед продолжением!
Шаг 2: Загрузка образов
# Загружаем все образы
docker compose pull
# Процесс может занять 5-15 минут
# Размер образов: ~2-3 GB
Шаг 3: Запуск
# Запускаем в фоновом режиме
docker compose up -d
# Смотрим логи
docker compose logs -f
Шаг 4: Проверка статуса
# Проверяем статус контейнеров
docker compose ps
Ожидаемый вывод:
NAME STATUS PORTS
safeline-pg Up (healthy)
safeline-mgt Up (healthy)
safeline-detector Up
safeline-tengine Up 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp
safeline-luigi Up
safeline-fvm Up
safeline-chaos Up
✅ Все контейнеры должны быть Up (или Up (healthy))
5.5 Troubleshooting начального запуска
Проблема: "network kodalinet not found"
Причина: Сеть не создана
Решение:
docker network create \
--driver bridge \
--subnet 172.20.0.0/24 \
--gateway 172.20.0.1 \
--opt com.docker.network.bridge.name=kodalinet \
kodalinet
Проблема: "postgres unhealthy"
Причина: PostgreSQL не запустился
Решение:
# Смотрим логи
docker logs safeline-pg
# Часто помогает перезапуск
docker restart safeline-pg
# Проверяем healthcheck
docker inspect safeline-pg | grep -A10 Health
Проблема: "tengine exited with code 1"
Причина: Порты 80/443 заняты
Решение:
# Проверяем порты
sudo netstat -tlnp | grep -E ':80|:443'
# Останавливаем конфликтующий сервис
sudo systemctl stop nginx
sudo systemctl stop apache2
Проблема: "permission denied"
Причина: Неправильные права на директории
Решение:
# Проверяем владельца
ls -la /app/safeline/
# Исправляем
sudo chown -R $USER:$USER /app/safeline
chmod -R 755 /app/safeline
chmod 700 /app/safeline/resources/postgres/data
5.6 Первый вход в Management UI
Вариант A: SSH Tunnel (РЕКОМЕНДУЕТСЯ!)
На своём компьютере:
ssh -L 9443:172.20.0.4:1443 user@your-server
Затем открыть в браузере:
https://localhost:9443
Вариант B: Временно открыть порт
В docker-compose.yml раскомментировать:
mgt:
ports:
- "127.0.0.1:9443:1443" # Только localhost
Перезапустить:
docker compose up -d --force-recreate mgt
Защитить firewall:
sudo ufw allow from YOUR_IP to any port 9443
Первоначальная настройка:
-
Браузер покажет предупреждение о сертификате (нормально, self-signed)
- Chrome: "Advanced" → "Proceed to localhost"
- Firefox: "Advanced" → "Accept Risk"
-
Создание аккаунта:
Email: your-email@company.com ← ВАЛИДНЫЙ! Для Let's Encrypt Password: [сложный пароль] -
Dashboard откроется:
- Overview: статистика (пока пусто)
- Web Services: сайты (пока пусто)
- Protection: правила WAF
- Settings: настройки
6. SSL сертификаты (Let's Encrypt)
🔐 Цель: Настроить автоматическое обновление SSL сертификатов
6.1 Механизм SafeLine SSL
SafeLine v7.2.0+ поддерживает автоматическое обновление SSL:
┌──────────────────────────────────────────────┐
│ SafeLine SSL Auto-Reload Mechanism │
├──────────────────────────────────────────────┤
│ │
│ 1. Certbot обновляет сертификаты: │
│ /etc/letsencrypt/live/domain/ │
│ │
│ 2. Скрипт копирует в SafeLine: │
│ /app/safeline/resources/nginx/certs/ │
│ │
│ 3. SafeLine проверяет файлы каждый час │
│ (автоматически, встроенный механизм) │
│ │
│ 4. При изменении - применяет сертификат │
│ БЕЗ рестарта контейнера! │
│ │
└──────────────────────────────────────────────┘
Источник: SafeLine SSL Auto-update Guide
6.2 Настройка DNS
КРИТИЧНО: Настройте DNS ПЕРЕД получением SSL!
В вашем DNS провайдере:
Type: A
Name: @ (для example.com)
ИЛИ
Name: * (для *.example.com - wildcard)
Value: <IP вашего сервера>
TTL: 300 (5 минут)
Проверка DNS:
# Способ 1: dig
dig quick-fly-space.shop +short
# Должен вернуть ваш IP
# Способ 2: nslookup
nslookup quick-fly-space.shop
# Server: 8.8.8.8
# Address: 8.8.8.8#53
#
# Non-authoritative answer:
# Name: quick-fly-space.shop
# Address: <YOUR_SERVER_IP> ← Это должен быть ваш IP!
# Способ 3: host
host quick-fly-space.shop
⏱️ Подождите 5-10 минут после изменения DNS!
6.3 Вариант A: SSL через SafeLine UI (Простой)
Шаг 1: Разрешить ACME запросы
⚠️ ВАЖНО: Без этого Let's Encrypt не сможет верифицировать домен!
В SafeLine UI:
- Protection → Allow & Deny
- Add Rule
- Настройте:
Rule Name: ACME Challenge Rule Type: Allow Path Prefix: /.well-known/ Priority: High Description: Let's Encrypt verification - Save
Шаг 2: Создать сайт (временно HTTP)
- Web Services → Add Site
- Заполните:
Site Name: quick-fly-space.shop Domain: quick-fly-space.shop Port: 80 SSL: Disabled (пока!) Upstream Servers: - Protocol: HTTP - Address: 127.0.0.1 (или ваш backend) - Port: 8080 - Save
Шаг 3: Проверить HTTP доступность
curl -v http://quick-fly-space.shop/.well-known/acme-challenge/test
# Должен вернуть 404 (это нормально, файла нет)
# НО соединение должно быть успешным!
Шаг 4: Получить SSL сертификат
- Settings → SSL Certificates
- Add Certificate
- Выберите: Let's Encrypt
- Заполните:
Domain: quick-fly-space.shop Email: your-email@company.com ☑ I agree to the Let's Encrypt Terms of Service - Request Certificate
⏱️ Подождите 30-60 секунд...
✅ SUCCESS: Сертификат появится в списке!
Шаг 5: Применить SSL к сайту
- Web Services → Sites → quick-fly-space.shop → Edit
- Измените:
Port: 443 ☑ Enable SSL SSL Certificate: [Выберите Let's Encrypt сертификат] - Save
Шаг 6: Добавить HTTP → HTTPS редирект
- Web Services → Add Site
- Создайте второй site:
Domain: quick-fly-space.shop Port: 80 В разделе Advanced → Custom Configuration: return 301 https://$host$request_uri; - Save
Проверка:
# Должен редиректить на HTTPS
curl -I http://quick-fly-space.shop
# HTTP/1.1 301 Moved Permanently
# Location: https://quick-fly-space.shop/
# HTTPS должен работать
curl -I https://quick-fly-space.shop
# HTTP/2 200
🎉 Готово! SSL работает!
6.4 Вариант B: SSL через Certbot (Advanced)
Для продвинутых пользователей или если UI не работает
Установка Certbot:
sudo apt update
sudo apt install certbot -y
Получение сертификата:
# ВАЖНО: Остановите tengine на время получения!
docker compose stop safeline-tengine
# Запросите сертификат
sudo certbot certonly \
--standalone \
-d quick-fly-space.shop \
--email your@email.com \
--agree-tos \
--non-interactive
# Сертификат сохранён в:
# /etc/letsencrypt/live/quick-fly-space.shop/
# Запустите tengine обратно
docker compose start safeline-tengine
Копирование в SafeLine:
# Копируем сертификат
sudo cp /etc/letsencrypt/live/quick-fly-space.shop/fullchain.pem \
/app/safeline/resources/nginx/certs/cert_1.crt
# Копируем приватный ключ
sudo cp /etc/letsencrypt/live/quick-fly-space.shop/privkey.pem \
/app/safeline/resources/nginx/certs/cert_1.key
# Права доступа
sudo chown 1000:1000 /app/safeline/resources/nginx/certs/cert_1.*
sudo chmod 644 /app/safeline/resources/nginx/certs/cert_1.crt
sudo chmod 600 /app/safeline/resources/nginx/certs/cert_1.key
# SafeLine подхватит изменения в течение часа
# Или рестартните tengine:
docker restart safeline-tengine
6.5 Автоматическое обновление SSL
📄 Используйте готовый скрипт из
/safeline-production-v2/scripts/ssl-renew.sh
Установка скрипта:
# Копируем скрипт
sudo cp scripts/ssl-renew.sh /usr/local/bin/safeline-ssl-renew
# Делаем исполняемым
sudo chmod +x /usr/local/bin/safeline-ssl-renew
# Редактируем переменные
sudo nano /usr/local/bin/safeline-ssl-renew
Важные переменные:
DOMAIN="quick-fly-space.shop" # Ваш домен
SAFELINE_DIR="/app/safeline" # Путь к SafeLine
NOTIFY_EMAIL="" # Email для уведомлений (опционально)
Тестирование скрипта:
# Запускаем вручную
sudo /usr/local/bin/safeline-ssl-renew
# Проверяем логи
tail -f /var/log/safeline-ssl-renew.log
Настройка Cron:
# Открываем crontab
sudo crontab -e
# Добавляем строку (каждый день в 3:00):
0 3 * * * /usr/local/bin/safeline-ssl-renew >> /var/log/safeline-ssl-renew.log 2>&1
Проверка Cron:
# Просмотр установленных задач
sudo crontab -l
# Проверка что cron работает
sudo systemctl status cron
6.6 Мониторинг срока действия SSL
Проверка вручную:
# Проверка срока действия
echo | openssl s_client -connect quick-fly-space.shop:443 -servername quick-fly-space.shop 2>/dev/null | \
openssl x509 -noout -dates
# Вывод:
# notBefore=Jan 27 00:00:00 2026 GMT
# notAfter=Apr 27 23:59:59 2026 GMT
Скрипт проверки:
#!/bin/bash
# check-ssl-expiry.sh
DOMAIN="quick-fly-space.shop"
# Получаем дату истечения
EXPIRY=$(echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
# Конвертируем в секунды
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
# Считаем дни
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))
echo "Сертификат истекает: $EXPIRY"
echo "Осталось дней: $DAYS_LEFT"
if [ $DAYS_LEFT -lt 30 ]; then
echo "⚠️ WARNING: Менее 30 дней до истечения!"
elif [ $DAYS_LEFT -lt 7 ]; then
echo "🚨 CRITICAL: Менее 7 дней до истечения!"
else
echo "✅ OK: Сертификат валидный"
fi
[Часть 2 продолжается в следующем файле...]
Навигация
📖 Часть 1: Введение, ошибки, требования
📖 Часть 2: Установка и конфигурация ← ВЫ ЗДЕСЬ
📖 Часть 3: Backend, мониторинг, troubleshooting
Следующий файл:
BOOKSTACK_ARTICLE_PART3.md

No comments to display
No comments to display