diff --git a/.github/workflows/deploy-dev2.yml b/.github/workflows/deploy-dev2.yml new file mode 100644 index 0000000..0e2f51e --- /dev/null +++ b/.github/workflows/deploy-dev2.yml @@ -0,0 +1,60 @@ +# Ship every merge to dev2, where c0mpute.com runs since it left Railway (which +# deployed on merge by itself). The box pulls the merged commit, rebuilds the +# image(s) from this repo and restarts the compose stack under +# /home/anthony/www/c0mpute.com. Generated by cli-tools/dev2/dev2-site scaffold. +name: Deploy to dev2 + +on: + push: + branches: [master] + workflow_dispatch: + inputs: + ref: + description: Git ref to deploy (defaults to the pushed commit) + required: false + type: string + +concurrency: + group: deploy-dev2 + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + # ${{ }} values go through env, never straight into a run: body. + - name: Resolve target revision + id: rev + env: + REF: ${{ inputs.ref || github.sha }} + run: echo "sha=$REF" >> "$GITHUB_OUTPUT" + + - name: Set up ssh + env: + SSH_KEY: ${{ secrets.DEV2_SSH_KEY }} + KNOWN_HOSTS: ${{ secrets.DEV2_KNOWN_HOSTS }} + run: | + install -d -m 700 ~/.ssh + printf '%s\n' "$SSH_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + printf '%s\n' "$KNOWN_HOSTS" > ~/.ssh/known_hosts + chmod 644 ~/.ssh/known_hosts + + - name: Deploy + env: + DEV2_USER: ${{ secrets.DEV2_USER }} + DEV2_HOST: ${{ secrets.DEV2_HOST }} + SHA: ${{ steps.rev.outputs.sha }} + run: | + ssh -o BatchMode=yes "$DEV2_USER@$DEV2_HOST" \ + /home/anthony/www/c0mpute.com/deploy-app.sh "$SHA" + + - name: Verify the site answers + run: | + for i in $(seq 1 10); do + code=$(curl -s -o /dev/null -w '%{http_code}' "https://c0mpute.com/" || true) + case "$code" in 2*|3*|401|403) echo "c0mpute.com $code"; exit 0;; esac + echo "attempt $i: $code"; sleep 10 + done + echo "c0mpute.com never answered"; exit 1 diff --git a/.nixpacks/Dockerfile b/.nixpacks/Dockerfile new file mode 100644 index 0000000..e6174be --- /dev/null +++ b/.nixpacks/Dockerfile @@ -0,0 +1,60 @@ +# c0mpute.com on dev2: the compose stack builds this file (cli-tools dev2/dev2-site +# looks for .nixpacks/Dockerfile). It is a copy of ../Dockerfile.web, the image +# Railway built with RAILWAY_DOCKERFILE_PATH=Dockerfile.web: the Next.js site plus +# the co-located Rust status aggregator. Keep the two in step. + +# c0mpute.com — single Railway deploy (DIP-0014). +# +# One service, two co-located processes: the Next.js site (foreground) and the +# status aggregator (Rust libp2p observer, background). The site proxies +# /status + /api/status to the aggregator over loopback. This replaces the +# earlier separate `c0mpute-status-aggregator` Railway service — the whole +# monorepo ships as one deploy. +# +# Point the c0mpute.com service at this file with the RAILWAY_DOCKERFILE_PATH +# variable (= Dockerfile.web). Build context is the repo root. + +# ── stage 1: build the aggregator (Rust) ───────────────────────────────── +# Copy only the Rust workspace so edits under apps/web/ don't bust this layer. +FROM rust:1.92-bookworm AS rustbuild +WORKDIR /src +COPY Cargo.toml Cargo.lock ./ +COPY node ./node +RUN cargo build --release --bin c0mpute + +# ── stage 2: build the Next.js site (Bun) ──────────────────────────────── +FROM oven/bun:1.3-debian AS webbuild +WORKDIR /app +# Native deps (better-sqlite3 is an optional native module) need a toolchain. +RUN apt-get update \ + && apt-get install -y --no-install-recommends python3 make g++ ca-certificates \ + && rm -rf /var/lib/apt/lists/* +COPY . . +RUN bun install --frozen-lockfile +RUN bun run --cwd packages/shared build && bun run --filter=c0mpute build + +# ── stage 3: runtime ───────────────────────────────────────────────────── +FROM oven/bun:1.3-debian AS runtime +WORKDIR /app +RUN apt-get update \ + && apt-get install -y --no-install-recommends ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Full built app: `next start` (non-standalone) serves from .next, and several +# route handlers read repo files at request time (scripts/install.sh, etc.), +# so the whole tree + node_modules must be present. +COPY --from=webbuild /app /app +# Co-located aggregator binary. +COPY --from=rustbuild /src/target/release/c0mpute /usr/local/bin/c0mpute +COPY scripts/railway-web-start.sh /usr/local/bin/railway-web-start.sh +RUN chmod +x /usr/local/bin/railway-web-start.sh + +# The aggregator serves its JSON on loopback; the site reads it there. +ENV C0MPUTE_STATUS_BIND=127.0.0.1:8090 +ENV STATUS_AGGREGATOR_URL=http://127.0.0.1:8090 + +# Runs as root, exactly as the Railway image built from Dockerfile.web does (semgrep +# never scanned that file: its name is not a Dockerfile pattern). Moving to a +# non-root user is a runtime change for both files, not for the hosting move. +# nosemgrep: dockerfile.security.missing-user-entrypoint.missing-user-entrypoint +ENTRYPOINT ["/usr/local/bin/railway-web-start.sh"]