2s-ui

command module
v1.7.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: GPL-3.0 Imports: 7 Imported by: 0

README

2S-UI

English · فارسی · Tiếng Việt · 简体中文 · 繁體中文 · Русский

2S-UI is an open-source management panel for sing-box. It gives you a clean, multilingual interface for deploying, configuring and monitoring a wide range of proxy and VPN protocols — from a single VPS to a multi-node deployment.

2S-UI began as a fork of s-ui. The frontend is rewritten in full, with a range of features added on top to make the panel nicer to use.

Docker Pulls Go Report Card Downloads License

Disclaimer: This project is only for personal learning and communication, please do not use it for illegal purposes, please do not use it in a production environment

Features

  • Multi-protocol — VLESS, VMess, Trojan, Shadowsocks, Hysteria2, TUIC, AnyTLS and more, inbound and outbound, plus WireGuard, WARP and Tailscale endpoints (full list).
  • Central TLS — Reality, uTLS fingerprints, XTLS, and certificates registered once then picked per inbound.
  • Routing rules — matching on domain, IP, port, protocol, process, user and rule-set, combined with and/or, with a separate rule list for DNS.
  • Client management — traffic quota, expiry date, IP limit, live online status, plus one-click share links, QR codes and subscriptions.
  • Traffic statistics — per inbound, per client and per outbound, with reset controls.
  • Subscriptionslink, json and clash formats, usage and expiry reported back to the client app, external links folded in.
  • Multi-node cluster — node health monitoring, users shared across nodes, every node's servers merged into one subscription (details).
  • Automatic HTTPS — Let's Encrypt issuance and renewal, plus an automatic nginx reverse proxy (details).
  • One-click updates — in-place upgrades from the panel, checksum-verified.
  • Rebuilt interface — a from-scratch frontend, hand-built components, dark and light themes, six languages including RTL.
Supported protocols
  • General: Mixed, SOCKS, HTTP/HTTPS, Direct, Tun, Redirect, TProxy
  • V2Ray based: VLESS, VMess, Trojan, Shadowsocks (incl. plugin / plugin_opts)
  • Other protocols: ShadowTLS, Hysteria, Hysteria2, Naive¹, TUIC, AnyTLS
  • Outbound only: Tor, SSH, Selector, URLTest
  • Endpoints: WireGuard, WARP, Tailscale — with a latency test per endpoint or for all at once
  • XTLS is supported, and Hysteria port hopping is available on the outbound form

1 Naive needs the cronet toolchain, which does not build everywhere: official Linux releases ship it on amd64, arm64, armv7 and 386 only. On armv6, armv5 and s390x a Naive outbound reports that the binary was built without it.

Languages

English · Farsi · Vietnamese · Chinese (Simplified) · Chinese (Traditional) · Russian

Supported platforms

Platform Architecture Status
Linux amd64, arm64, armv7, armv6, armv5, 386, s390x ✅ Supported
Windows amd64, 386, arm64 ✅ Supported
macOS amd64, arm64 🚧 Experimental

Screenshots

Other UI Screenshots

API Documentation

API-Documentation Wiki

Default Installation Information

Default
Panel port 2095, path /app/
Subscription port 2096, path /sub/
User / password admin / admin

Install

