Setup CI/CD GitHub Actions + Coolify (GHCR)
Catatan praktis arsitektur dan alur deployment otomatis menggunakan GitHub Actions (Build Runner) dan Coolify (Self-hosted VPS) via GitHub Container Registry (GHCR).
1. High-Level Architecture & Deployment Flow
Proses ini memindahkan beban build dari VPS ke GitHub Runner. VPS hanya bertugas melakukan docker pull image yang sudah jadi.
---
config:
look: handDrawn
---
graph TD
Developer([Developer / Local]) -->|1. git push main| GitHubRepo[GitHub Repository]
subgraph GitHub Cloud
GitHubRepo -->|2. Trigger Workflow| GHActions[GitHub Actions Runner]
GHActions -->|3. Build Docker Image| GHCR[GitHub Container Registry / GHCR]
GHActions -->|4. Push Image| GHCR
GHActions -->|5. Trigger Webhook POST| CoolifyAPI[Coolify API / VPS]
end
subgraph Production VPS
CoolifyAPI -->|6. Execute docker compose pull| DockerDaemon[Docker Daemon VPS]
DockerDaemon -->|7. Pull Latest Image| GHCR
DockerDaemon -->|8. docker compose up -d| AppContainer[App Container Running]
end
2. Checklist & Prerequisites
Sebelum membuat file workflow, pastikan item berikut sudah siap:
Personal Access Token (PAT) GitHub:
Coolify API Token:
Coolify Resource UUID:
GitHub Repository Secrets:
3. GitHub Actions Workflow Configuration
Buat file di .github/workflows/deploy.yml:
name: CI/CD Deployment
on:
push:
branches: [ "main" ]
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write # Wajib aktif untuk push package ke GHCR Org/Personal
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Convert Repository Name to Lowercase
id: repository
run: |
echo "REPO_LOWER=${GITHUB_REPOSITORY,,}" >> $GITHUB_ENV
- name: Build and Push Docker Image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ghcr.io/${{ env.REPO_LOWER }}:latest
# Masukkan argument jika butuh build-time env (misal: CMS/Public API)
build-args: |
NOTION_API_KEY=${{ secrets.NOTION_API_KEY }}
- name: Trigger Coolify Deployment
run: |
curl -X POST \
-H "Authorization: Bearer ${{ secrets.COOLIFY_API_TOKEN }}" \
"${{ secrets.COOLIFY_WEBHOOK_URL }}"
4. Kunci Konfigurasi Paling Penting
A. Memaksa Auto-Pull Image Terbaru di VPS
Agar Docker Compose tidak memakai cache image lama di VPS, pastikan salah satu/semua poin ini terpasang:
- Webhook Parameter: Tambahkan
&force=truepada URL Webhook di GitHub Secrets. - Docker Compose: Tambahkan
pull_policy: alwayspada service terkait:
web:
image: ghcr.io/username/repo:latest
pull_policy: always
- Coolify Dashboard: Aktifkan opsi Force Pull Image pada tab General/Advanced aplikasi.
B. Mencegah Error Autentikasi GHCR di VPS (unauthorized / denied)
Jika VPS menolak melakukan pull dari GHCR Private:
- Daftarkan Kredensial GHCR (PAT) di Coolify (Keys & Credentials -> Docker Registries).
- Hubungkan Docker Registry tersebut ke aplikasi target pada tab General di Coolify.
- Solusi SSH Host (Fallback): Jika runner helper Coolify tetap terisolasi, jalankan sekali di terminal SSH VPS:
echo "PAT_GITHUB_KAMU" | docker login ghcr.io -u USERNAME --password-stdin
cp ~/.docker/config.json /root/.docker/config.json
- Nama Repository Harus Lowercase: GHCR menolak nama image yang mengandung huruf kapital. Selalu gunakan helper
${GITHUB_REPOSITORY,,}pada Actions.
C. Pemisahan Environment Variables
- Build-Time Env (
NEXT_PUBLIC_*,NOTION_API_KEY): Disuntikkan di GitHub Actions melaluibuild-args. - Runtime Env (
DATABASE_URL,REDIS_URL,JWT_SECRET): Diisi di Dashboard Coolify (Environment Variables). Tidak perlu dimasukkan ke Docker Image / Actions.
5. Troubleshooting Cheat Sheet
| Symptom / Error | Cause | Quick Fix |
Nothing to do. Event '' is not supported | Menggunakan URL Git Webhook bawaan, bukan Deployment Webhook. | Ganti URL Webhook ke API deployment: /api/v1/deploy?uuid=... |
unauthorized saat trigger Webhook | Parameter Bearer Token tidak dikirimkan di header HTTP. | Tambahkan header -H "Authorization: Bearer ${{ secrets.COOLIFY_API_TOKEN }}" pada perintah curl. |
{"message":"No resources found."} | UUID aplikasi pada parameter ?uuid= tidak ditemukan/salah. | Periksa ulang Resource UUID di Dashboard Coolify target. |
denied: installation not allowed | GITHUB_TOKEN tidak punya izin menulis package di GHCR. | Tambahkan permissions: packages: write di file workflow YAML. |
| Code ter-update tapi container tidak berubah | Docker Compose menggunakan image lokal dari cache VPS. | Tambahkan pull_policy: always di docker-compose.yml & force=true pada Webhook. |