CI/CD Pipeline untuk CodeIgniter 4: Dari git push ke Coolify Deploy

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_USER dan $CI_REGISTRY_PASSWORD untuk login ke Container Registry-nya sendiri — tidak perlu bikin token manual.
  • Image di-push dengan 2 tag: $CI_COMMIT_SHORT_SHA (unique per commit) dan latest (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:

VariableDeskripsi
COOLIFY_CF_CLIENT_IDCloudflare Access Client ID
COOLIFY_CF_CLIENT_SECRETCloudflare Access Client Secret
COOLIFY_API_TOKENCoolify API token
COOLIFY_DEPLOY_URLEndpoint 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.

Salah Diagnosa Kerusakan Kamera

Pada cerita sebelumnya, saya baru saja service kamera karena rusak auto fokusnya. Dari proses service itu saya menyimpulkan, dikonfirmasi sama tukang servicenya, kalau body kamera saya aman, soalnya dipake buat autofocus lensa yang ada di sana aman.

Dari kesimpulan saya diatas, saya beli lensa baru dengan bukaan lebar dan rentang panjang fokus yang lebar juga. Sebelumnya, lensa yang saya beli di tempat service berupa lensa fix. Setelah lensa datang dan saya pasang di body kamera, saya kaget dan heran, kok perilakunya sama dengan lensa yang rusak sebelumnya, yaitu fokus gak bisa diputar. Saya sudah bersiap untuk ajukan pengembalian di platform marketplace.

Saya coba mencari-cari perbedaan dan penyebab. Beberapa faktor saya uji dan perhatikan cara kerjanya. Beberapa saya menemukan sesuatu yang mengarah pemecahan masalah. Lensa fix yang bisa autofocus, ternyata memiliki motor fokus internal lensa, soalnya ada pengaturan mf/af di body lensa. Kemudian Saya coba putar screw fokus di body gak jalan.

Saya mulai mencurigai kalau yang rusak adalah motor fokus yang ada di body, bukan gear fokus yang ada di lensa. Saya perhatikan dan otak-atik screw fokus di body, perhatikan mount antara lensa fix dan lensa baru. Saya menemukan di lensa fix yang bisa autofocus, tidak ada screw konektor. Artinya autofocus digerakkan oleh motor internal lensa.

Dari beberapa temuan diatas, saya melakukan percobaan dengan memutus koneksi antara screw fokus yang ada di body dengan screw yang ada di lensa. Karena kalau terhubung, fokus gak bisa diputar manual sekalipun. Saya mencoba akali dengan memasang pembatas, selotip bening, pada screw fokus di body. Kemudian saya pasang lensa dan Voilla… MANUAL FOKUS JALAN.

Ternyata dugaan selama ini salah. Yang rusak bukan lensanya, tetapi body kameranya. Semakin mengurangi rasa ingin mempertahankan body lama ini dan ingin beralih ke body kamera yang baru.

Sebelumnya saya selalu menduga kalau lensa nya yang bermasalah. Sempet suatu ketika fokus lensa saya putar bisa. Tapi saat itu kondisi tidak terpasang ke body. Begitu terpasang ke body, ternyata balik lagi gak bisa diputar. Herannya gak kepikiran kalau yang rusak body.

Menghidupkan Kembali Kamera DSLR Sony A200

Kamera saya ini sudah lama mati suri. Sejak sekitar tahun 2020 an, kamera ini ngandang. Penyebabnya adalah adanya kerusakan pada fokus lensa Kit bawaannya, lensa DT 18-70, sehingga fokus tidak bisa diatur sama sekali. Ulir fokusnya macet, jadi tidak bisa diputar, baik secara manual ataupun otomatis dari kamera.

Sebelum tahun 2020-an itu sebenarnya saya juga sudah jarang pakai, karena sejak tahun 2012 an praktis kebutuhan kamera sudah tercukupi di HP. Kemudian pada suatu waktu ada kebutuhan memotret dengan kualitas yang lebih baik. Tanpa saya sadari kamera dipegang oleh anak – anak yang belum seharusnya memegang kamera DSLR ini. Sepertinya ring ulir fokus diputar secara paksa sehingga gerigi didalamnya mungkin rampal. Sehingga sejak saat itu fokus tidak berfungsi, baik secara auto maupun manual.

Hingga beberapa waktu lalu ada kebutuhan dokumentasi. Baru kepikiran untuk menyelamatkan kembali kamera ini. Karena lama tidak dipakai jadi dalam body kameranya mulai ada jamur hingga ke mirror dan sensor. Jadi saya bawa ke tukang service untuk coba membetulkan lensa dan membersihkan jamur.

Lensa ternyata tidak terselamatkan karena katanya sparepart sudah jarang untuk barang lama ini. Lagipula saya pikir ongkos membetulkan dan effortnya tidak sebanding dengan harganya, soalnya ini lensa kit. Dengan pertimbangan tersebut akhirnya saya merelakan lensa tersebut dan menggantinya dengan lensa yang ada di tempat service.

Saya memilih lensa fix 50mm f/1.8 sebagai pengganti. Selain karena ketersediaan, saya juga ingin upgrade ke apperture yang lebih lebar, sehingga didapatkan kualitas bokeh dan penangkapan cahaya yang lebih lebar. Walupun kekurangannya opsi zoom jadi tidak ada dan fov terbatas.

Jun, 2026.

Buat Jaringan Internet Antar Kantor Dengan Point to Point

Sudah lama saya berfikir, bagaimana menghubungkan jaringan internet dari lokasi B ke lokasi A yang memiliki jarak sekitar 150 meter. Jalur internet utama ada di lokasi A dan saya ingin agar lokasi B punya akses internet melalui jaringan di lokasi A. Sementara ini saya hanya menggunakan router 4G dari TP-link sebagai akses internet di lokasi B.

Saya melakukan explorasi sekenario dan perangkat. Kemudian saya melihat review di youtube untuk mencari case yang sama. Konsultasi dengan AI juga saya lakukan untuk melihat solusi dan menambah wawasan skenari dari sudut pandang yang berbeda. Dari berbagai opsi perangkat dan skenario, saya memutuskan untuk menggunakan metode Point to Point menggunakan Totolink CP300.

Sambil menunggu barang datang, saya mencari spot dimana perangkat akan saya pasang diatas atap. Saya naik ke tempat toren air dan memasang HP di tongkat tongsis untuk melihat pandangan yang lebih luas. Saya berharap mendapat LOS atau Line of Sight yang tidak terhalang oleh apapun. Dari sini saya menemukan spot yang rasanya bisa dipertimbangkan dan dicoba, walaupun tidak free dari penghalang, tapi masih kelihatan disela-sela ranting pohon.

Lokasi A – Mode Access Point

Setelah Totolink CP300 datang, saya langsung melakukan uji coba. Dua perangkat saya nyalakan dan saling terhubung satu sama lain. Setelah saya yakin dengan skenario setup, saya naik ke area toren dan pasang satu Totolink CP300 di lokasi A dengan mode Access Point. Saya pasang di titik yang sudah saya tentukan sebelumnya dan saya hadapkan ke arah lokasi B.

Lokasi B – Mode Client

Selanjutnya di lokasi B, saya pasang Totolink CP300 juga dengan lokasi diatas teras dan menghadap ke lokasi A ke arah dimana Access Point dipasang. Sebelumnya sudah saya setting pengaturannya sehingga ketika diatas, langsung sat-set pasang dan atur pengkabelan dibawah. Nyalakan PoE dan cek halaman website pengaturan, didapatlah kekuatan sinyal 90 persen keatas. Kecepatan internet juga tidak jauh beda dengan lokasi A. Terus terang sangat puas dengan eksperimen ini dan saya putuskan untuk setup tempat kerja di lokasi B.

Mon, Dec 29, 2025

Membaca Banyak Modul PZEM-016 dan PZEM-017 dengan RS485

Tulisan ini sebenarnya adalah latepost lagi dari yang seharusnya saya tulis di pertengahan Agustus, tapi baru sempat saya tulis sekarang.

Pada tulisan sebelumnya kita cerita tentang membaca data dari Pzem dengan protokol RS485. Kali ini, kita akan bahas membaca banyak modul Pzem dengan protokol komunikasi RS485 dengan satu mikrokontroller ESP Wemos D1 Mini.

Secara umum, port RS485 yang biasa ditulis dengan tanda A dan B pada setiap device dihubungkan secara paralel dan disambung juga ke mikrokontroller melewati modul RS485 to TTL converter. Model topologi koneksinya yaitu daisy -chain, dimana di ujung awal adalah mikrokontroller sebagai master dan semua device sebagai slave.

Tiap – tiap device harus diberikan address yang berbeda sebagai identitas yang akan dibaca oleh ESP. Setelah ESP tau identitas masing-masing device, esp bisa membaca dan mengolah data untuk diteruskan atau sebagai input ke sistem lain yang lebih besar, tergantung skenario yang sudah dibuat.

Kira-kira seperti itu ide atau konsep membaca multiple devices dengan protokol komunikasi RS485, tidak hanya Pzem, tapi bisa juga device yang lain.

Fri, 12 Dec 25