Bedolaga Bot: a Telegram storefront bolted onto a Remnawave panel
Система для продажи подписок в тг и вебе с вебадминкой интегрированный c Remnawave 3.0.0+ (https://docs.rw)
At a glance
- What is it?
- Bedolaga Bot is a Python service that puts a subscription shop, a payment desk and an admin console inside Telegram, sitting on top of a Remnawave panel. It is broad rather than sharp, and it trades a rigid runtime floor for a large feature surface.
- Who is it for?
- Bedolaga Bot fits operators who already run a Remnawave panel and want the whole purchase to close inside Telegram without building a storefront. It does not fit teams that need a quiet, stable dependency base, since the runtime is pinned to one Python minor version and the licence is a custom file GitHub cannot classify.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A sales layer that assumes Remnawave is already running
Bedolaga is not a VPN server panel. The repository description calls it a system for selling subscriptions in Telegram and on the web, with a web admin panel, integrated with Remnawave 3.0.0 and later. The project page points to docs.bedolagam.ru as the documentation home and to the Remnawave backend repository as the panel it talks to. So the division of labour is clear: Remnawave holds the users, the nodes and the traffic; Bedolaga holds the catalogue, the checkout, the customer record and the operator console.
The audience is narrow but real: an operator running a small paid VPN service who wants Telegram to be the shop front, the support desk and the admin panel at once. The README lists device management per subscription, traffic quotas in the form of unlimited, a fixed cap or top-up packs, server auto-selection or manual picks, a trial period that can be paid and later converted, and auto-renewal three days before expiry. There is also a unified wallet, so a customer can top up by one method and buy with another.
The scope goes further than a payment bot. There are promo codes, a referral programme with cash withdrawal, an affiliate system, audience-segmented broadcast mailings, landing pages, campaigns, contests, and a requirement that a channel subscription be active for a customer to keep their own subscription, with auto-disconnect on unsubscribe. That last rule is the kind of coupling that shapes how you would actually use it.
Gift codes are derived from one token, not stored twice
The gifting flow is the most precisely specified mechanism in the repository, and it is worth reading closely because it shows how the team thinks about schema stability. A gift lives in a single GuestPurchase table with a 64 character token. The public code `GIFT_<59 characters>` is computed from that token, and the deep link and cabinet links are derived the same way. The README states plainly that no extra tables and no database migrations are required.
The 59 character public code is sized to the Telegram deep link parameter limit, and the README says the format was optimised for that constraint. Redemption happens in four ways: a `https://t.me/<bot_username>?start=GIFT_<59 characters>` deep link, manual entry of a code or a raw token in the Gifts menu, activation through the `/gift/activate` endpoint in the web cabinet, or a direct cabinet link of the form `https://<cabinet_url>/buy/gift/<64 characters>`.
Two details matter for a deployment. The full token, token fragments and public codes are never placed in callback data, logs, transaction descriptions or error messages. And the My Gifts section recovers a purchase even after the FSM context is cleared or the bot restarts, without charging the balance a second time, which is the kind of detail that separates a working shop from a demo.
One internal balance sits under 28 payment providers
The payment design is a single wallet with many doors. The README advertises 28 payment providers working at the same time, a shared balance so that top up by any method then purchase from the balance, and automatic subscription purchase after a top up. There are recurring payments with saved cards, automatic status checking of payments, guest purchases through landing pages, and fiscalisation through NaloGo for self-employed sellers.
The dependency list backs this up rather than contradicting it. `yookassa==3.12.1` is pinned, and `app-store-server-library[async]==3.1.2` points to Apple App Store server receipts, so the payment layer spans card processing, mobile store billing and a local fiscalisation service at once. The `cryptography==50.0.1`, `pyjwt==2.15.1` and `bcrypt==5.0.0` pins are consistent with a service that signs cabinet sessions, hashes admin credentials and encrypts stored data.
The architectural cost of that breadth shows up in the state space. Auto-renewal fires three days before expiry, promo codes can grant money, days or trials, and the top up and buy steps are separate transactions. A balance that is topped up in one provider and spent against a subscription issued by another is simple for the customer and demanding for whoever reconciles it. The README mentions auto payment status checks but does not describe a settlement or reconciliation report, so that part of the operational story is not settled in the text you can read.
Bringing it up with Docker Compose and a PostgreSQL 18 volume
There is no pip install guide in the README, but the repository ships a Dockerfile, a compose file, a Makefile and an .env.example, and the badge points to a Docker deployment page in the documentation. The compose file defines three services: a PostgreSQL 18 Alpine database, a Redis 7 Alpine cache, and the bot built from the local Dockerfile. The database service runs through a guard script as its entrypoint, and the compose file records why: with an empty volume, PostgreSQL 18 will not start against data written by 15, and it asks for `make pg-upgrade` rather than silently handing you an empty database.
The relevant pieces, copied from the shipped files:
image: postgres:18-alpine
container_name: remnawave_bot_db
POSTGRES_DB: ${POSTGRES_DB:-remnawave_bot}
POSTGRES_USER: ${POSTGRES_USER:-remnawave_user}The volume layout changed with PostgreSQL 18, which now stores data under a version specific directory:
volumes:
- postgres18_data:/var/lib/postgresql
- postgres_data:/mnt/pg-legacy-data:roThe legacy volume is mounted read only and exists only for the guard. The compose file says it can be deleted after `make pg-upgrade`, and points to docs/postgresql-18-upgrade.md.
Redis is configured with a hard memory ceiling and an eviction policy that can discard keys:
image: redis:7-alpine
command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lruFor the bot itself, the environment file starts with the Telegram credentials, which double as the Cabinet WebApp auth secret through `Telegram.WebApp.initData`:
BOT_TOKEN=
ADMIN_IDS=
ADMIN_EMAILS=
INVITE_ONLY_ENABLED=false
INVITE_ONLY_ALLOW_GIFT_LINKS=true
SUPPORT_USERNAME=@supportTwo optional switches decide whether traffic can reach Telegram at all. `PROXY_URL` routes bot traffic through a SOCKS5 endpoint, and `TELEGRAM_API_URL` points the bot at an alternative Bot API server for regions where api.telegram.org is blocked. Gifts are enabled with `CABINET_GIFT_ENABLED=true`, and tariffs are marked giftable with the `show_in_gift` flag.
The runtime floor is one Python minor version, pinned exactly
The project metadata is unusually strict. `requires-python = '==3.14.*'` allows a single minor series and nothing else, and every runtime dependency is pinned with `==`, from `aiogram==3.31.0` through `sqlalchemy==2.1.1` and `alembic==1.20.0` to `redis==8.1.0` and `fastapi[standard]==0.141.1`. The Docker build matches that, starting from `FROM python:3.14-slim` and installing the toolchain with uv.
requires-python = '==3.14.*'
'redis==8.1.0',
'alembic==1.20.0',The image is built as a two stage build, and the second stage removes the base image's pip and setuptools because a scanner flagged them, which tells you the team expects the image to be scanned in CI. The container runs as a non root `app` user, and the application listens on port 8080. The Dockerfile also takes a `VERSION` build argument and stamps `BUILD_DATE` and `VCS_REF` into the environment.
For a self hosted service, a locked minor version is a defensible choice: it makes a running deployment reproducible. It also means a routine base image rebuild is the moment you discover whether your host still has a Python 3.14 runtime. The dependency set also includes `aiohttp-socks==0.12.0` and `httpx[socks]==0.28.1`, which is how outbound SOCKS routing is handled for a bot that may live behind a proxy.
Where the documentation stops and you have to test
Several things a buyer would want are simply not in the text, and it is better to name them than to guess. The README does not document a rollback procedure for a failed release. It does not state how many concurrent users the bot handles, and it gives no latency or throughput figures for payment callbacks, so any performance expectation you form would be invented. It does not list the 28 payment providers by name, so you cannot check from the README whether your market is covered.
The feature list also hides some hard edges. Device management is capped at one to twenty devices per subscription, or you can disable the limit. Trial periods can be paid and converted into a paid plan, which implies a state machine for refunding a trial on cancellation that is not described. Referrals and the affiliate programme both include withdrawal of money, so the operator ends up running a payout process.
Licensing needs care. GitHub lists the licence as Other, a custom licence it cannot classify, pointing at the LICENSE file. The README badge says MIT and `pyproject.toml` declares `license = { text = 'MIT' }`. Those two statements are not the same thing, and only the LICENSE file settles what you are agreeing to. Separately, the gift work is presented as a cross channel lifecycle, and the same feature set is described as native in both the bot and the cabinet, which hints at how tightly the two are coupled.
The cabinet is a separate project, and the alternative is to write your own bot
The realistic alternative to Bedolaga is not another payment bot. It is a small aiogram script you write yourself, plus a storefront you write yourself, wired to the same Remnawave panel. That path gives you total control over the checkout flow and the data model, and it gives you nothing else: no unified balance across 28 providers, no recurring cards, no promo and referral logic, no admin console inside Telegram, no gifting, no backups with restore from the bot, no maintenance mode that detects an unreachable panel, and no RBAC.
The documented division between the two official pieces is worth reading carefully. Bedolaga Cabinet is a separate repository, a React and TypeScript web cabinet, and the README says it substantially extends what the bot does: a personal account area, OAuth login through Google, Yandex, Discord, VK and Telegram OIDC, landing pages, sales analytics, RBAC, and gift subscriptions. The bot therefore carries the transactional core while the cabinet carries the browser facing surface, and a gift can be bought in one and redeemed in the other because both read the same GuestPurchase record and derive the same code.
A third option is the Remnawave panel alone, if you want to manage nodes and users without selling anything. Bedolaga is the layer that turns a technical service into a paid one, and it also brings every operational obligation of a shop: refunds, fiscalisation, referral payouts, and payment provider support. Choosing it is choosing to run a small business backend as well as a VPN panel.
Editorial conclusion
Bedolaga Bot fits operators who already run a Remnawave panel and want the whole purchase to close inside Telegram without building a storefront. It does not fit teams that need a quiet, stable dependency base, since the runtime is pinned to one Python minor version and the licence is a custom file GitHub cannot classify. Before adopting, check the Python 3.14 requirement against your build hosts, read the LICENSE file rather than the MIT string in pyproject.toml, and confirm in your own Remnawave instance that trial periods, referrals and the 28 payment providers behave the way the feature list implies.
Frequently asked questions
What does Bedolaga Bot do and what does it need to run?
It is a Telegram bot for selling VPN subscriptions that integrates with a Remnawave 3.0.0 or later panel, and it also ships a web admin panel. The project metadata requires Python 3.14 exactly, with PostgreSQL 15 or later and Redis, and the README badges list Docker as ready.
How do I give a Bedolaga subscription as a gift and let the recipient redeem it?
Gifts are activated through a Telegram deep link of the form `https://t.me/<bot_username>?start=GIFT_<59 characters>`, by entering the code manually in the Gifts menu, through the `/gift/activate` endpoint in the web cabinet, or by a direct cabinet link. The public code is derived from the 64 character token stored in the GuestPurchase table, so no extra tables or migrations are needed.
Is Bedolaga Bot actively maintained and what licence does it use?
The last push was on 2026-10-06, and the most recent releases listed are v5.0.0 and v4.16.0 on 2026-09-29, followed by v4.15.0 on 2026-09-22, so work is ongoing. The licence is recorded as a custom file that GitHub cannot classify, even though the README badge and pyproject.toml say MIT, so read the LICENSE file before relying on it.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bedolaga-dev-remnawave-bedolaga-telegram-bot)Was this useful?