改为手动触发流水线

This commit is contained in:
admin8800
2026-05-10 15:28:59 +08:00
parent b21144ca46
commit 39d18aabd1
7 changed files with 1868 additions and 1888 deletions
+181 -159
View File
@@ -1,159 +1,181 @@
name: Docker Image CI name: Docker 镜像 CI
on:
push: on:
tags: workflow_dispatch:
- "*" inputs:
workflow_dispatch: tag:
description: "发布标签"
jobs: required: true
frontend-build: default: "v1.4.1"
runs-on: ubuntu-24.04 type: string
steps:
- name: Checkout repository jobs:
uses: actions/checkout@v6.0.2 frontend-build:
with: runs-on: ubuntu-24.04
submodules: recursive steps:
- name: Set up Node.js - name: 检出仓库
uses: actions/setup-node@v6 uses: actions/checkout@v6.0.2
with: with:
node-version: 25 ref: ${{ inputs.tag }}
- name: Install dependencies and build frontend submodules: recursive
run: |
cd frontend - name: 设置 Node.js
npm install uses: actions/setup-node@v6
npm run build with:
- name: Upload frontend build artifact node-version: 25
uses: actions/upload-artifact@v7
with: - name: 安装依赖并构建前端
name: frontend-dist run: |
path: frontend/dist/ cd frontend
npm install
build: npm run build
needs: frontend-build
strategy: - name: 上传前端构建产物
fail-fast: false uses: actions/upload-artifact@v7
matrix: with:
include: name: frontend-dist
- { platform: linux/amd64 } path: frontend/dist/
- { platform: linux/386 }
- { platform: linux/arm64/v8 } build:
- { platform: linux/arm/v7 } needs: frontend-build
- { platform: linux/arm/v6 } strategy:
runs-on: ubuntu-24.04 fail-fast: false
steps: matrix:
- name: Checkout repository include:
uses: actions/checkout@v6.0.2 - { platform: linux/amd64 }
- name: Download frontend build artifact - { platform: linux/386 }
uses: actions/download-artifact@v8 - { platform: linux/arm64/v8 }
with: - { platform: linux/arm/v7 }
name: frontend-dist - { platform: linux/arm/v6 }
path: frontend_dist runs-on: ubuntu-24.04
- name: Prepare steps:
run: | - name: 检出仓库
platform="${{ matrix.platform }}" uses: actions/checkout@v6.0.2
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV with:
- name: Docker meta ref: ${{ inputs.tag }}
id: meta
uses: docker/metadata-action@v6 - name: 下载前端构建产物
with: uses: actions/download-artifact@v8
images: | with:
alireza7/s-ui name: frontend-dist
ghcr.io/alireza0/s-ui path: frontend_dist
tags: |
type=ref,event=branch - name: 准备
type=ref,event=tag run: |
type=pep440,pattern={{version}} platform="${{ matrix.platform }}"
- name: Set up QEMU echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx - name: Docker 元数据
uses: docker/setup-buildx-action@v4 id: meta
- name: Cache Docker layers uses: docker/metadata-action@v6
uses: actions/cache@v5 with:
with: images: |
path: /tmp/.buildx-cache alireza7/s-ui
key: ${{ runner.os }}-buildx-${{ matrix.platform }}-${{ github.sha }} ghcr.io/alireza0/s-ui
restore-keys: | tags: |
${{ runner.os }}-buildx-${{ matrix.platform }}- type=raw,value=${{ inputs.tag }}
- name: Login to Docker Hub
uses: docker/login-action@v4 - name: 设置 QEMU
with: uses: docker/setup-qemu-action@v4
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }} - name: 设置 Docker Buildx
- name: Login to GHCR uses: docker/setup-buildx-action@v4
uses: docker/login-action@v4
with: - name: 缓存 Docker 层
registry: ghcr.io uses: actions/cache@v5
username: ${{ github.repository_owner }} with:
password: ${{ secrets.GITHUB_TOKEN }} path: /tmp/.buildx-cache
- name: Build and push by digest key: ${{ runner.os }}-buildx-${{ matrix.platform }}-${{ github.sha }}
id: build restore-keys: |
uses: docker/build-push-action@v7 ${{ runner.os }}-buildx-${{ matrix.platform }}-
with:
context: . - name: 登录 Docker Hub
file: Dockerfile.frontend-artifact uses: docker/login-action@v4
platforms: ${{ matrix.platform }} with:
labels: ${{ steps.meta.outputs.labels }} username: ${{ secrets.DOCKER_HUB_USERNAME }}
tags: | password: ${{ secrets.DOCKER_HUB_TOKEN }}
alireza7/s-ui
ghcr.io/alireza0/s-ui - name: 登录 GHCR
cache-from: type=local,src=/tmp/.buildx-cache uses: docker/login-action@v4
cache-to: type=local,dest=/tmp/.buildx-cache,mode=max with:
outputs: type=image,push-by-digest=true,name-canonical=true,push=true registry: ghcr.io
- name: Export digest username: ${{ github.repository_owner }}
run: | password: ${{ secrets.GITHUB_TOKEN }}
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}" - name: 按摘要构建并推送
echo "${digest#sha256:}" > "${{ runner.temp }}/digests/${digest#sha256:}" id: build
- name: Upload digest uses: docker/build-push-action@v7
uses: actions/upload-artifact@v7 with:
with: context: .
name: digests-${{ env.PLATFORM_PAIR }} file: Dockerfile.frontend-artifact
path: ${{ runner.temp }}/digests/* platforms: ${{ matrix.platform }}
if-no-files-found: error labels: ${{ steps.meta.outputs.labels }}
retention-days: 1 tags: |
alireza7/s-ui
merge: ghcr.io/alireza0/s-ui
needs: build cache-from: type=local,src=/tmp/.buildx-cache
runs-on: ubuntu-24.04 cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
steps: outputs: type=image,push-by-digest=true,name-canonical=true,push=true
- name: Download digests
uses: actions/download-artifact@v8 - name: 导出摘要
with: run: |
path: ${{ runner.temp }}/digests mkdir -p ${{ runner.temp }}/digests
pattern: digests-* digest="${{ steps.build.outputs.digest }}"
merge-multiple: true echo "${digest#sha256:}" > "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Login to Docker Hub
uses: docker/login-action@v4 - name: 上传摘要
with: uses: actions/upload-artifact@v7
username: ${{ secrets.DOCKER_HUB_USERNAME }} with:
password: ${{ secrets.DOCKER_HUB_TOKEN }} name: digests-${{ env.PLATFORM_PAIR }}
- name: Login to GHCR path: ${{ runner.temp }}/digests/*
uses: docker/login-action@v4 if-no-files-found: error
with: retention-days: 1
registry: ghcr.io
username: ${{ github.repository_owner }} merge:
password: ${{ secrets.GITHUB_TOKEN }} needs: build
- name: Set up Docker Buildx runs-on: ubuntu-24.04
uses: docker/setup-buildx-action@v4 steps:
- name: Docker meta - name: 下载摘要
id: meta uses: actions/download-artifact@v8
uses: docker/metadata-action@v6 with:
with: path: ${{ runner.temp }}/digests
images: | pattern: digests-*
alireza7/s-ui merge-multiple: true
ghcr.io/alireza0/s-ui
tags: | - name: 登录 Docker Hub
type=ref,event=branch uses: docker/login-action@v4
type=ref,event=tag with:
type=pep440,pattern={{version}} username: ${{ secrets.DOCKER_HUB_USERNAME }}
- name: Create manifest list and push password: ${{ secrets.DOCKER_HUB_TOKEN }}
env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }} - name: 登录 GHCR
working-directory: ${{ runner.temp }}/digests uses: docker/login-action@v4
run: | with:
set -e registry: ghcr.io
for img in alireza7/s-ui ghcr.io/alireza0/s-ui; do username: ${{ github.repository_owner }}
TAGS_ARGS=$(echo "$DOCKER_METADATA_OUTPUT_JSON" | jq -cr --arg img "$img" '.tags | map(select(startswith($img))) | map("-t " + .) | join(" ")') password: ${{ secrets.GITHUB_TOKEN }}
DIGEST_REFS=$(for f in *; do echo -n "${img}@sha256:$(cat "$f") "; done)
docker buildx imagetools create $TAGS_ARGS $DIGEST_REFS - name: 设置 Docker Buildx
done uses: docker/setup-buildx-action@v4
- name: Docker 元数据
id: meta
uses: docker/metadata-action@v6
with:
images: |
alireza7/s-ui
ghcr.io/alireza0/s-ui
tags: |
type=raw,value=${{ inputs.tag }}
- name: 创建清单列表并推送
env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }}
working-directory: ${{ runner.temp }}/digests
run: |
set -e
for img in alireza7/s-ui ghcr.io/alireza0/s-ui; do
TAGS_ARGS=$(echo "$DOCKER_METADATA_OUTPUT_JSON" | jq -cr --arg img "$img" '.tags | map(select(startswith($img))) | map("-t " + .) | join(" ")')
DIGEST_REFS=$(for f in *; do echo -n "${img}@sha256:$(cat "$f") "; done)
docker buildx imagetools create $TAGS_ARGS $DIGEST_REFS
done
+193 -202
View File
@@ -1,202 +1,193 @@
name: Release S-UI name: 发布 S-UI
on: on:
workflow_dispatch: workflow_dispatch:
release: inputs:
types: [published] tag:
push: description: "发布标签"
branches: required: true
- main default: "v1.4.1"
tags: type: string
- "*"
paths: env:
- '.github/workflows/release.yml' NODE_VERSION: "25"
- 'frontend/**' CRONET_GO_VERSION: "2fef65f9dba90ddb89a87d00a6eb6165487c10c1"
- '**.sh' CRONET_GO_REPO: https://github.com/sagernet/cronet-go.git
- '**.go' BOOTLIN_BASE_URL: https://toolchains.bootlin.com/downloads/releases/toolchains
- 'go.mod'
- 'go.sum' jobs:
- 's-ui.service' build-frontend:
runs-on: ubuntu-latest
env: steps:
NODE_VERSION: "25" - name: 检出仓库(仅前端)
CRONET_GO_VERSION: "2fef65f9dba90ddb89a87d00a6eb6165487c10c1" uses: actions/checkout@v6.0.2
CRONET_GO_REPO: https://github.com/sagernet/cronet-go.git with:
BOOTLIN_BASE_URL: https://toolchains.bootlin.com/downloads/releases/toolchains ref: ${{ inputs.tag }}
submodules: recursive
jobs: fetch-depth: 1
build-frontend:
runs-on: ubuntu-latest - name: 设置 Node.js
steps: uses: actions/setup-node@v6
- name: Checkout repository (frontend only) with:
uses: actions/checkout@v6.0.2 node-version: ${{ env.NODE_VERSION }}
with: cache: 'npm'
submodules: recursive cache-dependency-path: frontend/package-lock.json
fetch-depth: 1
- name: 构建前端
- name: Setup Node.js run: |
uses: actions/setup-node@v6 cd frontend
with: npm install
node-version: ${{ env.NODE_VERSION }} npm run build
cache: 'npm' cd ..
cache-dependency-path: frontend/package-lock.json
- name: 上传前端 dist
- name: Build frontend uses: actions/upload-artifact@v7
run: | with:
cd frontend name: frontend-dist
npm install path: frontend/dist/
npm run build
cd .. build-linux:
name: 构建-${{ matrix.platform }}
- name: Upload frontend dist needs: build-frontend
uses: actions/upload-artifact@v7 strategy:
with: fail-fast: false
name: frontend-dist matrix:
path: frontend/dist/ include:
- { platform: amd64, arch: amd64, bootlin: x86-64, naive: true }
build-linux: - { platform: arm64, arch: arm64, bootlin: aarch64, naive: true }
name: build-${{ matrix.platform }} - { platform: armv7, arch: arm, goarm: "7", bootlin: armv7-eabihf, naive: true }
needs: build-frontend - { platform: armv6, arch: arm, goarm: "6", bootlin: armv6-eabihf, naive: true }
strategy: - { platform: armv5, arch: arm, goarm: "5", bootlin: armv5-eabi, naive: false }
fail-fast: false - { platform: "386", arch: "386", bootlin: x86-i686, naive: true }
matrix: - { platform: s390x, arch: s390x, bootlin: s390x-z13, naive: false }
include: runs-on: ubuntu-latest
- { platform: amd64, arch: amd64, bootlin: x86-64, naive: true } steps:
- { platform: arm64, arch: arm64, bootlin: aarch64, naive: true } - name: 检出仓库
- { platform: armv7, arch: arm, goarm: "7", bootlin: armv7-eabihf, naive: true } uses: actions/checkout@v6.0.2
- { platform: armv6, arch: arm, goarm: "6", bootlin: armv6-eabihf, naive: true } with:
- { platform: armv5, arch: arm, goarm: "5", bootlin: armv5-eabi, naive: false } ref: ${{ inputs.tag }}
- { platform: "386", arch: "386", bootlin: x86-i686, naive: true }
- { platform: s390x, arch: s390x, bootlin: s390x-z13, naive: false } - name: 下载前端 dist
runs-on: ubuntu-latest uses: actions/download-artifact@v8
steps: with:
- name: Checkout repository name: frontend-dist
uses: actions/checkout@v6.0.2 path: web/html
- name: Download frontend dist - name: 设置 Go
uses: actions/download-artifact@v8 uses: actions/setup-go@v6
with: with:
name: frontend-dist cache: false
path: web/html go-version-file: go.mod
- name: Setup Go # Naive 平台:仅使用 cronet 工具链(不使用 Bootlin)。
uses: actions/setup-go@v6 - name: 克隆 cronet-gonaive 使用的 cronet 工具链)
with: if: matrix.naive
cache: false run: |
go-version-file: go.mod set -e
git init ~/cronet-go
# Naive platforms: use cronet toolchain only (no Bootlin). git -C ~/cronet-go remote add origin ${{ env.CRONET_GO_REPO }}
- name: Clone cronet-go (cronet toolchain for naive) git -C ~/cronet-go fetch --depth=1 origin "${{ env.CRONET_GO_VERSION }}"
if: matrix.naive git -C ~/cronet-go checkout FETCH_HEAD
run: | git -C ~/cronet-go submodule update --init --recursive --depth=1
set -e
git init ~/cronet-go - name: 重新生成 Debian keyringcronet sysroot
git -C ~/cronet-go remote add origin ${{ env.CRONET_GO_REPO }} if: matrix.naive
git -C ~/cronet-go fetch --depth=1 origin "${{ env.CRONET_GO_VERSION }}" run: |
git -C ~/cronet-go checkout FETCH_HEAD set -e
git -C ~/cronet-go submodule update --init --recursive --depth=1 rm -f ~/cronet-go/naiveproxy/src/build/linux/sysroot_scripts/keyring.gpg
cd ~/cronet-go
- name: Regenerate Debian keyring (cronet sysroot) GPG_TTY=/dev/null ./naiveproxy/src/build/linux/sysroot_scripts/generate_keyring.sh
if: matrix.naive
run: | - name: 缓存 Chromium 工具链
set -e if: matrix.naive
rm -f ~/cronet-go/naiveproxy/src/build/linux/sysroot_scripts/keyring.gpg id: cache-chromium-toolchain
cd ~/cronet-go uses: actions/cache@v5
GPG_TTY=/dev/null ./naiveproxy/src/build/linux/sysroot_scripts/generate_keyring.sh with:
path: |
- name: Cache Chromium toolchain ~/cronet-go/naiveproxy/src/third_party/llvm-build/
if: matrix.naive ~/cronet-go/naiveproxy/src/gn/out/
id: cache-chromium-toolchain ~/cronet-go/naiveproxy/src/chrome/build/pgo_profiles/
uses: actions/cache@v5 ~/cronet-go/naiveproxy/src/out/sysroot-build/
with: key: chromium-toolchain-${{ matrix.platform }}-musl-${{ env.CRONET_GO_VERSION }}
path: |
~/cronet-go/naiveproxy/src/third_party/llvm-build/ - name: 构建 cronet 库并设置工具链环境(CC、CXX、CGO_LDFLAGS、PATH
~/cronet-go/naiveproxy/src/gn/out/ if: matrix.naive
~/cronet-go/naiveproxy/src/chrome/build/pgo_profiles/ run: |
~/cronet-go/naiveproxy/src/out/sysroot-build/ set -e
key: chromium-toolchain-${{ matrix.platform }}-musl-${{ env.CRONET_GO_VERSION }} cd ~/cronet-go
go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl download-toolchain
- name: Build cronet lib and set toolchain env (CC, CXX, CGO_LDFLAGS, PATH) go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl env | while IFS= read -r line; do
if: matrix.naive line="${line#export }"
run: | [[ -z "$line" ]] && continue
set -e echo "$line" >> $GITHUB_ENV
cd ~/cronet-go done
go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl download-toolchain
go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl env | while IFS= read -r line; do - name: 设置 Go 构建环境(所有平台)
line="${line#export }" run: |
[[ -z "$line" ]] && continue echo "CGO_ENABLED=1" >> $GITHUB_ENV
echo "$line" >> $GITHUB_ENV echo "GOOS=linux" >> $GITHUB_ENV
done echo "GOARCH=${{ matrix.arch }}" >> $GITHUB_ENV
if [ -n "${{ matrix.goarm }}" ]; then echo "GOARM=${{ matrix.goarm }}" >> $GITHUB_ENV; fi
- name: Set Go build env (all platforms)
run: | # 仅非 naive 平台:Bootlin muslarmv5、s390x)。
echo "CGO_ENABLED=1" >> $GITHUB_ENV - name: 设置 Bootlin muslarmv5、s390x
echo "GOOS=linux" >> $GITHUB_ENV if: ${{ matrix.naive != true }}
echo "GOARCH=${{ matrix.arch }}" >> $GITHUB_ENV run: |
if [ -n "${{ matrix.goarm }}" ]; then echo "GOARM=${{ matrix.goarm }}" >> $GITHUB_ENV; fi set -e
BOOTLIN_ARCH="${{ matrix.bootlin }}"
# Non-naive platforms only: Bootlin musl (armv5, s390x). echo "正在解析 arch=$BOOTLIN_ARCH 的 Bootlin musl 工具链(平台=${{ matrix.platform }}"
- name: Set up Bootlin musl (armv5, s390x) TARBALL_BASE="${{ env.BOOTLIN_BASE_URL }}/$BOOTLIN_ARCH/tarballs/"
if: ${{ matrix.naive != true }} TARBALL_URL=$(curl -fsSL "$TARBALL_BASE" | grep -oE "${BOOTLIN_ARCH}--musl--stable-[^\"]+\\.tar\\.xz" | sort -r | head -n1)
run: | [ -z "$TARBALL_URL" ] && { echo "未找到 arch=$BOOTLIN_ARCH 的 Bootlin musl 工具链" >&2; exit 1; }
set -e echo "正在下载:$TARBALL_URL"
BOOTLIN_ARCH="${{ matrix.bootlin }}" cd /tmp
echo "Resolving Bootlin musl toolchain for arch=$BOOTLIN_ARCH (platform=${{ matrix.platform }})" curl -fL -sS -o "$(basename "$TARBALL_URL")" "$TARBALL_BASE/$TARBALL_URL"
TARBALL_BASE="${{ env.BOOTLIN_BASE_URL }}/$BOOTLIN_ARCH/tarballs/" tar -xf "$(basename "$TARBALL_URL")"
TARBALL_URL=$(curl -fsSL "$TARBALL_BASE" | grep -oE "${BOOTLIN_ARCH}--musl--stable-[^\"]+\\.tar\\.xz" | sort -r | head -n1) TOOLCHAIN_DIR=$(find . -maxdepth 1 -type d -name "${BOOTLIN_ARCH}--musl--stable-*" | head -n1)
[ -z "$TARBALL_URL" ] && { echo "Failed to locate Bootlin musl toolchain for arch=$BOOTLIN_ARCH" >&2; exit 1; } TOOLCHAIN_DIR="$(realpath "$TOOLCHAIN_DIR")"
echo "Downloading: $TARBALL_URL" BIN_DIR="$TOOLCHAIN_DIR/bin"
cd /tmp echo "PATH=$BIN_DIR:$PATH" >> $GITHUB_ENV
curl -fL -sS -o "$(basename "$TARBALL_URL")" "$TARBALL_BASE/$TARBALL_URL" CC=$(find "$BIN_DIR" -maxdepth 1 \( -name '*-gcc.br_real' -o -name '*-gcc' \) -type f -executable 2>/dev/null | grep -v g++ | head -n1)
tar -xf "$(basename "$TARBALL_URL")" [ -z "$CC" ] && { echo "在 $BIN_DIR 中未找到 gcc" >&2; exit 1; }
TOOLCHAIN_DIR=$(find . -maxdepth 1 -type d -name "${BOOTLIN_ARCH}--musl--stable-*" | head -n1) echo "CC=$(realpath "$CC")" >> $GITHUB_ENV
TOOLCHAIN_DIR="$(realpath "$TOOLCHAIN_DIR")" SYSROOT=""
BIN_DIR="$TOOLCHAIN_DIR/bin" F=$(find "$TOOLCHAIN_DIR" -name "libc-header-start.h" 2>/dev/null | head -1)
echo "PATH=$BIN_DIR:$PATH" >> $GITHUB_ENV if [ -n "$F" ]; then SYSROOT=$(dirname "$(dirname "$(dirname "$(dirname "$F")")")"); fi
CC=$(find "$BIN_DIR" -maxdepth 1 \( -name '*-gcc.br_real' -o -name '*-gcc' \) -type f -executable 2>/dev/null | grep -v g++ | head -n1) if [ -n "$SYSROOT" ] && [ -d "$SYSROOT" ]; then
[ -z "$CC" ] && { echo "No gcc found in $BIN_DIR" >&2; exit 1; } echo "CGO_CFLAGS=--sysroot=$SYSROOT" >> $GITHUB_ENV
echo "CC=$(realpath "$CC")" >> $GITHUB_ENV echo "CGO_LDFLAGS=--sysroot=$SYSROOT -static" >> $GITHUB_ENV
SYSROOT="" fi
F=$(find "$TOOLCHAIN_DIR" -name "libc-header-start.h" 2>/dev/null | head -1)
if [ -n "$F" ]; then SYSROOT=$(dirname "$(dirname "$(dirname "$(dirname "$F")")")"); fi - name: 构建 s-ui
if [ -n "$SYSROOT" ] && [ -d "$SYSROOT" ]; then run: |
echo "CGO_CFLAGS=--sysroot=$SYSROOT" >> $GITHUB_ENV set -e
echo "CGO_LDFLAGS=--sysroot=$SYSROOT -static" >> $GITHUB_ENV BUILD_TAGS="with_quic,with_grpc,with_utls,with_acme,with_gvisor,badlinkname,tfogo_checklinkname0,with_tailscale"
fi [ "${{ matrix.naive }}" = "true" ] && BUILD_TAGS="${BUILD_TAGS},with_naive_outbound,with_musl"
go build -ldflags="-w -s -checklinkname=0 -linkmode external -extldflags '-static'" -tags "$BUILD_TAGS" -o sui main.go
- name: Build s-ui file sui
run: | ldd sui 2>/dev/null || echo "已确认静态二进制文件"
set -e
BUILD_TAGS="with_quic,with_grpc,with_utls,with_acme,with_gvisor,badlinkname,tfogo_checklinkname0,with_tailscale" mkdir s-ui
[ "${{ matrix.naive }}" = "true" ] && BUILD_TAGS="${BUILD_TAGS},with_naive_outbound,with_musl" cp sui s-ui/
go build -ldflags="-w -s -checklinkname=0 -linkmode external -extldflags '-static'" -tags "$BUILD_TAGS" -o sui main.go cp s-ui.service s-ui/
file sui cp s-ui.sh s-ui/
ldd sui 2>/dev/null || echo "Static binary confirmed"
- name: 打包
mkdir s-ui run: tar -zcvf s-ui-linux-${{ matrix.platform }}.tar.gz s-ui
cp sui s-ui/
cp s-ui.service s-ui/ - name: 上传构建产物
cp s-ui.sh s-ui/ uses: actions/upload-artifact@v7
with:
- name: Package name: s-ui-linux-${{ matrix.platform }}
run: tar -zcvf s-ui-linux-${{ matrix.platform }}.tar.gz s-ui path: ./s-ui-linux-${{ matrix.platform }}.tar.gz
retention-days: 30
- name: Upload artifact
uses: actions/upload-artifact@v7 - name: 上传到 Release
with: uses: svenstaro/upload-release-action@v2
name: s-ui-linux-${{ matrix.platform }} with:
path: ./s-ui-linux-${{ matrix.platform }}.tar.gz repo_token: ${{ secrets.GITHUB_TOKEN }}
retention-days: 30 tag: ${{ inputs.tag }}
file: s-ui-linux-${{ matrix.platform }}.tar.gz
- name: Upload to Release asset_name: s-ui-linux-${{ matrix.platform }}.tar.gz
uses: svenstaro/upload-release-action@v2 prerelease: true
if: | overwrite: true
(github.event_name == 'release' && github.event.action == 'published') ||
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }}
file: s-ui-linux-${{ matrix.platform }}.tar.gz
asset_name: s-ui-linux-${{ matrix.platform }}.tar.gz
prerelease: true
overwrite: true
+132 -140
View File
@@ -1,140 +1,132 @@
name: Build S-UI for Windows name: 构建 Windows 版 S-UI
on: on:
workflow_dispatch: workflow_dispatch:
release: inputs:
types: [published] tag:
push: description: "发布标签"
branches: required: true
- main default: "v1.4.1"
tags: type: string
- "*"
paths: env:
- '.github/workflows/windows.yml' NODE_VERSION: "25"
- 'frontend/**' TAGS: "with_quic,with_grpc,with_utls,with_acme,with_gvisor,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0,with_tailscale"
- '**.go' LIBCRONET_BASE_URL: "https://github.com/SagerNet/cronet-go/releases/latest/download"
- 'go.mod'
- 'go.sum' jobs:
- 'windows/**' build-frontend:
runs-on: ubuntu-latest
env: steps:
NODE_VERSION: "25" - name: 检出仓库
TAGS: "with_quic,with_grpc,with_utls,with_acme,with_gvisor,with_naive_outbound,with_purego,badlinkname,tfogo_checklinkname0,with_tailscale" uses: actions/checkout@v6.0.2
LIBCRONET_BASE_URL: "https://github.com/SagerNet/cronet-go/releases/latest/download" with:
ref: ${{ inputs.tag }}
jobs: submodules: recursive
build-frontend: fetch-depth: 1
runs-on: ubuntu-latest
steps: - name: 设置 Node.js
- name: Checkout repository uses: actions/setup-node@v6
uses: actions/checkout@v6.0.2 with:
with: node-version: ${{ env.NODE_VERSION }}
submodules: recursive registry-url: 'https://registry.npmjs.org'
fetch-depth: 1
- name: 构建前端
- name: Setup Node.js run: |
uses: actions/setup-node@v6 cd frontend
with: npm install
node-version: ${{ env.NODE_VERSION }} npm run build
registry-url: 'https://registry.npmjs.org' cd ..
- name: Build frontend - name: 上传前端构建产物
run: | uses: actions/upload-artifact@v7
cd frontend with:
npm install name: frontend-dist
npm run build path: frontend/dist
cd .. retention-days: 1
- name: Upload frontend artifact build-windows:
uses: actions/upload-artifact@v7 needs: build-frontend
with: name: 构建-windows-${{ matrix.arch }}
name: frontend-dist strategy:
path: frontend/dist fail-fast: false
retention-days: 1 matrix:
include:
build-windows: - { arch: amd64, runner: windows-latest, cgo: "1" }
needs: build-frontend - { arch: arm64, runner: ubuntu-latest, cgo: "0" }
name: build-windows-${{ matrix.arch }} runs-on: ${{ matrix.runner }}
strategy: steps:
fail-fast: false - name: 检出仓库
matrix: uses: actions/checkout@v6.0.2
include: with:
- { arch: amd64, runner: windows-latest, cgo: "1" } ref: ${{ inputs.tag }}
- { arch: arm64, runner: ubuntu-latest, cgo: "0" }
runs-on: ${{ matrix.runner }} - name: 下载前端构建产物
steps: uses: actions/download-artifact@v8
- name: Checkout repository with:
uses: actions/checkout@v6.0.2 name: frontend-dist
path: web/html
- name: Download frontend artifact
uses: actions/download-artifact@v8 - name: 设置 Go
with: uses: actions/setup-go@v6
name: frontend-dist with:
path: web/html cache: false
go-version-file: go.mod
- name: Setup Go
uses: actions/setup-go@v6 - name: 为 Windows 安装 zip
with: if: matrix.arch == 'amd64'
cache: false shell: powershell
go-version-file: go.mod run: |
# 如果 Chocolatey 不可用,则安装 Chocolatey
- name: Install zip for Windows if (!(Get-Command choco -ErrorAction SilentlyContinue)) {
if: matrix.arch == 'amd64' Set-ExecutionPolicy Bypass -Scope Process -Force
shell: powershell [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
run: | iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install Chocolatey if not available }
if (!(Get-Command choco -ErrorAction SilentlyContinue)) { # 安装 zip
Set-ExecutionPolicy Bypass -Scope Process -Force choco install zip -y
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) - name: 构建 s-ui
} shell: bash
# Install zip run: |
choco install zip -y export CGO_ENABLED=${{ matrix.cgo }}
export GOOS=windows
- name: Build s-ui export GOARCH=${{ matrix.arch }}
shell: bash
run: | echo "正在为 Windows ${{ matrix.arch }} 构建"
export CGO_ENABLED=${{ matrix.cgo }} go version
export GOOS=windows go env GOOS GOARCH
export GOARCH=${{ matrix.arch }}
go build -ldflags="-w -s -checklinkname=0" -tags "${{ env.TAGS }}" -o sui.exe main.go
echo "Building for Windows ${{ matrix.arch }}" file sui.exe
go version
go env GOOS GOARCH mkdir s-ui-windows
cp sui.exe s-ui-windows/
go build -ldflags="-w -s -checklinkname=0" -tags "${{ env.TAGS }}" -o sui.exe main.go cp -r windows/* s-ui-windows/
file sui.exe
- name: 下载 libcronet-go
mkdir s-ui-windows shell: bash
cp sui.exe s-ui-windows/ run: |
cp -r windows/* s-ui-windows/ curl -qsL -o s-ui-windows/libcronet.dll ${{ env.LIBCRONET_BASE_URL }}/libcronet-windows-${{ matrix.arch }}.dll
- name: Download libcronet-go - name: 打包
shell: bash shell: bash
run: | run: |
curl -qsL -o s-ui-windows/libcronet.dll ${{ env.LIBCRONET_BASE_URL }}/libcronet-windows-${{ matrix.arch }}.dll zip -r "s-ui-windows-${{ matrix.arch }}.zip" s-ui-windows
- name: Package - name: 上传文件到构建产物
shell: bash uses: actions/upload-artifact@v7
run: | with:
zip -r "s-ui-windows-${{ matrix.arch }}.zip" s-ui-windows name: s-ui-windows-${{ matrix.arch }}
path: ./s-ui-windows-${{ matrix.arch }}.zip
- name: Upload files to Artifacts retention-days: 30
uses: actions/upload-artifact@v7
with: - name: 上传到 Release
name: s-ui-windows-${{ matrix.arch }} uses: svenstaro/upload-release-action@v2
path: ./s-ui-windows-${{ matrix.arch }}.zip with:
retention-days: 30 repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ inputs.tag }}
- name: Upload to Release file: s-ui-windows-${{ matrix.arch }}.zip
uses: svenstaro/upload-release-action@v2 asset_name: s-ui-windows-${{ matrix.arch }}.zip
if: | prerelease: true
(github.event_name == 'release' && github.event.action == 'published') || overwrite: true
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }}
file: s-ui-windows-${{ matrix.arch }}.zip
asset_name: s-ui-windows-${{ matrix.arch }}.zip
prerelease: true
overwrite: true
+239 -259
View File
@@ -1,259 +1,239 @@
# S-UI # S-UI
**An Advanced Web Panel • Built on SagerNet/Sing-Box** **基于 SagerNet/Sing-Box 构建的高级 Web 面板**
![](https://img.shields.io/github/v/release/alireza0/s-ui.svg)
![S-UI Docker pull](https://img.shields.io/docker/pulls/alireza7/s-ui.svg) > **免责声明:** 本项目仅供个人学习与交流使用,请勿用于非法用途,请勿在生产环境中使用。
[![Go Report Card](https://goreportcard.com/badge/github.com/admin8800/s-ui)](https://goreportcard.com/report/github.com/admin8800/s-ui)
[![Downloads](https://img.shields.io/github/downloads/alireza0/s-ui/total.svg)](https://img.shields.io/github/downloads/alireza0/s-ui/total.svg)
[![License](https://img.shields.io/badge/license-GPL%20V3-blue.svg?longCache=true)](https://www.gnu.org/licenses/gpl-3.0.en.html) ## 快速概览
| 功能 | 是否支持 |
> **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 | -------------------------------------- | :----------------: |
| 多协议 | :heavy_check_mark: |
**If you think this project is helpful to you, you may wish to give a**:star2: | 多语言 | :heavy_check_mark: |
| 多客户端/入站 | :heavy_check_mark: |
**Want to contribute?** See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding conventions, testing, and the pull request process. | 高级流量路由界面 | :heavy_check_mark: |
| 客户端、流量与系统状态 | :heavy_check_mark: |
[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/alireza7) | 订阅链接(link/json/clash + info | :heavy_check_mark: |
| 深色/浅色主题 | :heavy_check_mark: |
<a href="https://nowpayments.io/donation/alireza7" target="_blank" rel="noreferrer noopener"> | API 接口 | :heavy_check_mark: |
<img src="https://nowpayments.io/images/embeds/donation-button-white.svg" alt="Crypto donation button by NOWPayments">
</a> ## 支持平台
| 平台 | 架构 | 状态 |
## Quick Overview |----------|--------------|---------|
| Features | Enable? | | Linux | amd64, arm64, armv7, armv6, armv5, 386, s390x | 支持 |
| -------------------------------------- | :----------------: | | Windows | amd64, 386, arm64 | 支持 |
| Multi-Protocol | :heavy_check_mark: | | macOS | amd64, arm64 | 实验性支持 |
| Multi-Language | :heavy_check_mark: |
| Multi-Client/Inbound | :heavy_check_mark: | ## 截图
| Advanced Traffic Routing Interface | :heavy_check_mark: |
| Client & Traffic & System Status | :heavy_check_mark: | !["主界面"](https://github.com/admin8800/s-ui-frontend/raw/main/media/main.png)
| Subscription Link (link/json/clash + info)| :heavy_check_mark: |
| Dark/Light Theme | :heavy_check_mark: | ## API 文档
| API Interface | :heavy_check_mark: |
[API 文档 Wiki](https://github.com/admin8800/s-ui/wiki/API-Documentation)
## Supported Platforms
| Platform | Architecture | Status | ## 默认安装信息
|----------|--------------|---------| - 面板端口:2095
| Linux | amd64, arm64, armv7, armv6, armv5, 386, s390x | ✅ Supported | - 面板路径:/app/
| Windows | amd64, 386, arm64 | ✅ Supported | - 订阅端口:2096
| macOS | amd64, arm64 | 🚧 Experimental | - 订阅路径:/sub/
- 用户名/密码:admin
## Screenshots
## 安装或升级到最新版本
!["Main"](https://github.com/admin8800/s-ui-frontend/raw/main/media/main.png)
### Linux/macOS
[Other UI Screenshots](https://github.com/admin8800/s-ui-frontend/blob/main/screenshots.md) ```sh
bash <(curl -Ls https://raw.githubusercontent.com/admin8800/s-ui/main/install.sh)
## API Documentation ```
[API-Documentation Wiki](https://github.com/admin8800/s-ui/wiki/API-Documentation) ### Windows
1. 从 [GitHub Releases](https://github.com/admin8800/s-ui/releases/latest) 下载最新 Windows 版本。
## Default Installation Information 2. 解压 ZIP 文件。
- Panel Port: 2095 3. 以管理员身份运行 `install-windows.bat`
- Panel Path: /app/ 4. 按照安装向导操作。
- Subscription Port: 2096
- Subscription Path: /sub/ ## 安装旧版本
- User/Password: admin
**步骤 1** 如果要安装指定旧版本,请在安装命令末尾追加版本号。例如版本 `1.0.0`
## Install & Upgrade to Latest Version
```sh
### Linux/macOS VERSION=1.0.0 && bash <(curl -Ls https://raw.githubusercontent.com/admin8800/s-ui/$VERSION/install.sh) $VERSION
```sh ```
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/s-ui/master/install.sh)
``` ## 手动安装
### Windows ### Linux/macOS
1. Download the latest Windows release from [GitHub Releases](https://github.com/admin8800/s-ui/releases/latest) 1. 根据你的系统和架构,从 GitHub 获取最新版本 S-UI[https://github.com/admin8800/s-ui/releases/latest](https://github.com/admin8800/s-ui/releases/latest)
2. Extract the ZIP file 2. **可选:** 获取最新版 `s-ui.sh`[https://raw.githubusercontent.com/admin8800/s-ui/main/s-ui.sh](https://raw.githubusercontent.com/admin8800/s-ui/main/s-ui.sh)
3. Run `install-windows.bat` as Administrator 3. **可选:**`s-ui.sh` 复制到 `/usr/bin/`,并执行 `chmod +x /usr/bin/s-ui`
4. Follow the installation wizard 4. 将 s-ui tar.gz 文件解压到你选择的目录,并进入解压后的目录。
5.`*.service` 文件复制到 `/etc/systemd/system/`,然后执行 `systemctl daemon-reload`
## Install legacy Version 6. 使用 `systemctl enable s-ui --now` 启用开机自启并启动 S-UI 服务。
7. 使用 `systemctl enable sing-box --now` 启动 sing-box 服务。
**Step 1:** To install your desired legacy version, add the version to the end of the installation command. e.g., ver `1.0.0`:
### Windows
```sh 1. 从 GitHub 获取最新 Windows 版本:[https://github.com/admin8800/s-ui/releases/latest](https://github.com/admin8800/s-ui/releases/latest)
VERSION=1.0.0 && bash <(curl -Ls https://raw.githubusercontent.com/alireza0/s-ui/$VERSION/install.sh) $VERSION 2. 下载适合的 Windows 包,例如 `s-ui-windows-amd64.zip`
``` 3. 将 ZIP 文件解压到你选择的目录。
4. 以管理员身份运行 `install-windows.bat`
## Manual installation 5. 按照安装向导操作。
6. 访问面板:http://localhost:2095/app
### Linux/macOS
1. Get the latest version of S-UI based on your OS/Architecture from GitHub: [https://github.com/admin8800/s-ui/releases/latest](https://github.com/admin8800/s-ui/releases/latest) ## 卸载 S-UI
2. **OPTIONAL** Get the latest version of `s-ui.sh` [https://raw.githubusercontent.com/alireza0/s-ui/master/s-ui.sh](https://raw.githubusercontent.com/alireza0/s-ui/master/s-ui.sh)
3. **OPTIONAL** Copy `s-ui.sh` to /usr/bin/ and run `chmod +x /usr/bin/s-ui`. ```sh
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. sudo -i
5. Copy *.service files to /etc/systemd/system/ and run `systemctl daemon-reload`.
6. Enable autostart and start S-UI service using `systemctl enable s-ui --now` systemctl disable s-ui --now
7. Start sing-box service using `systemctl enable sing-box --now`
rm -f /etc/systemd/system/sing-box.service
### Windows systemctl daemon-reload
1. Get the latest Windows version from GitHub: [https://github.com/admin8800/s-ui/releases/latest](https://github.com/admin8800/s-ui/releases/latest)
2. Download the appropriate Windows package (e.g., `s-ui-windows-amd64.zip`) rm -fr /usr/local/s-ui
3. Extract the ZIP file to a directory of your choice rm /usr/bin/s-ui
4. Run `install-windows.bat` as Administrator ```
5. Follow the installation wizard
6. Access the panel at http://localhost:2095/app ## 使用 Docker 安装
## Uninstall S-UI <details>
<summary>点击查看详情</summary>
```sh
sudo -i ### 使用方式
systemctl disable s-ui --now **步骤 1** 安装 Docker
rm -f /etc/systemd/system/sing-box.service ```shell
systemctl daemon-reload curl -fsSL https://get.docker.com | sh
```
rm -fr /usr/local/s-ui
rm /usr/bin/s-ui **步骤 2** 安装 S-UI
```
> Docker compose 方式
## Install using Docker
```shell
<details> mkdir s-ui && cd s-ui
<summary>Click for details</summary> wget -q https://raw.githubusercontent.com/admin8800/s-ui/main/docker-compose.yml
docker compose up -d
### Usage ```
**Step 1:** Install Docker > 直接使用 docker
```shell ```shell
curl -fsSL https://get.docker.com | sh mkdir s-ui && cd s-ui
``` docker run -itd \
-p 2095:2095 -p 2096:2096 -p 443:443 -p 80:80 \
**Step 2:** Install S-UI -v $PWD/db/:/app/db/ \
-v $PWD/cert/:/root/cert/ \
> Docker compose method --name s-ui --restart=unless-stopped \
alireza7/s-ui:latest
```shell ```
mkdir s-ui && cd s-ui
wget -q https://raw.githubusercontent.com/alireza0/s-ui/master/docker-compose.yml > 自行构建镜像
docker compose up -d
``` ```shell
git clone https://github.com/admin8800/s-ui
> Use docker git submodule update --init --recursive
docker build -t s-ui .
```shell ```
mkdir s-ui && cd s-ui
docker run -itd \ </details>
-p 2095:2095 -p 2096:2096 -p 443:443 -p 80:80 \
-v $PWD/db/:/app/db/ \ ## 手动运行(贡献开发)
-v $PWD/cert/:/root/cert/ \
--name s-ui --restart=unless-stopped \ <details>
alireza7/s-ui:latest <summary>点击查看详情</summary>
```
### 构建并运行完整项目
> Build your own image ```shell
./runSUI.sh
```shell ```
git clone https://github.com/admin8800/s-ui
git submodule update --init --recursive ### 克隆仓库
docker build -t s-ui . ```shell
``` # 克隆仓库
git clone https://github.com/admin8800/s-ui
</details> # 克隆子模块
git submodule update --init --recursive
## Manual run ( contribution ) ```
<details> ### - 前端
<summary>Click for details</summary>
前端代码请查看 [s-ui-frontend](https://github.com/admin8800/s-ui-frontend)。
### Build and run whole project
```shell ### - 后端
./runSUI.sh > 请先至少构建一次前端。
```
构建后端:
### Clone the repository ```shell
```shell # 删除旧的前端编译文件
# clone repository rm -fr web/html/*
git clone https://github.com/admin8800/s-ui # 应用新的前端编译文件
# clone submodules cp -R frontend/dist/ web/html/
git submodule update --init --recursive # 构建
``` go build -o sui main.go
```
### - Frontend 运行后端(在仓库根目录执行):
```shell
Visit [s-ui-frontend](https://github.com/admin8800/s-ui-frontend) for frontend code ./sui
```
### - Backend
> Please build frontend once before! </details>
To build backend: ## 语言
```shell
# remove old frontend compiled files - 英语
rm -fr web/html/* - 波斯语
# apply new frontend compiled files - 越南语
cp -R frontend/dist/ web/html/ - 简体中文
# build - 繁体中文
go build -o sui main.go - 俄语
```
## 功能
To run backend (from root folder of repository):
```shell - 支持的协议:
./sui - 通用协议:Mixed、SOCKS、HTTP、HTTPS、Direct、Redirect、TProxy
``` - 基于 V2Ray 的协议:VLESS、VMess、Trojan、Shadowsocks
- 其他协议:ShadowTLS、Hysteria、Hysteria2、Naive、TUIC
</details> - 支持 XTLS 协议。
- 提供高级流量路由界面,支持 PROXY Protocol、External、透明代理、SSL 证书和端口配置。
## Languages - 提供高级入站和出站配置界面。
- 支持客户端流量上限和到期时间。
- English - 显示在线客户端、入站、出站流量统计和系统状态监控。
- Farsi - 订阅服务支持添加外部链接和订阅。
- Vietnamese - Web 面板和订阅服务支持 HTTPS 安全访问(需自行提供域名和 SSL 证书)。
- Chinese (Simplified) - 深色/浅色主题。
- Chinese (Traditional)
- Russian ## 环境变量
## Features <details>
<summary>点击查看详情</summary>
- Supported protocols:
- General: Mixed, SOCKS, HTTP, HTTPS, Direct, Redirect, TProxy ### 使用方式
- V2Ray based: VLESS, VMess, Trojan, Shadowsocks
- Other protocols: ShadowTLS, Hysteria, Hysteria2, Naive, TUIC | 变量 | 类型 | 默认值 |
- Supports XTLS protocols | -------------- | :--------------------------------------------: | :------------ |
- An advanced interface for routing traffic, incorporating PROXY Protocol, External, and Transparent Proxy, SSL Certificate, and Port | SUI_LOG_LEVEL | `"debug"` \| `"info"` \| `"warn"` \| `"error"` | `"info"` |
- An advanced interface for inbound and outbound configuration | SUI_DEBUG | `boolean` | `false` |
- Clients traffic cap and expiration date | SUI_BIN_FOLDER | `string` | `"bin"` |
- Displays online clients, inbounds and outbounds with traffic statistics, and system status monitoring | SUI_DB_FOLDER | `string` | `"db"` |
- Subscription service with ability to add external links and subscription | SINGBOX_API | `string` | - |
- HTTPS for secure access to the web panel and subscription service (self-provided domain + SSL certificate)
- Dark/Light theme </details>
## Environment Variables ## SSL 证书
<details> <details>
<summary>Click for details</summary> <summary>点击查看详情</summary>
### Usage ### Certbot
| Variable | Type | Default | ```bash
| -------------- | :--------------------------------------------: | :------------ | snap install core; snap refresh core
| SUI_LOG_LEVEL | `"debug"` \| `"info"` \| `"warn"` \| `"error"` | `"info"` | snap install --classic certbot
| SUI_DEBUG | `boolean` | `false` | ln -s /snap/bin/certbot /usr/bin/certbot
| SUI_BIN_FOLDER | `string` | `"bin"` |
| SUI_DB_FOLDER | `string` | `"db"` | certbot certonly --standalone --register-unsafely-without-email --non-interactive --agree-tos -d <你的域名>
| SINGBOX_API | `string` | - | ```
</details> </details>
## SSL Certificate
<details>
<summary>Click for details</summary>
### Certbot
```bash
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>
```
</details>
## Stargazers over Time
[![Stargazers over time](https://starchart.cc/alireza0/s-ui.svg)](https://starchart.cc/alireza0/s-ui)
+1 -6
View File
@@ -1,7 +1,6 @@
---
services: services:
s-ui: s-ui:
image: alireza7/s-ui image: admin8800/s-ui
container_name: s-ui container_name: s-ui
hostname: "s-ui" hostname: "s-ui"
volumes: volumes:
@@ -15,8 +14,4 @@ services:
networks: networks:
- s-ui - s-ui
entrypoint: "./entrypoint.sh" entrypoint: "./entrypoint.sh"
networks:
s-ui:
driver: bridge
+188 -188
View File
@@ -1,188 +1,188 @@
#!/bin/bash #!/bin/bash
red='\033[0;31m' red='\033[0;31m'
green='\033[0;32m' green='\033[0;32m'
yellow='\033[0;33m' yellow='\033[0;33m'
plain='\033[0m' plain='\033[0m'
cur_dir=$(pwd) cur_dir=$(pwd)
# check root # 检查 root 权限
[[ $EUID -ne 0 ]] && echo -e "${red}Fatal error: ${plain} Please run this script with root privilege \n " && exit 1 [[ $EUID -ne 0 ]] && echo -e "${red}致命错误:${plain}请使用 root 权限运行此脚本 \n " && exit 1
# Check OS and set release variable # 检查系统并设置 release 变量
if [[ -f /etc/os-release ]]; then if [[ -f /etc/os-release ]]; then
source /etc/os-release source /etc/os-release
release=$ID release=$ID
elif [[ -f /usr/lib/os-release ]]; then elif [[ -f /usr/lib/os-release ]]; then
source /usr/lib/os-release source /usr/lib/os-release
release=$ID release=$ID
else else
echo "Failed to check the system OS, please contact the author!" >&2 echo "检测系统失败,请联系作者!" >&2
exit 1 exit 1
fi fi
echo "The OS release is: $release" echo "当前系统发行版为:$release"
arch() { arch() {
case "$(uname -m)" in case "$(uname -m)" in
x86_64 | x64 | amd64) echo 'amd64' ;; x86_64 | x64 | amd64) echo 'amd64' ;;
i*86 | x86) echo '386' ;; i*86 | x86) echo '386' ;;
armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;; armv8* | armv8 | arm64 | aarch64) echo 'arm64' ;;
armv7* | armv7 | arm) echo 'armv7' ;; armv7* | armv7 | arm) echo 'armv7' ;;
armv6* | armv6) echo 'armv6' ;; armv6* | armv6) echo 'armv6' ;;
armv5* | armv5) echo 'armv5' ;; armv5* | armv5) echo 'armv5' ;;
s390x) echo 's390x' ;; s390x) echo 's390x' ;;
*) echo -e "${green}Unsupported CPU architecture! ${plain}" && rm -f install.sh && exit 1 ;; *) echo -e "${green}不支持的 CPU 架构!${plain}" && rm -f install.sh && exit 1 ;;
esac esac
} }
echo "arch: $(arch)" echo "架构:$(arch)"
install_base() { install_base() {
case "${release}" in case "${release}" in
centos | almalinux | rocky | oracle) centos | almalinux | rocky | oracle)
yum -y update && yum install -y -q wget curl tar tzdata yum -y update && yum install -y -q wget curl tar tzdata
;; ;;
fedora) fedora)
dnf -y update && dnf install -y -q wget curl tar tzdata dnf -y update && dnf install -y -q wget curl tar tzdata
;; ;;
arch | manjaro | parch) arch | manjaro | parch)
pacman -Syu && pacman -Syu --noconfirm wget curl tar tzdata pacman -Syu && pacman -Syu --noconfirm wget curl tar tzdata
;; ;;
opensuse-tumbleweed) opensuse-tumbleweed)
zypper refresh && zypper -q install -y wget curl tar timezone zypper refresh && zypper -q install -y wget curl tar timezone
;; ;;
*) *)
apt-get update && apt-get install -y -q wget curl tar tzdata apt-get update && apt-get install -y -q wget curl tar tzdata
;; ;;
esac esac
} }
config_after_install() { config_after_install() {
echo -e "${yellow}Migration... ${plain}" echo -e "${yellow}正在迁移... ${plain}"
/usr/local/s-ui/sui migrate /usr/local/s-ui/sui migrate
echo -e "${yellow}Install/update finished! For security it's recommended to modify panel settings ${plain}" echo -e "${yellow}安装/更新完成!出于安全考虑,建议修改面板设置 ${plain}"
read -p "Do you want to continue with the modification [y/n]? ": config_confirm read -p "是否继续修改设置 [y/n]": config_confirm
if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then if [[ "${config_confirm}" == "y" || "${config_confirm}" == "Y" ]]; then
echo -e "Enter the ${yellow}panel port${plain} (leave blank for existing/default value):" echo -e "请输入${yellow}面板端口${plain}(留空则使用现有/默认值):"
read config_port read config_port
echo -e "Enter the ${yellow}panel path${plain} (leave blank for existing/default value):" echo -e "请输入${yellow}面板路径${plain}(留空则使用现有/默认值):"
read config_path read config_path
# Sub configuration # 订阅配置
echo -e "Enter the ${yellow}subscription port${plain} (leave blank for existing/default value):" echo -e "请输入${yellow}订阅端口${plain}(留空则使用现有/默认值):"
read config_subPort read config_subPort
echo -e "Enter the ${yellow}subscription path${plain} (leave blank for existing/default value):" echo -e "请输入${yellow}订阅路径${plain}(留空则使用现有/默认值):"
read config_subPath read config_subPath
# Set configs # 设置配置
echo -e "${yellow}Initializing, please wait...${plain}" echo -e "${yellow}正在初始化,请稍候...${plain}"
params="" params=""
[ -z "$config_port" ] || params="$params -port $config_port" [ -z "$config_port" ] || params="$params -port $config_port"
[ -z "$config_path" ] || params="$params -path $config_path" [ -z "$config_path" ] || params="$params -path $config_path"
[ -z "$config_subPort" ] || params="$params -subPort $config_subPort" [ -z "$config_subPort" ] || params="$params -subPort $config_subPort"
[ -z "$config_subPath" ] || params="$params -subPath $config_subPath" [ -z "$config_subPath" ] || params="$params -subPath $config_subPath"
/usr/local/s-ui/sui setting ${params} /usr/local/s-ui/sui setting ${params}
read -p "Do you want to change admin credentials [y/n]? ": admin_confirm read -p "是否修改管理员账号密码 [y/n]": admin_confirm
if [[ "${admin_confirm}" == "y" || "${admin_confirm}" == "Y" ]]; then if [[ "${admin_confirm}" == "y" || "${admin_confirm}" == "Y" ]]; then
# First admin credentials # 首个管理员账号密码
read -p "Please set up your username:" config_account read -p "请设置用户名:" config_account
read -p "Please set up your password:" config_password read -p "请设置密码:" config_password
# Set credentials # 设置账号密码
echo -e "${yellow}Initializing, please wait...${plain}" echo -e "${yellow}正在初始化,请稍候...${plain}"
/usr/local/s-ui/sui admin -username ${config_account} -password ${config_password} /usr/local/s-ui/sui admin -username ${config_account} -password ${config_password}
else else
echo -e "${yellow}Your current admin credentials: ${plain}" echo -e "${yellow}当前管理员账号密码:${plain}"
/usr/local/s-ui/sui admin -show /usr/local/s-ui/sui admin -show
fi fi
else else
echo -e "${red}cancel...${plain}" echo -e "${red}已取消...${plain}"
if [[ ! -f "/usr/local/s-ui/db/s-ui.db" ]]; then if [[ ! -f "/usr/local/s-ui/db/s-ui.db" ]]; then
local usernameTemp=$(head -c 6 /dev/urandom | base64) local usernameTemp=$(head -c 6 /dev/urandom | base64)
local passwordTemp=$(head -c 6 /dev/urandom | base64) local passwordTemp=$(head -c 6 /dev/urandom | base64)
echo -e "this is a fresh installation,will generate random login info for security concerns:" echo -e "这是全新安装,出于安全考虑将生成随机登录信息:"
echo -e "###############################################" echo -e "###############################################"
echo -e "${green}username:${usernameTemp}${plain}" echo -e "${green}用户名:${usernameTemp}${plain}"
echo -e "${green}password:${passwordTemp}${plain}" echo -e "${green}密码:${passwordTemp}${plain}"
echo -e "###############################################" echo -e "###############################################"
echo -e "${red}if you forgot your login info,you can type ${green}s-ui${red} for configuration menu${plain}" echo -e "${red}如果忘记登录信息,可以输入 ${green}s-ui${red} 打开配置菜单${plain}"
/usr/local/s-ui/sui admin -username ${usernameTemp} -password ${passwordTemp} /usr/local/s-ui/sui admin -username ${usernameTemp} -password ${passwordTemp}
else else
echo -e "${red} this is your upgrade,will keep old settings,if you forgot your login info,you can type ${green}s-ui${red} for configuration menu${plain}" echo -e "${red}这是升级安装,将保留旧设置;如果忘记登录信息,可以输入 ${green}s-ui${red} 打开配置菜单${plain}"
fi fi
fi fi
} }
prepare_services() { prepare_services() {
if [[ -f "/etc/systemd/system/sing-box.service" ]]; then if [[ -f "/etc/systemd/system/sing-box.service" ]]; then
echo -e "${yellow}Stopping sing-box service... ${plain}" echo -e "${yellow}正在停止 sing-box 服务... ${plain}"
systemctl stop sing-box systemctl stop sing-box
rm -f /usr/local/s-ui/bin/sing-box /usr/local/s-ui/bin/runSingbox.sh /usr/local/s-ui/bin/signal rm -f /usr/local/s-ui/bin/sing-box /usr/local/s-ui/bin/runSingbox.sh /usr/local/s-ui/bin/signal
fi fi
if [[ -e "/usr/local/s-ui/bin" ]]; then if [[ -e "/usr/local/s-ui/bin" ]]; then
echo -e "###############################################################" echo -e "###############################################################"
echo -e "${green}/usr/local/s-ui/bin${red} directory exists yet!" echo -e "${green}/usr/local/s-ui/bin${red} 目录已存在!"
echo -e "Please check the content and delete it manually after migration ${plain}" echo -e "请检查其中内容,并在迁移后手动删除 ${plain}"
echo -e "###############################################################" echo -e "###############################################################"
fi fi
systemctl daemon-reload systemctl daemon-reload
} }
install_s-ui() { install_s-ui() {
cd /tmp/ cd /tmp/
if [ $# == 0 ]; then if [ $# == 0 ]; then
last_version=$(curl -Ls "https://api.github.com/repos/alireza0/s-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') last_version=$(curl -Ls "https://api.github.com/repos/admin8800/s-ui/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [[ ! -n "$last_version" ]]; then if [[ ! -n "$last_version" ]]; then
echo -e "${red}Failed to fetch s-ui version, it maybe due to Github API restrictions, please try it later${plain}" echo -e "${red}获取 s-ui 版本失败,可能是 Github API 限制导致,请稍后重试${plain}"
exit 1 exit 1
fi fi
echo -e "Got s-ui latest version: ${last_version}, beginning the installation..." echo -e "已获取 s-ui 最新版本:${last_version},开始安装..."
wget -N --no-check-certificate -O /tmp/s-ui-linux-$(arch).tar.gz https://github.com/admin8800/s-ui/releases/download/${last_version}/s-ui-linux-$(arch).tar.gz wget -N --no-check-certificate -O /tmp/s-ui-linux-$(arch).tar.gz https://github.com/admin8800/s-ui/releases/download/${last_version}/s-ui-linux-$(arch).tar.gz
if [[ $? -ne 0 ]]; then if [[ $? -ne 0 ]]; then
echo -e "${red}Downloading s-ui failed, please be sure that your server can access Github ${plain}" echo -e "${red}下载 s-ui 失败,请确认服务器可以访问 Github ${plain}"
exit 1 exit 1
fi fi
else else
last_version=$1 last_version=$1
url="https://github.com/admin8800/s-ui/releases/download/${last_version}/s-ui-linux-$(arch).tar.gz" url="https://github.com/admin8800/s-ui/releases/download/${last_version}/s-ui-linux-$(arch).tar.gz"
echo -e "Beginning the install s-ui v$1" echo -e "开始安装 s-ui v$1"
wget -N --no-check-certificate -O /tmp/s-ui-linux-$(arch).tar.gz ${url} wget -N --no-check-certificate -O /tmp/s-ui-linux-$(arch).tar.gz ${url}
if [[ $? -ne 0 ]]; then if [[ $? -ne 0 ]]; then
echo -e "${red}download s-ui v$1 failed,please check the version exists${plain}" echo -e "${red}下载 s-ui v$1 失败,请检查该版本是否存在${plain}"
exit 1 exit 1
fi fi
fi fi
if [[ -e /usr/local/s-ui/ ]]; then if [[ -e /usr/local/s-ui/ ]]; then
systemctl stop s-ui systemctl stop s-ui
fi fi
tar zxvf s-ui-linux-$(arch).tar.gz tar zxvf s-ui-linux-$(arch).tar.gz
rm s-ui-linux-$(arch).tar.gz -f rm s-ui-linux-$(arch).tar.gz -f
chmod +x s-ui/sui s-ui/s-ui.sh chmod +x s-ui/sui s-ui/s-ui.sh
cp s-ui/s-ui.sh /usr/bin/s-ui cp s-ui/s-ui.sh /usr/bin/s-ui
cp -rf s-ui /usr/local/ cp -rf s-ui /usr/local/
cp -f s-ui/*.service /etc/systemd/system/ cp -f s-ui/*.service /etc/systemd/system/
rm -rf s-ui rm -rf s-ui
config_after_install config_after_install
prepare_services prepare_services
systemctl enable s-ui --now systemctl enable s-ui --now
echo -e "${green}s-ui v${last_version}${plain} installation finished, it is up and running now..." echo -e "${green}s-ui v${last_version}${plain} 安装完成,现已启动并运行..."
echo -e "You may access the Panel with following URL(s):${green}" echo -e "你可以通过以下 URL 访问面板:${green}"
/usr/local/s-ui/sui uri /usr/local/s-ui/sui uri
echo -e "${plain}" echo -e "${plain}"
echo -e "" echo -e ""
s-ui help s-ui help
} }
echo -e "${green}Executing...${plain}" echo -e "${green}正在执行...${plain}"
install_base install_base
install_s-ui $1 install_s-ui $1
+934 -934
View File
File diff suppressed because it is too large Load Diff