6.3 KiB
Gitea to Cloudflare Pages — Linear Void
Goal
Deploy the Linear Void frontend (Vite + TypeScript SPA) from Gitea to Cloudflare Pages using Gitea Actions.
Prerequisites
Important: The Pages project must exist before the API deploy call works. You'll get error 8000007 ("Project not found") if you skip this step.
- Cloudflare Pages project created first:
- Dashboard → Workers & Pages → Create → Pages → Direct Upload
- Name it
linearvoid(or a different name iflinearvoidis already taken by a Worker — see note below) - See Cloudflare Pages Setup for full details.
- Project name: note the exact name (e.g.,
linearvoid). - API token with Pages permissions:
- Create at https://dash.cloudflare.com/profile/api-tokens
- Permission:
Account → Cloudflare Pages → Edit - Store in Gitea → Settings → Secrets as
CLOUDFLARE_API_TOKEN
- Account ID from Cloudflare dashboard overview → store as
CLOUDFLARE_ACCOUNT_ID
Naming conflict: If a Worker already exists with the name
linearvoid, the Pages project must use a different name (e.g.,linearvoid-site). Update theprojectNamein the workflow accordingly. Workers and Pages share a namespace under "Workers & Pages".
Project-specific values
| Setting | Value |
|---|---|
| Framework | Vite + TypeScript |
| Build command | cd frontend && npm install && npm run build |
| Output directory | frontend/dist |
| Node version | 20 |
| Multi-page entries | index.html, admin/index.html, admin/login/index.html |
Gitea Actions workflow
Create .gitea/workflows/pages-deploy.yml:
name: Deploy to Cloudflare Pages
on:
push:
branches: ["main"]
workflow_dispatch: {}
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: cd frontend && npm ci
- name: Build
run: cd frontend && npm run build
- name: Deploy to Cloudflare Pages
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: linearvoid
directory: frontend/dist
gitHubToken: ${{ secrets.GITEA_TOKEN }}
If the cloudflare/pages-action@v1 action is unavailable from Gitea, use the direct Cloudflare Pages API (multipart/form-data with manifest):
Snippet to generate a manifest in format -F manifest='{"index.html": "abc123", "style.css": "def456"}'
# Build manifest form argument from all files in frontend/dist
form_args="-F manifest={"
for file in $(find frontend/dist -type f | sed 's|^frontend/dist/||'); do
hash=$(sha256sum "frontend/dist/$file" | awk '{print $1}')
form_args="$form_args\"$file\":\"$hash\","
done
form_args="${form_args%,}}" # remove trailing comma and close JSON
- name: Generate deployment manifest
run: |
cd frontend/dist
form_args="-F manifest={"
for file in $(find . -type f ! -name manifest.json | sed 's|^\./||'); do
hash=$(sha256sum "$file" | awk '{print $1}')
form_args="$form_args\"$file\":\"$hash\","
done
form_args="${form_args%,}}" # remove trailing comma and close JSON
echo "Form arguments: $form_args"
echo "FORM_ARGS=$form_args" >> $GITHUB_ENV
- name: Deploy to Cloudflare Pages
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
cd frontend/dist
form_args="$FORM_ARGS" # use form arguments generated in previous step
COMMIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
curl -sS -X POST \
"https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/pages/projects/linearvoid/deployments" \
-H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \
-F "commit_hash=${COMMIT_HASH}" \
$form_args
This matches the Cloudflare Pages Direct Upload API: Content-Type: multipart/form-data, each file as a separate form field, and a manifest JSON mapping filenames to SHA-256 hashes.
Secrets to add in Gitea
| Secret | Value |
|---|---|
CLOUDFLARE_API_TOKEN |
API token with Pages:Edit permission |
CLOUDFLARE_ACCOUNT_ID |
Cloudflare account ID from dashboard |
Verify deployment
- Push to
mainor trigger manually from Gitea Actions. - Check Gitea Actions → job logs for the deploy step.
- Check Cloudflare Pages → Deployments for the new deployment.
- Visit the
.pages.devpreview URL, then promote tolinearvoid.tvwhen ready.
Notes
- The existing
ci.ymlalready builds the frontend; the Pages deploy workflow is additive and independent. - Multi-page SPA (
vite.config.ts) produces three entry points — Cloudflare Pages serves them correctly. - For SPA fallback routing, add a
frontend/public/_redirectsfile with/* /index.html 200before building. - If deployments fail with 403, verify the API token has
Account → Cloudflare Pages → Editpermission. - If you get error 8000007 ("Project not found"), the Pages project hasn't been created yet. Create it via the Cloudflare dashboard (Workers & Pages → Create → Pages → Direct Upload) first, then re-run.
- If
linearvoidis already taken by a Worker, use a different project name likelinearvoid-siteand update theprojectNameandPROJECT_NAMEvalues in the workflow.
Related resources
- Cloudflare Workers dashboard:
https://dash.cloudflare.com/{accountId}/workers/services/view/linearvoid/production/settings— for managing theinfrastructure/cloudflare/worker.jsdeployment - Cloudflare Pages project:
https://dash.cloudflare.com/{accountId}/pages/view/linearvoid— deployment history and custom domain settings