← Back to library
Panel Practice

Branding the subscription page for your service

The subscription page is the first thing the client sees. A clunky default page cuts trust and conversion. Below — how to stand up your own subscription domain, brand it, and turn on the flags that stop your key from being dragged off. Enter your own data in the builder above.

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.

What it is and why bother

The subscription page is the face of the service for the client. They open the link and either see a tidy page with "add to app" buttons and a QR, or their app silently pulls the config from it. The same URL can do both answers — the panel decides by the request.

By default the page is faceless. Branding it is worth it not for the looks: your own page with a logo and support contacts raises trust and conversion, and a couple of privacy flags stop the client from extracting and reselling your key. Let's go through it in order.

Your own subscription domain and path

We move the subscription onto a separate subdomain. It's set in the panel's .env, without the scheme (no https://):

.env
SUB_PUBLIC_DOMAIN=sub.your-domain.com
SHORT_UUID_LENGTH=48

Two things here work for security:

  • SHORT_UUID_LENGTH (16–64) — the length of the subscription's short identifier. Longer = harder to brute-force someone else's link. Set it toward the upper bound.
  • A non-standard path — change the default prefix to an arbitrary one (for example /s/ or /go/), so links can't be guessed by scanners.

After editing .env you need a full recreate — an ordinary restart doesn't re-read the variables:

bash
cd /opt/remnawave
docker compose down && docker compose up -d

By default the backend serves the subscription itself. A separate subscription-page container is needed only if you want your own custom/rebranded page — then the reverse proxy leads to it. Caddy for the subscription subdomain, if you're running a separate container:

Caddyfile
sub.your-domain.com {
    reverse_proxy * http://remnawave-subscription-page:3010
}

Branding: logo, colors, texts

In the subscription page editor (Subpage Editor) you set the service name, logo, colors, texts, and links to support and the channel. The logo and background are your own files, the contacts are your bot and channel. The key branding fields:

branding
{
  "brandingSettings": {
    "title": "BRANDNAME",
    "logoUrl": "https://your-domain.com/logo.svg",
    "supportUrl": "https://t.me/your_support_bot"
  },
  "metaTitle": "BRANDNAME"
}

Fill it with your own data — the page becomes "yours." The client sees not bare Remnawave but a service with a name and a face.

Privacy flags: don't let the key be dragged off

The main reason to dig into the page's app-config. Two flags that close off the most common leak:

app-config
{
  "showConnectionKeys": false,
  "hideGetLinkButton": true
}
  • showConnectionKeys: false — the client doesn't see the host's raw config (VLESS/Reality keys, SNI, address, port, shortId). Only the "add to app" buttons and QR. Why: the client can't pull out and resell your key as a standalone config, and the host's internals (donor, port, transport) don't show — less surface to copy your scheme.
  • hideGetLinkButton: true — the paired flag, removes the "get link" button so the subscription itself doesn't get dragged off either.

Both flags are direct revenue protection. Without them a technically savvy client yanks out the config and hands it to friends for free.

App buttons and QR

The page can serve deep-links to popular clients (Happ, Hiddify, v2rayTun, and others) — the client taps "Add to Happ" and the subscription imports in one tap. Plus a QR code for the phone. This sharply reduces the flood of "how do I connect" tickets.

In the app-config, clients are listed by platform with auto-import and step-by-step instructions. Placeholders like {{SUBSCRIPTION_LINK}} don't touch — the panel substitutes them for each user itself. Don't assemble the app-config by hand from scratch: take a ready template and change only the branding.

Applying it

The order is: Subscription-page → Subpage Editor → import app-config → paste the JSON → enter your own brandingSettings and metaTitle. After edits, in the client (for example, in Happ) it's better to delete and re-add the subscription, to reset the cache and pull the new look.

Hygiene

  • A long SHORT_UUID_LENGTH + a non-standard path — against brute-forcing other people's subscriptions.
  • The subscription is the only thing that shows publicly. From its address the panel and nodes can't be guessed: serve only host addresses, never flash the panel's address.
  • Privacy flags always on in production — this isn't an option but protection against free redistribution.

The page is branded and protected. Next in this section — fine-tuning hosts (how the panel assembles the client's link itself) and protecting the panel. And subscription formats for different apps are a separate topic, Response Rules, worth working through once clients on different apps start coming in.

Next guide Hosts and inbounds: how the panel assembles the client's link → 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.