---
title: "Cara Deploy Otomatis ke VPS dengan GitHub Actions"
description: "Langkah menyiapkan deploy otomatis dari GitHub ke VPS: user khusus, SSH key, secrets, file workflow, rsync, dan cara menjaga deploy tetap aman."
url: "https://nivelva.com/insight/cara-deploy-otomatis-vps-github-actions"
category: "Server \u0026 Infrastruktur"
tags: ["github actions","deploy","ci/cd","vps","ssh"]
author: "Lucas Tan"
published: "2026-11-11T12:59:00+07:00"
updated: "2026-11-11T12:59:00+07:00"
language: "id"
publisher: "Nivelva (https://nivelva.com)"
---

# Cara Deploy Otomatis ke VPS dengan GitHub Actions

> **Jawaban singkat:** Deploy otomatis ke VPS dengan GitHub Actions cukup butuh user deploy khusus di server, SSH key yang disimpan sebagai secret repo, dan satu file workflow yang menyalin kode lalu memuat ulang aplikasi setiap kali ada push ke branch utama.

Masih login ke VPS, menjalankan `git pull`, lalu me-restart aplikasi setiap kali ada perubahan kecil? Cara itu jalan, tapi rawan lupa langkah dan sulit dilacak siapa mengubah apa. GitHub Actions bisa mengambil alih pekerjaan ini: setiap kali kode masuk ke branch utama, GitHub menjalankan skrip yang menyalin kode ke VPS dan memuat ulang aplikasi.

Intinya ada tiga bahan. Satu user khusus deploy di server, satu SSH key yang disimpan sebagai secret di repo, dan satu file workflow YAML. Panduan ini memakai contoh aplikasi web biasa di Ubuntu, tapi polanya sama untuk Laravel, Node.js, atau situs statis.

## Bagaimana alurnya bekerja?

GitHub Actions menjalankan pekerjaan di mesin sementara yang disebut runner. Runner milik GitHub (misalnya `ubuntu-latest`) dibuat baru untuk setiap job lalu dibuang setelah selesai. Dari runner inilah koneksi SSH dibuka ke VPS kamu.

Urutannya kira-kira begini: kamu push ke `main`, workflow terpicu, runner mengambil kode dengan `actions/checkout`, menjalankan tes atau build bila ada, lalu memakai `rsync` lewat SSH untuk mengirim hasilnya ke folder aplikasi di server. Terakhir, runner menjalankan perintah reload di server.

Artinya, VPS harus bisa dihubungi lewat SSH dari internet. Kalau kamu sudah membatasi SSH hanya untuk IP kantor, ingat bahwa alamat IP runner GitHub tidak tetap. Solusinya bisa memakai self-hosted runner, atau membuka SSH dengan key saja (tanpa password) seperti dibahas di [SSH key vs password](https://nivelva.com/insight/ssh-key-vs-password).

## Langkah menyiapkan deploy otomatis

### 1. Buat user khusus deploy di VPS

Jangan memakai root untuk deploy. Buat user terpisah yang hanya punya hak atas folder aplikasi:

```
sudo adduser --disabled-password --gecos "" deploy
sudo mkdir -p /var/www/app
sudo chown deploy:deploy /var/www/app
```

Kalau aplikasi perlu di-restart lewat systemd, beri izin sudo hanya untuk satu perintah itu. Buat file dengan `sudo visudo -f /etc/sudoers.d/deploy` lalu isi:

```
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart app.service
```

Dengan begitu, kalau key deploy bocor, penyerang tidak otomatis mendapat akses root. Cara membuat user dan sudo lebih lengkap ada di [panduan user baru dan sudo](https://nivelva.com/insight/cara-membuat-user-baru-memberi-akses-sudo-linux).

### 2. Buat SSH key khusus deploy

Buat pasangan key baru di laptop, jangan memakai key pribadimu:

```
ssh-keygen -t ed25519 -C "github-deploy" -f ./deploy_key -N ""
```

Salin isi `deploy_key.pub` ke `/home/deploy/.ssh/authorized_keys` di server, dengan izin folder `.ssh` 700 dan file 600, dimiliki user `deploy`. Uji dulu dari laptop dengan `ssh -i ./deploy_key deploy@IP-SERVER`.

### 3. Simpan secrets di repository

Buka repo di GitHub, masuk ke Settings, lalu Secrets and variables, lalu Actions. Tambahkan:

| Nama secret | Isi |
|:--|:--|
| `SSH_PRIVATE_KEY` | Isi file `deploy_key` (private key) |
| `SSH_HOST` | IP atau hostname VPS |
| `SSH_USER` | `deploy` |
| `SSH_KNOWN_HOSTS` | Hasil `ssh-keyscan -t ed25519 IP-SERVER`, dicek cocok dengan fingerprint server |

Secret tidak tampil di log workflow dan tidak bisa dibaca ulang dari antarmuka GitHub setelah disimpan. Menyimpan `known_hosts` sebagai secret lebih aman daripada menjalankan `ssh-keyscan` di setiap deploy, karena kamu memastikan fingerprint sekali saat menyiapkan, bukan mempercayai apa pun yang menjawab di alamat itu.

Setelah tersimpan, hapus file `deploy_key` dari laptop atau simpan di pengelola password.

### 4. Tulis file workflow

Buat file `.github/workflows/deploy.yml` di repo:

```
name: Deploy ke VPS

on:
  push:
    branches: [main]
  workflow_dispatch:

concurrency:
  group: deploy-produksi
  cancel-in-progress: false

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

      - name: Siapkan SSH
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519
          echo "${{ secrets.SSH_KNOWN_HOSTS }}" > ~/.ssh/known_hosts

      - name: Kirim file
        run: |
          rsync -az --delete --exclude ".git" --exclude ".env" \
            ./ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/var/www/app/

      - name: Muat ulang aplikasi
        run: |
          ssh ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }} \
            "sudo /usr/bin/systemctl restart app.service"
```

Bagian `concurrency` mencegah dua deploy berjalan bersamaan kalau ada dua push beruntun. `workflow_dispatch` menambahkan tombol untuk menjalankan deploy secara manual dari tab Actions.

Perhatikan opsi `--delete` pada rsync. Opsi ini menghapus file di server yang tidak ada di repo, jadi pastikan folder upload pengguna atau file `.env` tidak berada di dalam folder tujuan, atau dikecualikan dengan `--exclude`.

### 5. Tambahkan tes sebelum deploy

Deploy otomatis paling berguna kalau kode yang rusak tidak ikut terkirim. Pisahkan job tes dan job deploy, lalu buat job deploy menunggu tes dengan `needs: test`. Bila tes gagal, deploy tidak dijalankan.

### 6. Uji dan pantau

Push perubahan kecil ke `main`, lalu buka tab Actions di repo. Setiap langkah punya log sendiri, sehingga kalau gagal kamu bisa melihat di mana berhentinya. Kesalahan yang paling sering muncul di percobaan pertama adalah izin folder di server dan isi `known_hosts` yang tidak cocok.

## Bagaimana menjaga deploy tetap aman?

Beberapa kebiasaan yang membantu:

- Pakai fitur Environments di GitHub untuk produksi, lalu aktifkan aturan persetujuan bila timmu lebih dari satu orang. Deploy baru jalan setelah ada yang menyetujui.
- Batasi siapa yang boleh push langsung ke `main` dengan branch protection.
- Jangan menaruh file `.env` produksi di repo. Simpan di server saja, di luar jangkauan rsync.
- Kunci versi action pihak ketiga. Untuk action dari luar GitHub, dokumentasi keamanan GitHub menyarankan merujuk ke commit SHA lengkap agar tidak berubah diam-diam.

> **Rollback tetap perlu disiapkan:**
>
> rsync menimpa file di tempat. Kalau versi baru bermasalah, cara tercepat kembali adalah menjalankan ulang workflow dari commit lama (revert lalu push). Untuk aplikasi yang tidak boleh berhenti sama sekali, pertimbangkan pola folder rilis bertanggal atau [deploy blue-green](https://nivelva.com/insight/cara-deploy-downtime-blue-green-vps).

## Ringkasan langkah dan hal yang sering terlewat

| Langkah | Yang perlu dicek |
|:--|:--|
| User deploy | Bukan root, hanya punya hak di folder aplikasi |
| SSH key | Key khusus, private key hanya di GitHub Secrets |
| known_hosts | Fingerprint dicek saat menyiapkan |
| Workflow | Ada `concurrency`, tes jalan sebelum deploy |
| rsync | `--exclude` untuk `.env` dan folder upload |
| Reload | Sudo terbatas pada satu perintah |

## Pertanyaan yang sering diajukan

### Apakah deploy lewat GitHub Actions gratis?

GitHub memberi kuota menit runner untuk akun gratis dan berbayar, dan repo publik punya ketentuan sendiri. Besarnya bisa berubah, jadi cek halaman billing GitHub untuk angka terbaru. Deploy sederhana dengan rsync biasanya hanya butuh waktu singkat per jalan.

### Lebih baik git pull di server atau rsync dari runner?

rsync dari runner membuat server tidak perlu akses ke repo dan memungkinkan build dilakukan di runner. git pull di server lebih sederhana, tapi server butuh deploy key untuk membaca repo dan build terjadi di mesin produksi.

### Bisakah deploy ke VPS yang SSH-nya hanya dibuka untuk IP tertentu?

Bisa, dengan self-hosted runner yang dipasang di jaringan yang diizinkan, atau lewat VPN. Runner milik GitHub memakai IP yang berganti-ganti, sehingga sulit dimasukkan ke whitelist.

### Bagaimana kalau aplikasinya pakai Docker?

Polanya mirip. Runner membangun image, mendorongnya ke registry, lalu lewat SSH menjalankan docker compose pull dan docker compose up -d di server.

Checklist sebelum menyalakan deploy otomatis:

- User `deploy` dibuat dan login dengan key berhasil
- Empat secret tersimpan di repo
- `.env` dan folder upload aman dari `--delete`
- Tes berjalan sebelum job deploy
- Cara rollback sudah dicoba sekali

## Sumber

- <https://docs.github.com/en/actions>
- <https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions>
- <https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions>

---

Diterbitkan oleh Nivelva Insight (https://nivelva.com/insight/). Artikel ini: https://nivelva.com/insight/cara-deploy-otomatis-vps-github-actions
Kontak Nivelva: WhatsApp https://wa.me/6285111245007, email hello@nivelva.com
