Studio product
Zhivchik
An accelerator for services abroad: own server fleet, two ways into one account, billing, support and failover.
- concurrent connections
- 1,000+
- users
- 700
- locations to choose from
- 11

A studio product: an access service with its own server fleet, billing, user area, bot and support desk. The service is now closed. At its peak it held over a thousand concurrent connections across seven hundred users.
What follows is the engineering only: what was built and why it was built that way.
The protocol was not picked by fashion
It started on WireGuard and hit a wall there. WireGuard is recognisable by the shape of its traffic, and wherever filtering looks at more than the address, it stops working entirely.
The production version runs on VLESS + Reality. The difference is fundamental: Reality does not encrypt “in its own special way” — it presents itself as a real website with a real TLS certificate. To an outside observer it looks like a request to an ordinary site, not to an access service. Speed follows from that: no obfuscation layered on obfuscation, no tunnel inside a tunnel.
WireGuard stayed in the codebase — disabled and marked as legacy. Removing it was not worth it: a working fallback road is worth more than a tidy repository.
A proxy inside the country in front of the main server
The main server sat abroad, but the domain pointed at an nginx proxy inside the country, which forwarded everything to it. The point is that filtering never reaches the main address — from the outside only the proxy is visible.
The split solved a second problem along the way: payment providers and external services talked to a local address rather than a foreign one.
One link instead of a page of instructions
The main point of failure for services like this is setup on the user’s side. So a client did not get a configuration file or a walkthrough — they got a subscription link: one address that returns a ready config in a format every common client understands.
Server changed, location added, keys rotated — the link stays the same and the client picks up the new config itself. Nothing to reinstall.
A server fleet synchronised over SSH
Up to eleven locations were supported. The list lives in the database, and the Xray configuration propagates to the remote nodes over SSH — switching location works from the bot and from the user area alike.
From which a non-obvious thing follows: updating the configuration across ten servers takes about a minute. So on registration the synchronisation goes to the background: the person gets working access immediately instead of watching a spinner for a minute. It is one of those decisions that are invisible in the interface and that define how the product feels.
Two ways into one account
You could sign in through the Telegram bot or through the website with an email. Those are two separate account stores, and they are linked by a six-digit code: the person presses “link Telegram” in their account, sends the code to the bot, and the subscriptions merge.
Signing up on the site immediately granted a three-day trial, created a client and handed over a working link — no confirmation emails, no waiting.
Billing across three providers
Three payment channels: cards and instant bank transfers, an alternative local one, and cryptocurrency through Telegram. Every payment follows the same path: a record marked pending, a redirect to the payment page, a callback with signature verification, then the subscription is extended.
The extension lands on the Telegram account or the web account depending on where the payment came from. On top of that: referrals, promo codes and a bonus for subscribing to the news channel.
Support as a separate bot
Tickets, not a shared chat. A user writes to the bot and a ticket card appears in the admins’ group. An admin claims the ticket, receives the conversation history, and talks to the person through the bot.
One detail matters — a ticket can be released back into the pool along with its whole history: if it reached the wrong person, the next admin does not start from a blank page. On closing, the user is asked to rate the exchange.
Failing over to the spare server
The emergency failover route deliberately does not authenticate through the database: its entire purpose is that the primary database may be unreachable. It checks a separate shared secret instead.
This is exactly the case where “do it like everywhere else” gets you a mechanism that fails precisely when it is needed.
How it ran
No Docker: systemd keeps the backend, the frontend and Xray as separate services. The database is a single SQLite file, and migrations run at application start.
Frontend and backend deploy independently: a change in the interface does not restart the bot and does not drop live connections. Deployment goes through a handler on the server that accepts a build archive and restarts only its own service.
Python · FastAPI · aiogram 3 · SQLite · Xray (VLESS + Reality) · Next.js 16 · React 19 · TypeScript · nginx · systemd