Linux/macOS
bash <(curl -Ls https://raw.githubusercontent.com/shenaba/2s-ui/main/install.sh)

The language follows $LANG, or pass en, fa, ru, vi, zhcn or zhtw:

SUI_LANG=zhcn bash <(curl -Ls https://raw.githubusercontent.com/shenaba/2s-ui/main/install.sh)
Alpine Linux

Alpine ships neither bash nor curl. Add them first; the installer then detects Alpine and sets the panel up as an OpenRC service:

apk add bash curl
bash <(curl -Ls https://raw.githubusercontent.com/shenaba/2s-ui/main/install.sh)
Windows
  1. Download the latest Windows release from GitHub Releases
  2. Extract the ZIP file
  3. Run install-windows.bat as Administrator
  4. Follow the installation wizard
  5. Access the panel at http://localhost:2095/app
Docker
mkdir 2s-ui && cd 2s-ui
wget -q https://raw.githubusercontent.com/shenaba/2s-ui/main/docker-compose.yml
docker compose up -d
Without compose, or building your own image

If Docker itself is not installed yet:

curl -fsSL https://get.docker.com | sh

Plain docker run:

mkdir 2s-ui && cd 2s-ui
docker run -itd \
    -p 2095:2095 -p 2096:2096 -p 443:443 \
    -v $PWD/db/:/app/db/ \
    -v $PWD/cert/:/root/cert/ \
    --name s-ui --restart=unless-stopped \
    ghcr.io/shenaba/2s-ui:latest

Build your own image:

git clone https://github.com/shenaba/2s-ui
docker build -t 2s-ui .
A specific version, manual installation, uninstall

A specific version. Add the version to the end of the installation command. e.g. v1.5.5:

VERSION=v1.5.5 && bash <(curl -Ls https://raw.githubusercontent.com/shenaba/2s-ui/$VERSION/install.sh) $VERSION

Manual installation — Linux/macOS

  1. Get the latest version of 2S-UI based on your OS/Architecture from GitHub: https://github.com/shenaba/2s-ui/releases/latest
  2. OPTIONAL Get the latest version of s-ui.sh https://raw.githubusercontent.com/shenaba/2s-ui/main/s-ui.sh
  3. OPTIONAL Copy s-ui.sh to /usr/bin/s-ui and run chmod +x /usr/bin/s-ui.
  4. Extract s-ui tar.gz file to a directory of your choice and navigate to the directory where you extracted the tar.gz file.
  5. Copy *.service files to /etc/systemd/system/ and run systemctl daemon-reload.
  6. Enable autostart and start 2S-UI service using systemctl enable s-ui --now
  7. Start sing-box service using systemctl enable sing-box --now

Manual installation — Windows

  1. Get the latest Windows version from GitHub: https://github.com/shenaba/2s-ui/releases/latest
  2. Download the appropriate Windows package (e.g., s-ui-windows-amd64.zip)
  3. Extract the ZIP file to a directory of your choice
  4. Run install-windows.bat as Administrator
  5. Follow the installation wizard
  6. Access the panel at http://localhost:2095/app

Uninstall — systemd

sudo -i

systemctl disable s-ui  --now

rm -f /etc/systemd/system/sing-box.service
systemctl daemon-reload

rm -fr /usr/local/s-ui
rm /usr/bin/s-ui

Uninstall — OpenRC (Alpine)

sudo -i

rc-service s-ui stop
rc-update del s-ui default
rm -f /etc/init.d/s-ui

rm -fr /usr/local/s-ui
rm /usr/bin/s-ui
Upgrading

New releases are flagged on the version pill in the sidebar — the check is client-side, so the panel host itself does not need to reach GitHub. On Linux (systemd or Docker) one click upgrades in place: the panel downloads the release, verifies it against the published SHA256SUMS, smoke-tests the new binary, then replaces it and restarts. No SSH.

A running .exe cannot replace itself, so on Windows the pill only links to the release page. In Docker the new binary lives in the container's writable layer: it survives docker restart, but recreating the container reverts to the image's version — pull a new image to make it stick.

Multi-Node Cluster

One panel can manage the others. Add a remote 2S-UI instance on the Nodes page with its address and an API token, and the master will:

  • Monitor it — a 5-second heartbeat reports each node as online, offline, or core-stopped (panel reachable but sing-box down).
  • Share users with it — clients on the master that reference a node's inbounds are pushed to that node and kept in sync, with each node's traffic folded back into the master's counters. Sync is scoped to a @cluster group, so a node's own local users are never touched.
  • Fold its servers into one subscription — a client's subscription link carries the master's servers and every bound node's servers together.

A node is just another 2S-UI instance talking over the v2 API (Token header): no agent to install, and the only node-side setup is creating that API token in its own panel, so existing panels can be adopted as they are. Inbounds adopted from a node become read-only replicas on the master — edit them on the node they belong to.

Driving node sync from the API

POST <panel path>apiv2/save (the panel path is /app/ by default, so /app/apiv2/save) triggers the web UI's immediate node fanout only when the request carries sync=true; without it, client/inbound changes still converge through the hourly reconcile safety net.

Domains & Certificates

Everything TLS lives in the Domains & Certificates tab of Panel Settings. Panel and subscription service each pick their own domain, and the certificate paths follow the domain you select — no file paths to copy around.

🔐 Automatic certificates (ACME / Let's Encrypt) — recommended. Enter a domain, add an email, and press issue: 2S-UI obtains and auto-renews a free Let's Encrypt certificate, and the panel becomes reachable at https://<your-domain>:2095/app. Requires TCP port 80 reachable from the internet (HTTP-01 challenge). ACME is Linux-only and is hidden on Windows.

How issuance works, and the Docker port-80 caveat

Issuance runs through acme.sh, which 2S-UI installs for you on first use (along with socat, needed for standalone validation) and registers for automatic renewal via acme.sh's own cron entry — there is nothing for you to schedule.

The validation method defaults to auto — standalone when port 80 is free, otherwise it borrows the running nginx, provisioning a minimal server_name block under /etc/nginx/conf.d if one is missing. Pick standalone or nginx explicitly if you would rather decide. Renewals hot-reload the certificate; no restart needed.

To publish port 80 with Docker: uncomment the 80:80 line in docker-compose.yml, or add -p 80:80 to docker run. Certificates are stored under /root/cert/<domain>/ as fullchain.pem / privkey.pem and survive restarts (the Docker volume above maps that path out). If the domain/port is misconfigured, 2S-UI falls back to HTTP.

Bring your own certificate

Certificates you manage yourself — a Cloudflare origin CA, a corporate CA, certbot output — can be registered in the same tab. 2S-UI verifies the files are readable, that the key matches the certificate, and that the certificate really covers the domain; the domain then becomes selectable on the Interface and Subscription tabs like any other. Registered certificates are included in database backups.

To issue one by hand with Certbot:

snap install core; snap refresh core
snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot

certbot certonly --standalone --register-unsafely-without-email --non-interactive --agree-tos -d <Your Domain Name>

Then register the resulting fullchain.pem / privkey.pem under Domains & Certificates.

Behind a reverse proxy

Turn on TLS terminated by a reverse proxy and 2S-UI writes the vhost for you: /etc/nginx/conf.d/s-ui-proxy-<domain>.conf, pointed at the panel with the right forwarding headers, checked with nginx -t, reloaded, and rolled back with nginx's own error message if anything fails. The subscription server can sit behind the same proxy.

Contributing

See CONTRIBUTING.md for development setup, coding conventions, testing, and the pull request process.

Building and running from source
git clone https://github.com/shenaba/2s-ui
cd 2s-ui
./runSUI.sh

build.sh builds the frontend, copies it into web/html/ for //go:embed, and builds the binary with the required build tags; runSUI.sh runs it on top of that. Building by hand needs those same tags — see CONTRIBUTING.md.

Environment variables
Variable Type Default
SUI_LOG_LEVEL "debug" | "info" | "warn" | "error" "info"
SUI_DEBUG boolean false
SUI_DB_FOLDER string "db"
SUI_BIN_FOLDER string "bin"

SUI_BIN_FOLDER is only read while migrating a database from the old subprocess-based layout; sing-box is embedded in the binary and there is no bin/ folder at runtime.

Special Thanks

Stargazers over Time

Star History Chart

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
cmd
protocol/anytls
Verbatim copy of sing-box protocol/anytls/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
Verbatim copy of sing-box protocol/anytls/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
protocol/hysteria
Verbatim copy of sing-box protocol/hysteria/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
Verbatim copy of sing-box protocol/hysteria/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
protocol/hysteria2
Verbatim copy of sing-box protocol/hysteria2/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
Verbatim copy of sing-box protocol/hysteria2/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
protocol/trojan
Verbatim copy of sing-box protocol/trojan/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
Verbatim copy of sing-box protocol/trojan/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
protocol/tuic
Verbatim copy of sing-box protocol/tuic/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
Verbatim copy of sing-box protocol/tuic/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
protocol/vless
Verbatim copy of sing-box protocol/vless/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
Verbatim copy of sing-box protocol/vless/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
protocol/vmess
Verbatim copy of sing-box protocol/vmess/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.
Verbatim copy of sing-box protocol/vmess/inbound.go, moved into this module so the panel can reach the unexported `service`/`users` fields that the sing-box Inbound type does not expose.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL