Deploy to a PaaS
PaaS providers have built-in GitHub integrations but no native Codebahn connection. You deploy by running the provider’s CLI in your CI workflow, the same way you would run tests. To get deploy status back on your commits and pull requests, you create a Codebahn environment and point the provider’s webhook at its callback URL.
The deploy steps below are ordinary CI. The Codebahn-specific part is the environment callback: when the provider POSTs a status to the callback URL you configured, Codebahn writes a commit status and, for previews, a PR comment. See environments for the callback mechanism, payload formats, and security model.
How it works
Section titled “How it works”- Add an environment in the repository’s Environments tab (name + provider). Codebahn gives you a callback URL with a secret token.
- Add the provider’s deploy CLI command to your CI workflow.
- In the provider’s settings, add a webhook pointed at the callback URL.
- On push, CI runs your tests and deploys via the CLI. When the provider POSTs to the callback URL, Codebahn writes the commit status.
The environment callback is optional. If you skip it, the commit status comes from the CI step’s exit code instead, which is enough when the deploy runs entirely inside your workflow.
Per-provider setup
Section titled “Per-provider setup”The workflow snippets are generic CI. Add provider secrets under Settings > Actions > Secrets (stock Forgejo; see the upstream docs). Jobs run on hosted EU runners, so any CLI you reference is installed in the step, not pre-baked into the image. See CI runners for what’s already on the image.
Secrets:
VERCEL_TOKENfrom vercel.com/account/tokensVERCEL_ORG_IDandVERCEL_PROJECT_IDfrom.vercel/project.json(runvercel linklocally)
Workflow:
deploy-production: runs-on: ubuntu-latest needs: check if: github.ref == 'refs/heads/main' env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} steps: - uses: actions/checkout@v4 - run: npm i -g vercel - run: vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}
deploy-preview: runs-on: ubuntu-latest needs: check if: github.event_name == 'pull_request' env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} steps: - uses: actions/checkout@v4 - run: npm i -g vercel - name: Deploy preview id: deploy run: | url=$(vercel deploy --token=${{ secrets.VERCEL_TOKEN }}) echo "url=$url" >> "$GITHUB_OUTPUT" - name: Comment preview URL run: | curl -s -X POST \ -H "Authorization: token ${{ secrets.CODEBAHN_TOKEN }}" \ -H "Content-Type: application/json" \ -d "{\"body\":\"Preview: ${{ steps.deploy.outputs.url }}\"}" \ "${{ github.server_url }}/api/v1/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/comments"The preview job posts the deploy URL as a PR comment via the API. CODEBAHN_TOKEN is a personal access token you create and add as an Actions secret yourself; it is not injected for you. If you set up the Vercel callback below, the environment posts its own preview comment and you can drop this step.
Callback: Create a webhook in Vercel > Project Settings > Webhooks pointed at the callback URL from your environment. Select deployment.succeeded, deployment.error, deployment.created, deployment.canceled. Vercel signs callbacks; paste the signing secret into the environment.
Secrets:
NETLIFY_AUTH_TOKENfrom app.netlify.comNETLIFY_SITE_IDfrom Site configuration > General
Workflow (build in CI, upload output):
deploy: runs-on: ubuntu-latest needs: check if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - run: pnpm install && pnpm build - run: npx netlify-cli deploy --dir=./dist --prod --auth=${{ secrets.NETLIFY_AUTH_TOKEN }} --site=${{ secrets.NETLIFY_SITE_ID }}Callback: In Site configuration > Notifications > Outgoing webhooks, add “Deploy succeeded” and “Deploy failed” pointed at the callback URL.
Secrets:
RAILWAY_TOKENfrom project settings (project-scoped token)
Workflow:
deploy: runs-on: ubuntu-latest needs: check if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - run: npm i -g @railway/cli - run: railway up --detach env: RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}Callback: In Project Settings > Webhooks, add the callback URL and select deployment events. Railway does not sign callbacks; the secret token in the callback URL is the authentication.
Secrets:
CLOUDFLARE_API_TOKENwith “Cloudflare Pages: Edit” permissionCLOUDFLARE_ACCOUNT_IDfrom the Cloudflare dashboard
Workflow (build in CI, upload output):
deploy: runs-on: ubuntu-latest needs: check if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - run: pnpm install && pnpm build - run: npx wrangler pages deploy ./dist --project-name=my-project env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}Cloudflare Pages can send deploy alerts as a dashboard notification (see environments). If you skip that, the commit status comes from the CI step’s exit code.
Render does not deploy from source without a connected git repo. Two options:
Option A: Docker image. Build and push an image to your Codebahn registry in CI, then trigger Render. The built-in token pushes to your own owner with no secret to manage; see Publish container images.
deploy: runs-on: ubuntu-latest needs: check if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v4 - run: echo "${{ github.token }}" | docker login codebahn.net -u "${{ github.actor }}" --password-stdin - run: docker build -t codebahn.net/${{ github.repository }}:${{ github.sha }} . - run: docker push codebahn.net/${{ github.repository }}:${{ github.sha }} - run: | curl -X POST "https://api.render.com/v1/services/${{ secrets.RENDER_SERVICE_ID }}/deploys" \ -H "Authorization: Bearer ${{ secrets.RENDER_API_KEY }}" \ -H "Content-Type: application/json" \ -d '{"imageUrl":"codebahn.net/${{ github.repository }}:${{ github.sha }}"}'Images are private, so give Render a read:package token as a registry credential to pull. See pull from outside Codebahn. Keeping the image on Codebahn rather than a US registry holds the no-US-vendor line.
Callback: In Settings > Webhooks (a paid Render plan is required; check your plan), add the callback URL.
Verify
Section titled “Verify”Push a commit. Open the repository’s Environments tab and watch for callback events as the provider processes the deploy, then check the commit for its status.