From 8d6e7c0098eec10209f76b8ba34632b99ec76032 Mon Sep 17 00:00:00 2001 From: Rogee Date: Mon, 24 Aug 2026 16:12:38 +0800 Subject: [PATCH] HH-620: expose SSClash Web UI on port 9091 Co-authored-by: multica-agent --- .env.example | 2 ++ Dockerfile | 4 ++-- README.md | 8 ++++---- compose.yaml | 1 + tests/container-smoke.sh | 13 +++++++++---- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.env.example b/.env.example index 5223a04..5864a2a 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,7 @@ IMAGE_NAME=mohomo-docker:local CONTAINER_NAME=mohomo-docker SUBSCRIPTION_URL=https://subscription.example.invalid/mihomo +WEB_BIND=0.0.0.0 +WEB_PORT=9091 PROXY_BIND=0.0.0.0 PROXY_PORT=7890 diff --git a/Dockerfile b/Dockerfile index e1999ba..daa8e5d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -77,12 +77,12 @@ COPY config/config.yaml /usr/local/share/ssclash/config.yaml ENV SSCLASH_ROOT=/opt/clash \ SSCLASH_TMP=/tmp/ssclash \ SSCLASH_PLATFORM=linux \ - SSCLASH_ADDR=127.0.0.1:9091 \ + SSCLASH_ADDR=0.0.0.0:9091 \ SAFE_PATHS=/usr/local/share/ssclash USER ssclash VOLUME ["/opt/clash"] -EXPOSE 7890/tcp 7890/udp +EXPOSE 9091/tcp 7890/tcp 7890/udp HEALTHCHECK --interval=15s --timeout=5s --start-period=20s --retries=4 \ CMD curl --fail --silent --show-error http://127.0.0.1:9090/version >/dev/null ENTRYPOINT ["/usr/local/bin/bootstrap"] diff --git a/README.md b/README.md index af6c30b..bb86bd3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # mohomo-docker -Minimal Mihomo service with the ACL4SSR `Online Full MultiMode` routing model. The host exposes only mixed proxy port `7890`; SSClash and Mihomo's controller remain loopback-only inside the container. +Minimal Mihomo service with the ACL4SSR `Online Full MultiMode` routing model. The host exposes the SSClash Web UI on port `9091` and the mixed proxy on port `7890`; Mihomo's controller remains private to the container. ## Quick start @@ -11,14 +11,14 @@ docker compose up -d --build docker compose logs -f ssclash ``` -The subscription endpoint must return a Clash/Mihomo proxy-provider YAML document (`proxies:`). Use an HTTPS endpoint when its URL contains a credential. Clients connect to either endpoint: +The subscription endpoint must return a Clash/Mihomo proxy-provider YAML document (`proxies:`). Use an HTTPS endpoint when its URL contains a credential. Open `http://:9091` to manage SSClash. Proxy clients connect to either endpoint: ```text HTTP proxy: http://:7890 SOCKS5 proxy: socks5://:7890 ``` -`PROXY_BIND` and `PROXY_PORT` are optional deployment overrides. Configure Mihomo proxy authentication before publishing port `7890` outside a trusted network. +`WEB_BIND`, `WEB_PORT`, `PROXY_BIND`, and `PROXY_PORT` are optional deployment overrides; both services bind all host interfaces by default. Set the SSClash administrator password and place the Web UI behind HTTPS and additional access control before exposing it to the Internet. Configure Mihomo proxy authentication before publishing port `7890` outside a trusted network. ## Update and secret handling @@ -55,7 +55,7 @@ The GitHub Actions workflow builds `linux/amd64`, runs tests first, publishes on ./tests/container-smoke.sh ``` -The unit suite checks atomic rollback, URL redaction, server-only listeners, local ACL4SSR providers, and at least 65% bootstrap coverage. The container smoke test builds the image, validates the generated configuration, checks that only port `7890` is published, and verifies that the subscription credential is neither persisted nor logged. +The unit suite checks atomic rollback, URL redaction, server-only listeners, local ACL4SSR providers, and at least 65% bootstrap coverage. The container smoke test builds the image, validates the generated configuration, reaches the Web UI through its published port, checks that only ports `7890` and `9091` are published, and verifies that the subscription credential is neither persisted nor logged. ## License boundary diff --git a/compose.yaml b/compose.yaml index 78c8631..b6b80e5 100644 --- a/compose.yaml +++ b/compose.yaml @@ -9,6 +9,7 @@ services: environment: SUBSCRIPTION_URL: ${SUBSCRIPTION_URL:?set SUBSCRIPTION_URL in .env} ports: + - "${WEB_BIND:-0.0.0.0}:${WEB_PORT:-9091}:9091/tcp" - "${PROXY_BIND:-0.0.0.0}:${PROXY_PORT:-7890}:7890/tcp" - "${PROXY_BIND:-0.0.0.0}:${PROXY_PORT:-7890}:7890/udp" volumes: diff --git a/tests/container-smoke.sh b/tests/container-smoke.sh index 64fbee0..5f3cd6e 100755 --- a/tests/container-smoke.sh +++ b/tests/container-smoke.sh @@ -67,6 +67,7 @@ docker run --detach \ --volume "$volume:/opt/clash" \ --publish 127.0.0.1::7890/tcp \ --publish 127.0.0.1::7890/udp \ + --publish 127.0.0.1::9091/tcp \ "$image" >/dev/null attempt=0 @@ -81,11 +82,15 @@ until [ "$(docker inspect --format '{{.State.Health.Status}}' "$container")" = h done published=$(docker port "$container") -printf '%s\n' "$published" | grep -E '^7890/(tcp|udp)' >/dev/null -if printf '%s\n' "$published" | grep -vE '^7890/(tcp|udp)' >/dev/null; then - echo "container published a port other than 7890" >&2 +for port in 7890/tcp 7890/udp 9091/tcp; do + printf '%s\n' "$published" | grep -F "$port ->" >/dev/null +done +if printf '%s\n' "$published" | grep -vE '^(7890/(tcp|udp)|9091/tcp)' >/dev/null; then + echo "container published a port other than 7890 or 9091" >&2 exit 1 fi +web_port=$(docker port "$container" 9091/tcp | awk -F: 'NR == 1 { print $NF }') +curl --fail --silent --show-error "http://127.0.0.1:${web_port}/" >/dev/null docker exec "$container" grep -Fx 'OPERATING_MODE=server' /opt/clash/.ssclash/settings >/dev/null docker exec "$container" grep -Fx 'PROXY_MODE=none' /opt/clash/.ssclash/settings >/dev/null @@ -104,4 +109,4 @@ if docker logs "$container" 2>&1 | grep -F "$secret" >/dev/null; then exit 1 fi -echo "container smoke test passed: only port 7890 published; subscription credential not persisted or logged" +echo "container smoke test passed: only ports 7890 and 9091 published; subscription credential not persisted or logged"