How the s-ui Subscription Service Generates and Encodes Client Links

The s-ui subscription service retrieves client records from the database, generates protocol-specific proxy links using LinkGenerator, assembles them into a newline-delimited payload, and optionally Base64-encodes the result before returning it with traffic usage headers.

The subscription mechanism in the alireza0/s-ui proxy management panel dynamically produces client configuration links for protocols including VMess, VLESS, Trojan, and Shadowsocks. Understanding exactly how this subscription service generates and encodes client links enables administrators to troubleshoot connectivity issues, optimize delivery formats, and customize client information displays.

Core Implementation Files

The subscription pipeline spans three primary components that handle orchestration, link resolution, and protocol-specific URI construction.

sub/subService.go - Subscription Orchestration

The entry point resides in sub/subService.go, where SubService.GetSubs (lines 20-44) coordinates the entire workflow. This function retrieves the client record, delegates link generation, assembles the final payload, and applies optional encoding before returning the result with HTTP headers.

The LinkService struct in sub/linkService.go handles the parsing and resolution logic through GetLinks (lines 11-18). It unmarshals the JSON-encoded link storage from the client model, processes external URLs, resolves nested subscription references, and optionally prepends client information to each link.

util/genLink.go - Protocol URI Generation

Raw protocol links are constructed in util/genLink.go via the LinkGenerator function. This utility builds standardized URIs for VMess, VLESS, Trojan, Shadowsocks, and other supported protocols, incorporating TLS settings, reality parameters, and transport configurations through helper functions like prepareTls, getTransportParams, and getTlsParams.

The subscription service executes a six-stage pipeline when processing a client request:

  1. Client Retrieval – The getClientBySubId function (lines 47-55 in sub/subService.go) queries the database for the Client model matching the provided subscription identifier.

  2. Statistics Compilation – If the global Show Sub Info setting is enabled, getClientInfo (lines 62-76) formats traffic-remaining statistics, expiry dates, and usage metrics into a display string.

  3. Link ResolutionLinkService.GetLinks unmarshals the client.Links JSON array and processes each entry:

    • Returns raw external URLs directly when type=="external"
    • Resolves nested subscription links via util.GetExternalLink and splits the fetched content by lines
    • Processes local links by passing them through addClientInfo to append the optional statistics string
  4. Protocol Construction – For local links, the system invokes util.LinkGenerator in util/genLink.go to construct protocol-specific URIs from inbound definitions, client configurations, and domain settings.

  5. Payload Assembly – The resulting slice of link strings is joined with newline characters ("\n") at lines 34-36 of sub/subService.go.

  6. Encoding and Headers – If the Sub Encode setting is true, the entire payload undergoes Base64 encoding using base64.StdEncoding.EncodeToString (lines 39-43). Simultaneously, getClientHeaders invokes util.GetHeaders (defined in util/outJson.go) to generate the Subscription-Userinfo header containing traffic statistics and update intervals.

Base64 Encoding and Transport Headers

Two optional formatting layers modify the final delivery format.

Optional Base64 Encoding

When the administrator enables the global Sub Encode configuration, the subscription service encodes the newline-delimited link list using Go's standard base64 library. This transformation occurs immediately before the function returns, ensuring that clients receive either plain text or encoded content based on their subscription client compatibility.

Subscription-Userinfo Headers

The getClientHeaders function (lines 57-60) produces standardized HTTP headers that communicate metadata to compatible clients. These headers include traffic usage statistics, remaining bandwidth quotas, and recommended update intervals parsed from the client's database record.

Practical Implementation Examples

The following examples demonstrate common interactions with the subscription generation system.

Fetching a Subscription for a Client

subService := &sub.SubService{}
payload, headers, err := subService.GetSubs("my-client-id")
if err != nil {
    // handle error
}
fmt.Println("Headers:", headers)
fmt.Println("Payload:")
fmt.Println(*payload) // Base64-encoded if the setting is on
// Assume inbound and clientConfig are already loaded from DB
links := util.LinkGenerator(clientConfig, inbound, "example.com")
for _, l := range links {
    fmt.Println(l) // e.g. vmess://eyJ2IjoiMiIsIn...
}
uri := "vmess://eyJ2IjoiMiIsIn..."
clientInfo := " 📊1.23GB 10Days"
finalURI := sub.LinkService{}.addClientInfo(uri, clientInfo)
// finalURI becomes "...#my‑remark 📊1.23GB 10Days"

Summary

  • The subscription flow originates in sub/subService.go where GetSubs orchestrates the entire generation pipeline.
  • Client records are retrieved via getClientBySubId and optionally enhanced with usage statistics through getClientInfo.
  • LinkService.GetLinks processes stored JSON link configurations, handling external URLs, nested subscriptions, and local protocol links.
  • Protocol-specific URIs are constructed in util/genLink.go using LinkGenerator, which incorporates TLS, reality, and transport parameters.
  • The final payload is assembled with newline delimiters and optionally Base64-encoded based on the Sub Encode global setting.
  • Traffic metadata is delivered via the Subscription-Userinfo header generated by util.GetHeaders.

Frequently Asked Questions

When processing stored links with type=="external", the LinkService in sub/linkService.go returns the raw URL directly or fetches referenced subscriptions via util.GetExternalLink, splitting the downloaded content into individual lines for inclusion in the final payload.

What proxy protocols does the LinkGenerator support?

The util.LinkGenerator function in util/genLink.go constructs standardized subscription URIs for VMess, VLESS, Trojan, Shadowsocks, and other protocols supported by the s-ui panel, automatically appending TLS, reality, and transport-specific parameters based on the inbound configuration.

When does the subscription service apply Base64 encoding?

Base64 encoding occurs in sub/subService.go (lines 39-43) only when the administrator enables the global Sub Encode setting, transforming the newline-delimited link list using base64.StdEncoding.EncodeToString before returning the payload to the client.

The system stores subscription link configurations as JSON-encoded arrays in the Links field of the Client database model. The LinkService.GetLinks method unmarshals this data in sub/linkService.go (lines 11-18) to process each link type according to its specific resolution requirements.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →