<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: v2hub</title>
    <description>The latest articles on DEV Community by v2hub (v2hub).</description>
    <link>https://dev.to/v2hub</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F14161%2F6f030cad-6f32-4af7-9fd1-5c24a2ad12a3.jpg</url>
      <title>DEV Community: v2hub</title>
      <link>https://dev.to/v2hub</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/v2hub"/>
    <language>en</language>
    <item>
      <title>How I Ended Up Building V2Hub</title>
      <dc:creator>nestt</dc:creator>
      <pubDate>Tue, 28 Jul 2026 06:11:56 +0000</pubDate>
      <link>https://dev.to/v2hub/how-i-ended-up-building-v2hub-3ehm</link>
      <guid>https://dev.to/v2hub/how-i-ended-up-building-v2hub-3ehm</guid>
      <description>&lt;p&gt;Like everyone else, I started out using popular tools like Marzban and 3x-ui. And to be fair, they're genuinely convenient — as long as you want to create a config &lt;em&gt;inside&lt;/em&gt; that tool and add it to a subscription. But here's the catch: what if you want to add a config to your subscription that wasn't created in Marzban or 3x-ui in the first place? Even if you spin up two independent servers running separate but identical Marzban instances, you can't just merge them. You end up hacking together some workaround to glue them together.&lt;/p&gt;

&lt;p&gt;It's a bit like British bathroom taps: hot on one side, cold on the other, and you have to rig up some extension just to mix them and actually be able to wash your hands.&lt;/p&gt;

&lt;p&gt;At some point I gave up on that whole approach and started manually setting up xray and writing configs myself. The problem is, if an IP got blocked and it was easier to just spin up a new VPS, I'd have to manually re-add all the configs into every app all over again. Tolerable when it's just you. Considerably less tolerable once you start sharing configs with friends — especially the older, less tech-savvy ones.&lt;/p&gt;

&lt;p&gt;So I wrote a scrappy little script where I'd manually punch in all the configs, and it would spit out a subscription link — one I could just send to end users. And that's when it hit me: how many other people out there are dealing with the exact same headache? Not just managing configs, but managing &lt;em&gt;subscriptions&lt;/em&gt; on top of that.&lt;/p&gt;

&lt;p&gt;Originally I wanted to build a simple website where users could assemble their own subscription from a bunch of configs. But things got a little out of hand along the way — and what I ended up with instead was a standalone FastAPI service where you can build subscriptions out of individual configs &lt;em&gt;and&lt;/em&gt; out of other subscriptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What good is an API without a nice client?
&lt;/h2&gt;

&lt;p&gt;But what's an API without a comfortable library to actually use it? And if a user isn't going to self-host the whole API, why would they need admin tooling bundled in? So I split it into two libraries: &lt;strong&gt;v2hub&lt;/strong&gt; and &lt;strong&gt;v2hub-admin&lt;/strong&gt;. Both ship sync and async clients, pick your poison.&lt;/p&gt;

&lt;p&gt;And what about people who want to use the service but don't want to touch any code at all? That's where the &lt;strong&gt;CLI&lt;/strong&gt; comes in — built on Typer and Rich, so it actually looks nice while you're at it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth without the pain
&lt;/h2&gt;

&lt;p&gt;How do you keep spam and throwaway accounts under control without forcing users through some invasive sign-up flow — email verification, phone number, ID scan, the works? Enter Telegram. I built a bot that hands users a token they can use to access everything, and lets them reset that token whenever they want without breaking anything — because subscriptions are tied to an internal &lt;code&gt;user_hash&lt;/code&gt;, not the token itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  And then it grew a bit too much
&lt;/h2&gt;

&lt;p&gt;Eventually the service grew to the point where it wasn't just useful for developers anymore — regular people wanted in too. Which surfaced a new problem: regular people don't really care for CLIs, client libraries, or, god forbid, raw curl requests against an API.&lt;/p&gt;

&lt;p&gt;So the natural next step was a proper web panel — something people could just click through, no terminal required. That's how &lt;strong&gt;v2hub-panel&lt;/strong&gt; came to be.&lt;/p&gt;

