Setup CI/CD GitHub Actions + Coolify (GHCR)

Mempermudah hidup aja~

Uqie Rachmadie

Uqierach

7/23/2026 · 17 min read

Setup CI/CD GitHub Actions + Coolify (GHCR)

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:

  1. Webhook Parameter: Tambahkan &force=true pada URL Webhook di GitHub Secrets.
  2. Docker Compose: Tambahkan pull_policy: always pada service terkait:
web:
  image: ghcr.io/username/repo:latest
  pull_policy: always
  1. 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:

  1. Daftarkan Kredensial GHCR (PAT) di Coolify (Keys & Credentials -> Docker Registries).
  2. Hubungkan Docker Registry tersebut ke aplikasi target pada tab General di Coolify.
  3. 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
  1. 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 melalui build-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 / ErrorCauseQuick Fix
Nothing to do. Event '' is not supportedMenggunakan URL Git Webhook bawaan, bukan Deployment Webhook.Ganti URL Webhook ke API deployment: /api/v1/deploy?uuid=...
unauthorized saat trigger WebhookParameter 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 allowedGITHUB_TOKEN tidak punya izin menulis package di GHCR.Tambahkan permissions: packages: write di file workflow YAML.
Code ter-update tapi container tidak berubahDocker Compose menggunakan image lokal dari cache VPS.Tambahkan pull_policy: always di docker-compose.yml & force=true pada Webhook.