en

Marzban Panel on a VPS: Multi-User Xray Management, Self-Hosted

Marzban is an open-source web panel that turns one Xray-core install into a multi-user proxy service. Instead of hand-editing JSON for every person, you create users in a dashboard, hand each one a subscription link, and the panel enforces per-user traffic quotas and expiry dates automatically. This guide covers a real production install on an offshore VPS: how Marzban sits on top of Xray, how to generate VLESS+Reality users at scale, how subscription links and quotas actually work, and how to harden the panel so the admin interface never becomes the thing that gets your IP probed and blocked.

Need this done for your project?

We implement, you ship. Async, documented, done in days.

Start a Brief

What Marzban is and when you actually need it

Xray-core by itself is a single binary driven by a static config.json. That is perfectly fine for one or two users: you add a UUID to the clients array, restart the service, and you are done. The model breaks down the moment you have to manage many people. Adding or revoking a user means editing JSON by hand and restarting Xray, there is no way to set a 100 GB monthly cap or a 30-day expiry, and you have no idea who consumed what. Marzban exists to solve exactly that gap.

Marzban is a management layer written in Python (FastAPI) that drives Xray-core through its gRPC API. You never touch config.json for day-to-day work. Instead you define your inbounds once, then create, suspend, reset, and delete users from a web dashboard or REST API. For each user Marzban tracks live upload/download counters, enforces a data-limit quota, enforces an expiry date, and exposes a single subscription URL that any compatible client app can import. When a user crosses their quota or expiry, Marzban disables them in Xray automatically without you logging in.

You want Marzban when any of the following is true:

  • You provision proxy access for more than a handful of people - family, a team, a small community, or paying users - and need self-service subscription links rather than copy-pasting configs.
  • You need to meter usage: monthly data caps, time-limited trials, or per-user expiry that turns access off on its own.
  • You run several protocols at once (VLESS+Reality, VMess, Trojan, Shadowsocks) and want every user to receive all of them in one subscription so their client picks whatever passes the censor that day.

If you only need a single private endpoint for yourself, you do not need a panel at all - a plain Xray or sing-box install on an offshore VPS is lighter and has a smaller attack surface. Marzban earns its keep specifically when the user count and the need to meter justify a management plane.

Installing Marzban on an offshore VPS

Marzban runs comfortably on a modest VPS. For dozens of users a 1 vCPU / 1 GB RAM box is enough, since the heavy lifting is done by Xray-core, not the panel; the bottleneck you actually hit first is network throughput, not CPU. An AnubizHost Romania VPS from $19.99/mo is a sensible starting point, and you can scale the instance up later without rebuilding. The reason to run a panel like this on an offshore VPS rather than a mainstream cloud provider is control: you want full root, a clean IP that is not on shared-abuse lists, and a provider that will not hand over your panel on a casual request.

Provision a Debian 11/12 or Ubuntu 22.04 instance, then SSH in as root and update it (apt update && apt upgrade -y). The maintained install script sets up Marzban, its SQLite database, Xray-core, and a systemd-managed Docker stack in one step:

sudo bash -c "$(curl -sL https://github.com/Gozargah/Marzban-scripts/raw/master/marzban.sh)" @ install

When it finishes, create the first admin (the panel ships with no default credentials, which is deliberate):

marzban cli admin create --sudo

By default the dashboard listens on port 8000 over plain HTTP, which you must not leave exposed. Two safe patterns:

  • Reverse proxy with TLS. Put Nginx or Caddy in front, terminate HTTPS with a real certificate on a hostname, and proxy to 127.0.0.1:8000. Set UVICORN_HOST=127.0.0.1 in /opt/marzban/.env so the panel never binds the public interface directly.
  • No public panel at all. Keep UVICORN_HOST=127.0.0.1 and reach the dashboard only through an SSH tunnel (ssh -L 8000:127.0.0.1:8000 root@your-vps), then browse http://127.0.0.1:8000 locally. This exposes zero admin surface to the internet and is the stronger choice for a single operator.

Configure your Xray inbounds in /opt/marzban/xray_config.json (or via the dashboard's config editor). Marzban's role is to inject per-user credentials into these inbounds at runtime, so you define the transports - for example a VLESS+Reality inbound on 443 - once, and every user you create inherits them.

Creating users, subscription links and traffic quotas

With inbounds defined, adding a user is a few fields in the dashboard: a username, which inbounds/protocols they get, a data limit, and an expiry. Marzban generates the UUID/password, pushes the credential into the live Xray config over gRPC (no restart, no downtime for existing users), and produces a single subscription URL for that user.

That subscription link is the whole point of the panel. It looks like https://your-host/sub/<token> and, when opened by a client app, returns the user's full set of configs - every protocol and inbound you assigned them - in one import. The user pastes one URL into v2rayN, NekoBox, Hiddify, sing-box, Streisand or Shadowrocket and gets all their nodes at once. Crucially, the client re-fetches the subscription periodically, so when you rotate a Reality key, change the dest, or add a new inbound, every user's app updates on its next refresh without you sending anything. You manage the fleet; they never edit a config.

Metering works on two independent dimensions, and you can use either or both:

  • Data limit. Set a byte quota (for example 100 GB). Marzban accumulates the user's live upload+download from Xray's stats API and, when the quota is reached, disables the user. With a reset strategy of monthly the counter zeroes on schedule so the cap renews each cycle; no_reset makes it a hard one-time allowance.
  • Expiry. Set an absolute expiry date, or use on-hold users whose timer only starts counting from first connection - ideal for trials or prepaid access that should not burn down while unused.

Status flows automatically: active users pass traffic; limited (quota hit) and expired (date passed) users are disabled in Xray on the spot; disabled is a manual suspension you control. Everything is also available over the REST API and via the official Telegram bot integration, so you can wire user creation into a billing flow or let users check their own remaining quota in chat. For a community of any size this is the difference between a sustainable service and a spreadsheet.

Hardening the panel and the node

A management panel is a liability if it is reachable and fingerprintable. The single most common way a Marzban deployment gets discovered and blocked is an exposed admin interface on a guessable port serving a self-signed or freshly issued certificate on the same IP that is supposed to look like an innocent host. Treat the panel and the proxy as two separate trust zones.

  • Never expose the dashboard on the proxy's IP at port 443. If port 443 is running VLESS+Reality, it must look like the borrowed site and nothing else. Run the panel behind a separate hostname/port, or keep it bound to localhost and reach it only over SSH. A panel login page on the same IP as your Reality endpoint hands a censor the anomaly that Reality was meant to erase.
  • Lock down the panel. Strong unique admin password, TLS in front of it, and an IP allowlist on the panel port if you have a stable management IP (a staff VPN or jump host). Do not rely on obscurity alone.
  • Harden the host. Key-only SSH on a non-standard port, fail2ban, a default-deny inbound firewall that opens only the proxy port(s) and your management path, and automatic security updates. The goal is that an external scan of the VPS sees only a clean, real-looking TLS 1.3 handshake from the proxy inbound.
  • Back up the database. Marzban keeps users, quotas and tokens in its database (SQLite by default, or MySQL/MariaDB for larger fleets). Snapshot /opt/marzban and the DB regularly; losing it means reissuing every subscription link.
  • Use Marzban-node for scale and separation. Marzban can drive remote Xray nodes (Marzban-node) over a control connection, letting you keep the panel on one host and run the actual exit traffic on separate clean IPs. This isolates the management plane from the IPs that face the censor, so a blocked node never takes the panel with it, and you can rotate exit IPs without rebuilding users.

The discipline mirrors single-user stealth hosting: a consistent, real-looking inbound on 443, a silent server, and the admin surface kept entirely out of the censor's view. What a panel adds is the operational reality that you now have a control plane worth protecting in its own right. Running it on a clean offshore IP with full root removes the two weak points that matter most - a shared or pre-flagged IP, and a provider that might cooperate with disclosure requests. For a busy multi-user fleet, an offshore dedicated server gives the throughput and IP headroom to run the panel plus several Marzban-node exits; for getting started or a single-node setup, an offshore VPS is the right fit.

Privacy & anti-censorship guides

Why Anubiz Host

100% async — no calls, no meetings
Delivered in days, not weeks
Full documentation included
Production-grade from day one
Security-first approach
Post-delivery support included

Ready to get started?

Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.

Anubiz Chat AI

Online
Marzban Panel on a VPS: Multi-User Xray Setup | Anubiz Host