# CI/CD Setup — EasyPanel Deploy Push to `main` triggers `build-and-deploy.yml`: 1. Builds the Astro static site into `dist/` 2. Uploads `dist/` as a 7-day artifact 3. Calls EasyPanel tRPC endpoint to trigger a redeploy ## Required Gitea repo secrets Go to **Settings → Actions → Secrets** and add three secrets: | Name | Value (for this site) | Where to get it | |---|---|---| | `EASYPANEL_TOKEN` | `cmq61xwrv000407qn9e2hhfuw` | EasyPanel → profile/settings → API tokens | | `EASYPANEL_PROJECT_NAME` | `customerwebsite` | EasyPanel → project name in the dashboard | | `EASYPANEL_SERVICE_NAME` | `dealplustech-astro` | EasyPanel → service name inside the project | > ⚠️ Project name ≠ repo name. The site lives in the `customerwebsite` > project on the panel; the repo is `dealplustech-astroreal`. If any of these are empty, the workflow logs a warning and skips the deploy trigger. The build still runs and the artifact is still uploaded. ## EasyPanel service requirements The service on the panel side must be: - **Type: `app`** - **Source: Git**, pointing at this repo (`kunthawat/dealplustech-astroreal`) on branch **`main`** (not `source-code`). - **Build type: `dockerfile`**, **file: `Dockerfile`** at the repo root. > The workflow used to trigger nixpacks builds, but nixpacks expects a > `start` script in `package.json` and an Astro static site doesn't > have one. Switching to a Dockerfile + nginx fixes that. - **Port: `80`** If you need a different service type later, swap the endpoint in `.gitea/workflows/build-and-deploy.yml` to the matching procedure: - `services.app.deployService` (Dockerfile / app) - `services.box.rebuildDockerImage` (low-level) - `services.compose.deployService` (docker-compose) ## Why Dockerfile and not nixpacks Astro builds to static files in `dist/` — there is no Node server to run. Nixpacks tries to find a `start` command and fails. The Dockerfile in this repo: 1. **Stage 1** (`node:20-alpine`): runs `npm ci` then `npm run build` to produce `dist/`. 2. **Stage 2** (`nginx:1.27-alpine`): copies `dist/` to nginx's web root and serves it. `nginx.conf` ships gzip, security headers, 1-year cache for hashed assets, and a `try_files` fallback for client-side routes (Astro's file-based routing produces UTF-8 slugs). ## Verifying the trigger payload If the deploy runs but the panel rejects it, the response in the workflow log will show the exact `zodErrors` field telling you which field name or shape is wrong. Update the `PAYLOAD` JSON in the workflow accordingly. To test the payload shape from your local machine: ```bash curl -sS -X POST \ "https://panelwebsite.moreminimore.com/api/trpc/services.app.deployService" \ -H "Authorization: Bearer *** -H "Content-Type: application/json" \ -d '{"json":{"projectName":"customerwebsite","serviceName":"dealplustech-astro"}}' ``` A 2xx response = the panel accepted the trigger. The service will start rebuilding/redploying in the EasyPanel dashboard. ## Common failure: "No start command could be found" (nixpacks) Astro builds to static files in `dist/` — there is no Node server to run. Nixpacks tries to find a `start` command and fails. The Dockerfile in this repo handles this with a two-stage build (node:22-alpine build + nginx:1.27-alpine serve). ## Common failure: "Node.js v20.x is not supported by Astro" Astro 6 requires Node `>=22.12.0`. The Dockerfile uses `node:22-alpine`. If you see this error, the panel is probably reading a stale `node:20` cached image. Push an empty commit to force a rebuild, or clear the panel's image cache from the EasyPanel UI. ## Common failure: "Failed to sync changes" (HTTP 500) This is a **server-side** error, not a payload problem. It usually means: - The EasyPanel service is currently in a state that can't be redeployed (e.g. the previous container is stuck, or a build is in progress). - The Docker daemon on the panel host is busy. Try again in a few seconds. If it persists, open the EasyPanel dashboard and check the service's container state.