Multifunctional telegram bot for ksiVPN project built on the Aiogram 3 framework. Handles subscriber onboarding, multi-provider payments (YooMoney + YooKassa) with optional ФНС fiscalization via «Мой налог», automated subscription lifecycle and expiry notifications, and VPN access provisioning through Remnawave Panel. Deploys with Docker Compose — PostgreSQL 17, Redis 8, and an optional built-in Caddy TLS reverse proxy included.
- Aiogram 3.27 support with Redis-backed FSM storage
- PostgreSQL usage
- Remnawave Panel integration for VPN access provisioning
- Multi-provider payments: YooMoney P2P + YooKassa acquiring
- Payment fiscalization via «Мой налог» (nalogo SDK, direct ФНС integration)
- Subscription mechanics: 30-day renewal, expiry notifications (1d / 3d / 7d before)
- Promocode mechanics: referral, global and local promo codes
- Referral system mechanics
- Personal account with subscription URL and device limit
- YAML-based localization (ru / en)
- Dynaconf + Pydantic typed configuration
- ChatGPT fallback for unrecognized messages (g4f + PollinationsAI, no API key required)
- Rapid deployment via Docker Compose (PostgreSQL 17 + Redis 8 + optional Caddy TLS)
- Database backups via bot (daily × 7, weekly × 4, monthly × 12)
- SOCKS5 proxy support for Telegram API
- Fully asynchronous codebase
- Structured logging with rotation
Use Case diagram can be found here.
- Docker Engine with the Compose plugin is installed
- Git is installed
- A running Remnawave Panel instance (≥ 2.7.0) with API token
- Telegram bot token from BotFather and your Telegram user ID
- At least one payment provider account — YooMoney or YooKassa
git clone https://github.com/exmanka/ksiVPN-telegram-bot.git
cd ksiVPN-telegram-botThe bot is configured via two .env files: .env holds shared defaults (committed to the repository), .env.local holds your secrets and overrides (not committed). Both files are passed on every docker compose invocation — later --env-file wins on key collision, so .env.local overrides .env.
Create .env.local with at minimum these mandatory values:
# Bot — token from BotFather, your numeric Telegram user ID
DOTENV_TGBOT_BOT_TOKEN=<your-bot-token>
DOTENV_TGBOT_ADMIN_ID=<your-telegram-user-id>
# Remnawave Panel — base URL and API token
DOTENV_TGBOT_REMNAWAVE_BASE_URL=https://panel.example.com
DOTENV_TGBOT_REMNAWAVE_TOKEN=<panel-api-token>
# Database — passwords for PostgreSQL and Redis
DOTENV_POSTGRES_PASSWORD=<strong-password>
DOTENV_REDIS_PASSWORD=<strong-password>
# At least one payment provider must be fully configured (see step 3).
# Both YooMoney and YooKassa are enabled by default, so each requires its
# credentials — or disable the one you don't use.
DOTENV_TGBOT_PAYMENTS_YOOMONEY_TOKEN=<wallet-oauth-token>
DOTENV_TGBOT_PAYMENTS_YOOMONEY_NOTIFICATION_SECRET=<hmac-sha256-secret>
DOTENV_TGBOT_PAYMENTS_YOOKASSA_SHOP_ID=<shop-id>
DOTENV_TGBOT_PAYMENTS_YOOKASSA_SECRET_KEY=<secret-key>The
.envfile ships sensible defaults for everything else (image tags, ports, PostgreSQL/Redis usernames, timezone, etc.). You only need to touch.envif you want to change those defaults. A full reference of every available variable is in the Environment variables chapter below.
YooMoney (enabled by default):
DOTENV_TGBOT_PAYMENTS_YOOMONEY_TOKEN=<wallet-oauth-token>
DOTENV_TGBOT_PAYMENTS_YOOMONEY_NOTIFICATION_SECRET=<hmac-sha256-secret>The HMAC secret is set in your YooMoney wallet under HTTP-notifications settings.
YooKassa (enabled by default):
DOTENV_TGBOT_PAYMENTS_YOOKASSA_SHOP_ID=<shop-id>
DOTENV_TGBOT_PAYMENTS_YOOKASSA_SECRET_KEY=<secret-key>To disable a provider, set DOTENV_TGBOT_PAYMENTS_YOOMONEY_ENABLED=false or DOTENV_TGBOT_PAYMENTS_YOOKASSA_ENABLED=false. At least one must remain enabled.
The bot runs an aiohttp server on port 8080 for inbound webhooks. This step is optional — the bot works without any public endpoint thanks to a built-in APScheduler reconciler that polls each payment provider every 2 minutes for still-pending payments. Exposing the listener over HTTPS only adds:
- Faster payment confirmation — webhooks deliver near-instantly; without them a payment is confirmed within up to ~2 minutes (the reconciler interval).
- Remnawave torrent-blocker notifications — these are push-only (no reconciler fallback). Without an exposed
/webhook/remnawaveendpoint, users will not receive torrent-block warning messages.
If instant confirmation and torrent notifications are not important to you, skip to step 5 and rely on the reconciler.
To expose the listener, terminate TLS with one of:
Option A — built-in Caddy reverse proxy (automated TLS via Let's Encrypt, recommended for simple setups):
DOTENV_CADDY_DOMAIN=vpn.example.com
DOTENV_CADDY_ACME_EMAIL=you@example.comStart with the with-reverse-proxy Compose profile (see step 6).
Option B — external nginx / Caddy on a separate host: configure your proxy to forward POST /webhook/* and GET /health to 127.0.0.1:8080. For LAN-accessible bind use DOTENV_TGBOT_WEBHOOK_HOST_BIND=<lan-ip>:8080.
After configuring your proxy, register the webhook URLs in each provider's dashboard:
- YooMoney:
https://vpn.example.com/webhook/payment/yoomoney - YooKassa:
https://vpn.example.com/webhook/payment/yookassa
For Remnawave torrent-blocker notifications, also set the shared secret (when empty, the /webhook/remnawave route is not mounted):
DOTENV_TGBOT_REMNAWAVE_WEBHOOK_SECRET=<hmac-sha256-secret>For self-employed direct income registration with ФНС via «Мой налог»:
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_ENABLED=true
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_PROVIDERS_YOOKASSA=true
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_PROVIDERS_YOOMONEY=true
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_SEND_RECEIPT=true
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_MOY_NALOG_INN=<12-digit-INN>
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_MOY_NALOG_PASSWORD=<lknpd-password>Without Caddy (simple):
docker compose --env-file .env --env-file .env.local up -d --build && docker compose logs -fWith built-in Caddy:
docker compose --env-file .env --env-file .env.local --profile with-reverse-proxy up -d --build && docker compose logs -fPopulate the remnawave_internal_squads table from your Remnawave Panel before users start registering:
# Requires Python 3.12
python3.12 -m venv .venv && .venv/bin/pip install asyncpg remnawave
# Dry run — review what would be synced
POSTGRES_HOST=127.0.0.1 POSTGRES_PORT=54320 \
POSTGRES_USER=ksivpn-tgbot POSTGRES_PASSWORD=<password> POSTGRES_DB=ksivpn-tgbot \
REMNAWAVE_BASE_URL=https://panel.example.com REMNAWAVE_TOKEN=<token> \
.venv/bin/python scripts/sync_remnawave_squads.py
# Apply
POSTGRES_HOST=127.0.0.1 POSTGRES_PORT=54320 \
POSTGRES_USER=ksivpn-tgbot POSTGRES_PASSWORD=<password> POSTGRES_DB=ksivpn-tgbot \
REMNAWAVE_BASE_URL=https://panel.example.com REMNAWAVE_TOKEN=<token> \
.venv/bin/python scripts/sync_remnawave_squads.py --applyEdit subscription plans, promo codes and referral settings directly in PostgreSQL. The schema is initialized from postgres/initdb/001_init_schema.sql with example rows — update the subscriptions table to match your pricing.
All variables are set in .env (defaults) or .env.local (your secrets and overrides). Variables in the Required column must be provided for the bot to start.
| Environment variable | Default value | Required | Purpose |
|---|---|---|---|
DOTENV_TGBOT_BOT_TOKEN |
"" |
Yes | Telegram bot token from BotFather |
DOTENV_TGBOT_ADMIN_ID |
"" |
Yes | Numeric Telegram user ID of the administrator |
DOTENV_TGBOT_LOCALIZATION_LANGUAGE |
en |
No | Interface language: ru or en |
DOTENV_TZ |
Europe/Moscow |
No | Container timezone (libc, logs, PostgreSQL, APScheduler) |
DOTENV_TGBOT_ENV |
default |
No | Dynaconf environment (ENV_FOR_DYNACONF) |
DOTENV_TGBOT_IMAGE |
ksivpn-tgbot |
No | Bot Docker image name |
DOTENV_TGBOT_TAG |
local |
No | Bot Docker image tag |
DOTENV_TGBOT_PROXY_ENABLED |
false |
No | Enable SOCKS5 proxy for the Telegram API |
DOTENV_TGBOT_PROXY_URL |
"" |
No | SOCKS5 proxy URL (required when proxy enabled) |
| Environment variable | Default value | Required | Purpose |
|---|---|---|---|
DOTENV_TGBOT_REMNAWAVE_BASE_URL |
"" |
Yes | Remnawave Panel base URL |
DOTENV_TGBOT_REMNAWAVE_TOKEN |
"" |
Yes | Remnawave Panel API token |
DOTENV_TGBOT_REMNAWAVE_CADDY_TOKEN |
"" |
No | Optional Caddy auth token for the panel |
DOTENV_TGBOT_REMNAWAVE_WEBHOOK_SECRET |
"" |
No | HMAC-SHA256 secret for inbound panel webhooks; empty = /webhook/remnawave route disabled |
| Environment variable | Default value | Required | Purpose |
|---|---|---|---|
DOTENV_POSTGRES_PASSWORD |
ksivpn-tgbot |
No | PostgreSQL password (change for production) |
DOTENV_REDIS_PASSWORD |
ksivpn-tgbot |
No | Redis password (change for production) |
DOTENV_POSTGRES_USER |
ksivpn-tgbot |
No | PostgreSQL user |
DOTENV_POSTGRES_DB |
ksivpn-tgbot |
No | PostgreSQL database name |
DOTENV_POSTGRES_IMAGE |
postgres |
No | PostgreSQL Docker image |
DOTENV_POSTGRES_TAG |
17.9-alpine3.23 |
No | PostgreSQL image tag |
DOTENV_POSTGRES_PORT |
54320 |
No | Host port mapped to PostgreSQL 5432 |
DOTENV_TGBOT_REDIS_FSM_PREFIX |
ksivpn_aiogram_fsm |
No | Redis key prefix for aiogram FSM storage |
At least one provider must be enabled and fully configured.
| Environment variable | Default value | Required | Purpose |
|---|---|---|---|
DOTENV_TGBOT_PAYMENTS_YOOMONEY_ENABLED |
true |
No | Enable the YooMoney provider |
DOTENV_TGBOT_PAYMENTS_YOOMONEY_TOKEN |
"" |
No | YooMoney wallet OAuth token (required when YooMoney enabled) |
DOTENV_TGBOT_PAYMENTS_YOOMONEY_NOTIFICATION_SECRET |
"" |
No | HMAC-SHA256 secret from YooMoney HTTP-notifications (required when YooMoney enabled) |
DOTENV_TGBOT_PAYMENTS_YOOKASSA_ENABLED |
true |
No | Enable the YooKassa provider |
DOTENV_TGBOT_PAYMENTS_YOOKASSA_SHOP_ID |
"" |
No | YooKassa shop ID (required when YooKassa enabled) |
DOTENV_TGBOT_PAYMENTS_YOOKASSA_SECRET_KEY |
"" |
No | YooKassa secret key (required when YooKassa enabled) |
DOTENV_TGBOT_PAYMENTS_RETURN_URL |
https://t.me/ksiVPN_bot |
No | Where the gateway redirects after payment (set to your bot link) |
DOTENV_TGBOT_PAYMENTS_TEST_USER_IDS |
[] |
No | JSON list of Telegram IDs that pay TEST_PRICE |
DOTENV_TGBOT_PAYMENTS_TEST_PRICE |
2 |
No | Per-30-day reference price (₽) for test users |
| Environment variable | Default value | Required | Purpose |
|---|---|---|---|
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_ENABLED |
false |
No | Master kill-switch for ФНС income registration |
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_PROVIDERS_YOOMONEY |
false |
No | Fiscalize YooMoney payments |
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_PROVIDERS_YOOKASSA |
false |
No | Fiscalize YooKassa payments |
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_SEND_RECEIPT |
false |
No | Include the receipt print URL in the user's payment message |
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_MOY_NALOG_INN |
"" |
No | 12-digit ИНН (required when fiscalization enabled for a provider) |
DOTENV_TGBOT_PAYMENTS_FISCALIZATION_MOY_NALOG_PASSWORD |
"" |
No | ЛК НПД password (required when fiscalization enabled for a provider) |
| Environment variable | Default value | Required | Purpose |
|---|---|---|---|
DOTENV_TGBOT_WEBHOOK_PORT |
8080 |
No | Port the aiohttp webhook server listens on |
DOTENV_TGBOT_WEBHOOK_HOST_BIND |
127.0.0.1:8080 |
No | Host-side bind for the port mapping ([ip:]port) |
DOTENV_CADDY_DOMAIN |
"" |
No | FQDN for ACME (required for the with-reverse-proxy profile) |
DOTENV_CADDY_ACME_EMAIL |
"" |
No | Let's Encrypt contact email (required for the with-reverse-proxy profile) |
Now you can write to your bot and enjoy all its pre-installed features. You are free to play with functionality and database filling. Learn something new for yourself! 🎉
🔥 ksiVPN — an independent open source project created by one person who is tired of constantly changing VPN services and watching ads for the sake of 512 Kb/s speed. The absence of unnecessary intermediaries and the use of open source software have allowed the project to offer a fast and stable VPN connection at a minimal cost for over four years.



