改为手动触发流水线

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
+54 -32
View File
@@ -1,28 +1,36 @@
name: Docker Image CI name: Docker 镜像 CI
on: on:
push:
tags:
- "*"
workflow_dispatch: workflow_dispatch:
inputs:
tag:
description: "发布标签"
required: true
default: "v1.4.1"
type: string
jobs: jobs:
frontend-build: frontend-build:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: Checkout repository - name: 检出仓库
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.2
with: with:
ref: ${{ inputs.tag }}
submodules: recursive submodules: recursive
- name: Set up Node.js
- name: 设置 Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: 25 node-version: 25
- name: Install dependencies and build frontend
- name: 安装依赖并构建前端
run: | run: |
cd frontend cd frontend
npm install npm install
npm run build npm run build
- name: Upload frontend build artifact
- name: 上传前端构建产物
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: frontend-dist name: frontend-dist
@@ -41,18 +49,23 @@ jobs:
- { platform: linux/arm/v6 } - { platform: linux/arm/v6 }
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: Checkout repository - name: 检出仓库
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.2
- name: Download frontend build artifact with:
ref: ${{ inputs.tag }}
- name: 下载前端构建产物
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
with: with:
name: frontend-dist name: frontend-dist
path: frontend_dist path: frontend_dist
- name: Prepare
- name: 准备
run: | run: |
platform="${{ matrix.platform }}" platform="${{ matrix.platform }}"
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Docker meta
- name: Docker 元数据
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v6
with: with:
@@ -60,32 +73,36 @@ jobs:
alireza7/s-ui alireza7/s-ui
ghcr.io/alireza0/s-ui ghcr.io/alireza0/s-ui
tags: | tags: |
type=ref,event=branch type=raw,value=${{ inputs.tag }}
type=ref,event=tag
type=pep440,pattern={{version}} - name: 设置 QEMU
- name: Set up QEMU
uses: docker/setup-qemu-action@v4 uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v4
- name: Cache Docker layers
- name: 缓存 Docker 层
uses: actions/cache@v5 uses: actions/cache@v5
with: with:
path: /tmp/.buildx-cache path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ matrix.platform }}-${{ github.sha }} key: ${{ runner.os }}-buildx-${{ matrix.platform }}-${{ github.sha }}
restore-keys: | restore-keys: |
${{ runner.os }}-buildx-${{ matrix.platform }}- ${{ runner.os }}-buildx-${{ matrix.platform }}-
- name: Login to Docker Hub
- name: 登录 Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@v4
with: with:
username: ${{ secrets.DOCKER_HUB_USERNAME }} username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }} password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Login to GHCR
- name: 登录 GHCR
uses: docker/login-action@v4 uses: docker/login-action@v4
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push by digest
- name: 按摘要构建并推送
id: build id: build
uses: docker/build-push-action@v7 uses: docker/build-push-action@v7
with: with:
@@ -99,12 +116,14 @@ jobs:
cache-from: type=local,src=/tmp/.buildx-cache cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache,mode=max cache-to: type=local,dest=/tmp/.buildx-cache,mode=max
outputs: type=image,push-by-digest=true,name-canonical=true,push=true outputs: type=image,push-by-digest=true,name-canonical=true,push=true
- name: Export digest
- name: 导出摘要
run: | run: |
mkdir -p ${{ runner.temp }}/digests mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}" digest="${{ steps.build.outputs.digest }}"
echo "${digest#sha256:}" > "${{ runner.temp }}/digests/${digest#sha256:}" echo "${digest#sha256:}" > "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
- name: 上传摘要
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: digests-${{ env.PLATFORM_PAIR }} name: digests-${{ env.PLATFORM_PAIR }}
@@ -116,26 +135,30 @@ jobs:
needs: build needs: build
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
steps: steps:
- name: Download digests - name: 下载摘要
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
with: with:
path: ${{ runner.temp }}/digests path: ${{ runner.temp }}/digests
pattern: digests-* pattern: digests-*
merge-multiple: true merge-multiple: true
- name: Login to Docker Hub
- name: 登录 Docker Hub
uses: docker/login-action@v4 uses: docker/login-action@v4
with: with:
username: ${{ secrets.DOCKER_HUB_USERNAME }} username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_TOKEN }} password: ${{ secrets.DOCKER_HUB_TOKEN }}
- name: Login to GHCR
- name: 登录 GHCR
uses: docker/login-action@v4 uses: docker/login-action@v4
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v4 uses: docker/setup-buildx-action@v4
- name: Docker meta
- name: Docker 元数据
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v6
with: with:
@@ -143,10 +166,9 @@ jobs:
alireza7/s-ui alireza7/s-ui
ghcr.io/alireza0/s-ui ghcr.io/alireza0/s-ui
tags: | tags: |
type=ref,event=branch type=raw,value=${{ inputs.tag }}
type=ref,event=tag
type=pep440,pattern={{version}} - name: 创建清单列表并推送
- name: Create manifest list and push
env: env:
DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }} DOCKER_METADATA_OUTPUT_JSON: ${{ steps.meta.outputs.json }}
working-directory: ${{ runner.temp }}/digests working-directory: ${{ runner.temp }}/digests
+36 -45
View File
@@ -1,22 +1,13 @@
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:
- '.github/workflows/release.yml'
- 'frontend/**'
- '**.sh'
- '**.go'
- 'go.mod'
- 'go.sum'
- 's-ui.service'
env: env:
NODE_VERSION: "25" NODE_VERSION: "25"
@@ -28,34 +19,35 @@ jobs:
build-frontend: build-frontend:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository (frontend only) - name: 检出仓库(仅前端)
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.2
with: with:
ref: ${{ inputs.tag }}
submodules: recursive submodules: recursive
fetch-depth: 1 fetch-depth: 1
- name: Setup Node.js - name: 设置 Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: ${{ env.NODE_VERSION }} node-version: ${{ env.NODE_VERSION }}
cache: 'npm' cache: 'npm'
cache-dependency-path: frontend/package-lock.json cache-dependency-path: frontend/package-lock.json
- name: Build frontend - name: 构建前端
run: | run: |
cd frontend cd frontend
npm install npm install
npm run build npm run build
cd .. cd ..
- name: Upload frontend dist - name: 上传前端 dist
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: frontend-dist name: frontend-dist
path: frontend/dist/ path: frontend/dist/
build-linux: build-linux:
name: build-${{ matrix.platform }} name: 构建-${{ matrix.platform }}
needs: build-frontend needs: build-frontend
strategy: strategy:
fail-fast: false fail-fast: false
@@ -70,23 +62,25 @@ jobs:
- { platform: s390x, arch: s390x, bootlin: s390x-z13, naive: false } - { platform: s390x, arch: s390x, bootlin: s390x-z13, naive: false }
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: 检出仓库
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.2
with:
ref: ${{ inputs.tag }}
- name: Download frontend dist - name: 下载前端 dist
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
with: with:
name: frontend-dist name: frontend-dist
path: web/html path: web/html
- name: Setup Go - name: 设置 Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
cache: false cache: false
go-version-file: go.mod go-version-file: go.mod
# Naive platforms: use cronet toolchain only (no Bootlin). # Naive 平台:仅使用 cronet 工具链(不使用 Bootlin)。
- name: Clone cronet-go (cronet toolchain for naive) - name: 克隆 cronet-gonaive 使用的 cronet 工具链)
if: matrix.naive if: matrix.naive
run: | run: |
set -e set -e
@@ -96,7 +90,7 @@ jobs:
git -C ~/cronet-go checkout FETCH_HEAD git -C ~/cronet-go checkout FETCH_HEAD
git -C ~/cronet-go submodule update --init --recursive --depth=1 git -C ~/cronet-go submodule update --init --recursive --depth=1
- name: Regenerate Debian keyring (cronet sysroot) - name: 重新生成 Debian keyringcronet sysroot
if: matrix.naive if: matrix.naive
run: | run: |
set -e set -e
@@ -104,7 +98,7 @@ jobs:
cd ~/cronet-go cd ~/cronet-go
GPG_TTY=/dev/null ./naiveproxy/src/build/linux/sysroot_scripts/generate_keyring.sh GPG_TTY=/dev/null ./naiveproxy/src/build/linux/sysroot_scripts/generate_keyring.sh
- name: Cache Chromium toolchain - name: 缓存 Chromium 工具链
if: matrix.naive if: matrix.naive
id: cache-chromium-toolchain id: cache-chromium-toolchain
uses: actions/cache@v5 uses: actions/cache@v5
@@ -116,7 +110,7 @@ jobs:
~/cronet-go/naiveproxy/src/out/sysroot-build/ ~/cronet-go/naiveproxy/src/out/sysroot-build/
key: chromium-toolchain-${{ matrix.platform }}-musl-${{ env.CRONET_GO_VERSION }} key: chromium-toolchain-${{ matrix.platform }}-musl-${{ env.CRONET_GO_VERSION }}
- name: Build cronet lib and set toolchain env (CC, CXX, CGO_LDFLAGS, PATH) - name: 构建 cronet 库并设置工具链环境(CC、CXXCGO_LDFLAGSPATH
if: matrix.naive if: matrix.naive
run: | run: |
set -e set -e
@@ -128,24 +122,24 @@ jobs:
echo "$line" >> $GITHUB_ENV echo "$line" >> $GITHUB_ENV
done done
- name: Set Go build env (all platforms) - name: 设置 Go 构建环境(所有平台)
run: | run: |
echo "CGO_ENABLED=1" >> $GITHUB_ENV echo "CGO_ENABLED=1" >> $GITHUB_ENV
echo "GOOS=linux" >> $GITHUB_ENV echo "GOOS=linux" >> $GITHUB_ENV
echo "GOARCH=${{ matrix.arch }}" >> $GITHUB_ENV echo "GOARCH=${{ matrix.arch }}" >> $GITHUB_ENV
if [ -n "${{ matrix.goarm }}" ]; then echo "GOARM=${{ matrix.goarm }}" >> $GITHUB_ENV; fi if [ -n "${{ matrix.goarm }}" ]; then echo "GOARM=${{ matrix.goarm }}" >> $GITHUB_ENV; fi
# Non-naive platforms only: Bootlin musl (armv5, s390x). # 仅非 naive 平台:Bootlin muslarmv5s390x)。
- name: Set up Bootlin musl (armv5, s390x) - name: 设置 Bootlin muslarmv5s390x
if: ${{ matrix.naive != true }} if: ${{ matrix.naive != true }}
run: | run: |
set -e set -e
BOOTLIN_ARCH="${{ matrix.bootlin }}" BOOTLIN_ARCH="${{ matrix.bootlin }}"
echo "Resolving Bootlin musl toolchain for arch=$BOOTLIN_ARCH (platform=${{ matrix.platform }})" echo "正在解析 arch=$BOOTLIN_ARCH 的 Bootlin musl 工具链(平台=${{ matrix.platform }}"
TARBALL_BASE="${{ env.BOOTLIN_BASE_URL }}/$BOOTLIN_ARCH/tarballs/" TARBALL_BASE="${{ env.BOOTLIN_BASE_URL }}/$BOOTLIN_ARCH/tarballs/"
TARBALL_URL=$(curl -fsSL "$TARBALL_BASE" | grep -oE "${BOOTLIN_ARCH}--musl--stable-[^\"]+\\.tar\\.xz" | sort -r | head -n1) TARBALL_URL=$(curl -fsSL "$TARBALL_BASE" | grep -oE "${BOOTLIN_ARCH}--musl--stable-[^\"]+\\.tar\\.xz" | sort -r | head -n1)
[ -z "$TARBALL_URL" ] && { echo "Failed to locate Bootlin musl toolchain for arch=$BOOTLIN_ARCH" >&2; exit 1; } [ -z "$TARBALL_URL" ] && { echo "未找到 arch=$BOOTLIN_ARCH 的 Bootlin musl 工具链" >&2; exit 1; }
echo "Downloading: $TARBALL_URL" echo "正在下载:$TARBALL_URL"
cd /tmp cd /tmp
curl -fL -sS -o "$(basename "$TARBALL_URL")" "$TARBALL_BASE/$TARBALL_URL" curl -fL -sS -o "$(basename "$TARBALL_URL")" "$TARBALL_BASE/$TARBALL_URL"
tar -xf "$(basename "$TARBALL_URL")" tar -xf "$(basename "$TARBALL_URL")"
@@ -154,7 +148,7 @@ jobs:
BIN_DIR="$TOOLCHAIN_DIR/bin" BIN_DIR="$TOOLCHAIN_DIR/bin"
echo "PATH=$BIN_DIR:$PATH" >> $GITHUB_ENV echo "PATH=$BIN_DIR:$PATH" >> $GITHUB_ENV
CC=$(find "$BIN_DIR" -maxdepth 1 \( -name '*-gcc.br_real' -o -name '*-gcc' \) -type f -executable 2>/dev/null | grep -v g++ | head -n1) CC=$(find "$BIN_DIR" -maxdepth 1 \( -name '*-gcc.br_real' -o -name '*-gcc' \) -type f -executable 2>/dev/null | grep -v g++ | head -n1)
[ -z "$CC" ] && { echo "No gcc found in $BIN_DIR" >&2; exit 1; } [ -z "$CC" ] && { echo "在 $BIN_DIR 中未找到 gcc" >&2; exit 1; }
echo "CC=$(realpath "$CC")" >> $GITHUB_ENV echo "CC=$(realpath "$CC")" >> $GITHUB_ENV
SYSROOT="" SYSROOT=""
F=$(find "$TOOLCHAIN_DIR" -name "libc-header-start.h" 2>/dev/null | head -1) F=$(find "$TOOLCHAIN_DIR" -name "libc-header-start.h" 2>/dev/null | head -1)
@@ -164,38 +158,35 @@ jobs:
echo "CGO_LDFLAGS=--sysroot=$SYSROOT -static" >> $GITHUB_ENV echo "CGO_LDFLAGS=--sysroot=$SYSROOT -static" >> $GITHUB_ENV
fi fi
- name: Build s-ui - name: 构建 s-ui
run: | run: |
set -e set -e
BUILD_TAGS="with_quic,with_grpc,with_utls,with_acme,with_gvisor,badlinkname,tfogo_checklinkname0,with_tailscale" BUILD_TAGS="with_quic,with_grpc,with_utls,with_acme,with_gvisor,badlinkname,tfogo_checklinkname0,with_tailscale"
[ "${{ matrix.naive }}" = "true" ] && BUILD_TAGS="${BUILD_TAGS},with_naive_outbound,with_musl" [ "${{ 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 go build -ldflags="-w -s -checklinkname=0 -linkmode external -extldflags '-static'" -tags "$BUILD_TAGS" -o sui main.go
file sui file sui
ldd sui 2>/dev/null || echo "Static binary confirmed" ldd sui 2>/dev/null || echo "已确认静态二进制文件"
mkdir s-ui mkdir s-ui
cp sui s-ui/ cp sui s-ui/
cp s-ui.service s-ui/ cp s-ui.service s-ui/
cp s-ui.sh s-ui/ cp s-ui.sh s-ui/
- name: Package - name: 打包
run: tar -zcvf s-ui-linux-${{ matrix.platform }}.tar.gz s-ui run: tar -zcvf s-ui-linux-${{ matrix.platform }}.tar.gz s-ui
- name: Upload artifact - name: 上传构建产物
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: s-ui-linux-${{ matrix.platform }} name: s-ui-linux-${{ matrix.platform }}
path: ./s-ui-linux-${{ matrix.platform }}.tar.gz path: ./s-ui-linux-${{ matrix.platform }}.tar.gz
retention-days: 30 retention-days: 30
- name: Upload to Release - name: 上传到 Release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
if: |
(github.event_name == 'release' && github.event.action == 'published') ||
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }} tag: ${{ inputs.tag }}
file: s-ui-linux-${{ matrix.platform }}.tar.gz file: s-ui-linux-${{ matrix.platform }}.tar.gz
asset_name: s-ui-linux-${{ matrix.platform }}.tar.gz asset_name: s-ui-linux-${{ matrix.platform }}.tar.gz
prerelease: true prerelease: true
+28 -36
View File
@@ -1,21 +1,13 @@
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:
- '.github/workflows/windows.yml'
- 'frontend/**'
- '**.go'
- 'go.mod'
- 'go.sum'
- 'windows/**'
env: env:
NODE_VERSION: "25" NODE_VERSION: "25"
@@ -26,26 +18,27 @@ jobs:
build-frontend: build-frontend:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: 检出仓库
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.2
with: with:
ref: ${{ inputs.tag }}
submodules: recursive submodules: recursive
fetch-depth: 1 fetch-depth: 1
- name: Setup Node.js - name: 设置 Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v6
with: with:
node-version: ${{ env.NODE_VERSION }} node-version: ${{ env.NODE_VERSION }}
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
- name: Build frontend - name: 构建前端
run: | run: |
cd frontend cd frontend
npm install npm install
npm run build npm run build
cd .. cd ..
- name: Upload frontend artifact - name: 上传前端构建产物
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: frontend-dist name: frontend-dist
@@ -54,7 +47,7 @@ jobs:
build-windows: build-windows:
needs: build-frontend needs: build-frontend
name: build-windows-${{ matrix.arch }} name: 构建-windows-${{ matrix.arch }}
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -63,42 +56,44 @@ jobs:
- { arch: arm64, runner: ubuntu-latest, cgo: "0" } - { arch: arm64, runner: ubuntu-latest, cgo: "0" }
runs-on: ${{ matrix.runner }} runs-on: ${{ matrix.runner }}
steps: steps:
- name: Checkout repository - name: 检出仓库
uses: actions/checkout@v6.0.2 uses: actions/checkout@v6.0.2
with:
ref: ${{ inputs.tag }}
- name: Download frontend artifact - name: 下载前端构建产物
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
with: with:
name: frontend-dist name: frontend-dist
path: web/html path: web/html
- name: Setup Go - name: 设置 Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
cache: false cache: false
go-version-file: go.mod go-version-file: go.mod
- name: Install zip for Windows - name: Windows 安装 zip
if: matrix.arch == 'amd64' if: matrix.arch == 'amd64'
shell: powershell shell: powershell
run: | run: |
# Install Chocolatey if not available # 如果 Chocolatey 不可用,则安装 Chocolatey
if (!(Get-Command choco -ErrorAction SilentlyContinue)) { if (!(Get-Command choco -ErrorAction SilentlyContinue)) {
Set-ExecutionPolicy Bypass -Scope Process -Force Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
} }
# Install zip # 安装 zip
choco install zip -y choco install zip -y
- name: Build s-ui - name: 构建 s-ui
shell: bash shell: bash
run: | run: |
export CGO_ENABLED=${{ matrix.cgo }} export CGO_ENABLED=${{ matrix.cgo }}
export GOOS=windows export GOOS=windows
export GOARCH=${{ matrix.arch }} export GOARCH=${{ matrix.arch }}
echo "Building for Windows ${{ matrix.arch }}" echo "正在为 Windows ${{ matrix.arch }} 构建"
go version go version
go env GOOS GOARCH go env GOOS GOARCH
@@ -109,31 +104,28 @@ jobs:
cp sui.exe s-ui-windows/ cp sui.exe s-ui-windows/
cp -r windows/* s-ui-windows/ cp -r windows/* s-ui-windows/
- name: Download libcronet-go - name: 下载 libcronet-go
shell: bash shell: bash
run: | run: |
curl -qsL -o s-ui-windows/libcronet.dll ${{ env.LIBCRONET_BASE_URL }}/libcronet-windows-${{ matrix.arch }}.dll curl -qsL -o s-ui-windows/libcronet.dll ${{ env.LIBCRONET_BASE_URL }}/libcronet-windows-${{ matrix.arch }}.dll
- name: Package - name: 打包
shell: bash shell: bash
run: | run: |
zip -r "s-ui-windows-${{ matrix.arch }}.zip" s-ui-windows zip -r "s-ui-windows-${{ matrix.arch }}.zip" s-ui-windows
- name: Upload files to Artifacts - name: 上传文件到构建产物
uses: actions/upload-artifact@v7 uses: actions/upload-artifact@v7
with: with:
name: s-ui-windows-${{ matrix.arch }} name: s-ui-windows-${{ matrix.arch }}
path: ./s-ui-windows-${{ matrix.arch }}.zip path: ./s-ui-windows-${{ matrix.arch }}.zip
retention-days: 30 retention-days: 30
- name: Upload to Release - name: 上传到 Release
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
if: |
(github.event_name == 'release' && github.event.action == 'published') ||
(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/'))
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ github.ref }} tag: ${{ inputs.tag }}
file: s-ui-windows-${{ matrix.arch }}.zip file: s-ui-windows-${{ matrix.arch }}.zip
asset_name: s-ui-windows-${{ matrix.arch }}.zip asset_name: s-ui-windows-${{ matrix.arch }}.zip
prerelease: true prerelease: true
+102 -122
View File
@@ -1,101 +1,85 @@
# 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 > **免责声明:** 本项目仅供个人学习与交流使用,请勿用于非法用途,请勿在生产环境中使用。
**If you think this project is helpful to you, you may wish to give a**:star2:
**Want to contribute?** See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, coding conventions, testing, and the pull request process. ## 快速概览
| 功能 | 是否支持 |
[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/alireza7)
<a href="https://nowpayments.io/donation/alireza7" target="_blank" rel="noreferrer noopener">
<img src="https://nowpayments.io/images/embeds/donation-button-white.svg" alt="Crypto donation button by NOWPayments">
</a>
## Quick Overview
| Features | Enable? |
| -------------------------------------- | :----------------: | | -------------------------------------- | :----------------: |
| Multi-Protocol | :heavy_check_mark: | | 多协议 | :heavy_check_mark: |
| Multi-Language | :heavy_check_mark: | | 多语言 | :heavy_check_mark: |
| Multi-Client/Inbound | :heavy_check_mark: | | 多客户端/入站 | :heavy_check_mark: |
| Advanced Traffic Routing Interface | :heavy_check_mark: | | 高级流量路由界面 | :heavy_check_mark: |
| Client & Traffic & System Status | :heavy_check_mark: | | 客户端、流量与系统状态 | :heavy_check_mark: |
| Subscription Link (link/json/clash + info)| :heavy_check_mark: | | 订阅链接(link/json/clash + info | :heavy_check_mark: |
| Dark/Light Theme | :heavy_check_mark: | | 深色/浅色主题 | :heavy_check_mark: |
| API Interface | :heavy_check_mark: | | API 接口 | :heavy_check_mark: |
## Supported Platforms ## 支持平台
| Platform | Architecture | Status | | 平台 | 架构 | 状态 |
|----------|--------------|---------| |----------|--------------|---------|
| Linux | amd64, arm64, armv7, armv6, armv5, 386, s390x | ✅ Supported | | Linux | amd64, arm64, armv7, armv6, armv5, 386, s390x | 支持 |
| Windows | amd64, 386, arm64 | ✅ Supported | | Windows | amd64, 386, arm64 | 支持 |
| macOS | amd64, arm64 | 🚧 Experimental | | macOS | amd64, arm64 | 实验性支持 |
## Screenshots ## 截图
!["Main"](https://github.com/admin8800/s-ui-frontend/raw/main/media/main.png) !["主界面"](https://github.com/admin8800/s-ui-frontend/raw/main/media/main.png)
[Other UI Screenshots](https://github.com/admin8800/s-ui-frontend/blob/main/screenshots.md) ## API 文档
## API Documentation [API 文档 Wiki](https://github.com/admin8800/s-ui/wiki/API-Documentation)
[API-Documentation Wiki](https://github.com/admin8800/s-ui/wiki/API-Documentation) ## 默认安装信息
- 面板端口:2095
- 面板路径:/app/
- 订阅端口:2096
- 订阅路径:/sub/
- 用户名/密码:admin
## Default Installation Information ## 安装或升级到最新版本
- Panel Port: 2095
- Panel Path: /app/
- Subscription Port: 2096
- Subscription Path: /sub/
- User/Password: admin
## Install & Upgrade to Latest Version
### Linux/macOS ### Linux/macOS
```sh ```sh
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/s-ui/master/install.sh) bash <(curl -Ls https://raw.githubusercontent.com/admin8800/s-ui/main/install.sh)
``` ```
### Windows ### Windows
1. Download the latest Windows release from [GitHub Releases](https://github.com/admin8800/s-ui/releases/latest) 1. [GitHub Releases](https://github.com/admin8800/s-ui/releases/latest) 下载最新 Windows 版本。
2. Extract the ZIP file 2. 解压 ZIP 文件。
3. Run `install-windows.bat` as Administrator 3. 以管理员身份运行 `install-windows.bat`
4. Follow the installation wizard 4. 按照安装向导操作。
## Install legacy Version ## 安装旧版本
**Step 1:** To install your desired legacy version, add the version to the end of the installation command. e.g., ver `1.0.0`: **步骤 1** 如果要安装指定旧版本,请在安装命令末尾追加版本号。例如版本 `1.0.0`
```sh ```sh
VERSION=1.0.0 && bash <(curl -Ls https://raw.githubusercontent.com/alireza0/s-ui/$VERSION/install.sh) $VERSION VERSION=1.0.0 && bash <(curl -Ls https://raw.githubusercontent.com/admin8800/s-ui/$VERSION/install.sh) $VERSION
``` ```
## Manual installation ## 手动安装
### Linux/macOS ### 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) 1. 根据你的系统和架构,从 GitHub 获取最新版本 S-UI[https://github.com/admin8800/s-ui/releases/latest](https://github.com/admin8800/s-ui/releases/latest)
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) 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. **OPTIONAL** Copy `s-ui.sh` to /usr/bin/ and run `chmod +x /usr/bin/s-ui`. 3. **可选:** `s-ui.sh` 复制到 `/usr/bin/`,并执行 `chmod +x /usr/bin/s-ui`
4. Extract s-ui tar.gz file to a directory of your choice and navigate to the directory where you extracted the tar.gz file. 4. s-ui tar.gz 文件解压到你选择的目录,并进入解压后的目录。
5. Copy *.service files to /etc/systemd/system/ and run `systemctl daemon-reload`. 5. `*.service` 文件复制到 `/etc/systemd/system/`,然后执行 `systemctl daemon-reload`
6. Enable autostart and start S-UI service using `systemctl enable s-ui --now` 6. 使用 `systemctl enable s-ui --now` 启用开机自启并启动 S-UI 服务。
7. Start sing-box service using `systemctl enable sing-box --now` 7. 使用 `systemctl enable sing-box --now` 启动 sing-box 服务。
### Windows ### Windows
1. Get the latest Windows version from GitHub: [https://github.com/admin8800/s-ui/releases/latest](https://github.com/admin8800/s-ui/releases/latest) 1. 从 GitHub 获取最新 Windows 版本:[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`) 2. 下载适合的 Windows 包,例如 `s-ui-windows-amd64.zip`
3. Extract the ZIP file to a directory of your choice 3. 将 ZIP 文件解压到你选择的目录。
4. Run `install-windows.bat` as Administrator 4. 以管理员身份运行 `install-windows.bat`
5. Follow the installation wizard 5. 按照安装向导操作。
6. Access the panel at http://localhost:2095/app 6. 访问面板:http://localhost:2095/app
## Uninstall S-UI ## 卸载 S-UI
```sh ```sh
sudo -i sudo -i
@@ -109,30 +93,30 @@ rm -fr /usr/local/s-ui
rm /usr/bin/s-ui rm /usr/bin/s-ui
``` ```
## Install using Docker ## 使用 Docker 安装
<details> <details>
<summary>Click for details</summary> <summary>点击查看详情</summary>
### Usage ### 使用方式
**Step 1:** Install Docker **步骤 1** 安装 Docker
```shell ```shell
curl -fsSL https://get.docker.com | sh curl -fsSL https://get.docker.com | sh
``` ```
**Step 2:** Install S-UI **步骤 2** 安装 S-UI
> Docker compose method > Docker compose 方式
```shell ```shell
mkdir s-ui && cd s-ui mkdir s-ui && cd s-ui
wget -q https://raw.githubusercontent.com/alireza0/s-ui/master/docker-compose.yml wget -q https://raw.githubusercontent.com/admin8800/s-ui/main/docker-compose.yml
docker compose up -d docker compose up -d
``` ```
> Use docker > 直接使用 docker
```shell ```shell
mkdir s-ui && cd s-ui mkdir s-ui && cd s-ui
@@ -144,7 +128,7 @@ docker run -itd \
alireza7/s-ui:latest alireza7/s-ui:latest
``` ```
> Build your own image > 自行构建镜像
```shell ```shell
git clone https://github.com/admin8800/s-ui git clone https://github.com/admin8800/s-ui
@@ -154,81 +138,80 @@ docker build -t s-ui .
</details> </details>
## Manual run ( contribution ) ## 手动运行(贡献开发)
<details> <details>
<summary>Click for details</summary> <summary>点击查看详情</summary>
### Build and run whole project ### 构建并运行完整项目
```shell ```shell
./runSUI.sh ./runSUI.sh
``` ```
### Clone the repository ### 克隆仓库
```shell ```shell
# clone repository # 克隆仓库
git clone https://github.com/admin8800/s-ui git clone https://github.com/admin8800/s-ui
# clone submodules # 克隆子模块
git submodule update --init --recursive git submodule update --init --recursive
``` ```
### - 前端
### - Frontend 前端代码请查看 [s-ui-frontend](https://github.com/admin8800/s-ui-frontend)。
Visit [s-ui-frontend](https://github.com/admin8800/s-ui-frontend) for frontend code ### - 后端
> 请先至少构建一次前端。
### - Backend 构建后端:
> Please build frontend once before!
To build backend:
```shell ```shell
# remove old frontend compiled files # 删除旧的前端编译文件
rm -fr web/html/* rm -fr web/html/*
# apply new frontend compiled files # 应用新的前端编译文件
cp -R frontend/dist/ web/html/ cp -R frontend/dist/ web/html/
# build # 构建
go build -o sui main.go go build -o sui main.go
``` ```
To run backend (from root folder of repository): 运行后端(在仓库根目录执行):
```shell ```shell
./sui ./sui
``` ```
</details> </details>
## Languages ## 语言
- English - 英语
- Farsi - 波斯语
- Vietnamese - 越南语
- Chinese (Simplified) - 简体中文
- Chinese (Traditional) - 繁体中文
- Russian - 俄语
## Features ## 功能
- Supported protocols: - 支持的协议:
- General: Mixed, SOCKS, HTTP, HTTPS, Direct, Redirect, TProxy - 通用协议:MixedSOCKSHTTPHTTPSDirectRedirectTProxy
- V2Ray based: VLESS, VMess, Trojan, Shadowsocks - 基于 V2Ray 的协议:VLESSVMessTrojanShadowsocks
- Other protocols: ShadowTLS, Hysteria, Hysteria2, Naive, TUIC - 其他协议:ShadowTLSHysteriaHysteria2NaiveTUIC
- Supports XTLS protocols - 支持 XTLS 协议。
- An advanced interface for routing traffic, incorporating PROXY Protocol, External, and Transparent Proxy, SSL Certificate, and Port - 提供高级流量路由界面,支持 PROXY ProtocolExternal、透明代理、SSL 证书和端口配置。
- An advanced interface for inbound and outbound configuration - 提供高级入站和出站配置界面。
- Clients traffic cap and expiration date - 支持客户端流量上限和到期时间。
- Displays online clients, inbounds and outbounds with traffic statistics, and system status monitoring - 显示在线客户端、入站、出站流量统计和系统状态监控。
- Subscription service with ability to add external links and subscription - 订阅服务支持添加外部链接和订阅。
- HTTPS for secure access to the web panel and subscription service (self-provided domain + SSL certificate) - Web 面板和订阅服务支持 HTTPS 安全访问(需自行提供域名和 SSL 证书)。
- Dark/Light theme - 深色/浅色主题。
## Environment Variables ## 环境变量
<details> <details>
<summary>Click for details</summary> <summary>点击查看详情</summary>
### Usage ### 使用方式
| Variable | Type | Default | | 变量 | 类型 | 默认值 |
| -------------- | :--------------------------------------------: | :------------ | | -------------- | :--------------------------------------------: | :------------ |
| SUI_LOG_LEVEL | `"debug"` \| `"info"` \| `"warn"` \| `"error"` | `"info"` | | SUI_LOG_LEVEL | `"debug"` \| `"info"` \| `"warn"` \| `"error"` | `"info"` |
| SUI_DEBUG | `boolean` | `false` | | SUI_DEBUG | `boolean` | `false` |
@@ -238,10 +221,10 @@ To run backend (from root folder of repository):
</details> </details>
## SSL Certificate ## SSL 证书
<details> <details>
<summary>Click for details</summary> <summary>点击查看详情</summary>
### Certbot ### Certbot
@@ -250,10 +233,7 @@ snap install core; snap refresh core
snap install --classic certbot snap install --classic certbot
ln -s /snap/bin/certbot /usr/bin/certbot ln -s /snap/bin/certbot /usr/bin/certbot
certbot certonly --standalone --register-unsafely-without-email --non-interactive --agree-tos -d <Your Domain Name> certbot certonly --standalone --register-unsafely-without-email --non-interactive --agree-tos -d <你的域名>
``` ```
</details> </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:
@@ -16,7 +15,3 @@ services:
- s-ui - s-ui
entrypoint: "./entrypoint.sh" entrypoint: "./entrypoint.sh"
networks:
s-ui:
driver: bridge
+42 -42
View File
@@ -7,10 +7,10 @@ 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
@@ -18,10 +18,10 @@ 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
@@ -32,11 +32,11 @@ arch() {
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
@@ -59,25 +59,25 @@ install_base() {
} }
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"
@@ -85,47 +85,47 @@ config_after_install() {
[ -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
@@ -135,24 +135,24 @@ 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
@@ -175,14 +175,14 @@ install_s-ui() {
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
+187 -187
View File
@@ -6,18 +6,18 @@ yellow='\033[0;33m'
plain='\033[0m' plain='\033[0m'
function LOGD() { function LOGD() {
echo -e "${yellow}[DEG] $* ${plain}" echo -e "${yellow}[调试] $* ${plain}"
} }
function LOGE() { function LOGE() {
echo -e "${red}[ERR] $* ${plain}" echo -e "${red}[错误] $* ${plain}"
} }
function LOGI() { function LOGI() {
echo -e "${green}[INF] $* ${plain}" echo -e "${green}[信息] $* ${plain}"
} }
[[ $EUID -ne 0 ]] && LOGE "ERROR: You must be root to run this script! \n" && exit 1 [[ $EUID -ne 0 ]] && LOGE "错误:必须使用 root 权限运行此脚本!\n" && exit 1
if [[ -f /etc/os-release ]]; then if [[ -f /etc/os-release ]]; then
source /etc/os-release source /etc/os-release
@@ -26,20 +26,20 @@ 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"
confirm() { confirm() {
if [[ $# > 1 ]]; then if [[ $# > 1 ]]; then
echo && read -p "$1 [Default$2]: " temp echo && read -p "$1 [默认$2]: " temp
if [[ x"${temp}" == x"" ]]; then if [[ x"${temp}" == x"" ]]; then
temp=$2 temp=$2
fi fi
else else
read -p "$1 [y/n]: " temp read -p "$1 [y/n] " temp
fi fi
if [[ x"${temp}" == x"y" || x"${temp}" == x"Y" ]]; then if [[ x"${temp}" == x"y" || x"${temp}" == x"Y" ]]; then
return 0 return 0
@@ -49,7 +49,7 @@ confirm() {
} }
confirm_restart() { confirm_restart() {
confirm "Restart the ${1} service" "y" confirm "重启 ${1} 服务" "y"
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
restart restart
else else
@@ -58,12 +58,12 @@ confirm_restart() {
} }
before_show_menu() { before_show_menu() {
echo && echo -n -e "${yellow}Press enter to return to the main menu: ${plain}" && read temp echo && echo -n -e "${yellow}按回车返回主菜单:${plain}" && read temp
show_menu show_menu
} }
install() { install() {
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/s-ui/main/install.sh) bash <(curl -Ls https://raw.githubusercontent.com/admin8800/s-ui/main/install.sh)
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
start start
@@ -74,40 +74,40 @@ install() {
} }
update() { update() {
confirm "This function will forcefully reinstall the latest version, and the data will not be lost. Do you want to continue?" "n" confirm "此功能将强制重装最新版本,数据不会丢失。是否继续?" "n"
if [[ $? != 0 ]]; then if [[ $? != 0 ]]; then
LOGE "Cancelled" LOGE "已取消"
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
before_show_menu before_show_menu
fi fi
return 0 return 0
fi fi
bash <(curl -Ls https://raw.githubusercontent.com/alireza0/s-ui/main/install.sh) bash <(curl -Ls https://raw.githubusercontent.com/admin8800/s-ui/main/install.sh)
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
LOGI "Update is complete, Panel has automatically restarted " LOGI "更新完成,面板已自动重启"
exit 0 exit 0
fi fi
} }
custom_version() { custom_version() {
echo "Enter the panel version (like 0.0.1):" echo "请输入面板版本(例如 0.0.1):"
read panel_version read panel_version
if [ -z "$panel_version" ]; then if [ -z "$panel_version" ]; then
echo "Panel version cannot be empty. Exiting." echo "面板版本不能为空。正在退出。"
exit 1 exit 1
fi fi
download_link="https://raw.githubusercontent.com/alireza0/s-ui/master/install.sh" download_link="https://raw.githubusercontent.com/admin8800/s-ui/main/install.sh"
install_command="bash <(curl -Ls $download_link) $panel_version" install_command="bash <(curl -Ls $download_link) $panel_version"
echo "Downloading and installing panel version $panel_version..." echo "正在下载并安装面板版本 $panel_version..."
eval $install_command eval $install_command
} }
uninstall() { uninstall() {
confirm "Are you sure you want to uninstall the panel?" "n" confirm "确定要卸载面板吗?" "n"
if [[ $? != 0 ]]; then if [[ $? != 0 ]]; then
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
show_menu show_menu
@@ -123,7 +123,7 @@ uninstall() {
rm /usr/local/s-ui/ -rf rm /usr/local/s-ui/ -rf
echo "" echo ""
echo -e "Uninstalled Successfully, If you want to remove this script, then after exiting the script run ${green}rm /usr/local/s-ui -f${plain} to delete it." echo -e "卸载成功。如果要删除此脚本,请在退出脚本后运行 ${green}rm /usr/local/s-ui -f${plain}"
echo "" echo ""
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
@@ -132,8 +132,8 @@ uninstall() {
} }
reset_admin() { reset_admin() {
echo "It is not recommended to set admin's credentials to default!" echo "不建议将管理员账号密码设置为默认值!"
confirm "Are you sure you want to reset admin's credentials to default ?" "n" confirm "确定要将管理员账号密码重置为默认值吗?" "n"
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
/usr/local/s-ui/sui admin -reset /usr/local/s-ui/sui admin -reset
fi fi
@@ -141,9 +141,9 @@ reset_admin() {
} }
set_admin() { set_admin() {
echo "It is not recommended to set admin's credentials to a complex text." echo "不建议将管理员账号密码设置为过于复杂的文本。"
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
/usr/local/s-ui/sui admin -username ${config_account} -password ${config_password} /usr/local/s-ui/sui admin -username ${config_account} -password ${config_password}
before_show_menu before_show_menu
} }
@@ -154,7 +154,7 @@ view_admin() {
} }
reset_setting() { reset_setting() {
confirm "Are you sure you want to reset settings to default ?" "n" confirm "确定要将设置重置为默认值吗?" "n"
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
/usr/local/s-ui/sui setting -reset /usr/local/s-ui/sui setting -reset
fi fi
@@ -162,17 +162,17 @@ reset_setting() {
} }
set_setting() { set_setting() {
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
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
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"
@@ -191,10 +191,10 @@ view_setting() {
view_uri() { view_uri() {
info=$(/usr/local/s-ui/sui uri) info=$(/usr/local/s-ui/sui uri)
if [[ $? != 0 ]]; then if [[ $? != 0 ]]; then
LOGE "Get current uri error" LOGE "获取当前 URI 失败"
before_show_menu before_show_menu
fi fi
LOGI "You may access the Panel with following URL(s):" LOGI "你可以通过以下 URL 访问面板:"
echo -e "${green}${info}${plain}" echo -e "${green}${info}${plain}"
} }
@@ -202,15 +202,15 @@ start() {
check_status $1 check_status $1
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
echo "" echo ""
LOGI -e "${1} is running, No need to start again, If you need to restart, please select restart" LOGI -e "${1} 正在运行,无需再次启动;如果需要重启,请选择重启"
else else
systemctl start $1 systemctl start $1
sleep 2 sleep 2
check_status $1 check_status $1
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
LOGI "${1} Started Successfully" LOGI "${1} 启动成功"
else else
LOGE "Failed to start ${1}, Probably because it takes longer than two seconds to start, Please check the log information later" LOGE "启动 ${1} 失败,可能是启动时间超过两秒,请稍后查看日志信息"
fi fi
fi fi
@@ -223,15 +223,15 @@ stop() {
check_status $1 check_status $1
if [[ $? == 1 ]]; then if [[ $? == 1 ]]; then
echo "" echo ""
LOGI "${1} stopped, No need to stop again!" LOGI "${1} 已停止,无需再次停止!"
else else
systemctl stop $1 systemctl stop $1
sleep 2 sleep 2
check_status check_status
if [[ $? == 1 ]]; then if [[ $? == 1 ]]; then
LOGI "${1} stopped successfully" LOGI "${1} 停止成功"
else else
LOGE "Failed to stop ${1}, Probably because the stop time exceeds two seconds, Please check the log information later" LOGE "停止 ${1} 失败,可能是停止时间超过两秒,请稍后查看日志信息"
fi fi
fi fi
@@ -245,9 +245,9 @@ restart() {
sleep 2 sleep 2
check_status $1 check_status $1
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
LOGI "${1} Restarted successfully" LOGI "${1} 重启成功"
else else
LOGE "Failed to restart ${1}, Probably because it takes longer than two seconds to start, Please check the log information later" LOGE "重启 ${1} 失败,可能是启动时间超过两秒,请稍后查看日志信息"
fi fi
if [[ $# == 1 ]]; then if [[ $# == 1 ]]; then
before_show_menu before_show_menu
@@ -264,9 +264,9 @@ status() {
enable() { enable() {
systemctl enable $1 systemctl enable $1
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
LOGI "Set ${1} to boot automatically on startup successfully" LOGI "已成功设置 ${1} 开机自启"
else else
LOGE "Failed to set ${1} Autostart" LOGE "设置 ${1} 开机自启失败"
fi fi
if [[ $# == 1 ]]; then if [[ $# == 1 ]]; then
@@ -277,9 +277,9 @@ enable() {
disable() { disable() {
systemctl disable $1 systemctl disable $1
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
LOGI "Autostart ${1} Cancelled successfully" LOGI "已成功取消 ${1} 开机自启"
else else
LOGE "Failed to cancel ${1} autostart" LOGE "取消 ${1} 开机自启失败"
fi fi
if [[ $# == 1 ]]; then if [[ $# == 1 ]]; then
@@ -298,11 +298,11 @@ update_shell() {
wget -O /usr/bin/s-ui -N --no-check-certificate https://github.com/admin8800/s-ui/raw/main/s-ui.sh wget -O /usr/bin/s-ui -N --no-check-certificate https://github.com/admin8800/s-ui/raw/main/s-ui.sh
if [[ $? != 0 ]]; then if [[ $? != 0 ]]; then
echo "" echo ""
LOGE "Failed to download script, Please check whether the machine can connect Github" LOGE "下载脚本失败,请检查当前机器是否可以连接 Github"
before_show_menu before_show_menu
else else
chmod +x /usr/bin/s-ui chmod +x /usr/bin/s-ui
LOGI "Upgrade script succeeded, Please rerun the script" && exit 0 LOGI "脚本升级成功,请重新运行脚本" && exit 0
fi fi
} }
@@ -331,7 +331,7 @@ check_uninstall() {
check_status s-ui check_status s-ui
if [[ $? != 2 ]]; then if [[ $? != 2 ]]; then
echo "" echo ""
LOGE "Panel is already installed, Please do not reinstall" LOGE "面板已安装,请勿重复安装"
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
before_show_menu before_show_menu
fi fi
@@ -345,7 +345,7 @@ check_install() {
check_status s-ui check_status s-ui
if [[ $? == 2 ]]; then if [[ $? == 2 ]]; then
echo "" echo ""
LOGE "Please install the panel first" LOGE "请先安装面板"
if [[ $# == 0 ]]; then if [[ $# == 0 ]]; then
before_show_menu before_show_menu
fi fi
@@ -359,15 +359,15 @@ show_status() {
check_status $1 check_status $1
case $? in case $? in
0) 0)
echo -e "${1} state: ${green}Running${plain}" echo -e "${1} 状态:${green}运行中${plain}"
show_enable_status $1 show_enable_status $1
;; ;;
1) 1)
echo -e "${1} state: ${yellow}Not Running${plain}" echo -e "${1} 状态:${yellow}未运行${plain}"
show_enable_status $1 show_enable_status $1
;; ;;
2) 2)
echo -e "${1} state: ${red}Not Installed${plain}" echo -e "${1} 状态:${red}未安装${plain}"
;; ;;
esac esac
} }
@@ -375,9 +375,9 @@ show_status() {
show_enable_status() { show_enable_status() {
check_enabled $1 check_enabled $1
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
echo -e "Start ${1} automatically: ${green}Yes${plain}" echo -e "${1} 开机自启:${green}${plain}"
else else
echo -e "Start ${1} automatically: ${red}No${plain}" echo -e "${1} 开机自启:${red}${plain}"
fi fi
} }
@@ -393,17 +393,17 @@ check_s-ui_status() {
show_s-ui_status() { show_s-ui_status() {
check_s-ui_status check_s-ui_status
if [[ $? == 0 ]]; then if [[ $? == 0 ]]; then
echo -e "s-ui state: ${green}Running${plain}" echo -e "s-ui 状态:${green}运行中${plain}"
else else
echo -e "s-ui state: ${red}Not Running${plain}" echo -e "s-ui 状态:${red}未运行${plain}"
fi fi
} }
bbr_menu() { bbr_menu() {
echo -e "${green}\t1.${plain} Enable BBR" echo -e "${green}\t1.${plain} 启用 BBR"
echo -e "${green}\t2.${plain} Disable BBR" echo -e "${green}\t2.${plain} 禁用 BBR"
echo -e "${green}\t0.${plain} Back to Main Menu" echo -e "${green}\t0.${plain} 返回主菜单"
read -p "Choose an option: " choice read -p "请选择一个选项: " choice
case "$choice" in case "$choice" in
0) 0)
show_menu show_menu
@@ -414,28 +414,28 @@ bbr_menu() {
2) 2)
disable_bbr disable_bbr
;; ;;
*) echo "Invalid choice" ;; *) echo "无效选择" ;;
esac esac
} }
disable_bbr() { disable_bbr() {
if ! grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf || ! grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then if ! grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf || ! grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
echo -e "${yellow}BBR is not currently enabled.${plain}" echo -e "${yellow}当前未启用 BBR。${plain}"
exit 0 exit 0
fi fi
sed -i 's/net.core.default_qdisc=fq/net.core.default_qdisc=pfifo_fast/' /etc/sysctl.conf sed -i 's/net.core.default_qdisc=fq/net.core.default_qdisc=pfifo_fast/' /etc/sysctl.conf
sed -i 's/net.ipv4.tcp_congestion_control=bbr/net.ipv4.tcp_congestion_control=cubic/' /etc/sysctl.conf sed -i 's/net.ipv4.tcp_congestion_control=bbr/net.ipv4.tcp_congestion_control=cubic/' /etc/sysctl.conf
sysctl -p sysctl -p
if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "cubic" ]]; then if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "cubic" ]]; then
echo -e "${green}BBR has been replaced with CUBIC successfully.${plain}" echo -e "${green}已成功将 BBR 替换为 CUBIC。${plain}"
else else
echo -e "${red}Failed to replace BBR with CUBIC. Please check your system configuration.${plain}" echo -e "${red} BBR 替换为 CUBIC 失败。请检查系统配置。${plain}"
fi fi
} }
enable_bbr() { enable_bbr() {
if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf && grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then if grep -q "net.core.default_qdisc=fq" /etc/sysctl.conf && grep -q "net.ipv4.tcp_congestion_control=bbr" /etc/sysctl.conf; then
echo -e "${green}BBR is already enabled!${plain}" echo -e "${green}BBR 已启用!${plain}"
exit 0 exit 0
fi fi
case "${release}" in case "${release}" in
@@ -452,7 +452,7 @@ enable_bbr() {
pacman -Sy --noconfirm ca-certificates pacman -Sy --noconfirm ca-certificates
;; ;;
*) *)
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" echo -e "${red}不支持的操作系统。请检查脚本并手动安装必要的软件包。${plain}\n"
exit 1 exit 1
;; ;;
esac esac
@@ -460,56 +460,56 @@ enable_bbr() {
echo "net.ipv4.tcp_congestion_control=bbr" | tee -a /etc/sysctl.conf echo "net.ipv4.tcp_congestion_control=bbr" | tee -a /etc/sysctl.conf
sysctl -p sysctl -p
if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "bbr" ]]; then if [[ $(sysctl net.ipv4.tcp_congestion_control | awk '{print $3}') == "bbr" ]]; then
echo -e "${green}BBR has been enabled successfully.${plain}" echo -e "${green}BBR 启用成功。${plain}"
else else
echo -e "${red}Failed to enable BBR. Please check your system configuration.${plain}" echo -e "${red}启用 BBR 失败。请检查系统配置。${plain}"
fi fi
} }
install_acme() { install_acme() {
cd ~ cd ~
LOGI "install acme..." LOGI "正在安装 acme..."
curl https://get.acme.sh | sh curl https://get.acme.sh | sh
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "install acme failed" LOGE "安装 acme 失败"
return 1 return 1
else else
LOGI "install acme succeed" LOGI "安装 acme 成功"
fi fi
return 0 return 0
} }
ssl_cert_issue_main() { ssl_cert_issue_main() {
echo -e "${green}\t1.${plain} Get SSL" echo -e "${green}\t1.${plain} 获取 SSL"
echo -e "${green}\t2.${plain} Revoke" echo -e "${green}\t2.${plain} 吊销证书"
echo -e "${green}\t3.${plain} Force Renew" echo -e "${green}\t3.${plain} 强制续签"
echo -e "${green}\t4.${plain} Self-signed Certificate" echo -e "${green}\t4.${plain} 自签名证书"
read -p "Choose an option: " choice read -p "请选择一个选项: " choice
case "$choice" in case "$choice" in
1) ssl_cert_issue ;; 1) ssl_cert_issue ;;
2) 2)
local domain="" local domain=""
read -p "Please enter your domain name to revoke the certificate: " domain read -p "请输入要吊销证书的域名: " domain
~/.acme.sh/acme.sh --revoke -d ${domain} ~/.acme.sh/acme.sh --revoke -d ${domain}
LOGI "Certificate revoked" LOGI "证书已吊销"
;; ;;
3) 3)
local domain="" local domain=""
read -p "Please enter your domain name to forcefully renew an SSL certificate: " domain read -p "请输入要强制续签 SSL 证书的域名: " domain
~/.acme.sh/acme.sh --renew -d ${domain} --force ;; ~/.acme.sh/acme.sh --renew -d ${domain} --force ;;
4) 4)
generate_self_signed_cert generate_self_signed_cert
;; ;;
*) echo "Invalid choice" ;; *) echo "无效选择" ;;
esac esac
} }
ssl_cert_issue() { ssl_cert_issue() {
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
echo "acme.sh could not be found. we will install it" echo "未找到 acme.sh,将进行安装"
install_acme install_acme
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "install acme failed, please check logs" LOGE "安装 acme 失败,请检查日志"
exit 1 exit 1
fi fi
fi fi
@@ -527,29 +527,29 @@ ssl_cert_issue() {
pacman -Sy --noconfirm socat pacman -Sy --noconfirm socat
;; ;;
*) *)
echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" echo -e "${red}不支持的操作系统。请检查脚本并手动安装必要的软件包。${plain}\n"
exit 1 exit 1
;; ;;
esac esac
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "install socat failed, please check logs" LOGE "安装 socat 失败,请检查日志"
exit 1 exit 1
else else
LOGI "install socat succeed..." LOGI "安装 socat 成功..."
fi fi
local domain="" local domain=""
read -p "Please enter your domain name:" domain read -p "请输入你的域名:" domain
LOGD "your domain is:${domain},check it..." LOGD "你的域名是:${domain},正在检查..."
local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}') local currentCert=$(~/.acme.sh/acme.sh --list | tail -1 | awk '{print $1}')
if [ ${currentCert} == ${domain} ]; then if [ ${currentCert} == ${domain} ]; then
local certInfo=$(~/.acme.sh/acme.sh --list) local certInfo=$(~/.acme.sh/acme.sh --list)
LOGE "system already has certs here,can not issue again,current certs details:" LOGE "系统中已存在证书,不能重复签发,当前证书详情:"
LOGI "$certInfo" LOGI "$certInfo"
exit 1 exit 1
else else
LOGI "your domain is ready for issuing cert now..." LOGI "你的域名已准备好签发证书..."
fi fi
certPath="/root/cert/${domain}" certPath="/root/cert/${domain}"
@@ -561,40 +561,40 @@ ssl_cert_issue() {
fi fi
local WebPort=80 local WebPort=80
read -p "please choose which port do you use,default will be 80 port:" WebPort read -p "请选择使用的端口,默认使用 80 端口:" WebPort
if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then if [[ ${WebPort} -gt 65535 || ${WebPort} -lt 1 ]]; then
LOGE "your input ${WebPort} is invalid,will use default port" LOGE "输入的 ${WebPort} 无效,将使用默认端口"
fi fi
LOGI "will use port:${WebPort} to issue certs,please make sure this port is open..." LOGI "将使用端口 ${WebPort} 签发证书,请确保该端口已开放..."
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
~/.acme.sh/acme.sh --issue -d ${domain} --standalone --httpport ${WebPort} ~/.acme.sh/acme.sh --issue -d ${domain} --standalone --httpport ${WebPort}
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "issue certs failed,please check logs" LOGE "签发证书失败,请检查日志"
rm -rf ~/.acme.sh/${domain} rm -rf ~/.acme.sh/${domain}
exit 1 exit 1
else else
LOGE "issue certs succeed,installing certs..." LOGE "证书签发成功,正在安装证书..."
fi fi
~/.acme.sh/acme.sh --installcert -d ${domain} \ ~/.acme.sh/acme.sh --installcert -d ${domain} \
--key-file /root/cert/${domain}/privkey.pem \ --key-file /root/cert/${domain}/privkey.pem \
--fullchain-file /root/cert/${domain}/fullchain.pem --fullchain-file /root/cert/${domain}/fullchain.pem
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "install certs failed,exit" LOGE "安装证书失败,退出"
rm -rf ~/.acme.sh/${domain} rm -rf ~/.acme.sh/${domain}
exit 1 exit 1
else else
LOGI "install certs succeed,enable auto renew..." LOGI "安装证书成功,正在启用自动续签..."
fi fi
~/.acme.sh/acme.sh --upgrade --auto-upgrade ~/.acme.sh/acme.sh --upgrade --auto-upgrade
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "auto renew failed, certs details:" LOGE "自动续签失败,证书详情:"
ls -lah cert/* ls -lah cert/*
chmod 755 $certPath/* chmod 755 $certPath/*
exit 1 exit 1
else else
LOGI "auto renew succeed, certs details:" LOGI "自动续签成功,证书详情:"
ls -lah cert/* ls -lah cert/*
chmod 755 $certPath/* chmod 755 $certPath/*
fi fi
@@ -602,11 +602,11 @@ ssl_cert_issue() {
ssl_cert_issue_CF() { ssl_cert_issue_CF() {
echo -E "" echo -E ""
LOGD "******Instructions for use******" LOGD "******使用说明******"
echo "1) New certificate from Cloudflare" echo "1) Cloudflare 申请新证书"
echo "2) Force renew existing Certificates" echo "2) 强制续签已有证书"
echo "3) Back to Menu" echo "3) 返回菜单"
read -p "Enter your choice [1-3]: " choice read -p "请输入你的选择 [1-3] " choice
certPath="/root/cert-CF" certPath="/root/cert-CF"
@@ -615,24 +615,24 @@ ssl_cert_issue_CF() {
force_flag="" force_flag=""
if [ "$choice" -eq 2 ]; then if [ "$choice" -eq 2 ]; then
force_flag="--force" force_flag="--force"
echo "Forcing SSL certificate reissuance..." echo "正在强制重新签发 SSL 证书..."
else else
echo "Starting SSL certificate issuance..." echo "开始签发 SSL 证书..."
fi fi
LOGD "******Instructions for use******" LOGD "******使用说明******"
LOGI "This Acme script requires the following data:" LOGI " Acme 脚本需要以下数据:"
LOGI "1.Cloudflare Registered e-mail" LOGI "1.Cloudflare 注册邮箱"
LOGI "2.Cloudflare Global API Key" LOGI "2.Cloudflare 全局 API Key"
LOGI "3.The domain name that has been resolved DNS to the current server by Cloudflare" LOGI "3.已通过 Cloudflare 将 DNS 解析到当前服务器的域名"
LOGI "4.The script applies for a certificate. The default installation path is /root/cert " LOGI "4.脚本将申请证书,默认安装路径为 /root/cert"
confirm "Confirmed?[y/n]" "y" confirm "是否确认?[y/n]" "y"
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then if ! command -v ~/.acme.sh/acme.sh &>/dev/null; then
echo "acme.sh could not be found. Installing..." echo "未找到 acme.sh。正在安装..."
install_acme install_acme
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "Install acme failed, please check logs" LOGE "安装 acme 失败,请检查日志"
exit 1 exit 1
fi fi
fi fi
@@ -645,23 +645,23 @@ ssl_cert_issue_CF() {
mkdir -p $certPath mkdir -p $certPath
fi fi
LOGD "Please set a domain name:" LOGD "请设置域名:"
read -p "Input your domain here: " CF_Domain read -p "请在此输入域名: " CF_Domain
LOGD "Your domain name is set to: ${CF_Domain}" LOGD "你的域名已设置为:${CF_Domain}"
CF_GlobalKey="" CF_GlobalKey=""
CF_AccountEmail="" CF_AccountEmail=""
LOGD "Please set the API key:" LOGD "请设置 API key"
read -p "Input your key here: " CF_GlobalKey read -p "请在此输入 key " CF_GlobalKey
LOGD "Your API key is: ${CF_GlobalKey}" LOGD "你的 API key 为:${CF_GlobalKey}"
LOGD "Please set up registered email:" LOGD "请设置注册邮箱:"
read -p "Input your email here: " CF_AccountEmail read -p "请在此输入邮箱: " CF_AccountEmail
LOGD "Your registered email address is: ${CF_AccountEmail}" LOGD "你的注册邮箱为:${CF_AccountEmail}"
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt ~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "Default CA, Let's Encrypt failed, script exiting..." LOGE "设置默认 CA Let's Encrypt 失败,脚本退出..."
exit 1 exit 1
fi fi
@@ -670,15 +670,15 @@ ssl_cert_issue_CF() {
~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} $force_flag --log ~/.acme.sh/acme.sh --issue --dns dns_cf -d ${CF_Domain} -d *.${CF_Domain} $force_flag --log
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "Certificate issuance failed, script exiting..." LOGE "证书签发失败,脚本退出..."
exit 1 exit 1
else else
LOGI "Certificate issued Successfully, Installing..." LOGI "证书签发成功,正在安装..."
fi fi
mkdir -p ${certPath}/${CF_Domain} mkdir -p ${certPath}/${CF_Domain}
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "Failed to create directory: ${certPath}/${CF_Domain}" LOGE "创建目录失败:${certPath}/${CF_Domain}"
exit 1 exit 1
fi fi
@@ -687,18 +687,18 @@ ssl_cert_issue_CF() {
--key-file ${certPath}/${CF_Domain}/privkey.pem --key-file ${certPath}/${CF_Domain}/privkey.pem
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "Certificate installation failed, script exiting..." LOGE "证书安装失败,脚本退出..."
exit 1 exit 1
else else
LOGI "Certificate installed Successfully, Turning on automatic updates..." LOGI "证书安装成功,正在开启自动更新..."
fi fi
~/.acme.sh/acme.sh --upgrade --auto-upgrade ~/.acme.sh/acme.sh --upgrade --auto-upgrade
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
LOGE "Auto update setup failed, script exiting..." LOGE "自动更新设置失败,脚本退出..."
exit 1 exit 1
else else
LOGI "The certificate is installed and auto-renewal is turned on." LOGI "证书已安装,并已开启自动续签。"
ls -lah ${certPath}/${CF_Domain} ls -lah ${certPath}/${CF_Domain}
chmod 755 ${certPath}/${CF_Domain} chmod 755 ${certPath}/${CF_Domain}
fi fi
@@ -706,11 +706,11 @@ ssl_cert_issue_CF() {
show_menu show_menu
;; ;;
3) 3)
echo "Exiting..." echo "正在退出..."
show_menu show_menu
;; ;;
*) *)
echo "Invalid choice, please select again." echo "无效选择,请重新选择。"
show_menu show_menu
;; ;;
esac esac
@@ -719,13 +719,13 @@ ssl_cert_issue_CF() {
generate_self_signed_cert() { generate_self_signed_cert() {
cert_dir="/etc/sing-box" cert_dir="/etc/sing-box"
mkdir -p "$cert_dir" mkdir -p "$cert_dir"
LOGI "Choose certificate type:" LOGI "请选择证书类型:"
echo -e "${green}\t1.${plain} Ed25519 (*recommended*)" echo -e "${green}\t1.${plain} Ed25519(推荐)"
echo -e "${green}\t2.${plain} RSA 2048" echo -e "${green}\t2.${plain} RSA 2048"
echo -e "${green}\t3.${plain} RSA 4096" echo -e "${green}\t3.${plain} RSA 4096"
echo -e "${green}\t4.${plain} ECDSA prime256v1" echo -e "${green}\t4.${plain} ECDSA prime256v1"
echo -e "${green}\t5.${plain} ECDSA secp384r1" echo -e "${green}\t5.${plain} ECDSA secp384r1"
read -p "Enter your choice [1-5, default 1]: " cert_type read -p "请输入你的选择 [1-5,默认 1] " cert_type
cert_type=${cert_type:-1} cert_type=${cert_type:-1}
case "$cert_type" in case "$cert_type" in
@@ -755,75 +755,75 @@ generate_self_signed_cert() {
;; ;;
esac esac
LOGI "Generating self-signed certificate ($algo)..." LOGI "正在生成自签名证书($algo..."
sudo openssl req -x509 -nodes -days 3650 $key_opt \ sudo openssl req -x509 -nodes -days 3650 $key_opt \
-keyout "${cert_dir}/self.key" \ -keyout "${cert_dir}/self.key" \
-out "${cert_dir}/self.crt" \ -out "${cert_dir}/self.crt" \
-subj "/CN=myserver" -subj "/CN=myserver"
if [[ $? -eq 0 ]]; then if [[ $? -eq 0 ]]; then
sudo chmod 600 "${cert_dir}/self."* sudo chmod 600 "${cert_dir}/self."*
LOGI "Self-signed certificate generated successfully!" LOGI "自签名证书生成成功!"
LOGI "Certificate path: ${cert_dir}/self.crt" LOGI "证书路径:${cert_dir}/self.crt"
LOGI "Key path: ${cert_dir}/self.key" LOGI "密钥路径:${cert_dir}/self.key"
else else
LOGE "Failed to generate self-signed certificate." LOGE "生成自签名证书失败。"
fi fi
before_show_menu before_show_menu
} }
show_usage() { show_usage() {
echo -e "S-UI Control Menu Usage" echo -e "S-UI 控制菜单用法"
echo -e "------------------------------------------" echo -e "------------------------------------------"
echo -e "SUBCOMMANDS:" echo -e "子命令:"
echo -e "s-ui - Admin Management Script" echo -e "s-ui - 管理员管理脚本"
echo -e "s-ui start - Start s-ui" echo -e "s-ui start - 启动 s-ui"
echo -e "s-ui stop - Stop s-ui" echo -e "s-ui stop - 停止 s-ui"
echo -e "s-ui restart - Restart s-ui" echo -e "s-ui restart - 重启 s-ui"
echo -e "s-ui status - Current Status of s-ui" echo -e "s-ui status - 查看 s-ui 当前状态"
echo -e "s-ui enable - Enable Autostart on OS Startup" echo -e "s-ui enable - 启用开机自启"
echo -e "s-ui disable - Disable Autostart on OS Startup" echo -e "s-ui disable - 禁用开机自启"
echo -e "s-ui log - Check s-ui Logs" echo -e "s-ui log - 查看 s-ui 日志"
echo -e "s-ui update - Update" echo -e "s-ui update - 更新"
echo -e "s-ui install - Install" echo -e "s-ui install - 安装"
echo -e "s-ui uninstall - Uninstall" echo -e "s-ui uninstall - 卸载"
echo -e "s-ui help - Control Menu Usage" echo -e "s-ui help - 控制菜单用法"
echo -e "------------------------------------------" echo -e "------------------------------------------"
} }
show_menu() { show_menu() {
echo -e " echo -e "
${green}S-UI Admin Management Script ${plain} ${green}S-UI 管理脚本 ${plain}
———————————————————————————————— ---------------------------------------------------------------
${green}0.${plain} Exit ${green}0.${plain} 退出
———————————————————————————————— ---------------------------------------------------------------
${green}1.${plain} Install ${green}1.${plain} 安装
${green}2.${plain} Update ${green}2.${plain} 更新
${green}3.${plain} Custom Version ${green}3.${plain} 自定义版本
${green}4.${plain} Uninstall ${green}4.${plain} 卸载
———————————————————————————————— ---------------------------------------------------------------
${green}5.${plain} Reset admin credentials to default ${green}5.${plain} 将管理员账号密码重置为默认值
${green}6.${plain} Set admin credentials ${green}6.${plain} 设置管理员账号密码
${green}7.${plain} View admin credentials ${green}7.${plain} 查看管理员账号密码
———————————————————————————————— ---------------------------------------------------------------
${green}8.${plain} Reset Panel Settings ${green}8.${plain} 重置面板设置
${green}9.${plain} Set Panel settings ${green}9.${plain} 设置面板设置
${green}10.${plain} View Panel Settings ${green}10.${plain} 查看面板设置
———————————————————————————————— ---------------------------------------------------------------
${green}11.${plain} S-UI Start ${green}11.${plain} 启动 S-UI
${green}12.${plain} S-UI Stop ${green}12.${plain} 停止 S-UI
${green}13.${plain} S-UI Restart ${green}13.${plain} 重启 S-UI
${green}14.${plain} S-UI Check State ${green}14.${plain} 查看 S-UI 状态
${green}15.${plain} S-UI Check Logs ${green}15.${plain} 查看 S-UI 日志
${green}16.${plain} S-UI Enable Autostart ${green}16.${plain} 启用 S-UI 开机自启
${green}17.${plain} S-UI Disable Autostart ${green}17.${plain} 禁用 S-UI 开机自启
———————————————————————————————— ---------------------------------------------------------------
${green}18.${plain} Enable or Disable BBR ${green}18.${plain} 启用或禁用 BBR
${green}19.${plain} SSL Certificate Management ${green}19.${plain} SSL 证书管理
${green}20.${plain} Cloudflare SSL Certificate ${green}20.${plain} Cloudflare SSL 证书
———————————————————————————————— ---------------------------------------------------------------
" "
show_status s-ui show_status s-ui
echo && read -p "Please enter your selection [0-20]: " num echo && read -p "请输入你的选择 [0-20] " num
case "${num}" in case "${num}" in
0) 0)
@@ -890,7 +890,7 @@ show_menu() {
ssl_cert_issue_CF ssl_cert_issue_CF
;; ;;
*) *)
LOGE "Please enter the correct number [0-20]" LOGE "请输入正确的数字 [0-20]"
;; ;;
esac esac
} }