Tutorial GitHub Actions untuk Deploy Otomatis ke VPS

Pernah nggak sih kamu ngerasain momen ini: sudah push kode ke GitHub, tapi masih harus buka terminal, SSH ke VPS, tarik perubahan, restart server — dan itu dilakukan setiap kali ada update? Kalau cuma sekali-dua kali sih nggak masalah. Tapi kalau kamu push kode beberapa kali sehari? Repot banget, kan?

Dulu saya juga gitu. Setiap kali ada perubahan kecil di aplikasi, saya harus login ke VPS via SSH, jalankan git pull, lalu restart layanan. Kadang lupa restart, kadang salah branch, dan ujung-ujungnya malah bikin bug di production. Capek.

Sampai akhirnya saya kenal GitHub Actions. Dan jujur saja, ini mengubah cara saya bekerja secara drastis. Sekarang, setiap kali saya push kode ke branch main, VPS saya otomatis mengambil perubahan terbaru dan menjalankan deploy — tanpa saya sentuh apa-apa. Tinggal push, duduk manis, dan lihat log di GitHub. Selesai.

Di artikel ini, saya mau berbagi pengalaman lengkap cara mengatur GitHub Actions untuk deploy otomatis ke VPS. Nggak pakai teori berbelit-belit, langsung praktik. Saya akan bimbing kamu langkah demi langkah, mulai dari nol sampai workflow-nya jalan. Siap? Mari kita mulai.

Apa Itu GitHub Actions dan Kenapa Kamu Butuh Ini?

Sebelum masuk ke tutorial, saya mau jelasin dulu konsep dasarnya biar kamu nggak bingung di tengah jalan.

GitHub Actions itu adalah fitur CI/CD (Continuous Integration / Continuous Deployment) yang sudah built-in di GitHub. Jadi kamu nggak perlu install tool tambahan, nggak perlu daftar layanan pihak ketiga seperti Jenkins atau CircleCI kalau kebutuhannya simpel. Semua konfigurasinya ditulis dalam file YAML dan disimpan langsung di repository GitHub kamu.

Bayangkan begini: kamu punya file instruksi di repo yang bilang “setiap kali ada push ke branch main, jalankan perintah-perintah ini.” GitHub akan membaca instruksi itu, menjalankannya di server mereka (atau di VPS kamu sendiri), dan kamu bisa memantau semuanya dari tab “Actions” di repository.

Kenapa ini penting buat deploy ke VPS? Karena banyak dari kita yang meng-host aplikasi di VPS sendiri — entah itu VPS dari DigitalOcean, Vultr, Linode, AWS EC2, atau penyedia lokal. Nggak semua orang pakai PaaS seperti Vercel atau Netlify. Kadang kita butuh kontrol penuh atas server, dan di situlah VPS unggul.

Masalahnya, deploy manual ke VPS itu:

  • Rentan human error — salah command, salah direktori, lupa pull
  • Makan waktu — meskipun cuma 2 menit, kalau dilakukan 5 kali sehari jadi 10 menit terbuang
  • Nggak konsisten — kadang lupa step tertentu

Dengan GitHub Actions, semua itu jadi otomatis, konsisten, dan bisa diaudit. Kamu bisa lihat kapan deploy terakhir, siapa yang push, apa yang berubah, dan apakah deploy-nya berhasil atau gagal. Transparan banget.

Saya pribadi pakai setup ini untuk proyek web berbasis Node.js dan juga aplikasi PHP. Prinsipnya sama saja, yang beda cuma perintah deploy-nya. Jadi tutorial ini bisa kamu adaptasi untuk stack apa pun.

Persiapan Sebelum Mulai

Oke, sebelum kita ngoprek workflow, ada beberapa hal yang harus kamu siapkan dulu. Anggap saja ini checklist sebelum masuk dapur.

1. VPS yang Sudah Aktif

Kamu butuh VPS yang sudah jalan. Pastikan kamu bisa SSH ke VPS tersebut dari terminal lokal. Kalau belum bisa, atur dulu SSH key-nya.

ssh root@ip-vps-kamu

Kalau berhasil masuk, berarti oke.

2. Repository GitHub yang Ingin Di-deploy

Siapkan repo yang mau kamu deploy. Bisa repo baru atau yang sudah ada. Pastikan kamu punya akses admin ke repo tersebut, karena kita perlu mengatur Secrets nanti.