&lt;p&gt;That's roughly how the V2Hub story started. Let's see where it goes from here.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you want to poke around:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Core API: &lt;a href="https://github.com/nestthub/v2hub-api" rel="noopener noreferrer"&gt;v2hub-api&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Web panel: &lt;a href="https://panel.v2hub.link" rel="noopener noreferrer"&gt;panel.v2hub.link&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Telegram bot: &lt;a href="https://t.me/v2hubot" rel="noopener noreferrer"&gt;t.me/v2hubot&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Libraries on PyPI: &lt;a href="https://pypi.org/project/v2hub" rel="noopener noreferrer"&gt;v2hub&lt;/a&gt; and &lt;a href="https://pypi.org/project/v2hub-admin" rel="noopener noreferrer"&gt;v2hub-admin&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;CLI: &lt;a href="https://pypi.org/project/v2hub-cli" rel="noopener noreferrer"&gt;v2hub-cli&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>python</category>
      <category>fastapi</category>
      <category>vpn</category>
    </item>
    <item>
      <title>V2Hub — An Ecosystem for Managing VPN Subscriptions (V2Ray/Xray/VLESS/VMess/Trojan/Hysteria2)</title>
      <dc:creator>nestt</dc:creator>
      <pubDate>Mon, 27 Jul 2026 16:21:05 +0000</pubDate>
      <link>https://dev.to/v2hub/v2hub-an-ecosystem-for-managing-vpn-subscriptions-v2rayxrayvlessvmesstrojanhysteria2-ln1</link>
      <guid>https://dev.to/v2hub/v2hub-an-ecosystem-for-managing-vpn-subscriptions-v2rayxrayvlessvmesstrojanhysteria2-ln1</guid>
      <description>&lt;h2&gt;
  
  
  Why this exists
&lt;/h2&gt;

