How to Add Custom Protocols to S-UI: A Complete Implementation Guide

To add custom protocols to S-UI, implement Sing-Box's Inbound and Outbound interfaces in a Go package, register it in core/register.go, and rebuild the binary.

S-UI is a web interface for the Sing-Box proxy library that requires protocol implementations to satisfy specific adapter interfaces. Adding custom protocols to S-UI involves creating a Go package that integrates with Sing-Box's registry system. This guide references the actual implementation patterns found in the alireza0/s-ui repository.

Understanding the Protocol Architecture

S-UI delegates all network protocol handling to the Sing-Box library. The application maintains a centralized registry in core/register.go where all inbound, outbound, and endpoint plugins hook into the system. This architecture allows developers to introduce new transport protocols without modifying the React frontend or database schemas, as the UI dynamically populates protocol dropdowns from this backend registry.

Step 1: Implement the Protocol Package

Create a new Go package that satisfies the Sing-Box Inbound and/or Outbound interfaces. Most custom protocols require both to handle traffic acceptance and routing.

Your package must expose two registration functions that follow the factory pattern used throughout Sing-Box:

  • RegisterInbound(registry *inbound.Registry) – Registers the protocol for accepting connections
  • RegisterOutbound(registry *outbound.Registry) – Registers the protocol for routing traffic

Study existing implementations in github.com/sagernet/sing-box/protocol/ as templates. The VMess protocol registration in core/register.go demonstrates the exact structure expected by the registry.

Step 2: Register in core/register.go

Open core/register.go, the central registry file where S-UI aggregates all protocol support.

Add an import for your new package:

import (
    // ... existing imports ...
    "github.com/yourname/sui-myproto"
)

Insert registration calls inside the appropriate factory functions. For inbound support, modify InboundRegistry():

func InboundRegistry() *inbound.Registry {
    registry := inbound.NewRegistry()
    // ... existing registrations ...
    myproto.RegisterInbound(registry)  // Add this line
    return registry
}

For outbound support, modify OutboundRegistry():

func OutboundRegistry() *outbound.Registry {
    registry := outbound.NewRegistry()
    // ... existing registrations ...
    myproto.RegisterOutbound(registry) // Add this line
    return registry
}

If your protocol requires custom endpoint logic (similar to WireGuard), also add the registration call inside EndpointRegistry() in the same file.

Step 3: Rebuild and Restart

Compile the modified source using the standard build script:

./build.sh

Alternatively, build manually:

go build -o sui main.go

Restart the S-UI service. The new protocol immediately appears in API responses and the web interface dropdowns without additional frontend changes.

Handling Custom Configuration Fields

S-UI stores outbound configurations as generic JSON. When creating outbounds via the API at /api/v2/outbounds, include custom fields in the request body:

curl -X POST http://localhost:2095/app/api/v2/inbounds \
  -H "Content-Type: application/json" \
  -d '{
        "tag": "my-inbound",
        "type": "myproto",
        "listen": "0.0.0.0",
        "listen_port": 12345,
        "settings": { "encryption": "aes-256-gcm" }
      }'

The backend persists these fields without requiring database schema migrations. You only need schema modifications if you intend to query specific protocol fields directly via SQL.

If your protocol uses a custom URL scheme (like vmess://), extend the subscription generator in sub/linkService.go. Modify the addClientInfo function to format your protocol's specific link syntax. Additionally, review util/genLink.go if you need to customize how subscription URLs are constructed and exported to clients.

Summary

  • S-UI relies on Sing-Box interfaces; protocols must implement Inbound and/or Outbound adapters.
  • Register new protocols in core/register.go by importing your package and calling RegisterInbound() and RegisterOutbound() inside the respective registry functions.
  • No frontend modifications are necessary—the UI dynamically reflects registered protocols from the backend.
  • Custom fields persist automatically as JSON; no database schema changes are required.
  • Rebuild the binary with ./build.sh to activate the protocol.

Frequently Asked Questions

Do I need to modify the S-UI frontend to add a new protocol?

No. The web interface dynamically queries the backend for available protocol types. Once registered in core/register.go and rebuilt, your protocol automatically populates the inbound and outbound dropdown menus in the settings panel.

What Sing-Box interfaces must my protocol implement?

Your package must satisfy the Inbound interface for accepting connections and the Outbound interface for routing traffic. These require implementing methods for adapter initialization, service startup, and graceful shutdown. Reference existing protocol implementations in the Sing-Box repository for exact method signatures.

Where are built-in protocols registered in S-UI?

Built-in protocols like VMess, Shadowsocks, and Trojan follow the same registration pattern in core/register.go. Examine the imports and registration calls in InboundRegistry() and OutboundRegistry() to see how native Sing-Box protocols hook into the system.

Can I use existing Sing-Box plugins instead of writing a new protocol?

Yes. If your desired protocol already exists as a Sing-Box plugin, simply import that package in core/register.go and call its RegisterInbound or RegisterOutbound functions. This approach requires no custom protocol code—only the registry import and rebuild steps.

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 →