← Back to library
Panel Theory

Nodes and subscriptions: how the panel hands out access

Before you hook up a node and issue a subscription by hand, let's break down what happens in the process: how the panel delivers config to a node, how a subscription differs from a "link to a server," and why one URL can give two different answers. The practice is in the paired article.

Go to practice

This material covers the engineering of your own network infrastructure and is educational in nature. Complying with the laws of your own jurisdiction is on you.

The panel is the brain, the node is the muscle

Let me repeat the key separation, because everything rests on it: the panel doesn't push traffic. It stores state and hands out configs. Real client traffic flows through the nodes, where Xray runs.

Hence two independent flows that mustn't be confused:

  1. Panel → node — configuration delivery. The panel tells the node: "here are your inbounds, here are the keys, bring Xray up like this."
  2. Panel → client — subscription delivery. The panel tells the client: "here's the list of servers you're allowed to connect to."

The node and the client don't know about each other directly through the panel — the panel is the intermediary in both flows. Let's break down each.

How the panel delivers config to a node

When you register a node, the panel doesn't "log into it over SSH." The mechanic is different and smarter:

  • A lightweight agent (in a container) is installed on the node's server. It knows the panel's address and the secret key.
  • The agent itself connects to the panel and waits for config.
  • The panel, having authorized the node by its key, pushes the Xray JSON to it — that same Config Profile with the enabled inbounds.
  • The agent brings up Xray with this config. The node goes online.

The beauty is that the node is a stateless consumable. All the brains are on the panel. A node dies — you bring up a new one with the same key, the panel loads config onto it, and it takes its place in the ranks. Nothing to transfer by hand.

The node key (SECRET_KEY) is its only password to the panel. It's what the node uses to prove it belongs to you. If the key leaks — assume someone else can impersonate your node. So it lives only in the node's config and shows up nowhere else.

One profile per node, but with checkboxes

A subtlety that saves nerves. A node references exactly one Config Profile, but inside the profile you mark with checkboxes which inbounds are enabled on this specific node. That is, a profile can describe three transports (TCP, gRPC, XHTTP), while on a specific node you'll enable only the ones you need.

This lets you keep one tidy profile and lay it out onto nodes differently. One node — only TCP-Reality, another — all three transports. The profile is shared, the set of enabled ones differs.

What a subscription really is

Now the second flow. A subscription isn't a "link to a server" but a link to a list of servers that the panel assembles for a specific client.

When a client pastes a subscription into an app, the following happens:

  • The app goes to the subscription URL.
  • The panel checks which squads this client belongs to, which inbounds are available to them, which hosts are visible.
  • From the intersection it assembles a list of servers and hands it to the app.
  • The app shows the client this list — each visible host becomes a separate server.

Hence an important consequence for the operator: when you swap servers on your side, the client just needs to "Refresh subscription." You changed the nodes in the panel — the list on the client updated itself, nothing to paste again. That's the whole point of a subscription: a dynamic list, not a server entered once.

Why one URL — two answers

A trick that confuses people at first. The same subscription URL serves two different things:

  • Opened in a browser — you see a nice page with "add to app" buttons and a QR code.
  • Opened by an app — it gets the config (the list of servers).

The panel figures out who came by the request — by the headers. A browser asks for HTML — gets the page. An app asks for config — gets config. One address, two behaviors.

Moreover, the panel also picks the config format for the client — by its User-Agent. Different apps understand different formats (base64 list, xray-json, sing-box, mihomo). The panel hands each its own. That's a big topic of its own (Response Rules), but know the principle right away: a subscription is adaptive, it adjusts to whoever opened it.

Client-level settings

For each user the panel stores several parameters that define their access over time:

  • Expiry — the date until which the subscription is active.
  • Traffic limit — how many gigabytes can be spent (and the reset strategy: day/week/month/no-reset).
  • Device limit (HWID) — from how many devices they can connect. Against key sharing.
  • Squads — which plans they belong to.

These parameters are the levers of managing a client: extend the term, reset traffic, raise the device limit, add to the premium squad. All of it is done at the level of the user record, without touching the nodes.

Putting the picture together

So, handing out access is two flows through the panel:

  1. Config travels to the node by push: the agent connects, the panel loads the Xray JSON by key, the node brings up Xray.
  2. The subscription travels to the client on request: the panel assembles the server list from the intersection of squads, inbounds, and hosts, picks a format for the app, and serves it.

Got the mechanics? Go to the paired practice. There we connect a real node and issue our first live subscription step by step, with commands. You already know what happens under the hood, so the commands will land on understanding rather than faith.

Next guide Connecting a node and issuing your first subscription → Article unclear or something off? Message me and I will help or fix it. @notrealvpn →
This material is educational and covers network-infrastructure engineering. You are responsible for complying with the laws of your jurisdiction.