Releases: shenaba/2s-ui
Release list
v1.6.2
Bug Fixes
Reverse proxy #80
The TLS terminated by reverse proxy switch is usable again, and can no longer take down what it is protecting.
- Switching it on failed on every install that had used the feature before the vhost was renamed — the old file collided with the new one on 443, and every retry replayed it. Both prefixes are swept now
- Switching it off deadlocked: the vhost was deleted before the save that travelled over it, leaving the vhost gone and the setting unsaved. That cleanup now runs after the restart
- Changing the panel's path or domain while the proxy is on no longer moves the nginx
locationout from under the request still in flight - Three ways a working vhost got destroyed are closed: a duplicate
server_nameon:80misread as a 443 conflict, an enabled side with no domain skipped silently, and a failed settings read at startup reconciling as "disabled" - The settings page reports drift between nginx and the saved settings on load, and ACME HTTP-01 validation no longer mistakes the proxy's 443-only vhost for a
:80block
Panel URI vs. panel path #80
Panel URI only decides where the redirect goes after a restart; the path the panel actually serves comes from Panel Path. Editing the former to move the panel sent the user to a 404 with no way back, since the only page that could undo it was the one that no longer loaded. Both are now refused at save time, with nothing written, and the same guard covers Subscription URI, where a mismatch is silent — the panel keeps working while every client stops updating.
Frontend #77
- Recovering from a failed chunk load returned to the route being left instead of the one that was clicked
out/OutTLScrashed on an entity with notlskey- Dates ignored the language switch until reload; seven render sites pointed at i18n keys that do not exist
- Build assets are named by content hash instead of a per-build id, so
Cache-Control: max-age=31536000stops serving stale bundles across releases
Enhancements
- First paint is roughly half the payload — the single 2.1 MB chunk is split, and the unused
wofffallback is dropped from the font CSS #77 - The
in/andout/form duplicates (Dial, Multiplex, Listen, Transport, Headers, Network, UoT) are merged, andDnsServerDrawerreuses them #77
Chores
- Every GitHub Action is pinned to a commit SHA, and dependabot updates are grouped into one PR per ecosystem #71
- Release and Windows builds no longer run the full matrix twice on a merge-then-publish #74
- Dependency bumps: frontend group (11) #73, gomod group (2) #72,
sing-vmess#70,docker/login-action#76
Full Changelog: v1.6.1...v1.6.2
v1.6.1
Enhancements
- Automatic nginx reverse proxy with a new Domains & Certificates tab — generate and manage vhosts and certificates straight from the panel, key each vhost by its domain, and optionally put the sub server behind the proxy too #68
Bug Fixes
- Complete the
actions.*i18n keys across all six locales, so success toasts and the Changes audit log no longer render raw keys such asactions.reconcileNodeinto the UI #69 (fixes #66) - Drop the duplicate success toast on node reconcile / adopt — the shared response handler already shows one, so the hand-rolled component toast was firing a second time #69
- Fall back to the raw action name when an
actions.*key is missing (matchingHome.vue), so a future unkeyed action degrades to a plain name instead of leaking theactions.prefix #69
Full Changelog: v1.6.0...v1.6.1
v1.6.0
Two large subsystems land in this release — cluster management and one-click ACME. Both are shipping for the first time here and have not had a real-world shakedown yet. Back up your db/ folder before upgrading, and read the two warnings below.
⚠️ Before you upgrade
Downgrading is one-way once you have adopted a cluster node. Older binaries don't know the node_id column. Roll a database that contains adopted replicas back to 1.5.x and the old binary hands the remote node's ports to its own local core, putting the panel into a ~15s restart loop. De-adopt every node before downgrading.
If your panel already has webNginx set, check its scheme after upgrading. Earlier versions turned webNginx on automatically whenever nginx was detected on the host, so some installs carry the flag without ever having chosen it. Those panels keep serving plain HTTP after the upgrade, and in reverse-proxy mode the certificate-path inputs are hidden — so a stale value cannot be cleared from the UI. If that locks you out, SSH in and run UPDATE settings SET value='false' WHERE key='webNginx'; against the panel database, then restart. While diagnosing, don't rely on sui uri — it was reworked in this release — check ss -lntp and curl -I directly.
Cluster management #29 #53
Run several 2S-UI panels from one master. A node is just another full 2S-UI install: the master drives it through the node's existing apiv2 with a Token header, so nodes need no agent and no upgrade — older versions can be adopted as they are.
- 5s heartbeat monitoring for every node
- Adopt a node's inbounds into the master, which then holds the single authoritative ledger for users
- Shared clients across nodes, with node traffic reconciled back into the master's ledger by baseline diffing, plus cluster-wide quota and enable/disable
- Node routes are aggregated into the master's subscription as
[node name] tagentries - Deleting a node that still has live replicas is refused — de-adopt first
One-click ACME certificates #55
Issue a certificate from the panel with the validation method picked automatically — standalone, or an nginx block when a reverse proxy fronts the panel — and an automatic proxy reload on renewal.
sui urinow reports the configured panel URI and the subscription address, and no longer claimshttpsfor a panel that a proxy fronts- Standalone validation binds IPv6 on v6-only hosts
- Failures name the actual cause — missing
conf.d, denied:80— instead of failing generically - ACME is hidden on Windows, where it does not apply
Enhancements #61
- Latency test for endpoints, one at a time or all at once
- Enable or disable a client straight from the client list
- Hysteria port hopping on the outbound form
- Shadowsocks
pluginandplugin_optssupport - The panel reports the server OS
Bug Fixes
- Editing one user no longer disconnects every other user on the same inbound. Users are now updated in place instead of rebuilding the listener, which used to destroy the QUIC session for anytls, hysteria, hysteria2, tuic, vless, vmess and trojan #60
- Rework Clash proxy-group assembly and ws headers, emit
max-early-data, and stop aliasing the default group slice #59 - Carry ws early data into generated share links #59
- Omit a disabled
tlsblock from the core config #59 - Keep the ACME section visible when it is already configured #61
v1.5.7
Bug Fixes
- Strip server-only TLS fields (
certificate_path,key,acme) from client-facing configs — a leakedcertificate_pathmade sing-box clients fail outright on per-domain TLS, with a migration to clean existing rows #52 - Stop the self-update modal spinning forever after a successful update — it now reloads into the new version and times out after 120s instead #44
Enhancements
- Check for a new release on every page load instead of caching the result for 24h #44
Dependencies
v1.5.6
This release brings in-panel self-update, inlines the frontend into the main repository, and refreshes the whole frontend dependency stack. No database migration is required.
Upgrading from v1.5.5 is a manual install — self-update ships in this release, so 1.5.5 panels do not have it yet. From v1.5.6-alpha.1, the in-panel updater will offer this build.
Features
- In-panel self-update. Check, download and apply a new panel release from the dashboard — no shell, no
s-ui update. The archive is verified against the releaseSHA256SUMSbefore the running binary is replaced, and the panel restarts itself on success. #30 - Self-update works in Docker too, not just on systemd hosts. The container path swaps the binary in the writable layer and re-execs the entrypoint; the confirm dialog spells out that recreating the container reverts it. #30
- Update surfacing in the UI: a sidebar version pill with an update popover (manual re-check included), and an update-available chip on the dashboard server card. The GitHub release lookup runs from the browser and is cached for 24h, so the panel host never needs outbound access. #30
Bug Fixes
- Fix
ERESOLVEon everynpm installbuild path (release, Windows, Docker,build.sh) after the pinia 4 bump — vue-router 5.0.7 declaredpeerOptional pinia@^3.0.4. Bumped to vue-router 5.2.0, which widens the range to^3.0.4 || ^4.0.2. #39 - The documented legacy-install command now works. The README example passed
VERSION=1.0.0— novprefix, and a tag that never existed in this repo.install.shinterpolates the argument verbatim into both theraw.githubusercontent.comref and the release download URL, and every tag here isvX.Y.Z, so both 404'd. Corrected across all six locales. #41 install.shno longer printss-ui vv1.5.6. It kept a v-prefixed tag in one code path and a bare version in the other, while every message hardcoded its ownv. The prefix is now normalised, so both1.5.6andv1.5.6work as the version argument. #41- Drop an API dedup interceptor that never actually ran. #30
Frontend
- New
VersionMenupopover andUpdateModal, backed by a dedicatedversionstore; update strings added across all six locales (en / fa / vi / ru / zh-CN / zh-TW). #30 - Dependency refresh: pinia 4.0.2, vue-router 5.2.0, vite 8.1.4, axios 1.18.1, vue-i18n 11.4.6, eslint 10.7.0, vue-tsc 3.3.7, @vitejs/plugin-vue 6.0.8, typescript-eslint 8.64.0, @types/node 26.1.1, globals 17.7.0.
@vue/devtools-apiis now declared explicitly. pinia 4 requires it as a non-optional peer, and until now it resolved only because vue-router happens to depend on it directly — the range was inherited rather than owned. #41- form-data 4.0.6, up from 4.0.5 (GHSA-hmw2-7cc7-3qxx). Hygiene rather than a security fix: it reaches the tree through axios but never shipped — the browser build uses the native
FormData, and the Node adapter that imports the package is tree-shaken out. The bundle is byte-identical before and after. #41
Maintenance
- The frontend is now inlined under
frontend/. It used to be a submodule (shenaba/2s-ui-frontend); a plaingit clonenow gives you the whole tree, with nosubmodule update --init. Build scripts and docs are rewired accordingly. #33 - CI now runs
go vet, a tagged Go build, andvue-tsc+vite buildon every pull request. #31 - Bump
golang.org/x/cryptoto 0.54.0,actions/setup-nodeto v7.
Full changelog: v1.5.5...v1.5.6
v1.5.6-alpha.1
This is a pre-release.
v1.5.5stays the stable Latest. GitHub'sreleases/latestAPI excludes pre-releases, and that is the endpoint both the in-panel updater and the dashboard update check read — so panels running 1.5.5 are not offered this build and will not pull it. Install it deliberately, or wait forv1.5.6.
Enhancements
- In-panel self-update. Check, download and apply a new panel release from the dashboard — no shell, no
s-ui update. The archive is verified against the releaseSHA256SUMSbefore the running binary is replaced, and the panel restarts itself on success. #30 - Self-update works in Docker too, not just on systemd hosts. The container path swaps the binary in the writable layer and re-execs the entrypoint; the confirm dialog spells out that recreating the container reverts it. #30
- Update surfacing in the UI: a sidebar version pill with an update popover (manual re-check included), and an update-available chip on the dashboard server card. The GitHub release lookup runs from the browser and is cached for 24h, so the panel host never needs outbound access. #30
Frontend
- New
VersionMenupopover andUpdateModal, backed by a dedicatedversionstore; update strings added across all six locales (en / fa / vi / ru / zh-CN / zh-TW). #30 - Dependency refresh: pinia 4.0.2, vue-router 5.2.0, vite 8.1.4, axios 1.18.1, vue-i18n 11.4.6, eslint 10.7.0, vue-tsc 3.3.7, @vitejs/plugin-vue 6.0.8, typescript-eslint 8.64.0, @types/node 26.1.1, globals 17.7.0.
Bug Fixes
- Fix
ERESOLVEon everynpm installbuild path (release, Windows, Docker,build.sh) after the pinia 4 bump — vue-router 5.0.7 declaredpeerOptional pinia@^3.0.4. Bumped to vue-router 5.2.0, which widens the range to^3.0.4 || ^4.0.2. #39 - Drop an API dedup interceptor that never actually ran. #30
Maintenance
- The frontend is now inlined under
frontend/. It used to be a submodule (shenaba/2s-ui-frontend); a plaingit clonenow gives you the whole tree, with nosubmodule update --init. Build scripts and docs are rewired accordingly. #33 - CI now runs
go vet, a tagged Go build, andvue-tsc+vite buildon every pull request. #31 - Bump
golang.org/x/cryptoto 0.54.0,actions/setup-nodeto v7.
Full changelog: v1.5.5...v1.5.6-alpha.1
v1.5.5
This release brings full parity with upstream s-ui v1.5.3, an update notice on the dashboard, a six-language management script, and a round of dependency updates. No database migration is required.
Features
- Update-available notice on the dashboard. The server card shows an amber chip when a newer 2s-ui release is out, linking straight to the release page. The check runs in your browser against the GitHub API (no server egress), is cached for 24 hours, and stays silent when GitHub is unreachable.
- Optional Clash default groups (upstream #1155): a new setting skips injecting the default
Proxy/Autoproxy-groups so fully custom configs stay untouched, and a case-insensitiveallentry inside a custom proxy-group expands to every generated proxy tag. Both toggles live in Settings → Subscription → Clash. - Management script in six languages:
s-ui.shnow speaks English, 简体中文, 繁體中文, Русский, فارسی and Tiếng Việt — same coverage as the panel. The language menu always lists languages by their native names so anyone can find their way back.
Fixes
- Timezones no longer depend on OS data (upstream #1166): the timezone database is embedded in the binary; the installer and Docker image no longer need the OS tzdata package.
- Share-link certificate pin key follows each protocol's convention (upstream #1093 follow-up):
pinSHA256on Hysteria/Hysteria2 links,pcson Xray-based protocols — matching what the client apps actually parse. - Dev-only: the dashboard demo data (API mock) works again when the backend isn't running behind the Vite proxy.
Dependencies
- golang.org/x/crypto 0.53.0 — ships a batch of SSH security fixes (ssh/agent constraint handling,
@revokedknown-hosts keys, channel-handling DoS issues) relevant to the embedded sing-box SSH outbound. bcrypt, used for panel passwords, is unchanged. - gopsutil 4.26.6 (system-stats bugfixes) and certmagic 0.25.4 (memory-leak and handshake-waiter fixes on the ACME path).
- CI: actions/checkout v7 and actions/cache v6.
v1.5.4
This release syncs everything from upstream s-ui v1.5.0 through v1.5.2 into 2s-ui, on top of our own fixes. Full parity with upstream v1.5.2, plus a few corrections upstream doesn't have yet.
Security
- Panel passwords are now stored as bcrypt hashes instead of plaintext (upstream #1159). Existing databases are migrated automatically; passwords keep working unchanged.
s-ui admin -showno longer prints the password — uses-ui admin -username <user> -password <pass>to set a new one. - SQL injection fix in the changes-log query (upstream #1131).
- Unknown-SNI TLS handshakes are rejected when a panel/sub domain is configured with manual certificates. If you connect by raw IP over HTTPS, either use the domain or leave the domain setting empty.
- Dependency security updates: sing-box v1.13.14, golang.org/x/crypto and friends.
Features (from upstream v1.5.0–v1.5.2)
- External JSON subscriptions with connection timeout and optional default routing rules.
- Client enhancements: creation time and remark fields, improved bulk add.
- Reset all clients' traffic — manual API and scheduled (
globalResetcron setting); re-enables depleted clients and restarts the core. - TLS certificate hot reload for panel and subscription servers — renewed certificates are picked up without a restart.
- Automatic SHA256 pinning for self-signed certificates, applied to configs and share links (with back-fill migration).
- CLI backup command:
s-ui backup -output <file|-> [-exclude changes,stats]. - Configurable traffic sampling (
statsBucketSeconds) with deduplicated storage. getCertPingAPI returns the leaf certificate SPKI hash of a remote TLS endpoint.- Subscription improvements: Content-Disposition filename, Clash default groups only injected when referenced, TUIC
udp_relay_modeon links.
Fixes
- VLESS over plain TCP+TLS keeps
flow: xtls-rprx-visionin generated Clash/JSON configs (upstream #1156). - Share links carry the correct certificate pin: hex fingerprint under the standard
pinSHA256key. (Upstream v1.5.2 emits this under apcskey that clients don't recognize — we kept the standard name.) getCertPinghardening over upstream: no crash on CN-only certificates (no SANs), and the probe connection is closed properly.- External subscriptions with no outbounds now return a real error instead of silently succeeding with empty data.
- Traffic chart adapts its resolution to the stored bucket size, so raising the sampling interval can't blank the dashboard charts (upstream #1150).
- h3 ALPN in Clash subs, Clash sub headers, WARP connection timeout, stricter VLESS flow validation (upstream v1.5.0).
Upgrade notes
- Docker: migrations run automatically via the entrypoint. Nothing to do.
- Bare-metal (systemd): run
s-ui migrateonce after upgrading. Without it, plaintext passwords are still upgraded lazily on each successful login, but the self-signed-certificate pin back-fill only runs through the migration. - The stats table is deduplicated and gains a unique index on first start after the upgrade; on very large databases the first start may take a little longer.
v1.5.3
Fixes
- Docker — published images could not start (#24):
entrypoint.shwas tracked in git without the execute bit and both Dockerfiles copied it verbatim, so images shipped/app/entrypoint.shas non-executable and the exec-formENTRYPOINTfailed with permission denied. The script is now tracked as executable and both Dockerfiles useCOPY --chmod=755, so containers from GHCR / Docker Hub start normally with the stockdocker-compose.yml. - Dashboard — Network throughput chart losing its right margin (#15): a bare
1frgrid track mins atauto, so the fixed-width SVG that ECharts renders could widen its own column; the chart then re-measured against the inflated width and never shrank back, and the card's overflow clipping left the plot hugging the card's right edge. Chart grid columns are now floored at 0 (minmax(0, 1fr)), including the narrow-viewport breakpoints.
v1.5.2
Features
- Certificates — Force Renew: added a Force Renew button next to Issue Certificate that runs
acme.sh --issue --force, so you can renew early even when the domain still has a valid, not-yet-expiring certificate (which acme.sh otherwise skips). A confirmation dialog warns that--forcecounts against Let's Encrypt's duplicate-certificate rate limit (~5/week). - Clients — redesigned dialog & page: the client dialog now folds Inbounds & Limits into a wider, two-column General tab (UUID/password and Links stay as separate tabs); inbound selection is a compact multi-select dropdown; new clients default to a 30-day auto-reset period. The page is retitled User Management.
Fixes
- Dashboard — charts overflowing their card (#15): toggling a dashboard tile (e.g. hiding Traffic then showing it again) shrank a neighbouring chart's column, but the ECharts SVG kept its widened size and spilled past the card border. Charts now re-measure on the next animation frame using their container's explicit width/height, and dashboard cards clip overflow as a hard backstop.