name: Publish Docker Images on: #push: # branches: # - stable # - testing release: types: - published workflow_dispatch: inputs: tag: description: "The tag version you want to build" env: REGISTRY_IMAGE: ghcr.io/sagernet/sing-box jobs: build_binary: name: Build binary runs-on: ubuntu-latest strategy: fail-fast: true matrix: include: # Naive-enabled builds (musl) - { arch: amd64, naive: true, docker_platform: "linux/amd64" } - { arch: arm64, naive: true, docker_platform: "linux/arm64" } - { arch: "386", naive: true, docker_platform: "linux/386" } - { arch: arm, goarm: "7", naive: true, docker_platform: "linux/arm/v7" } - { arch: mipsle, gomips: softfloat, naive: true, docker_platform: "linux/mipsle" } - { arch: riscv64, naive: true, docker_platform: "linux/riscv64" } - { arch: loong64, naive: true, docker_platform: "linux/loong64" } # Non-naive builds - { arch: arm, goarm: "6", docker_platform: "linux/arm/v6" } - { arch: ppc64le, docker_platform: "linux/ppc64le" } - { arch: s390x, docker_platform: "linux/s390x" } steps: - name: Get commit to build id: ref run: |- if [[ -z "${{ github.event.inputs.tag }}" ]]; then ref="${{ github.ref_name }}" else ref="${{ github.event.inputs.tag }}" fi echo "ref=$ref" echo "ref=$ref" >> $GITHUB_OUTPUT - name: Checkout uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: ref: ${{ steps.ref.outputs.ref }} fetch-depth: 0 - name: Setup Go uses: actions/setup-go@v5 with: go-version: ~1.25.8 - name: Clone cronet-go if: matrix.naive run: | set -xeuo pipefail CRONET_GO_VERSION=$(cat .github/CRONET_GO_VERSION) git init ~/cronet-go git -C ~/cronet-go remote add origin https://github.com/sagernet/cronet-go.git git -C ~/cronet-go fetch --depth=1 origin "$CRONET_GO_VERSION" git -C ~/cronet-go checkout FETCH_HEAD git -C ~/cronet-go submodule update --init --recursive --depth=1 - name: Regenerate Debian keyring if: matrix.naive run: | set -xeuo pipefail rm -f ~/cronet-go/naiveproxy/src/build/linux/sysroot_scripts/keyring.gpg cd ~/cronet-go GPG_TTY=/dev/null ./naiveproxy/src/build/linux/sysroot_scripts/generate_keyring.sh - name: Cache Chromium toolchain if: matrix.naive id: cache-chromium-toolchain uses: actions/cache@v4 with: path: | ~/cronet-go/naiveproxy/src/third_party/llvm-build/ ~/cronet-go/naiveproxy/src/gn/out/ ~/cronet-go/naiveproxy/src/chrome/build/pgo_profiles/ ~/cronet-go/naiveproxy/src/out/sysroot-build/ key: chromium-toolchain-${{ matrix.arch }}-musl-${{ hashFiles('.github/CRONET_GO_VERSION') }} - name: Download Chromium toolchain if: matrix.naive run: | set -xeuo pipefail cd ~/cronet-go go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl download-toolchain - name: Set version run: | set -xeuo pipefail VERSION=$(go run ./cmd/internal/read_tag) echo "VERSION=${VERSION}" >> "${GITHUB_ENV}" - name: Set Chromium toolchain environment if: matrix.naive run: | set -xeuo pipefail cd ~/cronet-go go run ./cmd/build-naive --target=linux/${{ matrix.arch }} --libc=musl env >> $GITHUB_ENV - name: Set build tags run: | set -xeuo pipefail if [[ "${{ matrix.naive }}" == "true" ]]; then TAGS="$(cat release/DEFAULT_BUILD_TAGS),with_musl" else TAGS=$(cat release/DEFAULT_BUILD_TAGS_OTHERS) fi echo "BUILD_TAGS=${TAGS}" >> "${GITHUB_ENV}" - name: Set shared ldflags run: | echo "LDFLAGS_SHARED=$(cat release/LDFLAGS)" >> "${GITHUB_ENV}" - name: Build (naive) if: matrix.naive run: | set -xeuo pipefail go build -v -trimpath -o sing-box -tags "${BUILD_TAGS}" \ -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=${VERSION}' ${LDFLAGS_SHARED} -s -w -buildid=" \ ./cmd/sing-box env: CGO_ENABLED: "1" GOOS: linux GOARCH: ${{ matrix.arch }} GOARM: ${{ matrix.goarm }} GOMIPS: ${{ matrix.gomips }} - name: Build (non-naive) if: ${{ ! matrix.naive }} run: | set -xeuo pipefail go build -v -trimpath -o sing-box -tags "${BUILD_TAGS}" \ -ldflags "-X 'github.com/sagernet/sing-box/constant.Version=${VERSION}' ${LDFLAGS_SHARED} -s -w -buildid=" \ ./cmd/sing-box env: CGO_ENABLED: "0" GOOS: linux GOARCH: ${{ matrix.arch }} GOARM: ${{ matrix.goarm }} - name: Prepare artifact run: | platform=${{ matrix.docker_platform }} echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV # Rename binary to include arch info for Dockerfile.binary BINARY_NAME="sing-box-${{ matrix.arch }}" if [[ -n "${{ matrix.goarm }}" ]]; then BINARY_NAME="${BINARY_NAME}v${{ matrix.goarm }}" fi mv sing-box "${BINARY_NAME}" echo "BINARY_NAME=${BINARY_NAME}" >> $GITHUB_ENV - name: Upload binary uses: actions/upload-artifact@v4 with: name: binary-${{ env.PLATFORM_PAIR }} path: ${{ env.BINARY_NAME }} if-no-files-found: error retention-days: 1 build_docker: name: Build Docker image runs-on: ubuntu-latest needs: - build_binary strategy: fail-fast: true matrix: include: - { platform: "linux/amd64" } - { platform: "linux/arm/v6" } - { platform: "linux/arm/v7" } - { platform: "linux/arm64" } - { platform: "linux/386" } # mipsle: no base Docker image available for this platform - { platform: "linux/ppc64le" } - { platform: "linux/riscv64" } - { platform: "linux/s390x" } - { platform: "linux/loong64", base_image: "ghcr.io/loong64/alpine:edge" } steps: - name: Get commit to build id: ref run: |- if [[ -z "${{ github.event.inputs.tag }}" ]]; then ref="${{ github.ref_name }}" else ref="${{ github.event.inputs.tag }}" fi echo "ref=$ref" echo "ref=$ref" >> $GITHUB_OUTPUT - name: Checkout uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: ref: ${{ steps.ref.outputs.ref }} fetch-depth: 0 - name: Prepare run: | platform=${{ matrix.platform }} echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV - name: Download binary uses: actions/download-artifact@v5 with: name: binary-${{ env.PLATFORM_PAIR }} path: . - name: Prepare binary run: | # Find and make the binary executable chmod +x sing-box-* ls -la sing-box-* - name: Setup QEMU uses: docker/setup-qemu-action@v3 - name: Setup Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Docker meta id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY_IMAGE }} - name: Build and push by digest id: build uses: docker/build-push-action@v6 with: platforms: ${{ matrix.platform }} context: . file: Dockerfile.binary build-args: | BASE_IMAGE=${{ matrix.base_image || 'alpine' }} labels: ${{ steps.meta.outputs.labels }} outputs: type=image,name=${{ env.REGISTRY_IMAGE }},push-by-digest=true,name-canonical=true,push=true - name: Export digest run: | mkdir -p /tmp/digests digest="${{ steps.build.outputs.digest }}" touch "/tmp/digests/${digest#sha256:}" - name: Upload digest uses: actions/upload-artifact@v4 with: name: digests-${{ env.PLATFORM_PAIR }} path: /tmp/digests/* if-no-files-found: error retention-days: 1 merge: if: github.event_name != 'push' runs-on: ubuntu-latest needs: - build_docker steps: - name: Get commit to build id: ref run: |- if [[ -z "${{ github.event.inputs.tag }}" ]]; then ref="${{ github.ref_name }}" else ref="${{ github.event.inputs.tag }}" fi echo "ref=$ref" echo "ref=$ref" >> $GITHUB_OUTPUT - name: Checkout uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 with: ref: ${{ steps.ref.outputs.ref }} fetch-depth: 0 - name: Detect track run: bash .github/detect_track.sh - name: Download digests uses: actions/download-artifact@v5 with: path: /tmp/digests pattern: digests-* merge-multiple: true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Create manifest list and push if: github.event_name != 'push' working-directory: /tmp/digests run: | docker buildx imagetools create \ -t "${{ env.REGISTRY_IMAGE }}:${{ env.DOCKER_TAG }}" \ -t "${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}" \ $(printf '${{ env.REGISTRY_IMAGE }}@sha256:%s ' *) - name: Inspect image if: github.event_name != 'push' run: | docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ env.DOCKER_TAG }} docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.ref.outputs.ref }}