↓ Skip to main content

MyPointVPN: how a VPN bot learned to manage servers

·809 words·4 mins
Alexander Sokolov aka s0k0l
Author
Alexander Sokolov aka s0k0l
I emulate user behavior, extract data and protect information. I take projects from idea to release.

On September 23 I made the first commit to a portfolio project: a Telegram bot that installs and configures the 3x-ui panel by itself, so a person gets their own VPN without any manual fiddling. Three weeks and about 40 commits later, the VPN turned out not to be the most interesting part.

How it looks
#

You rent a server with Debian 12 or 13 from any hosting provider, get an IP and a root password, and send the bot one line: ip:password. The bot moves ssh to a random port with key-only login, turns on a firewall, updates the system and from then on manages the server itself.

You can take the server back at any time with the “Return” button. The bot removes its access, rolls back ssh and the firewall and sends you a new root password. Your data on the server stays.

VPN
#

This is what it all started for. The bot installs 3x-ui and sets up:

  • a VLESS + XHTTP + Reality connection on port 443, with the Reality target picked by the bot
  • an optional camouflage server: clients connect to it, it forwards traffic to the panel, and the panel’s address is never exposed
  • a domain with a Let’s Encrypt certificate for the panel and the subscription, and without a domain a short-lived IP certificate that renews automatically
  • an outbound proxy: your own or Cloudflare WARP
  • encrypted DNS on the server: DNS-over-TLS, with DNS-over-HTTPS as a fallback if TLS gets blocked

The bot issues and revokes client keys and hands out subscription links for v2rayN, Hiddify, Happ and v2rayNG. Keys have no limits: no traffic cap, no expiry, no device limit. For every key you can see the traffic and when the client was last online.

Once a day the bot checks the panel, Xray and the subscription certificate and tells you if something broke or got fixed.

Why no Cloudflare
#

At first the bot could work through Cloudflare, and I had to drop it. Cloudflare terminates TLS on its side and opens a new connection to the server. Reality lives right inside the client’s TLS handshake, and the server has to see it untouched. Reality can’t work behind Cloudflare, so I removed the support.

Where the real work is
#

When I looked at the code, almost all of the bot’s work came down to one thing: take a bare Debian, lock it down and then manage it by key. Roughly what I described in initial Debian server setup, just without a human. 3x-ui is only one of the tasks on top of that.

So I moved the server setup code into a separate package, serverus. It’s an ansible-based library with no Django and no Telegram and a clear programmatic API. The Telegram part also became a separate package. The Django app stayed as the glue with the business logic.

Second scenario: a docker server
#

With that foundation in place, the next scenario comes together quickly. I built a docker server:

  • the bot installs Docker, Caddy and automatic system updates, and Caddy issues certificates for domains
  • an app is a folder with docker-compose.yaml, .env and caddy.conf, sent to the bot as an archive or file by file
  • before applying, the bot shows a diff and per-file warnings, and warns you if a domain doesn’t point to the server
  • while applying, it checks the compose file, busy ports and the Caddy config, and if something is wrong it leaves the app untouched
  • only the changed services are recreated
  • the “Roll back” button restores the previous version of the files
  • there are start, stop, restart and logs per service, login to a private docker registry and guest access to volumes for uploading data

The example in the repo is a self-hosted RustDesk server.

One codebase, different bots
#

What the bot can do is decided by the interface selected in the admin panel: “MyPoint VPN”, “Serverus” or both. It switches on the fly, without a restart. That’s how one codebase makes different bots.

The bot hosts itself
#

My favorite part. Production MyPointVPN is deployed as a Serverus app on a docker server managed by this very bot. To the bot, its own new version is just another app, like RustDesk.

Stack
#

Python, Django, PostgreSQL, RabbitMQ + dramatiq (background jobs with a supervisor), ansible, a self-hosted Telegram Bot API server, Docker, Caddy, 3x-ui v3.8.5.

Try it and talk about it
#

The project has its own page: mypointvpn.sokolab.xyz.

What’s next
#

Serverus will most likely become a separate project. I’ll write about it in a separate post, and it will get its own landing page. To be continued.