3. SSH Key Khusus untuk Deploy

Ini penting banget. Jangan pakai SSH key pribadi kamu. Buat key baru yang khusus dipakai untuk deploy. Caranya:

ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/deploy_key

Ini akan menghasilkan dua file:

  • ~/.ssh/deploy_key — private key (jangan pernah share ini)
  • ~/.ssh/deploy_key.pub — public key

Public key kamu tambahkan ke VPS:

cat ~/.ssh/deploy_key.pub | ssh root@ip-vps-kamu "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Private key akan kamu simpan di GitHub Secrets. Nggak perlu diingat, nanti saya tunjukkan caranya.

4. Pastikan Git Sudah Terinstall di VPS

git --version

Kalau belum ada, install dulu:

# Ubuntu/Debian
sudo apt update && sudo apt install git -y

# CentOS/RHEL
sudo yum install git -y

5. Aplikasi Sudah di-clone di VPS

Di VPS, clone repo kamu ke direktori yang kamu inginkan. Misalnya:

cd /var/www
git clone [email protected]:username/repo-kamu.git
cd repo-kamu

Kalau aplikasi butuh build (misalnya Node.js), jalankan build pertama kali secara manual:

npm install
npm run build

Atau kalau PHP, pastikan web server (Nginx/Apache) sudah pointing ke direktori yang benar.

Membuat Workflow GitHub Actions

Sekarang masuk ke bagian inti. Di repo kamu, buat direktori dan file berikut:

.giwtohrdukebfp/lloowys.yml

Isi deploy.yml dengan workflow berikut. Saya akan jelaskan setiap bagiannya:

name: Deploy to VPS

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Deploy to VPS via SSH
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USERNAME }}
          key: ${{ secrets.VPS_SSH_KEY }}
          port: 22
          script: |
            cd /var/www/repo-kamu
            git pull origin main
            npm install --production
            pm2 restart all

Wah, langsung panjang ya? Tenang, saya bedah satu-satu.

Penjelasan Tiap Bagian

on: push: branches: [main] Ini artinya workflow akan berjalan setiap kali ada push ke branch main. Kamu bisa ganti ke branch lain, atau tambahkan event lain seperti pull_request.

runs-on: ubuntu-latest Workflow akan dijalankan di environment Ubuntu terbaru yang disediakan oleh GitHub. Ini adalah “runner” virtual yang dipakai sementara.

uses: actions/checkout@v4 Ini step untuk clone repository ke runner. Biasanya dipakai kalau kamu butuh install dependencies atau build di sisi GitHub dulu sebelum deploy.

uses: appleboy/[email protected] Ini adalah action pihak ketiga yang sangat populer untuk menjalankan perintah SSH dari GitHub Actions. Dibuat oleh developer bernama appleboy, action ini sudah dipakai oleh ribuan project. Kamu nggak perlu install apa-apa, GitHub akan mengunduhnya otomatis.

${{ secrets.VPS_HOST }} Ini merujuk ke GitHub Secrets — tempat kamu menyimpan data rahasia seperti IP server, username, dan SSH key. Nggak akan terlihat di log, jadi aman.

script: | Bagian ini berisi perintah yang akan dijalankan di VPS kamu lewat SSH. Dalam contoh ini:

  1. cd /var/www/repo-kamu — masuk ke direktori project
  2. git pull origin main — tarik kode terbaru
  3. npm install --production — install dependencies
  4. pm2 restart all — restart aplikasi

Sesuaikan dengan kebutuhanmu. Kalau pakai PHP + Nginx, mungkin kamu cuma perlu git pull saja. Kalau pakai Docker, kamu bisa ganti dengan docker compose up -d --build.

Mengatur GitHub Secrets

Oke, sekarang kamu perlu memberi tahu GitHub tentang informasi rahasia VPS kamu. Caranya:

  1. Buka repository GitHub kamu
  2. Klik Settings → Secrets and variables → Actions
  3. Klik New repository secret
  4. Tambahkan tiga secrets berikut:
Nama SecretIsi
VPS_HOSTIP address VPS kamu, misalnya 123.45.67.89
VPS_USERNAMEUsername SSH, misalnya root
VPS_SSH_KEYSeluruh isi dari file ~/.ssh/deploy_key (private key)

