120 lines
3.1 KiB
Markdown
120 lines
3.1 KiB
Markdown
# Ghabilee Telegram Relay
|
||
|
||
Thin HTTP service that lives on a **foreign** VPS and forwards ops alerts to
|
||
Telegram Bot API. The Iran-hosted Nest backend calls this relay instead of
|
||
`api.telegram.org` directly (which is often unreachable from inside Iran).
|
||
|
||
Repo: <https://git.ghabilee.ir/AliSaZa/telegrambot.git>
|
||
|
||
## Why
|
||
|
||
- Core product (Jibit, Kavenegar, Postgres) stays in Iran.
|
||
- Only Telegram delivery needs outbound access to `api.telegram.org`.
|
||
- Failures here must not break user flows (backend already treats most alerts as best-effort).
|
||
|
||
## API
|
||
|
||
### `GET /health`
|
||
|
||
Liveness for Docker/load balancers. No auth.
|
||
|
||
### `POST /v1/send`
|
||
|
||
Auth header (required):
|
||
|
||
```http
|
||
X-Ghabilee-Telegram-Relay-Secret: <RELAY_SECRET>
|
||
```
|
||
|
||
Body (JSON):
|
||
|
||
| Field | Type | Required | Notes |
|
||
| ----- | ---- | -------- | ----- |
|
||
| `text` | string | yes | 1–4096 chars (Telegram limit) |
|
||
| `chatId` | string | no | Override default chat from env |
|
||
| `messageThreadId` | number \| null | no | Forum topic; `null` = no topic; omit = env default |
|
||
| `disableWebPagePreview` | boolean | no | Default `true` |
|
||
|
||
Success:
|
||
|
||
```json
|
||
{ "ok": true, "messageId": 123 }
|
||
```
|
||
|
||
Errors: `401` unauthorized, `400` validation, `502` Telegram API failure.
|
||
|
||
### Example
|
||
|
||
```bash
|
||
curl -sS -X POST "https://relay.example.com/v1/send" \
|
||
-H "Content-Type: application/json" \
|
||
-H "X-Ghabilee-Telegram-Relay-Secret: $RELAY_SECRET" \
|
||
-d '{"text":"hello from relay","messageThreadId":8}'
|
||
```
|
||
|
||
## Local run
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
# fill TELEGRAM_BOT_TOKEN, chat ids, RELAY_SECRET (≥32 chars)
|
||
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
Tests / typecheck:
|
||
|
||
```bash
|
||
npm test
|
||
npm run typecheck
|
||
```
|
||
|
||
## Docker
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
docker compose up -d --build
|
||
```
|
||
|
||
## CI/CD (Gitea Actions)
|
||
|
||
On push to `main`:
|
||
|
||
1. `.gitea/workflows/ci.yml` — typecheck + tests
|
||
2. `.gitea/workflows/deploy.yml` — rsync to VPS + `scripts/deploy-on-vps.sh`
|
||
|
||
Repo Actions secrets (Settings → Actions → Secrets):
|
||
|
||
| Secret | Value |
|
||
| ------ | ----- |
|
||
| `DEPLOY_SSH_KEY` | private key that can SSH as `root` on the VPS |
|
||
| `VPS_HOST` | `65.108.18.151` (public IP; job runs in Docker) |
|
||
| `VPS_USER` | `root` |
|
||
|
||
Production app dir: `/opt/ghabilee-telegram-relay`
|
||
Nginx host: `telegram-relay.ghabilee.ir` (add DNS A record, then `certbot --nginx -d telegram-relay.ghabilee.ir`)
|
||
|
||
Gitea git SSH uses port **222**: `ssh://git@git.ghabilee.ir:222/AliSaZa/telegrambot.git`
|
||
|
||
## Env
|
||
|
||
See [`.env.example`](.env.example). Production needs:
|
||
|
||
- `RELAY_SECRET` (≥32)
|
||
- `TELEGRAM_BOT_TOKEN`
|
||
- `TELEGRAM_GROUP_CHAT_ID` (preferred) or `TELEGRAM_CHAT_ID`
|
||
- optional `TELEGRAM_GROUP_THREAD_ID` (ops forum topic)
|
||
|
||
## Backend integration (next step)
|
||
|
||
In `ghabilee-backend` `OpsAlertsService.sendTelegram`, when
|
||
`TELEGRAM_RELAY_URL` is set, POST to `{TELEGRAM_RELAY_URL}/v1/send` with the
|
||
shared secret instead of calling Telegram directly. Keep a direct-Telegram
|
||
fallback for local/dev if useful.
|
||
|
||
## Security notes
|
||
|
||
- Do **not** put the secret in query strings (access logs).
|
||
- Expose only HTTPS on the foreign VPS (Caddy/Nginx + Let’s Encrypt).
|
||
- Firewall: ideally allow only the Iran VPS egress IP to hit `/v1/send`.
|