The previous doc assumed a Gitea Actions workflow (which requires a self-hosted act_runner that we don't have, hence the 'No matching online runner with label: ubuntu-latest' error). The actual setup is much simpler: a Gitea Webhook pointing at the deploy endpoint. No runner, no workflow file. Setup is one-time in Settings -> Webhooks -> Add Webhook. Documents: - The push -> webhook -> deploy -> EasyPanel flow - Exact payload URL, method, content type, events - Test Delivery verification step - Why Gitea Actions doesn't work without act_runner - Troubleshooting: push not triggering, build failure modes (nixpacks 'No start command', node 20 vs 22), and a curl recipe for redeploying without a code change.
3.8 KiB
CI/CD Setup — Deploy via Gitea Webhook
The site auto-rebuilds on every push to main via a Gitea webhook
(no Actions runner, no .gitea/workflows/, no act_runner required).
How it works
git push origin main
│
▼
Gitea Webhook (Gitea built-in, not Gitea Actions)
│ POST Content-Type: application/json
▼
http://110.164.146.47:3000/api/deploy/<token>
│ HTTP 200 "Deploying..."
▼
EasyPanel pulls repo, builds with Dockerfile, redeploys
One-time webhook setup
In https://git.moreminimore.com/kunthawat/dealplustech-astroreal/settings/hooks:
- Click Add Webhook → Gitea
- Fill in:
- Payload URL:
http://110.164.146.47:3000/api/deploy/772d2c3a4a7d8671657c947c059bc1cdc64bd816efb7fbe2 - HTTP Method:
POST - Content Type:
application/json - Events: Push events
- Active: ✓
- Branch filter: leave empty (or
mainto restrict)
- Payload URL:
- Click Add Webhook
- Test: click the webhook row → Test Delivery → Push events → confirm Last Response is HTTP 200.
Done. From now on every push to main redeploys automatically.
EasyPanel service requirements
The service on the panel side (project=customerwebsite,
service=dealplustech-astro) must be:
- Type:
app - Source: Git, branch
main - Build type:
dockerfile, fileDockerfileat repo root - Port:
80
The Dockerfile is two-stage:
node:22-alpine— runsnpm ciandnpm run buildto producedist/nginx:1.27-alpine— copiesdist/to nginx's web root and serves it (with gzip, security headers, 1-year cache for hashed assets, and atry_filesfallback for Astro's UTF-8 slugs)
Why not Gitea Actions?
Gitea Actions does not ship with managed runners (unlike GitHub
Actions' ubuntu-latest). Without a self-hosted act_runner registered
with matching labels, any workflow run will fail with
"No matching online runner with label: ubuntu-latest".
The Gitea Webhook mechanism is built into Gitea itself — no runner required. It fires the same events but POSTs to a URL you control, which is the simplest possible deploy trigger.
If a real CI step is ever needed (lint, test, build artifact), install
act_runner on a box, register it, and write a workflow using
runs-on: self-hosted. See act_runner docs for setup.
Troubleshooting
Push happened, but site didn't update
- Open the webhook row in Settings → Webhooks
- Open Recent Deliveries
- Check the most recent one:
- Status 200 → deploy endpoint received it, check EasyPanel logs
- Status != 200 → check the response body
- No recent delivery → webhook is not bound to this branch/event or the push target branch doesn't match the filter
Build fails inside EasyPanel
- EasyPanel UI → service
dealplustech-astro→ Logs tab - Look for the
nixpacksordocker buildstep - Common failures:
- "No start command could be found": you're on
nixpacks. Switch build type todockerfileand point atDockerfileat repo root. - "Node.js v20.x is not supported by Astro": the Dockerfile is
using
node:20-alpine. It should benode:22-alpine(Astro 6 requires>=22.12.0). - "Failed to sync changes" (HTTP 500 from the deploy endpoint): usually a panel-side state issue. Retry, or open the service in the panel UI and check container state.
- "No start command could be found": you're on
Want to redeploy without a code change
The webhook URL itself is idempotent. You can hit it directly with:
curl -X POST \
"http://110.164.146.47:3000/api/deploy/772d2c3a4a7d8671657c947c059bc1cdc64bd816efb7fbe2"
A 200 response with body Deploying... means the panel accepted the
trigger. The actual rebuild happens in the background — check EasyPanel
UI for the progress.