Untuk mengambil isi private key, jalankan:

cat ~/.ssh/deploy_key

Copy semua outputnya — termasuk bagian -----BEGIN OPENSSH PRIVATE KEY----- sampai -----END OPENSSH PRIVATE KEY----- — dan paste ke kolom value secret.

Penting: Pastikan nggak ada spasi atau karakter aneh yang tertambah saat copy-paste. Kadang masalah deploy gagal itu cuma gara-gara ada newline ekstra di SSH key.

Kalau VPS Pakai Password (Bukan SSH Key)

Meskipun saya sangat nggak menyarankan pakai password untuk deploy otomatis, kalau terpaksa kamu juga bisa menambahkan:

Nama SecretIsi
VPS_PASSWORDPassword SSH VPS kamu

Lalu di workflow, tambahkan password:

with:
  host: ${{ secrets.VPS_HOST }}
  username: ${{ secrets.VPS_USERNAME }}
  password: ${{ secrets.VPS_PASSWORD }}
  port: 22
  script: |
    cd /var/www/repo-kamu
    git pull origin main

Tapi serius deh, pakai SSH key jauh lebih aman. Password mudah di-brute-force, sementara SSH key secara kriptografi hampir mustahil ditebak.

Contoh Workflow untuk Berbagai Stack

Saya tahu nggak semua orang pakai Node.js. Jadi saya kasih beberapa contoh workflow untuk stack yang umum dipakai.

Untuk Aplikasi Node.js dengan PM2

name: Deploy Node.js App

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy via SSH
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USERNAME }}
          key: ${{ secrets.VPS_SSH_KEY }}
          port: 22
          script: |
            cd /var/www/my-node-app
            git pull origin main
            npm install --production
            npm run build
            pm2 restart ecosystem.config.js

Untuk Aplikasi PHP (Laravel)

name: Deploy Laravel App

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy via SSH
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USERNAME }}
          key: ${{ secrets.VPS_SSH_KEY }}
          port: 22
          script: |
            cd /var/www/my-laravel-app
            git pull origin main
            composer install --no-dev --optimize-autoloader
            php artisan migrate --force
            php artisan config:cache
            php artisan route:cache
            php artisan view:cache
            sudo systemctl reload php8.2-fpm

Perhatikan flag --force di artisan migrate. Ini penting karena di environment production, Laravel butuh konfirmasi sebelum menjalankan migration. Dengan --force, kita bypass konfirmasi itu (karena memang kita mau jalankan otomatis).

Untuk Aplikasi Docker

name: Deploy Docker App

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy via SSH
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USERNAME }}
          key: ${{ secrets.VPS_SSH_KEY }}
          port: 22
          script: |
            cd /var/www/my-docker-app
            git pull origin main
            docker compose down
            docker compose up -d --build
            docker system prune -f

docker system prune -f di akhir itu untuk membersihkan image dan container yang sudah nggak dipakai. Biar nggak makan disk space VPS.

Strategi Build di GitHub, Deploy Hasilnya ke VPS

Workflow di atas menjalankan build langsung di VPS. Ini fine-fine saja untuk proyek kecil. Tapi kalau proyekmu besar, build di VPS bisa memakan resource yang bikin aplikasi down sebentar.

Solusinya? Build di GitHub Actions, lalu upload hasilnya ke VPS.

name: Build and Deploy

on:
  push:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install and Build
        run: |
          npm ci
          npm run build

      - name: Deploy to VPS
        uses: SamKirkland/[email protected]
        with:
          server: ${{ secrets.VPS_HOST }}
          username: ${{ secrets.VPS_USERNAME }}
          password: ${{ secrets.VPS_PASSWORD }}
          local-dir: ./dist/
          server-dir: /var/www/my-app/public/

Atau kalau mau tetap pakai SSH dan rsync (lebih fleksibel):

      - name: Upload build to VPS
        uses: easingthemes/[email protected]
        with:
          SSH_PRIVATE_KEY: ${{ secrets.VPS_SSH_KEY }}
          REMOTE_HOST: ${{ secrets.VPS_HOST }}
          REMOTE_USER: ${{ secrets.VPS_USERNAME }}
          SOURCE: "dist/"
          TARGET: "/var/www/my-app/public/"