&lt;p&gt;If you've ever handed out VPN configs or small subscription links to friends or clients manually, you know the pain: one provider goes down, another changes its address, a third needs to be temporarily hidden — and the end user is supposed to keep using a single, unchanging subscription URL that always resolves to the current list of servers. V2Hub is an attempt to solve this end-to-end: not just a proxy aggregator, but a full ecosystem — API, web panel, CLI, Telegram bot, and admin tooling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One clarification up front: this project does not generate VPN configs. If you're looking for how to set up a VPN server from scratch, check out vless.wiki. V2Hub is purely about managing subscriptions and configs you already have — aggregating them, hiding sources, annotating them, resolving nested references, and serving it all as one link.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The components
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Try it live&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;v2hub-api&lt;/td&gt;
&lt;td&gt;&lt;a href="https://v2hub.link" rel="noopener noreferrer"&gt;v2hub.link&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Core — FastAPI service that aggregates and resolves subscriptions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2hub-core&lt;/td&gt;
&lt;td&gt;&lt;a href="https://pypi.org/project/v2hub/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Python library with core methods for managing subscriptions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2hub-admin&lt;/td&gt;
&lt;td&gt;&lt;a href="https://pypi.org/project/v2hub-admin/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Add-on module providing admin functionality (HMAC auth, user CRUD)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2hub-cli&lt;/td&gt;
&lt;td&gt;&lt;a href="https://pypi.org/project/v2hub-cli/" rel="noopener noreferrer"&gt;PyPI&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Terminal client built with Typer and Rich&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2hub-panel&lt;/td&gt;
&lt;td&gt;&lt;a href="https://panel.v2hub.link" rel="noopener noreferrer"&gt;panel.v2hub.link&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Web panel for managing subscriptions (FastAPI + vanilla JS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;v2hub-bot&lt;/td&gt;
&lt;td&gt;&lt;a href="https://t.me/v2hubot" rel="noopener noreferrer"&gt;Telegram Bot&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Telegram bot for self-service subscription access&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The core — v2hub-api
&lt;/h2&gt;

&lt;p&gt;This is the most fleshed-out piece, so it's worth going into some detail.&lt;/p&gt;

&lt;p&gt;Multi-source aggregation. A subscription can pull configs from three kinds of sources at once: raw URIs (vless://, vmess://, trojan://, ss://, etc.), external subscription URLs from another provider, and internal references to other subscriptions inside the same system.&lt;/p&gt;

&lt;p&gt;Recursive resolution. If subscription A references subscription B, which references C, everything gets flattened into a single list by the time it reaches the client. There's circular-reference detection built in, plus a configurable nesting depth limit (max_depth, default 3).&lt;/p&gt;

&lt;p&gt;Per-source fine-tuning. Any source inside a subscription can be hidden from the resolved output (is_hidden) without deleting it, and annotated with its own comment.&lt;/p&gt;

&lt;p&gt;Two-tier caching. Redis as a fast L1 cache, PostgreSQL as the source of truth. A Celery worker refreshes external sources on a schedule (Celery beat, every 15 minutes), so resolution is almost always served from cache. Next up: replacing the periodic worker with lazy refresh, triggered right at request time instead.&lt;/p&gt;

&lt;p&gt;Admin-side security. Admin endpoints aren't protected by a plain token — they require an HMAC-SHA256 signature over the request (timestamp + method + path + body), plus an IP whitelist on top. There's also Redis-backed rate limiting per endpoint, with automatic IP bans once violations pile up.&lt;/p&gt;

&lt;p&gt;Core stack: FastAPI 0.136, SQLAlchemy 2.0 (async) + asyncpg, Pydantic 2.13, Celery 5.6, Alembic for migrations, Uvicorn + Nginx.&lt;/p&gt;

&lt;h2&gt;
  
  
  Panel, CLI, bot
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;v2hub-panel&lt;/strong&gt; is a minimal web UI for managing subscriptions and sources straight from the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;v2hub-cli&lt;/strong&gt; is built on Typer and Rich — you can create subscriptions, add sources, and run admin operations right from the terminal with nicely formatted output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;v2hub-bot&lt;/strong&gt; is a simple bot whose main job is issuing access tokens. It embeds v2hub-panel as a mini-app for extra convenience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python libraries on PyPI
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;v2hub&lt;/strong&gt; — a library that bundles everything an end user needs to work with subscriptions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;v2hub-admin&lt;/strong&gt; — an add-on to the core library that handles user CRUD, plus allow-lists and ban-lists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this might be useful for
&lt;/h2&gt;

&lt;p&gt;Anyone running a small VPN service for themselves, friends, or a small company, who wants a ready-made infrastructure with monitoring built in instead of hacking something together.&lt;br&gt;
Anyone curious what a genuinely "production-ready" FastAPI project looks like end to end — migrations, async ORM, HMAC auth, observability, CI/CD — regardless of the domain (VPN is more the excuse here than the point).&lt;br&gt;
Developers who want to see a working example of recursive resolution over nested entities with cycle protection — a pattern that's useful well beyond VPN tooling.&lt;br&gt;
Where this is headed&lt;/p&gt;

&lt;p&gt;If the project finds an audience and builds up a small community around it, we'll keep developing it. The long-term goal is for V2Hub to become a real alternative to Marzban API and 3x-ui for subscription management — something usable not just by hobbyists and small projects, but by full-fledged VPN companies too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ecosystem overview: &lt;a href="https://github.com/nestthub/nestthub/blob/main/ecosystems/v2hub/README.md" rel="noopener noreferrer"&gt;nestthub/nestthub — ecosystems/v2hub&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Core (API): &lt;a href="https://github.com/nestthub/v2hub-api" rel="noopener noreferrer"&gt;nestthub/v2hub-api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Shared logic: &lt;a href="https://github.com/nestthub/v2hub-core" rel="noopener noreferrer"&gt;nestthub/v2hub-core&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Web panel: &lt;a href="https://github.com/nestthub/v2hub-panel" rel="noopener noreferrer"&gt;nestthub/v2hub-panel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CLI: &lt;a href="https://github.com/nestthub/v2hub-cli" rel="noopener noreferrer"&gt;nestthub/v2hub-cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Admin module: &lt;a href="https://github.com/nestthub/v2hub-admin" rel="noopener noreferrer"&gt;nestthub/v2hub-admin&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Telegram bot: &lt;a href="https://github.com/nestthub/v2hub-bot" rel="noopener noreferrer"&gt;nestthub/v2hub-bot&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Licenses vary by repo (the API is Apache-2.0, the panel is GPL-3.0), so check the specific repo before using this commercially.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>python</category>
      <category>vpn</category>
      <category>fastapi</category>
    </item>
  </channel>
</rss>
