1133 Commits
Author SHA1 Message Date
風雪 914053a7ac fix(i18n): declare listeners.httpHint and socksHint in zh-CN 2026-10-10 00:56:56 +08:00
風雪 d0f115011f fix(i18n): declare listeners.httpHint and socksHint in en 2026-10-10 00:56:55 +08:00
風雪 89ca102a25 fix(i18n): add zh-CN httpHint/socksHint for HTTP and SOCKS 2026-10-10 00:56:27 +08:00
風雪 6102c33f57 fix(i18n): add listeners.httpHint and socksHint for CI 2026-10-10 00:56:26 +08:00
風雪 97a445d5a1 fix(ui): restore ListenerConfigFields; optional TLS for HTTP/SOCKS 2026-10-10 00:45:18 +08:00
風雪 5d4430de0e fix(ui): restore ListenerConfigFields and enable HTTP/SOCKS optional TLS 2026-10-09 23:47:13 +08:00
風雪 d59b46a215 fix(ui): expose optional TLS form for HTTP and SOCKS listeners 2026-10-09 23:43:54 +08:00
風雪 5bb47282a0 Delete scripts/tests/test_ssh_menu.sh 2026-10-09 00:40:49 +08:00
風雪 c6cf289228 fix(scripts): make SSH menu config access indentation-agnostic (#101)
* fix(scripts): make SSH menu config access indentation-agnostic

Running the panel built from source exposed two defects that static review
could not see, because both depend on what the Go binary actually writes to
config.yaml.

The Go binary rewrites config.yaml through a YAML marshaller. `init` emits
two-space indentation, but any later rewrite — notably `reset-config`, the SSH
rescue path — emits four, and re-sorts the keys. Every shell helper matched on
a hardcoded two-space prefix, so the menu and the binary disagreed about the
file's shape.

1. Duplicate keys after an SSH rescue

After `reset-config`, `yaml_get '  port:'` matched nothing, so the menu showed
an empty current port. `yaml_set` then took its insert branch and appended a
two-space `port:` line alongside the marshaller's four-space one:

    server:
        mode: release
        port: 8080
        sub_port: 0
      port: 9090          <- inserted, duplicate

The menu then reported "Configured port: 9090" and restarted the service. The
failure mode matters more than the diff: SSH rescue is what an operator reaches
for when the panel is unreachable, which is exactly when the menu has to work.

2. `3m-ui config port <port>` left the panel unable to boot

That command hardcoded a two-space indent, producing mixed indentation inside
one block:

    server:
        mode: release
      port: 19090
        public_url: ""

The binary then refuses to start at all:

    failed to decode config YAML: yaml: line 12: did not find expected key

This command is documented in the README, so following the documentation
bricks the panel.

Both are fixed the same way: key lookup is now indentation-agnostic (matched
on $1 rather than a fixed prefix, which also removes any ambiguity between
`port:` and `sub_port:`), replacement preserves the indentation of the line it
rewrites, and insertion adopts the block's existing indent. Callers pass
"port:" instead of "  port:".

Also fixed: menu item 17 (Healthcheck) produced no output at all, because the
binary's healthcheck exits 0 silently on success. It now reports pass/fail
based on the exit status.

Verified against a panel compiled from source and running on loopback:
rescue -> change port -> restart yields a single `port:` key with consistent
indentation, config stays 0600, the panel serves HTTP 200, and the healthcheck
item reports OK. The regression script (scripts regression, 16 cases) covers
both defects by reproducing them against the old implementation first.

* fix(scripts): make SSH menu config access indentation-agnostic

Running the panel built from source exposed two defects that static review
could not see, because both depend on what the Go binary actually writes to
config.yaml.

The Go binary rewrites config.yaml through a YAML marshaller. `init` emits
two-space indentation, but any later rewrite — notably `reset-config`, the SSH
rescue path — emits four, and re-sorts the keys. Every shell helper matched on
a hardcoded two-space prefix, so the menu and the binary disagreed about the
file's shape.

1. Duplicate keys after an SSH rescue

After `reset-config`, `yaml_get '  port:'` matched nothing, so the menu showed
an empty current port. `yaml_set` then took its insert branch and appended a
two-space `port:` line alongside the marshaller's four-space one:

    server:
        mode: release
        port: 8080
        sub_port: 0
      port: 9090          <- inserted, duplicate

The menu then reported "Configured port: 9090" and restarted the service. The
failure mode matters more than the diff: SSH rescue is what an operator reaches
for when the panel is unreachable, which is exactly when the menu has to work.

2. `3m-ui config port <port>` left the panel unable to boot

That command hardcoded a two-space indent, producing mixed indentation inside
one block:

    server:
        mode: release
      port: 19090
        public_url: ""

The binary then refuses to start at all:

    failed to decode config YAML: yaml: line 12: did not find expected key

This command is documented in the README, so following the documentation
bricks the panel.

Both are fixed the same way: key lookup is now indentation-agnostic (matched
on $1 rather than a fixed prefix, which also removes any ambiguity between
`port:` and `sub_port:`), replacement preserves the indentation of the line it
rewrites, and insertion adopts the block's existing indent. Callers pass
"port:" instead of "  port:".

Also fixed: menu item 17 (Healthcheck) produced no output at all, because the
binary's healthcheck exits 0 silently on success. It now reports pass/fail
based on the exit status.

Verified against a panel compiled from source and running on loopback:
rescue -> change port -> restart yields a single `port:` key with consistent
indentation, config stays 0600, the panel serves HTTP 200, and the healthcheck
item reports OK. The regression script (scripts regression, 16 cases) covers
both defects by reproducing them against the old implementation first.

* test(scripts): add regression coverage for the SSH menu config helpers

The existing lifecycle tests exercise install.sh end to end but never touch
the menu's config read/write path, which is where both defects in the previous
commit lived. This adds 16 cases.

Each case runs the pre-fix implementation and the fixed one against the same
input and asserts both directions: the old one must reproduce the defect, the
new one must not exhibit it. A case whose "before" assertion passes is scored
FAIL — otherwise the suite could go green without ever having exercised the
bug.

Covers: block-scoped writes, 0600 preservation, `config port` with a missing
argument, the self-referencing entrypoint loop, insertion placement, missing
`server:` block, indentation-agnostic lookup, and indentation consistency.

The suite is self-contained: it needs no installed panel, writes only to a
temp dir, and the one case that touches /usr/local/bin/3m-ui skips itself if
that path already exists.
2026-10-09 00:39:10 +08:00
風雪 84eab7750c fix(scripts): scope SSH menu config writes to the server: block (#100)
* fix(scripts): scope SSH menu config writes to the server: block

The SSH management menu edited /etc/3m-ui/config.yaml with a global sed
substitution, which rewrote every identically-indented key in the file rather
than just the panel's. Changing the panel port therefore also rewrote unrelated
listener ports, and because the menu restarts the service right afterwards the
corruption went live immediately.

The same code path wrote the new file with `mv`, so a 0600 config holding the
JWT and credential-encryption keys came back as a umask-default 0644 file,
readable by every local user after any port or path change.

Both are fixed by scoping reads/writes to the `server:` block and by writing
back through the original inode (`cat > file`) instead of replacing it.

Three further defects found while auditing the menu:

- scripts/3m-ui.sh: `config port` read a bare "$2" under `set -u`, so running
  it without an argument aborted with "parameter not set" and the usage
  message below it was unreachable. Now "${2:-}".
- scripts/3m-ui.sh: the no-arg branch exec'd /usr/local/bin/3m-ui without
  checking whether it resolves back to this script, which spun in an endless
  exec loop on a broken entrypoint. Direct and indirect self-reference are now
  detected and reported with an actionable message.
- scripts/3m-ui: `enable_bbr` wrote into /etc/sysctl.d without creating it; on
  minimal/container images the redirect failed and `set -e` tore down the whole
  interactive menu. Now mkdir -p with a guarded failure.

Hardening and consistency:

- yaml_set reports an error instead of silently no-oping when neither the key
  nor a `server:` block exists; the menu no longer restarts the service for a
  change that never happened.
- yaml_get is scoped to the `server:` block so it matches yaml_set.
- temp files come from mktemp (0600) instead of a predictable .$$ name.
- open_firewall asks for confirmation before opening 22/80/443.
- status reports boot-time enablement on OpenRC, not only systemd.
- menu item 8 reports invalid input instead of returning silently.
- menu item 23 is relabelled: it updates all of 3m-ui, not only the script.
- the acme.sh helper is annotated as an example to review before running.

Verified locally: the listener port is left untouched when the panel port
changes, config mode stays 0600, `config port` with no argument prints usage,
the self-referencing entrypoint fails fast instead of looping, and both files
pass `sh -n`.

* fix(scripts): scope SSH menu config writes to the server: block

The SSH management menu edited /etc/3m-ui/config.yaml with a global sed
substitution, which rewrote every identically-indented key in the file rather
than just the panel's. Changing the panel port therefore also rewrote unrelated
listener ports, and because the menu restarts the service right afterwards the
corruption went live immediately.

The same code path wrote the new file with `mv`, so a 0600 config holding the
JWT and credential-encryption keys came back as a umask-default 0644 file,
readable by every local user after any port or path change.

Both are fixed by scoping reads/writes to the `server:` block and by writing
back through the original inode (`cat > file`) instead of replacing it.

Three further defects found while auditing the menu:

- scripts/3m-ui.sh: `config port` read a bare "$2" under `set -u`, so running
  it without an argument aborted with "parameter not set" and the usage
  message below it was unreachable. Now "${2:-}".
- scripts/3m-ui.sh: the no-arg branch exec'd /usr/local/bin/3m-ui without
  checking whether it resolves back to this script, which spun in an endless
  exec loop on a broken entrypoint. Direct and indirect self-reference are now
  detected and reported with an actionable message.
- scripts/3m-ui: `enable_bbr` wrote into /etc/sysctl.d without creating it; on
  minimal/container images the redirect failed and `set -e` tore down the whole
  interactive menu. Now mkdir -p with a guarded failure.

Hardening and consistency:

- yaml_set reports an error instead of silently no-oping when neither the key
  nor a `server:` block exists; the menu no longer restarts the service for a
  change that never happened.
- yaml_get is scoped to the `server:` block so it matches yaml_set.
- temp files come from mktemp (0600) instead of a predictable .$$ name.
- open_firewall asks for confirmation before opening 22/80/443.
- status reports boot-time enablement on OpenRC, not only systemd.
- menu item 8 reports invalid input instead of returning silently.
- menu item 23 is relabelled: it updates all of 3m-ui, not only the script.
- the acme.sh helper is annotated as an example to review before running.

Verified locally: the listener port is left untouched when the panel port
changes, config mode stays 0600, `config port` with no argument prints usage,
the self-referencing entrypoint fails fast instead of looping, and both files
pass `sh -n`.
2026-10-08 23:49:39 +08:00
kazeyukiro a534463c18 test(listener): allow HTTP/SOCKS; keep excluding tun/tproxy/mixed 2026-10-07 16:47:54 +00:00
kazeyukiro a46b3b010b feat(listener): HTTP/SOCKS inbounds with client share and Clash proxies
Re-apply on post-theme baseline (52e848a): schema, compile modules,
http:// and socks5:// share URIs, and client subscription YAML
(type: http / socks5). Fixes gofmt for CI.
2026-10-07 16:42:27 +00:00
kazeyukiro 52e848ae82 fix(i18n): put dashboard metric keys inside dashboard section 2026-10-07 02:16:54 +00:00
kazeyukiro cc632bd62b fix(i18n): ensure common.total is declared 2026-10-07 01:50:49 +00:00
kazeyukiro c306d1bd7e fix(i18n): add common.value and common.total for dashboard tables 2026-10-07 01:50:25 +00:00
kazeyukiro d43f57c3b1 fix(i18n): add missing comma before dashboard metric keys 2026-10-07 01:46:57 +00:00
kazeyukiro 6e0b20c1ae feat(ui): restyle dashboard after m-ui observability layout 2026-10-07 01:42:52 +00:00
kazeyukiro b63dad2992 fix(shadowquic): require jls-upstream.addr so Mihomo -t succeeds
Empty/missing jls-upstream caused whole config reload to fail and left
new listeners stuck as config_not_applied. Autofill defaults and ensure
addr/sni when compiling shadowquic listeners.
2026-10-06 01:46:45 +00:00
kazeyukiro 0a00487291 fix(sub): apply tfo/mptcp only to TCP outbound types 2026-10-06 01:15:32 +00:00
kazeyukiro 6126381e6c fix(config): persist clientTfo/clientMptcp in visual-config
yaml:"-" dropped the subscription dial flags on save so UI switches
reset after refresh. Store as client-tfo/client-mptcp and strip them
when merging the visual fragment into the serving Mihomo YAML.
2026-10-06 01:12:25 +00:00
kazeyukiro 94473c9356 fix(i18n): remove duplicate config.inboundTfoHint keys 2026-10-06 00:48:33 +00:00
kazeyukiro 2554b4dbaf fix(ui): tidy general kernel settings layout on Config page 2026-10-06 00:44:57 +00:00
kazeyukiro 29da3acda7 fix(sub): stamp client tfo/mptcp on subscription nodes 2026-10-06 00:38:37 +00:00
kazeyukiro 325f603420 fix(docs): restore openapi.yaml after accidental truncate 2026-10-05 15:27:19 +00:00
kazeyukiro b787cd9fda fix(config): separate server inbound dial flags from client proxy tfo/mptcp
- Remove mode from Config general settings UI
- Client proxies only emit wiki tfo/mptcp booleans; strip inbound-* and
  other server-only keys from subscription YAML
- OpenAPI SSL engine notes match current acmez stack
2026-10-05 15:26:56 +00:00
kazeyukiro 04d637f817 docs(api): document visual TFO/MPTCP and certmagic SSL engine
OpenAPI: GET/POST /config/visual with inboundTfo/inboundMptcp and
per-proxy tfo/mptcp; SSL notes use certmagic instead of autocert/acmez.
2026-10-05 15:10:39 +00:00
7099315eb1 feat(proxy): expose per-proxy tfo / mptcp (#97)
* feat(proxy): expose per-proxy tfo / mptcp (TCP Fast Open / Multipath TCP)

Add Mihomo's proxy-level `tfo` and `mptcp` options (wiki.metacubex.one/config/proxies)
to the panel so clients can opt into TCP Fast Open / Multipath TCP on a per-node basis.

Mapping accuracy:
- These are PROXY-level keys, distinct from the global `inbound-tfo` / `inbound-mptcp`
  general switches. They travel through ProxyEntry.Options (the same catch-all that already
  feeds both the serving config and the client subscription document), so they surface in
  BOTH the server mihomo config and the generated client subscription config — no field is
  lost or misrouted.

Frontend (web + mobile share the same Config page / responsive Modal):
- Proxy editor gains TFO (TCP Fast Open) and MPTCP (Multipath TCP) switches.
- An info note states they only take effect on TCP transports.
- Modal body becomes scrollable on phones (maxHeight 78vh) so the added rows stay reachable
  on small screens; width/top already adapt via useIsMobile.

i18n: zh-CN / en strings for proxyTfo, proxyMptcp, proxyTcpOnly.

Tests:
- config: tfo/mptcp serialize into proxy YAML and round-trip; absent stays absent, explicit
  false is preserved.
- converter: client subscription document preserves tfo/mptcp from visual proxies.

* fix(i18n): add missing commas after proxy TFO/MPTCP keys

---------

Co-authored-by: 3m-ui dev <dev@local>
Co-authored-by: kazeyukiro <kazeyukiro@users.noreply.github.com>
2026-10-05 22:18:50 +08:00
d26b7e1534 feat(config): add inbound-tfo / inbound-mptcp global kernel settings (#96)
* feat(config): add inbound-tfo / inbound-mptcp global kernel settings

Expose Mihomo's top-level `inbound-tfo` and `inbound-mptcp` general keys
(TCP Fast Open / Multipath TCP applied to every inbound listener socket) in
the panel. These are GLOBAL switches, not per-listener fields, so they are
carried on VisualConfig — the same struct that feeds the serving Mihomo
config fragment — and never copied into client subscription documents.

Backend:
- VisualConfig gains InboundTfo / InboundMPTCP (json inboundTfo/inboundMptcp,
  yaml inbound-tfo/inbound-mptcp), matching Mihomo's exact key names.
- MihomoConfig gains the same keys (omitempty) for schema completeness.
- GenerateFinalConfig already merges the visual-config fragment over the
  template (only listeners/rules/proxies/groups are stripped), so the keys
  surface in the serving config exactly as Mihomo expects.

Frontend:
- Config page gains a 'General' card (mode, log level, allow-lan, ipv6,
  inbound-tfo, inbound-mptcp) loaded from /config/visual and saved via
  POST /config/visual. The full VisualConfig is preserved on save so existing
  proxies/groups/rules/DNS are not clobbered.
- i18n zh-CN / en strings added.

Tests:
- config package tests assert inbound-tfo / inbound-mptcp appear as `true`
  in GenerateFinalConfig output when enabled and never become `true` when off.

* fix: gofmt visual.go; type saveVisualConfig payload as VisualConfig

---------

Co-authored-by: 3m-ui dev <dev@local>
Co-authored-by: kazeyukiro <kazeyukiro@users.noreply.github.com>
2026-10-05 22:16:49 +08:00
風雪and3m-ui dev 9b1d243dc5 fix(ui): stop the port field from showing the required error twice (#95)
The port Form.Item had both a `required` rule and a custom validator
that rejected on empty with the same message. AntD renders every failed
rule, so an empty port produced the identical "Port is required"
message twice.

Let `required` own the empty case and have the validator only check the
format (returning early on empty). Add `whitespace: true` so a
spaces-only value still counts as empty.

Co-authored-by: 3m-ui dev <dev@local>
2026-10-05 20:06:25 +08:00
風雪and風雪 2ac3714619 fix(config): also let TCP+UDP coexist on the same port at generate time (#94)
PR #91 made the creation-time guards (ensureEndpointAvailable,
ensureBatchEndpointsAvailable) transport-aware so a TCP listener and a UDP
listener can share an address:port. But the third copy of the conflict check
inside Mihomo config generation — validateListenerEndpoints in
internal/mihomo/config/generator.go — was left untouched. So a TCP+UDP pair
that creation now permits was still rejected when the panel regenerated the
Mihomo config, surfacing as:

  warning: Mihomo config generate after listener change failed: ...
  listeners "节点2" and "节点5" have conflicting bind address/port ranges
  (0.0.0.0:16201 and 0.0.0.0:16201)

Make validateListenerEndpoints reuse protocol.ListenerTransports and only flag
a conflict when the two listeners share an L4 transport, matching the
creation-time guard. Same-protocol pairs on the same address:port still
conflict.

Tests:
- TestValidateListenerEndpointsAllowsTCPandUDPOnSamePort
- TestValidateListenerEndpointsRejectsTwoTCPOnSamePort
- TestValidateListenerEndpointsRejectsTwoUDPOnSamePort

Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com>
2026-10-05 19:09:18 +08:00
風雪and風雪 d73613387d fix(backup): snapshot the live DB with VACUUM INTO instead of a racy file copy (#92)
The in-app "Download backup" button exported the SQLite file with a plain
`os.Open` + `io.Copy` while the panel's GORM pool was still open and writing.
That copy races with concurrent writes (torn pages) and, even after the prior
WAL checkpoint, could leave committed frames in -wal that the copy never
replayed — an inconsistent or partially-lost backup.

Replace the checkpoint + file copy with SQLite's online backup primitive
VACUUM INTO, which reads through the WAL and in-flight transactions to produce
a self-contained, fully-replayed snapshot without stopping the panel.

Also stop bundling 3m-ui.db-wal / 3m-ui.db-shm into the zip. The VACUUM INTO
result is already complete (WAL merged in), so the sidecars were dead weight —
and they were never restored on import anyway, which silently dropped
un-checkpointed writes on restore.

Tests:
- TestWriteZipSnapshotIsConsistentAndSelfContained: a WAL-mode db with 200 rows
  held open by a live connection; WriteZip produces a zip whose 3m-ui.db opens
  standalone with all 200 rows and contains no -wal/-shm entries.
- go vet + go test -tags sqlite_modernc ./... green.

Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com>
2026-10-05 17:17:27 +08:00
風雪and風雪 f18419da8b fix(listener): allow TCP and UDP listeners to share a port (#91)
The endpoint conflict guard in ensureEndpointAvailable (and its batch
counterpart ensureBatchEndpointsAvailable) compared only port ranges and
bind addresses — it never looked at the L4 protocol. A TCP listener on
443 and a UDP listener on 443 are independent sockets at the OS level and
Mihomo serves both fine, but 3m-ui rejected the second one with
"conflicts on 0.0.0.0:443". So you could not run e.g. VLESS (TCP) and
TUIC/Hysteria2 (UDP) on the same port.

Add protocol.ListenerTransports, which maps a listener's protocol kind to
the L4 transport(s) its inbound binds (UDP for tuic / hysteria /
hysteria2 / shadowquic / mieru; TCP for everything else). The proxy `udp`
toggle is UDP relay over an established connection and is intentionally
ignored — it does not open a UDP listening socket. The conflict check now
also requires the two listeners to share an L4 transport, so a TCP+UDP
pair on the same address:port no longer collides while two TCP or two UDP
listeners still do.

Tests:
- protocol.ListenerTransports unit tests (udp/tcp/case-insensitive).
- listener.listenersShareTransport unit tests.
- End-to-end: a TCP+UDP pair on 443 coexists and the UDP listener stays on
  443 through Create (it is not silently reassigned to a free port), while
  two TCP or two UDP on 443 still conflict.

Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com>
2026-10-05 16:51:18 +08:00
風雪and風雪 ee14b06680 fix(ui): stop reusing the port help text as the validation error (#90)
The create/edit listener form set the port field's `tooltip` and its
`required`/format validation `message` to the same i18n key (`portHint`).
When the field was empty or malformed, the identical "监听端口(wiki:
port)。单端口或官方 ports 语法。" string showed up twice — once as the
hover help and once as the red validation error — which read as two
duplicate hints.

Split the validation copy out of the help string: `portRequired` for the
empty case and `portFormat` for the syntax case, while `portHint` stays
purely as the hover help. The "ports syntax" phrasing itself is correct
per the Mihomo listener docs (port supports single port or
comma/hyphen ranges), so only the duplication is fixed.

Co-authored-by: 風雪 <kazeyukiro@users.noreply.github.com>
2026-10-05 16:51:03 +08:00
kazeyukiro 141961be8d fix(menu): report invalid choice in BBR menu
与其它菜单保持一致:0/空输入直接返回,其它无效项给出提示,
而不是静默退出。
2026-10-05 14:13:44 +08:00
kazeyukiro 7bff84bcfa fix(cli): stop rejecting reset-config own flags as unknown arguments
main() 的全局参数扫描在遇到子命令后仍继续遍历,把 reset-config 的
--panel/--access/--public/--all/--yes 当成未知参数直接 log.Fatal,
导致 SSH 救援菜单(选项 16)必然失败并回滚重启:

    unknown argument: --panel

但 reset_config.go 本身是支持这些 flag 的(且 main.go 里的注释也
写了要交给子命令自己解析),只是扫描循环抢先拒绝了。

改为登记接受自有 flag 的子命令,扫描时放行其 flag。无子命令时的
未知参数(如 3m-ui --foo)仍照旧拒绝。
2026-10-05 14:13:44 +08:00
kazeyukiro 200427c11d fix(menu): return from SSL cert helper without prompting for domain
选 0 或无效项时 ssl_cert_menu 仍会继续索要域名,必须再回车一次
才能回到主菜单。改为先校验选项:0/空直接返回,无效项给出提示。

同时把 `[ -z "$dom" ] && return 0` 改成 if 形式,避免 set -e 下
AND 列表非零退出状态的边缘行为。
2026-10-05 14:07:20 +08:00
kazeyukiro a1c7013a0c docs(api): document split panel vs Mihomo log endpoints
OpenAPI: GET /system/panel-logs; clarify /mihomo/logs is core-only;
add LogEntry schema; note SSL auto-renew windows on SSL status.
2026-10-04 10:41:51 +00:00
kazeyukiro 3d93b2497a feat(logs): separate panel and Mihomo log streams
Mihomo: GET /mihomo/logs only. Panel: GET /system/panel-logs.
Logs page uses tabs (core vs panel). Stdlib log still captured in panellog.
2026-10-04 10:35:00 +00:00
kazeyukiro a52ab85ab8 feat(logs): include panel runtime logs in UI log stream
Ring-buffer stdlib log output (ACME, bootstrap, errors) with [panel]
prefix and merge with Mihomo lines on GET /mihomo/logs, sorted by time.
2026-10-04 10:31:42 +00:00
kazeyukiro 605533003e fix(acme): restore IP GetCertificate via certificate()/ALPN 2026-10-04 10:20:54 +00:00
kazeyukiro 8af4b09733 fix(acme): check cert renewal every 6 hours 2026-10-04 10:00:26 +00:00
kazeyukiro ab444a8f22 fix(acme): renew domain certs 15 days before expiry
HTTP-01 and DNS-01: renew when <15d remain (was 30d). IP short-lived
certs unchanged (<48h). Status API domain_note documents the window.
2026-10-04 09:57:04 +00:00
kazeyukiro 6698e496ae refactor(acme): merge panel SSL onto acmez only
Replace golang.org/x/crypto/acme/autocert domain HTTP-01 with
domainHTTPIssuer (acmez + scheduled renew). DNS-01 and IP already used
acmez. PEM cache: http-<domain>.crt/.key; auto-renew ~30d before expiry.
2026-10-04 09:48:09 +00:00
kazeyukiro 6ecfe86ad7 fix(ci): align sing-box TUN test with current sub template
Restore interface_name=singbox_tun; expect dns.final=google (wuziwei-style
Ali/Google DNS) instead of legacy remote tag.
2026-10-04 08:26:04 +00:00
kazeyukiro 1871d0c586 feat(sub): add http_clients to sing-box sub; keep jsDelivr rule-sets
Restore wuziwei-style remote rule-sets (no panel hosting) and add
http_clients default (HTTP/2) for rule-set downloads per template.
2026-10-04 05:22:52 +00:00
kazeyukiro 622f42d82f feat(sub): add sing-box http_clients for rule-set downloads 2026-10-04 05:22:11 +00:00
kazeyukiro b1e19b2f7e feat(sub): sing-box CN split via jsDelivr (wuziwei sb-1.15 style)
No panel-hosted rule-sets. Remote MetaCubeX geosite (cn/apple@cn/…) and
cn_ip via cdn.jsdelivr.net; DNS Ali for CN, Google DoH via proxy otherwise.
Remove embedded .srs and /client/rule-set routes.
2026-10-04 05:19:23 +00:00
kazeyukiro 4f1002229d fix(sub): drop TUN route_exclude_address_set for SFI compatibility 2026-10-04 05:14:51 +00:00
kazeyukiro 5c6c856c0f feat(sub): sing-box CN/overseas split per LongLights v1.14 template
DNS: cn_dns (119.29.29.29) for cnsite, proxy_dns (DoH) for gfw/default.
Route: private/BT → Direct-Out, gfw → Default, resolve, cnip → Direct-Out.
Embed MetaCubeX cnsite/cnip/gfw.srs and serve from the panel rule-set API.
2026-10-04 05:14:24 +00:00
kazeyukiro 37d81aaccf feat(sub): full CN split via panel-hosted sing-box rule-sets
Embed geosite-cn.srs / geoip-cn.srs and serve them at
/api/v1/client/rule-set/*.srs on the same host as the subscription.
Subscription stays small for SFI while domain+IP CN coverage is complete.
Remove multi-MB inline domain/IP dumps that broke mobile clients.
2026-10-04 03:47:16 +00:00