Cara ini lebih efisien karena:

  1. Build terjadi di infrastruktur GitHub yang powerful
  2. Hanya file hasil build yang dikirim ke VPS
  3. VPS nggak perlu install dependencies atau compile apa pun
  4. Waktu deploy jadi jauh lebih singkat

Debugging: Kalau Workflow Gagal, Gimana?

Nggak semua deploy berjalan mulus. Saya pernah menghabiskan hampir 2 jam gara-gara workflow gagal dan saya nggak tahu kenapa. Jadi saya mau kasih tips debugging biar kamu nggak mengalami hal yang sama.

Cek Tab Actions di GitHub

Setiap kali workflow berjalan, hasilnya tercatat di tab Actions di repository kamu. Klik workflow run yang gagal, lalu klik job-nya. Kamu akan melihat log detail untuk setiap step.

Masalah Umum yang Sering Terjadi

1. Permission denied (publickey)

Ini artinya SSH key yang kamu masukkan di Secrets nggak cocok dengan yang ada di VPS. Solusi: generate ulang key dan pastikan public key benar-benar tercatat di ~/.ssh/authorized_keys di VPS.

2. Command not found

Artinya ada perintah di script yang nggak tersedia di VPS. Misalnya kamu pakai pm2 tapi belum diinstall global di VPS. Solusi: install dulu di VPS secara manual.

npm install -g pm2

3. Build gagal karena environment berbeda

Kadang build di GitHub Actions (Ubuntu terbaru) bisa berbeda dengan environment di VPS. Kalau kamu build di GitHub, pastikan versi Node.js/PHP/Python-nya sama dengan yang di VPS.

Tambahkan Notifikasi Kalau Deploy Gagal

Biar kamu nggak ketinggalan info kalau deploy gagal, tambahkan step notifikasi:

      - name: Notify on failure
        if: failure()
        uses: appleboy/[email protected]
        with:
          to: ${{ secrets.TELEGRAM_CHAT_ID }}
          token: ${{ secrets.TELEGRAM_BOT_TOKEN }}
          message: "❌ Deploy gagal! Cek log di GitHub Actions."

Atau kalau pakai Discord:

      - name: Notify Discord
        if: failure()
        uses: sarisia/actions-status-discord@v1
        with:
          webhook: ${{ secrets.DISCORD_WEBHOOK }}
          status: "failure"

Dengan notifikasi, kamu akan langsung tahu kalau ada masalah tanpa harus cek GitHub setiap saat.

Tips Tambahan yang Sering Dilupakan

Saya mau kasih beberapa tips tambahan berdasarkan pengalaman saya pribadi. Tips-tips ini mungkin terdengar sepele, tapi dampaknya besar.

Gunakan Concurrency Control

Kalau kamu push beberapa kali dalam waktu singkat, bisa jadi beberapa workflow berjalan bersamaan dan deploy-nya saling tumpang-tindih. Untuk mencegah ini:

concurrency:
  group: deploy-production
  cancel-in-progress: true

Tambahkan bagian ini di level yang sama dengan on: dan jobs:. Dengan ini, kalau ada workflow baru yang berjalan, workflow lama yang belum selesai akan dibatalkan.

Batasi Deploy Hanya untuk Perubahan Tertentu

Kadang kamu cuma edit README atau file .gitignore. Nggak perlu deploy kan? Kamu bisa pakai paths filter:

on:
  push:
    branches:
      - main
    paths-ignore:
      - '*.md'
      - '.gitignore'
      - 'docs/**'

Ini menghemat waktu dan resource.

Buat Branch Proteksi

Di GitHub, atur branch protection rules untuk main:

  1. Buka Settings → Branches
  2. Tambahkan rule untuk main
  3. Centang Require pull request before merging
  4. Centang Require status checks to pass dan pilih workflow kamu

Dengan ini, kode nggak bisa langsung push ke main. Harus lewat pull request dulu, dan workflow harus berhasil sebelum bisa di-merge. Ini menambah lapisan keamanan ekstra.

Backup Sebelum Deploy

Ini tip yang jarang dibahas tapi sangat penting. Tambahkan step backup di script deploy kamu:

# Backup sebelum pull
cp -r /var/www/my-app /var/www/my-app-backup-$(date +%Y%m%d%H%M%S)

# Deploy
cd /var/www/my-app
git pull origin main
npm install --production
pm2 restart all

Kalau ada masalah setelah deploy, kamu tinggal restore dari backup:

# Rollback
cp -r /var/www/my-app-backup-20260819120000/* /var/www/my-app/
pm2 restart all

Nggak ada yang lebih menakutkan daripada deploy gagal dan nggak punya backup. Trust me.


Mulai Sekarang, Jangan Tunda Lagi

Saya tahu di awal mungkin terasa ribet — bikin SSH key, atur Secrets, tulis workflow YAML, debug kalau gagal. Tapi percayalah, investasi waktu 30-60 menit di awal ini akan menghemat berjam-jam waktu kamu ke depannya.

Bayangkan: setiap kali kamu push kode, VPS kamu langsung update. Nggak perlu SSH manual. Nggak perlu ingat perintah apa yang harus dijalankan. Nggak perlu khawatir lupa step. Semuanya tercatat, terstruktur, dan otomatis.

Saya sudah pakai setup ini selama lebih dari dua tahun untuk berbagai proyek — dari aplikasi sederhana sampai yang cukup kompleks. Dan saya belum pernah kembali ke cara manual. Nggak ada alasan untuk kembali.

Mulai dari yang sederhana dulu. Workflow pertama kamu mungkin cuma git pull di VPS. Itu sudah cukup. Lama-kelamaan, kamu bisa tambah step: build, test, notifikasi, rollback otomatis. Tapi yang penting adalah mulai.

Dan kalau kamu butuh bantuan, jangan ragu buat reach out.


Ada pertanyaan seputar setup GitHub Actions untuk deploy ke VPS? Atau butuh bantuan mengatur workflow untuk project spesifik kamu? Kirim email ke [email protected] — saya senang bisa bantu.


FAQ

Apakah GitHub Actions gratis untuk deploy ke VPS?

GitHub Actions punya free tier yang cukup generous: 2.000 menit per bulan untuk repository public, dan 500 menit per bulan untuk repository private (di akun free). Untuk kebutuhan deploy biasa, 500 menit itu lebih dari cukup. Satu kali workflow run biasanya cuma butuh 1-3 menit. Jadi kalau kamu deploy 5 kali sehari, itu baru sekitar 150 menit per bulan. Masih aman. Kalau butuh lebih, kamu bisa upgrade ke GitHub Pro atau Teams yang memberikan lebih banyak menit.

Bagaimana kalau saya punya beberapa VPS untuk staging dan production?

Bisa banget. Kamu bisa buat dua workflow terpisah atau satu workflow dengan dua jobs. Contohnya, deploy ke staging saat push ke branch develop, dan deploy ke production saat push ke branch main. Tinggal buat Secrets terpisah untuk masing-masing VPS (misalnya STAGING_VPS_HOST dan PROD_VPS_HOST), lalu arahkan di masing-masing workflow. Kamu juga bisa menggunakan environments di GitHub untuk memisahkan konfigurasi staging dan production, plus menambahkan approval sebelum deploy ke production.

Apakah aman menyimpan SSH key di GitHub Secrets?

Ya, GitHub Secrets dirancang khusus untuk menyimpan data sensitif. Nilainya tidak akan pernah ditampilkan di log workflow — GitHub secara otomatis akan menyensor secret yang muncul di output. Namun, tetap ada best practice: gunakan SSH key khusus deploy (bukan key pribadi kamu), batasi akses key hanya untuk direktori yang diperlukan, dan rotasi key secara berkala. Selain itu, pastikan hanya collaborator yang dipercaya yang punya akses ke repository Settings, karena mereka bisa melihat dan mengubah secrets.

Workflow saya jalan tapi VPS nggak berubah. Kenapa?

Ada beberapa kemungkinan. Pertama, pastikan git pull benar-benar menarik perubahan baru — cek apakah branch yang kamu push sama dengan branch yang ada di VPS. Kedua, kalau kamu pakai build output (misalnya folder dist/), pastikan file yang di-deploy adalah hasil build, bukan source code mentah. Ketiga, kalau pakai web server seperti Nginx, pastikan Nginx pointing ke direktori yang benar dan kamu sudah reload Nginx setelah deploy. Terakhir, cek apakah ada caching — kadang browser atau CDN masih menampilkan versi lama meskipun file di server