💜 Поддержать разработку
TRC-20 USDT · @killu_zl
TFEu63dmxdHyXZ4CnASydr7cvmLtkdQqQq
TRC-20
VPN INFRA · MONITORING

Централизованный сбор логов
с VPN-нод в S3 + Telegram

Ежедневная автоматическая загрузка xray-логов со всех нод в S3-хранилище, парсинг ошибок и красивый отчёт в Telegram. Полная инструкция.

Время ~30 минут
Нод от 1 до 100+
OS Debian 12+ / Ubuntu 22+
КАК ЭТО РАБОТАЕТ

Архитектура

Каждая нода ежедневно загружает свежие access.log и error.log от remnanode в S3-bucket. Раз в день collector проходит по bucket'у, формирует отчёт и шлёт в Telegram. Все логи остаются в S3 для расследований.

N VPN нод remnanode 📦 access.log.1.gz 📦 error.log.1.gz log-upload.sh systemd timer 01:00 UTC ↓ mc cp ☁ S3 bucket Timeweb / Selectel / etc. 2026/MM/DD/{node}__{ip}/ Collector 1 ядро · 1 ГБ log-report.py обходит bucket парсит ошибки сравнивает с inventory ↓ Telegram bot 06:00 UTC caption + .gz файл
ПОДГОТОВКА

Что нужно

Без баз данных и Docker. Полностью на стандартных инструментах Linux.

Ротация логов делается через стандартный logrotate — установщик заменяет дефолтный конфиг remnanode (size 50M, rotate 3) на daily-схему. Uploader забирает access.log.1 утром, gzip'ит и шлёт в S3.
ШАГ 1 · ХРАНИЛИЩЕ

S3 bucket в Timeweb

Можно использовать любого S3-совместимого провайдера. Я покажу на Timeweb.

1.1

Создать бакет

Зайти в Timeweb Cloud → Хранилище S3Создать бакет:

  • Регион: Санкт-Петербург
  • Класс хранения: Холодный — логи пишутся раз в сутки и читаются раз в сутки коллектором, поэтому холодный класс выходит дешевле стандартного по итоговому счёту.
  • Тип: Приватный
  • Имя бакета: своё (например vpn-logs)

После создания у бакета сразу есть встроенные S3-ключи (Access Key + Secret Key) — найти их в свойствах созданного бакета.

Холодный класс, приватный тип
Класс хранения «Холодный» + тип «Приватный»
ЧТО ЗАПИСАТЬ
S3 endpoint:  https://s3.twcstorage.ru
S3 bucket:    YOUR_BUCKET_NAME
Access Key:   YOUR_ACCESS_KEY
Secret Key:   YOUR_SECRET_KEY
ШАГ 2 · TELEGRAM

Telegram-бот

Нужны две вещи: токен бота и твой Telegram ID куда слать отчёты.

2.1

Создать бота

Через @BotFather создай бота — получишь токен.

2.2

Запустить бота

Найди своего бота по username в Telegram → отправь ему /start. Без этого бот не сможет тебе писать.

ЧТО ЗАПИСАТЬ
Bot token:    YOUR_BOT_TOKEN
Chat ID:      YOUR_CHAT_ID
ШАГ 3 · COLLECTOR СЕРВЕР

Установка collector

Любой VPS с Debian 12+ / Ubuntu 22+. Желательно не в РФ (чтобы избежать блокировок Telegram API). Финский / эстонский — идеально.

3.1

Подключиться и запустить установщик

SSH под root на collector-сервер и одной командой:

root@collectorcopy
curl -fsSL https://logs.killu.net/install-collector.sh | bash

Скрипт спросит твои значения и сам всё настроит:

  • S3 endpoint, bucket, access/secret keys
  • Telegram bot token + chat_id
  • Установит fail2ban, UFW, Python с зависимостями, MinIO client
  • Создаст systemd timer на ежедневный отчёт в 06:00 UTC
  • Сделает тестовое сообщение в Telegram (проверит что всё работает)
3.2

Настроить inventory (список нод)

Файл /etc/log-collector/inventory.yaml — это список ожидаемых нод. По нему collector понимает «кто из 36 нод загрузил логи за сегодня, кого нет».

Руками лезть не нужно — для добавления новых нод используй add-node.sh (Шаг 5). Он сам добавит запись в правильном формате.

Если всё-таки хочется глянуть/поправить — открой файл редактором:

root@collectorcopy
nano /etc/log-collector/inventory.yaml

Формат внутри:

inventory.yaml
nodes:
  - { country: DE, name: de-1, ip: NODE_IP_1 }
  - { country: NL, name: nl-1, ip: NODE_IP_2 }
  - { country: US, name: us-1, ip: NODE_IP_3 }

Три поля, всё что нужно:

