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 whenmultiMode: 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(), andgetTunMultiStreamName()methods intransport/internet/grpc/config.gocontrol all name resolution. - The listener in
transport/internet/grpc/hub.gologs resolved names and registers RPC methods accordingly. - Combine with TLS via
security: tlsandtlsSettingsfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →