Skip to content

Repository files navigation

Telegram Bot for 3x-ui VLESS Subscription Distribution

GitHub release CI Go Coverage Docker License: AGPL-3.0

Нужен VPN? » telegram: @kereal
По всем вопросам пишите в telegram: @kereal
Ставьте звездочки! =)

Features

  • 📥 Get subscription on demand with QR code import
  • 🔗 Invite/trial landing page (/i/{code}) with one-click Happ setup
  • 👥 Referral system — users generate invite codes with in-memory cache + periodic sync
  • 📊 Plans & pricing — plan-based traffic/device limits, products, orders, multi-node via nodes/plan_nodes schema
  • 🔗 Subscription server endpoint (/sub/{subID}) with multi-source aggregation, devices/IPs tracking, and profile headers, node-state synchronization via subscription_nodes table
  • 🌐 Multi-node VPN abstraction — internal/vpn/ with Client interface, 3x-ui, proxman, and fetch support, per-node client provisioning
  • 📈 Prometheus metrics — /metrics endpoint with HTTP, bot, XUI, DB, cache, circuit breaker, subscription metrics
  • 🗄️ Daily database backups with rotation, embedded SQLite migrations
  • 🐛 Sentry error tracking (+ performance traces)
  • 🐳 Docker support with health checks, non-root user, UPX compression
  • 🧪 Unit + E2E tests (~63.1% aggregate coverage, race-safe, fuzzing)
  • 🔒 Security hardening — X-Forwarded-For rightmost IP (S2), URL scheme allowlist http/https (S3), web↔bot dependency isolation (A1)

Quick Start

docker pull ghcr.io/kereal/rs8kvn_bot:latest

docker run -d \
  --name rs8kvn_bot \
  --restart unless-stopped \
  -v $(pwd)/.env:/app/.env:ro \
  -v $(pwd)/data:/app/data \
  -p 127.0.0.1:8880:8880 \
  ghcr.io/kereal/rs8kvn_bot:latest

See Installation Guide for:

  • All 4 installation methods (Docker, Docker Compose, Build from Source, Air hot reload)
  • Full configuration table (all env vars)
  • 3x-ui panel setup instructions
  • Database migrations and backups

Usage

  1. Start the bot with /start
  2. Use the inline buttons:
    • For users with subscription:
      • 📋 Подписка — View subscription info (traffic usage, subscription link)
        • 📱 QR-код — Generate QR code for Happ app import
        • 🏠 В начало — Return to main menu
      • ☕ Донат — View donation info
      • ❓ Помощь — View VPN setup instructions
    • For users without subscription:
      • 📥 Получить подписку — Create a new subscription
  3. Admin users also see 📊 Стат — View bot statistics

All menu buttons are inline (shown under the message). Each submenu has a "🏠 В начало" button to return.

Admin Commands

Command Description
/lastreg Show the last 10 registered users
/del <id> Delete a subscription by database ID
/broadcast <message> Send a message to all users who have a subscription (MarkdownV2, special chars auto-escaped)
/send <id or @username> <message> Send a message to a specific user
/refstats Show referral statistics (count per user from cache)

Examples:

/del 5                                    # Delete subscription with DB ID 5
/broadcast 🔔 Важное обновление!          # Broadcast to all subscribers (MarkdownV2 supported)
/send 123456789 Привет!                   # Private message by Telegram ID
/send @username Привет!                   # Private message by username

Broadcast formatting: messages are sent as MarkdownV2. Special characters (., !, _, *, etc.) are escaped automatically, so plain text needs no manual escaping — but *bold*, _italic_, `code` and [text](url) are preserved. At the end the admin gets a report splitting successful deliveries, users who blocked the bot, and other errors.

Health Check & Web Endpoints

The bot exposes HTTP endpoints on port 8880:

Endpoint Description Status Codes
GET /healthz Basic health (process alive, DB status) 200/503
GET /readyz Ready state (accepting requests after init) 200/503
GET /i/{code} Trial invites landing page 200/404/429/500
GET /metrics Prometheus metrics endpoint 200
GET /sub/{subID} Subscription server 200/404/502/405
GET /static/logo.png Logo image (mobile-optimized PNG) 200/404
POST /payment/callback Platega payment webhook (X-MerchantId / X-Secret) 200/400/401/405/503

Payment Callback (/payment/callback)

Receives Platega payment notifications. Guard chain, in order:

  1. Method: POST-only (405 otherwise).
  2. Service availability: payments must be enabled, orderService/bot wired, and runtime payment readiness enabled only after the real bot and SyncService are initialized (→ 503 otherwise).
  3. Auth: X-MerchantId / X-Secret headers compared constant-time to cfg.PlategaMerchantID / cfg.PlategaSecret (→ 401). Both credentials must be non-empty.
  4. Body: http.MaxBytesReader(256 KiB), json.Decoder.UseNumber, single JSON object (extra trailing JSON rejected).
  5. payload.ID must be a UUID provider transaction ID; payload.Validate() requires id/amount/currency/status (→ 400 otherwise). paymentMethod and payload принимаются при наличии; официальная документация Platega противоречит сама себе по обязательности этих полей, поэтому интеграция сохраняет совместимость и уведомляет администратора о malformed callback. Provider transaction IDs are UUIDs; malformed or non-UUID IDs are rejected with 400.
  6. Status CONFIRMEDOrderService.ConfirmPayment (CAS with pending guard, exact amount match, atomic plan application in the same DB transaction).
  7. Status CANCELED|CHARGEBACKEDOrderService.CancelPaymentByProvider; a chargeback on a previously-paid order automatically downgrades the subscription to the free plan (unless another paid order exists), otherwise it is recorded for manual review.

Development: expose the webhook with ngrok http 8880 and configure the resulting URL in the Platega dashboard. The shared .env controls the endpoint via PAYMENT_ENABLED, PLATEGA_MERCHANT_ID, PLATEGA_SECRET. Link lifetime is taken from Platega expiresIn; a valid saved link is reused. CHARGEBACKED on a paid order automatically downgrades the subscription to the free plan unless another paid order exists; otherwise it is recorded for manual review. A confirmed payment (purchase or renewal) sends the admin a Telegram alert with the tariff, formatted amount and a clickable buyer link (utils.FormatUserLink); a CHARGEBACKED on a paid order additionally sends a dedicated chargeback alert with the access status (downgraded to free vs preserved). Uncertain provider outcomes and late confirmed payments generate an admin Telegram alert containing the order, user, amount, currency and provider transaction ID.

Invite/Trial Landing Page (/i/{code})

Each user can generate an invite code via the referral flow. The landing page validates the code, applies IP-based rate limiting (429 if exceeded), creates a trial subscription in 3x-ui, and renders a mobile-friendly page with:

  • Happ app download links (Android / iOS)
  • One-click "Добавить в Happ" button (happ://add/ deep-link)
  • Copy-to-clipboard subscription URL
  • Telegram activation link

Subscription Server (/sub/{subID})

Serves subscriptions with optional extra servers and custom headers. Validates subID, checks cache (240s TTL), fetches from all active nodes (3x-ui, proxman, fetch), merges responses, returns combined output. Fetch nodes use subscription_url directly; other types append subID.

When SUBSERVER_ACCESS_LOG is set, each /sub/{id} request is appended to the configured access log file in a zap-console line without a message, caller, or field keys. The record includes timestamp, level, method, URL, response status, client IP, device headers, and User-Agent as space-separated values; values containing spaces are quoted, and empty optional values are written as -. The main log also records an INFO message when access logging is enabled. Access log writes are buffered asynchronously; if the file cannot be opened, the bot continues without the access log and writes an error to the main log.

Traffic and Expiry

  • Auto-reset: Every 30 days from creation date — 3x-ui resets traffic to 0 and extends expiresAt by 30 days automatically when expiresAt > 0
  • Source: 3x-ui inbound.go - autoRenewClients()

Development

Test & Lint

# Run all tests
go test ./...

# Run with coverage
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out

# Run specific package
go test ./internal/database/... -v

# Lint
golangci-lint run ./...
gosec ./...

Test suite: ~63.1% aggregate coverage (generated with go test -coverprofile), race-safe, fuzzing, table-driven tests, integration tests with mock HTTP server.

Build

go build -ldflags="-s -w" -o rs8kvn_bot ./cmd/bot

Project Documentation

About

telegram bot + 3x-ui panel = vpn subscription link

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages