Saya ingin berbagi pengalaman setup CI/CD pipeline untuk project CodeIgniter 4 yang saya kerjakan. Project ini menggunakan GitLab sebagai repository, GitLab Container Registry untuk menyimpan Docker image, dan Coolify sebagai platform deployment.
Tantangannya: bagaimana membuat workflow yang otomatis — setiap kali push ke branch master, pipeline jalan, build Docker image, push ke registry, lalu trigger deploy ke Coolify?
Berikut langkah-langkahnya.
Arsitektur Pipeline
Pipeline kami terdiri dari 2 stage sederhana:
Build → Docker build & push ke GitLab Container Registry Deploy → Trigger Coolify via webhook
git push → master
└─ build (docker build + push image)
└─ deploy (curl ke Coolify)
Sederhana, tapi ada beberapa hal yang perlu diperhatikan.
1. GitLab CI Pipeline
File .gitlab-ci.yml di root project:
stages:
- build
- deploy
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
IMAGE_LATEST: $CI_REGISTRY_IMAGE:latest
build:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build -t $IMAGE_TAG -t $IMAGE_LATEST .
- docker push $IMAGE_TAG
- docker push $IMAGE_LATEST
only:
- master
deploy_to_coolify:
stage: deploy
image: curlimages/curl:latest
needs: [build]
script:
- echo "Memicu deployment ke Coolify..."
- >
curl -L -X POST
-H "CF-Access-Client-Id: $COOLIFY_CF_CLIENT_ID"
-H "CF-Access-Client-Secret: $COOLIFY_CF_CLIENT_SECRET"
-H "Authorization: Bearer $COOLIFY_API_TOKEN"
"$COOLIFY_DEPLOY_URL"
only:
- master
Penjelasan:
- Build stage menggunakan Docker-in-Docker (
dind). GitLab secara built-in menyediakan$CI_REGISTRY_USERdan$CI_REGISTRY_PASSWORDuntuk login ke Container Registry-nya sendiri — tidak perlu bikin token manual. - Image di-push dengan 2 tag:
$CI_COMMIT_SHORT_SHA(unique per commit) danlatest(selalu yang terbaru). - Deploy stage menggunakan
curlimages/curl— image kecil (~5MB) yang isinya cuma curl. Lebih efisien daripada pakai alpine penuh. - Header Cloudflare Access (
CF-Access-Client-*) diperlukan karena server Coolify di belakang Cloudflare Tunnel.
CI Variables yang perlu diset di GitLab → Settings → CI/CD → Variables:
| Variable | Deskripsi |
|---|---|
COOLIFY_CF_CLIENT_ID | Cloudflare Access Client ID |
COOLIFY_CF_CLIENT_SECRET | Cloudflare Access Client Secret |
COOLIFY_API_TOKEN | Coolify API token |
COOLIFY_DEPLOY_URL | Endpoint deploy dari Coolify |
2. Production Docker Compose
Untuk development lokal kami pakai docker-compose.yml biasa yang build dari source. Tapi untuk production di Coolify, kami buat file terpisah: docker-compose.prod.yml.
Perbedaan utamanya:
- Menggunakan pre-built image dari registry, bukan build langsung.
- Healthcheck — Coolify bisa monitor apakah container benar-benar siap.
- Semua env variable via
${VAR:-default}— nilainya diisi dari Coolify UI.
services:
cldu-app:
image: registry.gitlab.com/username/nama-project:latest
pull_policy: always
container_name: cldu_app
ports:
- "${APP_FORWARD_PORT:-8070}:80"
environment:
APP_BASEURL: "${APP_BASEURL}"
CI_ENVIRONMENT: "${CI_ENVIRONMENT}"
DB_HOST: "${DB_HOST}"
DB_DATABASE: "${DB_DATABASE}"
DB_USERNAME: "${DB_USERNAME}"
DB_PASSWORD: "${DB_PASSWORD}"
volumes:
- cldu_writable:/var/www/writable
depends_on:
- cldu-db
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/robots.txt"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Di Coolify, kita arahkan deployment ke file docker-compose.prod.yml ini.
3. Masalah: Pull Access Denied
Pas pertama kali deploy, muncul error:
Error: pull access denied for registry.gitlab.com/username/nama-project,
repository does not exist or may require 'docker login'
Coolify tidak punya akses untuk pull image dari GitLab Container Registry karena registry-nya private. Wajar — kita perlu memberikan credentials.
Awalnya saya coba setting COOLIFY_CONTAINER_REGISTRY_USERNAME dan COOLIFY_CONTAINER_REGISTRY_PASSWORD di environment variable Coolify, tapi ternyata tidak bekerja. Variabel-variabel itu mungkin untuk versi Coolify tertentu atau cara yang berbeda.
Saya juga coba docker login di terminal server, tapi akan kerepotan jika ada banyak project dengan registry berbeda. Karena tiap registry akan ada username dan token masing-masing dari gitlab.
4. Solusi: DOCKER_AUTH_CONFIG + GitLab Deploy Token
Setelah searching, akhirnya nemu referensi tentang DOCKER_AUTH_CONFIG — environment variable standar yang digunakan Docker Engine untuk menyimpan credentials registry. Biasanya ini dibuat otomatis saat docker login dan disimpan di ~/.docker/config.json. Ternyata environment variable ini bisa di-inject langsung.
Ini masuk akal: di belakang layar, docker login nulis file config.json, Coolify bisa membaca varian env-nya langsung tanpa perlu file. Solusi yang akhirnya bekerja adalah DOCKER_AUTH_CONFIG. Ini adalah konfigurasi standar Docker untuk login ke registry — jadi pasti didukung oleh environment manapun, termasuk Coolify.
Langkah 1: Buat GitLab Deploy Token
Buka project di GitLab → Settings → Repository → Deploy Tokens.
Buat token baru dengan scope read_registry:
Name: coolify-deploy-token
Scope: ✅ read_registry
GitLab akan generate username (misal: gitlab+deploy-token-123456) dan password. Simpan password-nya, karena tidak bisa dilihat lagi setelah halaman di-refresh.
Langkah 2: Generate Base64
Deploy token adalah username:password biasa. Kita perlu meng-encode-nya ke base64:
echo -n "gitlab+deploy-token-123456:token-secret-xxx" | base64
Output: Z2l0bGFiK2RlcGxveS10b2tlbi14eHhhOnRva2VuLXNlY3JldC14eHg=
Langkah 3: Set DOCKER_AUTH_CONFIG di Coolify
Di Coolify, buka Resource → Envs, tambahkan variable baru:
DOCKER_AUTH_CONFIG = {"auths":{"registry.gitlab.com":{"auth":"Z2l0bGFiK2RlcGxveS10b2tlbi14eHhhOnRva2VuLXNlY3JldC14eHg="}}}
Setelah itu, redeploy. Sekarang Coolify bisa login ke GitLab Container Registry dan pull image dengan sukses.
Deploy Flow End-to-End
Setelah semuanya beres, beginilah workflow lengkapnya:
1. Developer: git push ke master
↓
2. GitLab CI Runner mendeteksi perubahan
↓
3. Build stage:
- docker build -t image:abc1234 -t image:latest .
- docker push image:abc1234
- docker push image:latest
↓
4. Deploy stage:
- curl -X POST -H "Authorization: Bearer coapi_xxx" \
"https://coolify.domain/api/v1/deploy?uuid=xxx"
↓
5. Coolify menerima webhook
↓
6. Coolify login ke registry (via DOCKER_AUTH_CONFIG)
↓
7. docker compose -f docker-compose.prod.yml up -d
↓
8. Healthcheck: cek /robots.txt di localhost
↓
9. App live! 🚀
Total waktu dari git push sampai app hidup biasanya sekitar 1-2 menit, tergantung ukuran image dan kecepatan build.
Troubleshooting
Beberapa error yang sempat saya alami dan solusinya:
Pull Access Denied
Error: pull access denied for registry.gitlab.com/...
Solusi: Set DOCKER_AUTH_CONFIG dengan base64 dari GitLab Deploy Token (scope read_registry).
Pipeline gagal — Docker not found
Error: docker: not found atau Cannot connect to the Docker daemon
Solusi: Pastikan GitLab Runner menggunakan executor docker dengan privileged = true. Ini diperlukan untuk menjalankan Docker-in-Docker.
Image tidak ditemukan
Error: manifest for registry.gitlab.com/... not found
Solusi: Pipeline build belum pernah jalan. Push ke master atau trigger manual pipeline dulu.
Penutup
Dengan pipeline ini, deploy jadi semudah git push. Tidak perlu SSH ke server, tidak perlu build manual, tidak perlu copy file. Semua otomatis.
Yang saya pelajari: masalah yang paling tricky bukan di GitLab CI-nya, tapi di autentikasi antara Coolify dan registry. Solusi DOCKER_AUTH_CONFIG adalah standar Docker yang bekerja di mana saja — tidak hanya Coolify, tapi juga di Kubernetes, Docker Swarm, atau VPS biasa.