Document all four ways to deploy: manual/CI x config-only/full-recreate

- New "Ways to run this" comparison table up top
- Step 9 split into 9a (in-container runner) / 9b (host-level runner,
  with the RUNNER_USER=claude-deploy warning and single-line paste-safe
  command) / 9c (secrets) / removal instructions
- CI/CD section split into deploy.yml and deploy-from-scratch.yml
  subsections, each explaining its own runner/scope, plus what's common
  to both
- File layout updated with every script and workflow file added this
  session (bootstrap-host.sh, cleanup-host.sh, fix-lxc-apparmor.sh,
  setup-forgejo-runner.sh, alerts/, dashboards/, .forgejo/workflows/)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
byrsapty 2026-07-22 23:40:59 +03:00
parent 5316136eb6
commit 7274cee1eb
2 changed files with 258 additions and 86 deletions

171
README.md
View file

@ -26,6 +26,24 @@ the pipeline rules, and prints the admin credentials at the end.
Both scripts are idempotent — re-running after a failure (or to apply an
update) picks up from where it left off instead of duplicating work.
## Ways to run this
Four ways to apply this project, from "type one command" to "click a
button in a browser" - pick whichever fits what changed and how much
setup you're willing to do first.
| Way | Run from | What it does | One-time setup | When to use |
|---|---|---|---|---|
| **Manual, full** | terminal on the Proxmox host | `create-graylog-lxc.sh` → creates/repairs the LXC container, installs everything | none | first-ever deploy, or when you'd rather watch it happen |
| **Manual, config-only** | terminal, `pct exec` into the container | re-run `install-graylog.sh` directly | none | quick config-only fix without touching git |
| **CI, config-only** | Forgejo web UI | workflow `deploy.yml` → re-runs `install-graylog.sh` from the latest git commit | `setup-forgejo-runner.sh` *inside the container* (see step 9) | pushed a new rule/alert/dashboard, container already exists |
| **CI, full** | Forgejo web UI | workflow `deploy-from-scratch.yml` → runs `create-graylog-lxc.sh` from the latest git commit | `setup-forgejo-runner.sh` *on the Proxmox host* (see step 9) | one-click recreate after a manual `pct destroy`, no terminal needed |
All four end up running the exact same idempotent scripts - there's no
"CI-only" behavior to diverge from what you'd type by hand. Neither CI
workflow runs `pct destroy` - that's always a deliberate, manual step (see
"CI/CD via Forgejo Actions" below for why).
## Step-by-step deployment from scratch
### 0. Prerequisites
@ -187,27 +205,55 @@ Discord within about a minute.
### 9. (Optional) Set up Forgejo Actions CI
If you push this project to a Forgejo instance, `setup-forgejo-runner.sh`
registers a self-hosted Actions runner inside the container itself, so
`.forgejo/workflows/deploy.yml` can re-run `install-graylog.sh` on demand
straight from git instead of scp'ing files by hand. See "CI/CD via Forgejo
Actions" further down for what the workflow does and how to trigger it;
this step is just the one-time runner setup.
`setup-forgejo-runner.sh` registers a self-hosted Actions runner - it can
run in two different places, one script for both, just different
parameters. See "CI/CD via Forgejo Actions" further down for what each
workflow does; this step is just the one-time runner setup. Both are
optional and independent - set up either, neither, or both.
1. In the Forgejo web UI: repo → Settings → Actions → Runners → "Create
new Runner" to get a registration token (one-time value, not something
to guess or reuse from another repo).
2. Run the setup script inside the container:
```bash
pct exec <VMID> -- env \
FORGEJO_URL="https://your-forgejo-instance" \
FORGEJO_RUNNER_TOKEN="<token from step 1>" \
bash /opt/graylog-deploy/setup-forgejo-runner.sh
```
3. Add the two secrets the workflow needs (repo → Settings → Actions →
Secrets): `GRAYLOG_ADMIN_PASSWORD` and `DISCORD_WEBHOOK_URL`. A third
value, `secrets.GITHUB_TOKEN`, doesn't need creating - Forgejo issues it
automatically per job, scoped to just this repo.
**Shared first step:** repo → Settings → Actions → Runners → "Create new
Runner" to get a registration token (one-time value, not something to
guess or reuse from another repo - get a fresh one for each runner you
register).
**9a. Runner inside the container** (for `deploy.yml` - config-only
redeploys):
```bash
pct exec <VMID> -- env \
FORGEJO_URL="https://your-forgejo-instance" \
FORGEJO_RUNNER_TOKEN="<token>" \
bash /opt/graylog-deploy/setup-forgejo-runner.sh
```
**9b. Runner on the Proxmox host itself** (for `deploy-from-scratch.yml` -
full recreate). `git` must be installed on the host first (`apt-get
install -y git` - the container has it, the bare host usually doesn't).
`RUNNER_USER=claude-deploy` is required here, not optional: without it the
systemd service runs as root, handing every CI job unrestricted root on
the host instead of claude-deploy's narrowly-scoped sudo:
```bash
sudo env FORGEJO_URL="https://your-forgejo-instance" FORGEJO_RUNNER_TOKEN="<token>" RUNNER_NAME="proxmox-host-runner" RUNNER_LABEL="proxmox-host:host" RUNNER_DIR="/opt/forgejo-runner-host" SERVICE_NAME="forgejo-runner-host" RUNNER_USER="claude-deploy" bash /home/claude-deploy/graylog-deploy/setup-forgejo-runner.sh
```
(One line, no `\` continuations - multi-line pastes with backslashes have
been observed dropping the continuation in some terminals, silently
running `sudo env` with no arguments and none of the variables set.)
**9c. Secrets** the workflows need (repo → Settings → Actions → Secrets):
`GRAYLOG_ADMIN_PASSWORD` and `DISCORD_WEBHOOK_URL`. A third value,
`secrets.GITHUB_TOKEN`, doesn't need creating - Forgejo issues it
automatically per job, scoped to just this repo.
**Removing a runner later** (e.g. the host-level one, if you'd rather not
leave it registered when not actively deploying):
```bash
sudo systemctl disable --now forgejo-runner-host
sudo rm -f /etc/systemd/system/forgejo-runner-host.service
sudo systemctl daemon-reload
sudo rm -rf /opt/forgejo-runner-host
```
then delete it from repo → Settings → Actions → Runners in the UI too.
Re-registering later needs a fresh token from that same page - the old
one won't be reused automatically.
## Parameters
@ -538,29 +584,59 @@ channel.
## CI/CD via Forgejo Actions
This project's Forgejo repo (`git.zotac.keenetic.link/zotac/graylog-deploy`)
has a manually-triggered deploy workflow: `.forgejo/workflows/deploy.yml`.
Running it clones the repo fresh and re-runs `install-graylog.sh` - the
same idempotent script described throughout this README, just automated
instead of scp'd by hand. One-time setup is `setup-forgejo-runner.sh`
(see step 9 above); this section covers what the workflow does and how to
run it day to day.
has two manually-triggered workflows, each with its own runner (see step 9
above for setup). Both just automate scripts already described elsewhere
in this README - there's nothing CI-specific about their actual behavior.
### `deploy.yml` — config-only redeploy
Clones the repo fresh and re-runs `install-graylog.sh` inside the
container. Use this after pushing a new rule/alert/dashboard/pipeline
change to an already-existing container.
**Running it:** repo → **Actions** tab → **Deploy Graylog config** in the
left sidebar → **Run workflow** button → confirm. Progress and per-step
logs show up immediately under the run list.
left sidebar → **Run workflow** button → confirm.
- **Trigger is manual on purpose** (`workflow_dispatch` only, no
`on: push`) - this repo drives a production monitoring system, so a
human reviews the diff and clicks "Run workflow" rather than every push
silently redeploying.
- **The runner lives inside the Graylog container itself** (VMID 200,
`self-hosted:host` label, installed at `/usr/local/bin/forgejo-runner`,
running as a systemd service). No new SSH keys or cross-host access were
needed - the workflow just clones the repo into `/tmp/graylog-deploy-ci`
and runs the script locally, exactly like a human operator would.
- **No `actions/checkout`** - that action needs Node.js, which this
appliance container doesn't have and shouldn't need just for CI. The
workflow does a plain `git clone --depth 1` instead.
### `deploy-from-scratch.yml` — full recreate
Clones the repo fresh and re-runs `create-graylog-lxc.sh` **on the Proxmox
host**. Use this after a manual `pct destroy` (or on a container that was
never created), when you'd rather click a button than type the full
`create-graylog-lxc.sh` invocation.
**Running it:** repo → **Actions** tab → **Deploy Graylog from scratch
(host-level)** in the left sidebar → **Run workflow** button → confirm.
- **The runner lives on the Proxmox host itself**, running as
`claude-deploy` (not root - see step 9b above for why that matters),
registered with a distinct label (`proxmox-host:host`) so it only picks
up jobs meant for this workflow, not `deploy.yml`'s.
- **`pct destroy` is deliberately NOT part of this workflow.** Recreating
infrastructure automatically is fine because `create-graylog-lxc.sh` is
idempotent (repairs in place if the container already exists, creates
fresh if it doesn't); destroying it is irreversible data loss and stays
a human typing the command on purpose. A CI button that can destroy
production with one accidental click was considered and rejected.
`pct destroy` isn't even in `claude-deploy`'s sudo scope, on purpose.
- **`git` must be installed on the bare host** - unlike the container
(which has it from the Debian 12 template), a fresh Proxmox host
usually doesn't (`apt-get install -y git`, one-time, root).
### Common to both workflows
- **Trigger is manual on purpose** (`workflow_dispatch` only, no
`on: push`) - these drive a production monitoring system, so a human
reviews the diff and clicks "Run workflow" rather than every push
silently redeploying.
- **No `actions/checkout`** - that action needs Node.js, which neither
runner has and shouldn't need just for CI. Both workflows do a plain
`git clone --depth 1` instead.
- **The clone is authenticated with `secrets.GITHUB_TOKEN`** - a
short-lived token Forgejo creates automatically at the start of each
workflow run and destroys when it finishes, scoped to only this repo
@ -572,7 +648,7 @@ logs show up immediately under the run list.
- **Secrets** (`GRAYLOG_ADMIN_PASSWORD`, `DISCORD_WEBHOOK_URL`) are stored
as repo-level Forgejo Actions secrets, not in any tracked file.
`GRAYLOG_EXTERNAL_URI` isn't secret (it's the public Web UI address) so
it's inlined directly in the workflow.
it's inlined directly in both workflows.
## What's still NOT included
@ -594,13 +670,22 @@ ones were built.
## File layout
```
create-graylog-lxc.sh # run on the Proxmox host
install-graylog.sh # run inside the container (invoked automatically)
docker-compose.yml # MongoDB + OpenSearch + Graylog stack definition
nftables.conf # firewall ruleset applied inside the container
rules/*.json # Graylog Pipeline Rule definitions (imported via API)
pipelines/*.json # Graylog Pipeline definitions referencing the rules
streams/*.json # Graylog Stream definitions (routes by input port)
create-graylog-lxc.sh # run on the Proxmox host - creates/repairs the LXC container
install-graylog.sh # run inside the container (invoked automatically)
bootstrap-host.sh # one-time, root, Proxmox host - automates the AppArmor fix
cleanup-host.sh # reverses bootstrap-host.sh
fix-lxc-apparmor.sh # installed by bootstrap-host.sh, not run directly
setup-forgejo-runner.sh # registers a CI runner - in the container or on the host
docker-compose.yml # MongoDB + OpenSearch + Graylog stack definition
nftables.conf # firewall ruleset applied inside the container
rules/*.json # Graylog Pipeline Rule definitions (imported via API)
pipelines/*.json # Graylog Pipeline definitions referencing the rules
streams/*.json # Graylog Stream definitions (routes by input port)
alerts/*.json # Event Definitions + the Discord notification template
dashboards/search_*.json # Views API search objects, one pair per dashboard
dashboards/view_*.json # Views API dashboard/widget layout, paired with search_*.json
.forgejo/workflows/deploy.yml # CI: config-only redeploy (in-container runner)
.forgejo/workflows/deploy-from-scratch.yml # CI: full recreate (host-level runner)
```
Inside the container, everything lives under `/opt/graylog/`

View file

@ -27,6 +27,24 @@
Обидва скрипти ідемпотентні — повторний запуск після збою (або для
оновлення) продовжує з того місця, де зупинився, а не дублює роботу.
## Варіанти запуску
Чотири способи застосувати цей проєкт — від "ввести одну команду" до
"натиснути кнопку в браузері". Обирайте залежно від того, що змінилося і
скільки налаштування готові зробити наперед.
| Спосіб | Звідки запускається | Що робить | Одноразове налаштування | Коли використовувати |
|---|---|---|---|---|
| **Вручну, повний** | термінал на хості Proxmox | `create-graylog-lxc.sh` → створює/ремонтує LXC-контейнер, встановлює все | немає | перший деплой, або коли хочете бачити процес наживо |
| **Вручну, тільки конфіг** | термінал, `pct exec` у контейнер | повторний запуск `install-graylog.sh` напряму | немає | швидкий фікс конфігурації без git |
| **CI, тільки конфіг** | веб-інтерфейс Forgejo | workflow `deploy.yml` → перезапускає `install-graylog.sh` з останнього коміту | `setup-forgejo-runner.sh` **всередині контейнера** (див. крок 9) | запушили нове правило/алерт/дашборд, контейнер уже існує |
| **CI, повний** | веб-інтерфейс Forgejo | workflow `deploy-from-scratch.yml` → запускає `create-graylog-lxc.sh` з останнього коміту | `setup-forgejo-runner.sh` **на хості Proxmox** (див. крок 9) | одна кнопка для пересоздання після ручного `pct destroy`, без терміналу |
Усі чотири варіанти виконують ті самі ідемпотентні скрипти — жодної
"CI-only" поведінки, яка б відрізнялась від того, що ввели б вручну.
Жоден з CI-workflow не виконує `pct destroy` — це завжди свідомий ручний
крок (дивіться "CI/CD через Forgejo Actions" нижче, чому саме так).
## Покрокове розгортання з нуля
### 0. Передумови
@ -191,27 +209,56 @@ Graylog під кожен пристрій не потрібно — inputs і
### 9. (Опційно) Налаштувати Forgejo Actions CI
Якщо ви пушите цей проєкт на інстанс Forgejo, `setup-forgejo-runner.sh`
реєструє self-hosted Actions runner прямо всередині контейнера, тож
`.forgejo/workflows/deploy.yml` може повторно запускати `install-graylog.sh`
на вимогу прямо з git, замість ручного scp файлів. Див. "CI/CD через
Forgejo Actions" нижче — що саме робить workflow і як його запускати; цей
крок — лише одноразове налаштування runner'а.
`setup-forgejo-runner.sh` реєструє self-hosted Actions runner — він може
працювати у двох різних місцях, один скрипт для обох, просто різні
параметри. Див. "CI/CD через Forgejo Actions" нижче, що саме робить кожен
workflow; цей крок — лише одноразове налаштування раннера. Обидва
опційні й незалежні — налаштуйте один, жодного чи обидва.
1. У веб-інтерфейсі Forgejo: репо → Settings → Actions → Runners →
"Create new Runner", щоб отримати токен реєстрації (одноразове
значення, не вгадуйте й не перевикористовуйте з іншого репо).
2. Запустіть скрипт налаштування всередині контейнера:
```bash
pct exec <VMID> -- env \
FORGEJO_URL="https://ваш-forgejo-інстанс" \
FORGEJO_RUNNER_TOKEN="<токен з кроку 1>" \
bash /opt/graylog-deploy/setup-forgejo-runner.sh
```
3. Додайте два секрети, які потребує workflow (репо → Settings → Actions →
Secrets): `GRAYLOG_ADMIN_PASSWORD` та `DISCORD_WEBHOOK_URL`. Третє
значення, `secrets.GITHUB_TOKEN`, створювати не треба — Forgejo видає
його автоматично на кожен job, прив'язаним лише до цього репо.
**Спільний перший крок:** у веб-інтерфейсі Forgejo: репо → Settings →
Actions → Runners → "Create new Runner", щоб отримати токен реєстрації
(одноразове значення, не вгадуйте й не перевикористовуйте з іншого репо
— беріть новий токен для кожного раннера, який реєструєте).
**9a. Раннер усередині контейнера** (для `deploy.yml` — редеплой тільки
конфігурації):
```bash
pct exec <VMID> -- env \
FORGEJO_URL="https://ваш-forgejo-інстанс" \
FORGEJO_RUNNER_TOKEN="<токен>" \
bash /opt/graylog-deploy/setup-forgejo-runner.sh
```
**9b. Раннер на самому хості Proxmox** (для `deploy-from-scratch.yml`
повне пересоздання). Спочатку на хості має бути встановлений `git`
(`apt-get install -y git`у контейнері він уже є, на голому хості
зазвичай нема). `RUNNER_USER=claude-deploy` тут обов'язковий, не
опційний: без нього systemd-сервіс працює від root, видаючи кожному
CI-job необмежений root на хості замість вузько-скоупленого sudo
`claude-deploy`:
```bash
sudo env FORGEJO_URL="https://ваш-forgejo-інстанс" FORGEJO_RUNNER_TOKEN="<токен>" RUNNER_NAME="proxmox-host-runner" RUNNER_LABEL="proxmox-host:host" RUNNER_DIR="/opt/forgejo-runner-host" SERVICE_NAME="forgejo-runner-host" RUNNER_USER="claude-deploy" bash /home/claude-deploy/graylog-deploy/setup-forgejo-runner.sh
```
(Одним рядком, без `\`у деяких терміналах багаторядкова вставка з
переносами губила продовження, і `sudo env` виконувався зовсім без
аргументів і без жодної встановленої змінної.)
**9c. Секрети**, які потребують workflow (репо → Settings → Actions →
Secrets): `GRAYLOG_ADMIN_PASSWORD` та `DISCORD_WEBHOOK_URL`. Третє
значення, `secrets.GITHUB_TOKEN`, створювати не треба — Forgejo видає
його автоматично на кожен job, прив'язаним лише до цього репо.
**Видалення раннера пізніше** (наприклад, host-level, якщо не хочете
тримати його зареєстрованим, коли активно не деплоїте):
```bash
sudo systemctl disable --now forgejo-runner-host
sudo rm -f /etc/systemd/system/forgejo-runner-host.service
sudo systemctl daemon-reload
sudo rm -rf /opt/forgejo-runner-host
```
а потім видаліть його й у UI: репо → Settings → Actions → Runners.
Повторна реєстрація пізніше потребує нового токена з тієї ж сторінки —
старий автоматично не перевикористається.
## Параметри
@ -556,29 +603,60 @@ Discord-канал.
## CI/CD через Forgejo Actions
Forgejo-репозиторій проєкту (`git.zotac.keenetic.link/zotac/graylog-deploy`)
має вручну-запускний деплой-workflow: `.forgejo/workflows/deploy.yml`.
Його запуск клонує репо наново й повторно запускає `install-graylog.sh`
той самий ідемпотентний скрипт, описаний по всьому цьому README, просто
автоматизований замість ручного scp. Одноразове налаштування —
`setup-forgejo-runner.sh` (див. крок 9 вище); цей розділ описує, що робить
workflow і як його запускати щодня.
має два вручну-запускні workflow, кожен зі своїм раннером (див. крок 9
вище про налаштування). Обидва просто автоматизують скрипти, вже описані
в іншому місці цього README — жодної CI-специфічної поведінки немає.
### `deploy.yml` — редеплой тільки конфігурації
Клонує репо наново й повторно запускає `install-graylog.sh` усередині
контейнера. Використовуйте після пушу нового правила/алерту/дашборду/
pipeline на вже існуючий контейнер.
**Як запускати:** репо → вкладка **Actions****Deploy Graylog config** у
лівому меню → кнопка **Run workflow** → підтвердити. Прогрес і логи
кожного кроку з'являються одразу під списком запусків.
лівому меню → кнопка **Run workflow** → підтвердити.
- **Тригер навмисно ручний** (тільки `workflow_dispatch`, без
`on: push`) — це репо керує продакшн-системою моніторингу, тож людина
переглядає диф і сама натискає "Run workflow", а не кожен push тихо
передеплоює систему.
- **Раннер живе прямо всередині контейнера Graylog** (VMID 200, лейбл
`self-hosted:host`, встановлений у `/usr/local/bin/forgejo-runner`,
працює як systemd-сервіс). Нових SSH-ключів чи міжхостового доступу не
знадобилося — workflow просто клонує репо в `/tmp/graylog-deploy-ci` і
запускає скрипт локально, точно як це робив би оператор вручну.
- **Без `actions/checkout`** — ця дія вимагає Node.js, якого немає (і не
повинно бути) на цьому appliance-контейнері лише заради CI. Замість неї
workflow робить звичайний `git clone --depth 1`.
### `deploy-from-scratch.yml` — повне пересоздання
Клонує репо наново й повторно запускає `create-graylog-lxc.sh` **на
хості Proxmox**. Використовуйте після ручного `pct destroy` (чи на
контейнері, якого ще ніколи не було), коли хочете просто натиснути
кнопку замість вводу повної команди `create-graylog-lxc.sh`.
**Як запускати:** репо → вкладка **Actions** → **Deploy Graylog from
scratch (host-level)** у лівому меню → кнопка **Run workflow**
підтвердити.
- **Раннер живе прямо на хості Proxmox**, працює від `claude-deploy`
(не root — див. крок 9b вище, чому це важливо), зареєстрований з
окремим лейблом (`proxmox-host:host`), тож підхоплює лише job'и для
цього workflow, не для `deploy.yml`.
- **`pct destroy` навмисно НЕ входить у цей workflow.** Автоматичне
пересоздання інфраструктури безпечне, бо `create-graylog-lxc.sh`
ідемпотентний (ремонтує на місці, якщо контейнер уже існує, створює
заново, якщо ні); знищення — незворотна втрата даних і залишається
свідомим набором команди людиною. Кнопка в CI, яка може знищити
продакшн одним випадковим кліком, розглядалась і була відхилена.
`pct destroy` навіть не входить у sudo-скоуп `claude-deploy` — свідомо.
- **На голому хості має бути встановлений `git`** — на відміну від
контейнера (де він є з шаблону Debian 12), свіжий хост Proxmox зазвичай
його не має (`apt-get install -y git`, одноразово, root).
### Спільне для обох workflow
- **Тригер навмисно ручний** (тільки `workflow_dispatch`, без
`on: push`) — вони керують продакшн-системою моніторингу, тож людина
переглядає диф і сама натискає "Run workflow", а не кожен push тихо
передеплоює систему.
- **Без `actions/checkout`** — ця дія вимагає Node.js, якого немає в
жодного раннера й не повинно бути лише заради CI. Обидва workflow
роблять звичайний `git clone --depth 1`.
- **Clone автентифікований через `secrets.GITHUB_TOKEN`** — короткоживучий
токен, який Forgejo сама створює на початок кожного запуску workflow і
знищує по завершенню, прив'язаний тільки до цього репо (підтверджено
@ -589,7 +667,7 @@ workflow і як його запускати щодня.
- **Секрети** (`GRAYLOG_ADMIN_PASSWORD`, `DISCORD_WEBHOOK_URL`) зберігаються
як repo-level секрети Forgejo Actions, а не в жодному відстежуваному
файлі. `GRAYLOG_EXTERNAL_URI` не є секретом (це публічна адреса Web UI),
тож вказаний прямо у workflow.
тож вказаний прямо в обох workflow.
## Що ще НЕ реалізовано
@ -611,13 +689,22 @@ workflow і як його запускати щодня.
## Структура файлів
```
create-graylog-lxc.sh # запускається на хості Proxmox
install-graylog.sh # запускається всередині контейнера (автоматично)
docker-compose.yml # опис стеку MongoDB + OpenSearch + Graylog
nftables.conf # firewall-правила, що застосовуються всередині контейнера
rules/*.json # визначення Graylog Pipeline Rule (імпортуються через API)
pipelines/*.json # визначення Graylog Pipeline, що посилаються на правила
streams/*.json # визначення Graylog Stream (маршрутизація за портом input)
create-graylog-lxc.sh # хост Proxmox - створює/ремонтує LXC-контейнер
install-graylog.sh # усередині контейнера (запускається автоматично)
bootstrap-host.sh # одноразово, root, хост Proxmox - автоматизує AppArmor-фікс
cleanup-host.sh # відкочує bootstrap-host.sh
fix-lxc-apparmor.sh # встановлюється bootstrap-host.sh, напряму не запускати
setup-forgejo-runner.sh # реєструє CI-раннер - у контейнері чи на хості
docker-compose.yml # опис стеку MongoDB + OpenSearch + Graylog
nftables.conf # firewall-правила, що застосовуються всередині контейнера
rules/*.json # визначення Graylog Pipeline Rule (імпортуються через API)
pipelines/*.json # визначення Graylog Pipeline, що посилаються на правила
streams/*.json # визначення Graylog Stream (маршрутизація за портом input)
alerts/*.json # Event Definitions + шаблон Discord-нотифікації
dashboards/search_*.json # об'єкти пошуку Views API, пара на кожен дашборд
dashboards/view_*.json # макет дашборду/віджетів Views API, у парі з search_*.json
.forgejo/workflows/deploy.yml # CI: редеплой тільки конфігурації (раннер у контейнері)
.forgejo/workflows/deploy-from-scratch.yml # CI: повне пересоздання (раннер на хості)
```
Всередині контейнера все лежить у `/opt/graylog/` (`docker-compose.yml`,