diff --git a/.gitea/workflows/publish.yml b/.gitea/workflows/publish.yml new file mode 100644 index 0000000..01b814b --- /dev/null +++ b/.gitea/workflows/publish.yml @@ -0,0 +1,28 @@ +name: Build and publish image + +on: + pull_request: + push: + branches: [main] + schedule: + - cron: "17 3 * * *" + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + image: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check scripts + run: ./tests/check.sh + - name: Log in to Gitea registry + if: gitea.event_name != 'pull_request' + run: echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.ipao.vip --username "${{ gitea.actor }}" --password-stdin + - name: Build image + env: + PUSH: ${{ gitea.event_name != 'pull_request' }} + run: ./scripts/build.sh git.ipao.vip/rogee/fingerprint-chromium diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..b977b1b --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,28 @@ +name: Build and publish image + +on: + pull_request: + push: + branches: [main] + schedule: + - cron: "17 3 * * *" + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + image: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check scripts + run: ./tests/check.sh + - name: Log in to GitHub Container Registry + if: github.event_name != 'pull_request' + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username "${{ github.actor }}" --password-stdin + - name: Build image + env: + PUSH: ${{ github.event_name != 'pull_request' }} + run: ./scripts/build.sh ghcr.io/rogeecn/fingerprint-chromium diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5212216 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,6 @@ +# Repository instructions + +- Keep Chromium headed by default. Do not add `--headless` to `docker-entrypoint.sh`. +- Keep upstream downloads restricted to `adryfish/fingerprint-chromium` Linux x86_64 release assets. +- Keep registry credentials in workflow secrets; never commit credentials. +- Before submitting changes, run `./tests/check.sh`, build the image, and smoke-test Chromium. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..35cb4d8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,67 @@ +FROM ubuntu:24.04 AS download + +ARG CHROME_URL + +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates curl xz-utils \ + && case "$CHROME_URL" in \ + https://github.com/adryfish/fingerprint-chromium/releases/download/*/*-x86_64_linux.tar.xz) ;; \ + *) echo "unexpected CHROME_URL: $CHROME_URL" >&2; exit 1 ;; \ + esac \ + && mkdir -p /opt/chromium \ + && curl --fail --location --retry 3 --proto '=https' --tlsv1.2 "$CHROME_URL" \ + | tar -xJ --strip-components=1 -C /opt/chromium + +FROM ubuntu:24.04 + +ARG CHROME_VERSION + +LABEL org.opencontainers.image.source="https://github.com/adryfish/fingerprint-chromium" \ + org.opencontainers.image.version="$CHROME_VERSION" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + ca-certificates \ + fonts-liberation \ + fonts-noto-color-emoji \ + libasound2t64 \ + libatk-bridge2.0-0t64 \ + libatk1.0-0t64 \ + libcups2t64 \ + libdbus-1-3 \ + libdrm2 \ + libgbm1 \ + libglib2.0-0t64 \ + libgtk-3-0t64 \ + libnspr4 \ + libnss3 \ + libpango-1.0-0 \ + libpangocairo-1.0-0 \ + libx11-6 \ + libx11-xcb1 \ + libxcb1 \ + libxcomposite1 \ + libxdamage1 \ + libxext6 \ + libxfixes3 \ + libxkbcommon0 \ + libxrandr2 \ + libxshmfence1 \ + xdg-utils \ + xvfb \ + && rm -rf /var/lib/apt/lists/* \ + && install -d -o ubuntu -g ubuntu /data + +RUN apt-get update \ + && apt-get install -y --no-install-recommends socat \ + && rm -rf /var/lib/apt/lists/* \ + && install -d -m 1777 /tmp/.X11-unix + +COPY --from=download /opt/chromium /opt/chromium +COPY --chmod=755 docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh + +USER ubuntu +VOLUME ["/data"] +EXPOSE 9222 + +ENTRYPOINT ["docker-entrypoint.sh"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..b6d8c46 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# fingerprint-chromium Docker + +将 [adryfish/fingerprint-chromium](https://github.com/adryfish/fingerprint-chromium) 最新 Linux x86_64 安装包封装为 Docker 镜像。 + +容器始终通过 Xvfb 启动普通的有头 Chromium,不默认使用 `--headless`。上游仅处理了部分无头特征,因此不要把无头模式设为默认。 + +## 构建 + +需要 Docker、curl 和 jq: + +```bash +./scripts/build.sh +``` + +指定上游 Chrome 版本或镜像名: + +```bash +CHROME_VERSION=148.0.7778.215 ./scripts/build.sh my-registry/fingerprint-chromium +``` + +脚本从上游 GitHub Release 解析唯一的 Linux x86_64 压缩包,镜像 tag 使用完整 Chrome 版本。设置 `PUSH=true` 时,构建完成后推送镜像。 + +## 运行 + +```bash +docker run --rm \ + -p 127.0.0.1:9222:9222 \ + -v fingerprint-profile:/data \ + fingerprint-chromium:148.0.7778.215 \ + --fingerprint=1000 \ + about:blank +``` + +CDP 端口默认是 `9222`;不要直接暴露到公网。每个账号应使用独立的数据卷与 fingerprint seed。可通过 `SCREEN_SIZE` 调整虚拟显示器,例如 `1600x900x24`。 + +上游 Linux 包未携带 SUID sandbox,且普通 Docker runner 默认不允许 Chromium 使用 user namespace sandbox,因此入口使用 `--no-sandbox` 并以非 root 用户运行。镜像依赖容器边界隔离浏览器;访问不可信内容时应额外限制网络、文件挂载和容器权限。 + +## 自动发布 + +- Gitea Workflow:推送 `git.ipao.vip/rogee/fingerprint-chromium:`,使用仓库 secret `REGISTRY_TOKEN`。 +- GitHub Workflow:推送 `ghcr.io/rogeecn/fingerprint-chromium:`,使用内置 `GITHUB_TOKEN`。 + +两个 Workflow 都会在 PR 中只构建验证,在 `main` 更新、每日定时任务或手动触发时构建并推送。仓库需要允许 Actions job token 写入 Packages。 + +## 验证 + +```bash +./tests/check.sh +docker run --rm fingerprint-chromium:148.0.7778.215 --version +``` + +本仓库只支持上游当前提供的 `linux/amd64` 安装包。 diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..aecdecc --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,36 @@ +#!/bin/sh +set -eu + +Xvfb :99 -screen 0 "${SCREEN_SIZE:-1920x1080x24}" -nolisten tcp -ac & +xvfb_pid=$! + +for _ in 1 2 3 4 5 6 7 8 9 10; do + [ -S /tmp/.X11-unix/X99 ] && break + kill -0 "$xvfb_pid" 2>/dev/null || exit 1 + sleep 0.1 +done + +[ -S /tmp/.X11-unix/X99 ] || { + echo "Xvfb did not become ready" >&2 + exit 1 +} + +export DISPLAY=:99 + +remote_debugging_port=${REMOTE_DEBUGGING_PORT:-9222} +case "$remote_debugging_port" in + ''|*[!0-9]*) echo "REMOTE_DEBUGGING_PORT must be numeric" >&2; exit 2 ;; +esac + +socat \ + "TCP-LISTEN:${remote_debugging_port},fork,reuseaddr,bind=$(hostname -i)" \ + "TCP:127.0.0.1:${remote_debugging_port}" & + +exec /opt/chromium/chrome \ + --disable-dev-shm-usage \ + --no-sandbox \ + --no-default-browser-check \ + --no-first-run \ + --remote-debugging-port="$remote_debugging_port" \ + --user-data-dir=/data \ + "$@" diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..5dfda41 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -euo pipefail + +image="${1:-fingerprint-chromium}" +release_api="https://api.github.com/repos/adryfish/fingerprint-chromium/releases" + +if [[ -n "${CHROME_VERSION:-}" ]]; then + release_url="$release_api/tags/$CHROME_VERSION" +else + release_url="$release_api/latest" +fi + +release="$(curl --fail --location --retry 3 --silent --show-error "$release_url")" +version="$(jq -er '.tag_name | select(test("^[0-9]+(\\.[0-9]+){3}$"))' <<<"$release")" +asset_url="$(jq -er --arg version "$version" ' + [.assets[] | select(.name | startswith("ungoogled-chromium-\($version)-") and endswith("-x86_64_linux.tar.xz"))] + | if length == 1 then .[0].browser_download_url else error("expected exactly one Linux x86_64 archive") end +' <<<"$release")" + +tag="$image:$version" +docker build --pull --platform linux/amd64 \ + --build-arg "CHROME_VERSION=$version" \ + --build-arg "CHROME_URL=$asset_url" \ + --tag "$tag" . + +if [[ "${PUSH:-false}" == "true" ]]; then + docker push "$tag" +fi + +printf 'Built %s\n' "$tag" diff --git a/tests/check.sh b/tests/check.sh new file mode 100755 index 0000000..7e8dc46 --- /dev/null +++ b/tests/check.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail + +bash -n scripts/build.sh tests/check.sh +sh -n docker-entrypoint.sh + +grep -q 'Xvfb :99' docker-entrypoint.sh +! grep -q -- '--headless' docker-entrypoint.sh +grep -q -- '--no-sandbox' docker-entrypoint.sh +grep -q 'TCP-LISTEN:' docker-entrypoint.sh +grep -q 'git.ipao.vip/rogee/fingerprint-chromium' .gitea/workflows/publish.yml +grep -q 'ghcr.io/rogeecn/fingerprint-chromium' .github/workflows/publish.yml +grep -q 'packages: write' .gitea/workflows/publish.yml +grep -q 'packages: write' .github/workflows/publish.yml