ПолеЧто писать · откуда брать
country Двухбуквенный код страны: DE, NL, US, RU, FR... Используется только для группировки в Telegram-отчёте. Не знаешь — ставь ??.
name Короткое уникальное имя — de-1, nl-2, us-spb. Должно совпадать с тем именем, которое ты введёшь при установке uploader'а на самой ноде (от него зависит путь в S3).
ip Публичный IP ноды — тот же что в панели Remnawave или у хостера. По нему collector проверяет «загрузилась ли эта нода».

Опционально: можно добавить поле role со значением routing или vpn-wl если у тебя есть роутинговые/whitelist-ноды. По умолчанию все ноды считаются обычными VPN — это работает для большинства случаев.

ПРОВЕРКА
systemctl status log-report.timer
journalctl -u log-report -n 50

→ в Telegram придёт тестовый отчёт
ШАГ 4 · УСТАНОВКА НА НОДЫ

Uploader на каждую VPN-ноду

Запускается на каждой ноде где стоит remnanode. После установки нода каждый день в 01:00 UTC отправляет вчерашние логи в твой S3.

Прежде чем ставить uploader — убедись что xray-логи видны на хосте по пути /var/log/remnanode/. По умолчанию remnanode пишет их внутрь docker-контейнера, и uploader их там не достанет.

Если стоит Tblocker — он уже всё смонтировал, можешь сразу к 4.1. Проверь: ls /var/log/remnanode/ — должны быть access.log / error.log.

Если Tblocker'а нет — нужно один раз настроить ноду (см. 4.0 ниже).
4.0

Открыть логи xray на хост (один раз, если нет Tblocker)

Открой docker-compose.yml твоего remnanode (обычно /opt/remnanode/docker-compose.yml) и добавь volume:

/opt/remnanode/docker-compose.yml
services:
  remnanode:
    image: remnawave/node:latest
    ...
    volumes:
      - /var/log/remnanode:/var/log/remnanode   ← добавь эту строку

Дальше в Remnawave-панели в конфиге xray для этой ноды убедись что пути логов правильные:

config xray ноды (в панели Remnawave)
"log": {
    "access": "/var/log/remnanode/access.log",
    "error":  "/var/log/remnanode/error.log",
    "loglevel": "warning"
}

Применить — пересоздать контейнер:

root@vpn-nodecopy
cd /opt/remnanode
docker compose up -d

После любой активности на ноде в /var/log/remnanode/ появятся файлы. Можно идти к 4.1.

4.1

Один раз — заполни ключи в самом скрипте

Скачай install-uploader.sh к себе, открой и впиши свои S3-параметры в самом верху файла. Потом просто заливай его на каждую новую ноду — интерактивно будет спрашивать только имя.

install-uploader.sh (начало файла)
S3_BUCKET="YOUR_BUCKET_ID"
S3_ENDPOINT="https://s3.twcstorage.ru"
S3_ACCESS_KEY="YOUR_ACCESS_KEY"
S3_SECRET_KEY="YOUR_SECRET_KEY"

NODE_NAME=""
UPLOAD_TIME="01:00"

Дальше — заливаешь на ноду как обычно (scp + ssh) и запускаешь. Скрипт спросит имя ноды (например de-1, nl-2) — это уникальное короткое имя. В S3 финальный путь собирается автоматически как {имя}__{ip-ноды}/, IP подтягивается через api.ipify.org. Имя должно совпадать с тем что ты добавил в inventory.yaml на collector'е.

Если хочешь передать имя сразу без интерактива — добавь флаг --node-name=de-5 к команде запуска.

4.2

Что делает скрипт

  • Устанавливает gzip, curl, mc (MinIO client)
  • Создаёт /etc/log-upload/secrets.env с твоими S3-ключами (chmod 600)
  • Кладёт /usr/local/sbin/log-upload.sh
  • Заменяет /etc/logrotate.d/remnanode на daily-ротацию (старый бэкапится в .bak_*). Дефолтный конфиг от remnanode (size 50M, rotate 3) на нагруженных нодах перетирает вчерашние логи до того как uploader успеет их забрать.
  • Создаёт systemd timer на ежедневный запуск в 01:00 UTC (с random delay 10 мин)

