From 09faf443ce6786a466ec7dd6e582b700998dbf92 Mon Sep 17 00:00:00 2001 From: Nick Date: Fri, 26 Dec 2025 20:56:08 +0800 Subject: [PATCH] feat(server): add Dockerfile + CI docker build/push (#10) * feat: add server Docker image build (Dockerfile + GH Actions) Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .dockerignore | 28 ++++++++++++++ .github/workflows/docker-server.yml | 57 +++++++++++++++++++++++++++++ README.md | 48 ++++++++++++++++++++++++ server/Dockerfile | 46 +++++++++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 .dockerignore create mode 100644 .github/workflows/docker-server.yml create mode 100644 server/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..9a70669c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,28 @@ +.git +.github + +**/.DS_Store + +**/node_modules +**/dist + +cli/dist-exe +cli/release-artifacts + +cli/** +!cli/package.json +!cli/bunfig.toml +!cli/tsconfig.json +!cli/src/** +!cli/scripts/** +!cli/tools/licenses/** +!cli/tools/archives/difftastic-LICENSE +!cli/tools/archives/ripgrep-LICENSE +!cli/tools/archives/*.tar.gz + +**/*.log + +**/.env +**/.env.* + +.factory diff --git a/.github/workflows/docker-server.yml b/.github/workflows/docker-server.yml new file mode 100644 index 00000000..dd73e79b --- /dev/null +++ b/.github/workflows/docker-server.yml @@ -0,0 +1,57 @@ +name: Docker (server) + +on: + pull_request: + push: + branches: + - main + tags: + - 'v*' + workflow_dispatch: + +concurrency: + group: docker-server-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + packages: write + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: docker/setup-qemu-action@v3 + - uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }}-server + tags: | + type=ref,event=branch + type=ref,event=tag + type=sha + + - name: Build and (optionally) push + uses: docker/build-push-action@v6 + with: + context: . + file: server/Dockerfile + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/README.md b/README.md index caee9c55..16a3cf6a 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,54 @@ Download from [Releases](https://github.com/tiann/hapi/releases). xattr -d com.apple.quarantine ./hapi ``` +### Docker + +Pull the pre-built image from GitHub Container Registry: + +```bash +docker pull ghcr.io/tiann/hapi-server:latest +``` + +Run the server: + +```bash +docker run -d --name hapi -p 3006:3006 -v hapi-data:/data ghcr.io/tiann/hapi-server:latest +``` + +
+More options (Telegram + environment variables) + +#### Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `WEBAPP_PORT` | `3006` | Server listening port | +| `CLI_API_TOKEN` | (auto-generated) | Access token for CLI and web UI | +| `TELEGRAM_BOT_TOKEN` | - | Telegram bot token (optional) | +| `WEBAPP_URL` | - | Public URL for Telegram Mini App | +| `ALLOWED_CHAT_IDS` | - | Comma-separated Telegram chat IDs | + +#### With Telegram Support + +```bash +docker run -d \ + --name hapi \ + -p 3006:3006 \ + -v hapi-data:/data \ + -e WEBAPP_URL="https://your-domain.example" \ + -e TELEGRAM_BOT_TOKEN="your-bot-token" \ + -e ALLOWED_CHAT_IDS="12345678" \ + ghcr.io/tiann/hapi-server:latest +``` + +#### Build from Source + +```bash +docker build -t hapi-server -f server/Dockerfile . +``` + +
+ ## Quickstart 1. Start the server on a machine you control: diff --git a/server/Dockerfile b/server/Dockerfile new file mode 100644 index 00000000..9a1c62c9 --- /dev/null +++ b/server/Dockerfile @@ -0,0 +1,46 @@ +FROM oven/bun:1.3.4 AS deps + +WORKDIR /home/bun/app + +COPY bun.lock package.json tsconfig.base.json ./ +COPY cli/package.json ./cli/package.json +COPY server/package.json ./server/package.json +COPY web/package.json ./web/package.json + +RUN bun install --frozen-lockfile + + +FROM deps AS build + +COPY cli ./cli +COPY server ./server +COPY web ./web + +RUN bun add --no-save react-devtools-core@6.1.2 \ + && bun run build:single-exe \ + && mkdir -p /out \ + && cp cli/dist-exe/bun-linux-*/hapi /out/hapi + + +FROM oven/bun:1.3.4-slim AS runtime + +WORKDIR /home/bun/app + +ENV NODE_ENV=production +ENV WEBAPP_PORT=3006 +ENV HAPI_HOME=/data + +USER root +RUN mkdir -p /data && chown bun:bun /data +USER bun + +VOLUME /data + +EXPOSE 3006 + +COPY --from=build /out/hapi ./hapi + +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ + CMD bun -e "fetch('http://127.0.0.1:' + (process.env.WEBAPP_PORT ?? '3006') + '/').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))" + +CMD ["./hapi", "server"]