How to Configure gRPC Transport in Xray-core with Custom Service Names

To configure gRPC transport in Xray-core with custom service names, set the serviceName field in grpcSettings—use a plain string for classic mode or a slash-prefixed path with pipe-separated stream names for hierarchical services.

Xray-core implements gRPC as a native Internet transport, with configuration parsing in transport/internet/grpc/config.go and listener implementation in transport/internet/grpc/hub.go. The serviceName field supports two distinct modes: simple strings for standard deployments and custom hierarchical paths for advanced multi-service configurations.

Understanding gRPC Service Name Parsing in Xray-core

The Config struct in transport/internet/grpc/config.go provides three key methods that determine how your serviceName value is interpreted:

Method Purpose Source Location
getServiceName() Returns the registered gRPC service name, with URL-escaping for simple names or path-component extraction for slash-prefixed values config.go lines 17-34
getTunStreamName() Determines the Tun stream name—defaults to "Tun" for classic configs, or extracts the segment after the last / (respecting | separators) config.go lines 36-44
getTunMultiStreamName() Determines the TunMulti stream name—uses the second component after | splitting on the server side config.go lines 46-58

Slash-prefixed vs. plain service names

When serviceName does not start with /, Xray-core treats it as a simple identifier. The value is URL-escaped and used directly as the service name, with "Tun" as the default stream name.

When serviceName starts with /, Xray-core interprets it as a hierarchical path. The path components (everything between the first and last /) become the service name, while segments after the final /—split by |—determine custom stream names for Tun and TunMulti RPCs.

Classic gRPC Configuration (Simple Service Name)

For most deployments, use a plain string without leading slashes. This creates a standard gRPC service with default stream naming.

Client configuration

inbounds:
  - port: 1080
    protocol: socks
    settings:
      auth: noauth
    streamSettings:
      network: grpc
      grpcSettings:
        serviceName: myservice
        multiMode: false

Server configuration

inbounds:
  - port: 2080
    protocol: vmess
    settings:
      clients:
        - id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    streamSettings:
      network: grpc
      grpcSettings:
        serviceName: myservice
        multiMode: false

Internal behavior: The getServiceName() method returns "myservice" (URL-escaped). getTunStreamName() returns "Tun". No TunMulti stream is registered when multiMode: false.

Custom Hierarchical Service Names with Multiple Streams

Advanced deployments can use slash-prefixed paths to specify custom service hierarchies and distinct stream names for Tun and TunMulti RPCs.

Configuration with custom stream names


# Client configuration

inbounds:
  - port: 1080
    protocol: socks
    streamSettings:
      network: grpc
      grpcSettings:
        serviceName: "/myapp/api/v1|tunnel|multistream"
        multiMode: true

# Server configuration

inbounds:
  - port: 2080
    protocol: vmess
    settings:
      clients:
        - id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    streamSettings:
      network: grpc
      grpcSettings:
        serviceName: "/myapp/api/v1|tunnel|multistream"
        multiMode: true

How Xray-core parses this value

Component Resolved Value Source Method
Service name myapp/api/v1 getServiceName()
Tun stream name tunnel getTunStreamName()
TunMulti stream name multistream getTunMultiStreamName()

The listener in transport/internet/grpc/hub.go logs these resolved names at line 27-29 and registers two RPC methods:

  • /myapp/api/v1/tunnel — handles single-stream connections
  • /myapp/api/v1/multistream — handles multiplexed connections when multiMode: true

Enabling TLS with Custom gRPC Service Names

Production deployments should wrap gRPC in TLS. The TLS configuration is processed in transport/internet/tls/ and passed to the gRPC server via grpc.Creds().

TLS-enabled server configuration

inbounds:
  - port: 443
    protocol: vmess
    settings:
      clients:
        - id: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
    streamSettings:
      network: grpc
      security: tls
      tlsSettings:
        alpn: ["h2"]
        certificates:
          - certificateFile: /path/to/cert.pem
            keyFile: /path/to/key.pem
      grpcSettings:
        serviceName: "/secure/service|secureTun|secureMulti"
        multiMode: true

Internally, tls.ConfigFromStreamSettings() in the TLS package constructs a tls.Config, which the hub passes to credentials.NewTLS() at hub.go lines 80-85.

Key Source Files for gRPC Transport

File Purpose Direct Link
transport/internet/grpc/config.go Config struct with getServiceName(), getTunStreamName(), getTunMultiStreamName() config.go
transport/internet/grpc/hub.go gRPC listener, server creation, service registration, TLS integration hub.go
transport/internet/grpc/config.pb.go Protobuf-generated configuration types config.pb.go
transport/internet/tls/*.go TLS configuration utilities tls package
transport/internet/grpc/encoding/*.go Generated gRPC service stubs encoding package

Summary

  • Plain service names (no leading /) create standard gRPC services with default "Tun" stream naming—use for simple deployments.
  • Slash-prefixed paths enable hierarchical service names and custom Tun/TunMulti stream names, split by | delimiters.
  • The getServiceName(), getTunStreamName(), and getTunMultiStreamName() methods in transport/internet/grpc/config.go control all name resolution.
  • The listener in transport/internet/grpc/hub.go logs resolved names and registers RPC methods accordingly.
  • Combine with TLS via security: tls and tlsSettings for production use.

Frequently Asked Questions

What happens if I omit the leading slash in serviceName?

Without a leading /, Xray-core treats serviceName as a simple identifier. The value is URL-escaped and used directly as the service name, and getTunStreamName() returns the default "Tun". This is the classic mode suitable for most basic deployments.

Can I use custom stream names without multiMode enabled?

Yes, but the custom TunMulti stream name will only be used when multiMode: true. With multiMode: false, Xray-core registers only the Tun stream. The pipe-separated syntax still parses correctly—the unused TunMulti name is simply ignored during service registration in hub.go.

How do I verify my custom service names are registered correctly?

Check the Xray-core logs at debug level. The listener in transport/internet/grpc/hub.go logs the resolved service name and stream names at line 27-29:


gRPC listen for service name `myapp/api/v1` tun `tunnel` multi tun `multistream`

If these values match your intended configuration, the gRPC service is registered correctly.

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 →