Перейти к содержимому

Развертывание на Yandex Cloud

Облачная версия Notifly целиком работает на serverless-сервисах Yandex Cloud: ни одного «всегда включённого» VM нет, оплата идёт только за реальный трафик и хранение.

Этот документ описывает, как устроен развёрнутый стенд и как воспроизвести его в своём фолдере.

┌──────────────────────────────────────────────────────────────────────────┐
│ Клиент │
│ (браузер · Android · desktop · MCP-агент · cron · веб-сайт · SMTP) │
└──────┬──────────────┬──────────────┬───────────────┬────────────────────┘
│ HTTPS REST │ WSS │ POST /script │ SMTP
▼ ▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────────┐
│ Yandex Cloud API Gateway (notifly-ws-gateway) │
│ ─ /api/* → notifly-api (REST) │
│ ─ /ws → notifly-ws-handler (WebSocket) │
│ ─ /script/* → notifly-api (публичные web-script триггеры) │
└──────┬─────────────────────┬──────────────────────────┬─────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌────────────────────────────┐
│ notifly-api │ │ notifly-ws- │ │ notifly-email │
│ (golang121) │ │ handler │ │ (Mail Trigger → Email Inbox)│
└─────┬────────┘ │ (golang123) │ └──────────┬─────────────────┘
│ └──────┬───────────┘ │
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────────────────┐
│ YDB Serverless (notifly-db) │
│ users · applications · clients · messages · webhooks · email_inboxes │
│ web_scripts · heartbeats · monitors · mcp_tokens · channel_shares │
└──────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────┴──────────────────────────┐
│ Object Storage notifly-ws-connections │
│ connections/<id>.json — состояние WebSocket-сессий │
└──────────────────────────────────────────────────────┘
Timer triggers (cron `* * * * ? *`):
• notifly-heartbeat — проверяет просроченные heartbeat-ы
• notifly-monitor — выполняет активные проверки HTTP/TCP/TLS/...
КомпонентРесурсТип
notifly-apiCloud FunctionREST + Web Script triggers
notifly-ws-handlerCloud FunctionWebSocket-обработчик
notifly-emailCloud Functionприём писем через Mail Trigger
notifly-heartbeatCloud Functionтаймер-проверка heartbeat-ов
notifly-monitorCloud Functionтаймер-проверка активных мониторов
notifly-ws-gatewayAPI Gatewayединая входная точка
notifly-dbYDB Serverlessвся бизнес-логика
notifly-ws-connectionsObject Storageсостояние WebSocket-соединений

При миграции с self-hosted-версии сознательно исключены:

  • Go-плагины (.so) — runtime YC Functions их не поддерживает. См. Введение в плагины для альтернатив.
  • OIDC — авторизация только локальная (BasicAuth + Bearer-токены).
  • Embed UI — фронтенд деплоится отдельно в bucket app.notifly.ru.
  • Image upload — заглушка (выгрузка картинок в Object Storage — в roadmap).
  • Fractional sort keys для сообщений — упрощено до строкового поля.

Понадобятся:

  • Yandex Cloud аккаунт с фолдером;
  • yc CLI (установка);
  • сервисный аккаунт с ролями serverless.functions.admin, ydb.admin, storage.editor, api-gateway.admin;
  • статические ключи доступа сервисного аккаунта (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY) — для S3 из Cloud Function;
  • IAM-токен (короткоживущий, 12 часов) — для самого деплоя.

Все секреты держатся в .env в корне репозитория и подгружаются через set -a; source .env; set +a перед деплой-скриптами.

Окно терминала
yc ydb database create notifly-db --serverless
# .env: YDB_DSN=grpcs://ydb.serverless.yandexcloud.net:2135/?database=...
cd server_ya
go run ./cmd/initdb # создаёт схему + admin/admin

Скрипт initdb идемпотентный: повторный запуск не сломает существующие таблицы и не пересоздаст admin-а.

Окно терминала
yc storage bucket create --name notifly-ws-connections --max-size 1073741824
Окно терминала
cd server_ya
bash deploy/deploy.sh

Скрипт:

  1. Собирает zip с notifly-api, заливает как Cloud Function;
  2. Собирает zip с notifly-ws-handler, заливает как Cloud Function;
  3. Применяет единую OpenAPI-спецификацию к API Gateway (REST /{proxy+} + WebSocket /ws).

Если перевыкатить ws-handler/deploy.sh отдельно — он перезапишет API Gateway WS-only спекой; чтобы вернуть REST, перезапустите server_ya/deploy/deploy.sh.

Окно терминала
cd server_ya
bash deploy/deploy_heartbeat.sh
bash deploy/deploy_monitor.sh

Каждый скрипт создаёт Cloud Function и навешивает на неё timer-trigger с расписанием * * * * ? * (раз в минуту). Внутри функции делается SELECT WHERE next_check_at <= now() по соответствующему индексу YDB.

Окно терминала
cd server_ya
bash deploy/deploy_email.sh

После деплоя в консоли Mail Trigger привяжите функцию notifly-email к нужному ящику (<local>+<alias>@<domain>). Пользовательские ящики управляются через Email Inbox — алиасы хранятся в YDB, а Mail Trigger маршрутизирует письма уже по subaddress-части.

Окно терминала
cd admin_ya
npm ci
npm run build
bash deploy.sh # синхронизирует dist/ в bucket app.notifly.ru

См. также инструкции по деплою admin — во многом этот шаг уже автоматизирован.

После деплоя запустите:

Окно терминала
bash server_ya/deploy/smoke_test.sh
python3 server_ya/deploy/ws_test.py

Проверяется:

  • GET /health{"health":"green","database":"green"}
  • POST /auth/local/login (Basic admin/admin)
  • POST /application + POST /message ×N
  • GET /message, GET /application/{id}/message
  • wss://.../ws?token=<C...> — handshake 101, ping → pong, status с connection_id и source_ip.
ДействиеГде смотреть
Логи функцийyc logging read --group-id <log-group> --format json
Метрики функцийYandex Cloud Console → Cloud Functions → метрики
Состояние таблиц YDBYDB UI или yc ydb yql ...
Активные WS-соединенияaws s3 ls s3://notifly-ws-connections/connections/

Стенд оптимизирован под FREE-tier:

  • YDB Serverless — Request Units, без always-on storage; индексы на next_check_at дают O(1)-проверки в heartbeat/monitor таймерах.
  • Cloud Functions — оплата по millisec-execution. Функции просыпаются только при активности (POST /message, ping, cron).
  • Object Storage — несколько байт на каждое WebSocket-соединение (connections/<id>.json ~200 байт).
  • API Gateway — оплата по запросам.

При нулевой активности Notifly не съедает ничего, кроме платы за зарезервированное место в YDB (~10 ₽/месяц на free-tier).