Скрипт не трогает:

  • xray / remnanode — не перезапускается
  • docker-compose.yml — не модифицирует (volume mount должен быть сделан заранее, см. 4.0)
  • файлы /var/log/remnanode/*.log — не удаляет, не редактирует, только читает
что прописывается в /etc/logrotate.d/remnanode
/var/log/remnanode/*.log {
    daily
    rotate 7
    compress
    delaycompress
    copytruncate
    missingok
    notifempty
    su root root
}
ШАГ 5 · ДОБАВЛЕНИЕ НОВЫХ НОД

Купил новую ноду — что делать

Два шага: добавить ноду в inventory на collector'е, потом поставить uploader на саму ноду.

5.1

На collector-сервере — добавить в inventory

root@collectorcopy
curl -fsSL https://logs.killu.net/add-node.sh | bash -s -- \
    --name=de-5 \
    --ip=NODE_IP

Скрипт проверит что ноды ещё нет, добавит запись в /etc/log-collector/inventory.yaml. В конце выведет готовую команду для следующего шага.

5.2

На самой ноде — поставить uploader

Зайди на ноду по обычному SSH и запусти install-uploader.sh (как в Шаге 4). Команду со всеми правильными ключами тебе подсказал add-node.sh в предыдущем шаге.

ШАГ 6 · ПРОВЕРКА

Проверить что всё работает

5.1

На ноде

root@vpn-nodecopy
# статус таймера
systemctl status log-upload.timer

# ручной тестовый запуск
/usr/local/sbin/log-upload.sh

# лог скрипта
tail -30 /var/log/log-upload.log

В /var/log/log-upload.log должны быть строки:

[2026-05-21T01:00:12Z] ═══ START upload for de-1@NODE_IP ═══
[2026-05-21T01:00:13Z]   picked /var/log/remnanode/access.log.1.gz (already gz)
[2026-05-21T01:00:14Z]   uploaded → 2026/05/20/de-1__NODE_IP/xray-access.log.gz
[2026-05-21T01:00:15Z]   uploaded → 2026/05/20/de-1__NODE_IP/_meta.json
[2026-05-21T01:00:15Z] ═══ DONE ok=5 fail=0 ═══
5.2

На collector'е

root@collectorcopy
# посмотреть S3
mc ls -r tw/YOUR_BUCKET/

# ручной отчёт (придёт в Telegram)
/usr/local/bin/log-report.py
5.3

Через web-консоль Timeweb

Открой бакет в web-UI Timeweb. Должна быть структура:

bucket structure
2026/
└── 05/
    └── 20/
        ├── de-1__NODE_IP/
        │   ├── xray-access.log.gz
        │   ├── xray-error.log.gz
        │   ├── fail2ban.log.gz
        │   └── _meta.json
        ├── de-2__NODE_IP/
        │   └── ...
Структура бакета
Web-консоль Timeweb — содержимое бакета
5.4

Отчёт в Telegram

На следующее утро (06:00 UTC = 09:00 МСК) придёт отчёт автоматически:

Telegram отчёт
Ежедневный отчёт в Telegram

Состоит из двух сообщений:

  1. Текстовая сводка — сколько нод загрузило и топ ошибок
  2. Файл report-YYYY-MM-DD.txt.gz — детальная разбивка
РАСПИСАНИЕ

Когда что работает

Время UTCМСКЧто происходит
00:0003:00cron.daily запускает logrotate: access.log → access.log.1 (несжатый из-за delaycompress)
01:0004:00На каждой ноде запускается uploader (с random delay до 10 мин)
~01:0504:05Все ноды обычно закончили загрузку
06:0009:00Collector формирует отчёт и шлёт в Telegram
Между загрузкой нод и отчётом — 5 часов запаса. Даже самые нагруженные ноды (3 ГБ access.log) успевают за 1-2 мин.
ФАЙЛЫ И ПУТИ

Что где лежит

На каждой VPN-ноде

ПутьЧто
/usr/local/sbin/log-upload.shосновной скрипт загрузки
/etc/log-upload/secrets.envS3 credentials (chmod 600)
/etc/systemd/system/log-upload.timerрасписание (01:00 UTC)
/var/log/log-upload.logлог работы скрипта

На collector-сервере

ПутьЧто
/usr/local/bin/log-report.pyскрипт отчёта
/etc/log-collector/inventory.yamlсписок нод
/etc/log-collector/secrets.envS3 + Telegram креды
/etc/systemd/system/log-report.timerрасписание (06:00 UTC)
/var/log/log-collector/сохранённые отчёты
СКАЧАТЬ СКРИПТЫ

Все файлы по порядку

Что качать, когда и куда. Каждый файл с описанием назначения.

Файл Где запускать Что делает
1 install-collector.sh один раз на
collector-сервере
Ставит на пустой VPS всё необходимое: Python, mc, fail2ban, UFW. Создаёт systemd-timer на ежедневный отчёт. Шлёт тестовое сообщение в Telegram.
2 install-uploader.sh на каждой
VPN-ноде
Ставит zstd, mc. Создаёт systemd-timer (01:00 UTC ежедневно), который загружает access.log.1.gz от remnanode в S3.
3 add-node.sh на collector'е
(когда купил новую ноду)
Добавляет ноду в inventory.yaml. После этого зайди на саму ноду по SSH и поставь там uploader (файл #2).
log-upload.sh автоматически
лежит на ноде
Рабочий скрипт ежедневной загрузки. Ставится автоматом через install-uploader.sh. Скачивать вручную не нужно.
log-report.py автоматически
на collector'е
Рабочий скрипт отчёта. Ставится через install-collector.sh. Скачивать вручную не нужно.
Минимум что качаешь руками: только #1 (один раз) и #2 (на каждую ноду). #3 пригодится когда купишь следующую ноду.