Selamat datang di bagian terakhir dari seri Belajar Laravel dari Nol! Di tiga belas bagian sebelumnya kita sudah membangun aplikasi Laravel yang lengkap — dari instalasi, routing, controller, Blade, migration, Eloquent, relasi, form, autentikasi, authorization, file upload, API, hingga testing. Sekarang saatnya membawa semua itu ke dunia nyata: deploy ke VPS production agar aplikasimu bisa diakses oleh pengguna di seluruh dunia.
💡 Ini adalah bagian keempat belas dan terakhir dari seri "Belajar Laravel dari Nol". Di bagian ini kita akan melakukan full deployment — dari konfigurasi server, setup Nginx, SSL, environment production, hingga otomasi deploy dengan GitHub Actions. Semua konsep yang dibahas bisa langsung diterapkan untuk project Laravel apapun, termasuk project Filament seperti DevPath, riwayat-hidup.id, atau aplikasi lainnya.
Gambaran Arsitektur Production
Sebelum mulai, penting untuk memahami arsitektur lengkap yang akan kita bangun. Di production, Laravel tidak berjalan sendirian — ia dikelilingi oleh beberapa komponen yang masing-masing memiliki peran penting dalam memastikan aplikasi berjalan cepat, aman, dan stabil.
─── ARSITEKTUR PRODUCTION YANG AKAN DIBANGUN ─────────────
Internet
│
▼
Cloudflare (CDN + DDoS Protection + SSL Termination)
│
▼
VPS Ubuntu 22.04
│
├── Nginx (Web Server / Reverse Proxy)
│ ├── SSL Certificate (Let's Encrypt via Certbot)
│ ├── Gzip Compression
│ ├── Static File Caching
│ └── PHP-FPM Upstream
│
├── PHP 8.3-FPM (Process Manager untuk PHP)
│
├── Laravel Application
│ ├── Queue Worker (via Supervisor)
│ └── Task Scheduler (via Cron)
│
├── MySQL 8.0 (Database)
│
└── Redis (Cache + Queue + Session)
TOOLS TAMBAHAN:
- Composer — Package manager PHP
- Node.js + NPM — Build frontend assets
- Git — Version control + deployment trigger
- Supervisor — Menjaga queue worker tetap berjalan
- GitHub Actions — CI/CD otomatis
Langkah 1: Persiapan dan Keamanan VPS
Setelah mendapatkan VPS baru (DigitalOcean, Hetzner, IDCloudHost, atau provider lain), langkah pertama adalah mengamankan server sebelum menginstal apapun. VPS yang baru dibuat sudah langsung menjadi target scan otomatis dari seluruh internet dalam hitungan menit.
# ── LOGIN PERTAMA KALI ─────────────────────────────────
ssh root@IP_VPS_KAMU
# ── BUAT USER NON-ROOT ─────────────────────────────────
adduser deploy
usermod -aG sudo deploy
# Setup SSH key untuk user deploy
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
# ── AMANKAN SSH ────────────────────────────────────────
nano /etc/ssh/sshd_config
# Ubah / tambahkan:
# Port 2222 ← Ganti port default (opsional)
# PermitRootLogin no ← Nonaktifkan login root
# PasswordAuthentication no ← Hanya SSH key
# PubkeyAuthentication yes
systemctl restart sshd
# ── KONFIGURASI FIREWALL (UFW) ─────────────────────────
ufw allow 2222/tcp # Port SSH kustom (atau 22 jika tidak diubah)
ufw allow 80/tcp # HTTP
ufw allow 443/tcp # HTTPS
ufw enable
ufw status
# ── INSTALL FAIL2BAN ───────────────────────────────────
apt install fail2ban -y
systemctl enable fail2ban
systemctl start fail2ban
# ── UPDATE SISTEM ──────────────────────────────────────
# Login sebagai deploy mulai dari sini
ssh deploy@IP_VPS_KAMU -p 2222
sudo apt update && sudo apt upgrade -y
sudo apt autoremove -y
Langkah 2: Install Software Stack
Setelah server aman, saatnya menginstal semua software yang dibutuhkan untuk menjalankan aplikasi Laravel. Kita akan menginstal Nginx, PHP 8.3 dengan semua extension yang dibutuhkan, MySQL, Redis, Composer, dan Node.js.
# ── INSTALL NGINX ──────────────────────────────────────
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx
# ── INSTALL PHP 8.3 ────────────────────────────────────
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
sudo apt install php8.3-fpm \
php8.3-mysql \
php8.3-redis \
php8.3-mbstring \
php8.3-xml \
php8.3-curl \
php8.3-zip \
php8.3-gd \
php8.3-intl \
php8.3-bcmath \
php8.3-tokenizer \
php8.3-ctype \
php8.3-fileinfo \
-y
# Verifikasi PHP
php -v
# PHP 8.3.x
# ── KONFIGURASI PHP-FPM ────────────────────────────────
sudo nano /etc/php/8.3/fpm/php.ini
# Ubah nilai berikut:
# upload_max_filesize = 20M
# post_max_size = 25M
# memory_limit = 256M
# max_execution_time = 60
# max_input_vars = 3000
sudo systemctl restart php8.3-fpm
# ── INSTALL MYSQL 8 ────────────────────────────────────
sudo apt install mysql-server -y
sudo mysql_secure_installation
# Ikuti prompt: set root password, hapus anonymous users,
# disable remote root login, hapus test database
# Buat database dan user untuk aplikasi
sudo mysql -u root -p
# CREATE DATABASE laravel_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# CREATE USER 'laravel'@'localhost' IDENTIFIED BY 'password_kuat_di_sini';
# GRANT ALL PRIVILEGES ON laravel_prod.* TO 'laravel'@'localhost';
# FLUSH PRIVILEGES;
# EXIT;
# ── INSTALL REDIS ──────────────────────────────────────
sudo apt install redis-server -y
sudo systemctl enable redis-server
sudo systemctl start redis-server
# Test Redis
redis-cli ping
# PONG
# ── INSTALL COMPOSER ───────────────────────────────────
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version
# ── INSTALL NODE.JS & NPM ──────────────────────────────
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install nodejs -y
node -v && npm -v
Langkah 3: Upload dan Konfigurasi Aplikasi Laravel
Dengan software stack sudah siap, saatnya upload kode aplikasi Laravel ke server. Cara terbaik dan paling umum adalah menggunakan Git — clone repository langsung dari GitHub ke server, bukan upload file secara manual via FTP.
Buat folder untuk aplikasi di /var/www/, clone repository dari GitHub, dan set permission yang benar. Jika repository private, setup SSH key atau deploy key di GitHub agar server bisa mengakses repository tanpa password.
Buat file .env khusus production dengan semua nilai yang sesuai untuk lingkungan production — APP_ENV=production, APP_DEBUG=false, konfigurasi database, Redis, mail, dan semua service yang dipakai.
Jalankan composer install dengan flag production (tanpa dev dependencies), install npm dependencies, dan build assets frontend dengan npm run build untuk menghasilkan file CSS dan JS yang sudah diminifikasi.
Laravel menyediakan beberapa perintah optimasi yang meng-cache route, config, dan view agar aplikasi berjalan lebih cepat di production — sangat penting untuk performa yang optimal.
# ── BUAT FOLDER APLIKASI ───────────────────────────────
sudo mkdir -p /var/www/devpath.id
sudo chown -R deploy:deploy /var/www/devpath.id
# ── SETUP SSH KEY UNTUK GITHUB (jika repo private) ────
ssh-keygen -t ed25519 -C "deploy@server" -f ~/.ssh/github_deploy
cat ~/.ssh/github_deploy.pub
# Salin output dan tambahkan sebagai Deploy Key di:
# GitHub → Repository → Settings → Deploy keys
# Tambahkan ke SSH config
nano ~/.ssh/config
# Host github.com
# HostName github.com
# User git
# IdentityFile ~/.ssh/github_deploy
# ── CLONE REPOSITORY ───────────────────────────────────
cd /var/www/devpath.id
git clone git@github.com:sabda/devpath.git .
# ── KONFIGURASI .ENV ───────────────────────────────────
cp .env.example .env
nano .env
# Isi nilai-nilai penting:
# APP_NAME="DevPath"
# APP_ENV=production
# APP_KEY= ← akan di-generate
# APP_DEBUG=false
# APP_URL=https://devpath.id
#
# DB_CONNECTION=mysql
# DB_HOST=127.0.0.1
# DB_DATABASE=laravel_prod
# DB_USERNAME=laravel
# DB_PASSWORD=password_kuat_di_sini
#
# CACHE_STORE=redis
# SESSION_DRIVER=redis
# QUEUE_CONNECTION=redis
#
# REDIS_HOST=127.0.0.1
# REDIS_PORT=6379
#
# MAIL_MAILER=resend ← atau smtp, mailgun, ses
# RESEND_API_KEY=re_xxxxx
# MAIL_FROM_ADDRESS=noreply@devpath.id
# ── INSTALL DEPENDENCIES ───────────────────────────────
composer install \
--no-dev \ # Jangan install dev dependencies
--optimize-autoloader \
--no-interaction
# ── GENERATE APP KEY ───────────────────────────────────
php artisan key:generate
# ── BUILD FRONTEND ASSETS ──────────────────────────────
npm ci # Install exact versions dari package-lock.json
npm run build # Build untuk production (minify, hash)
# ── JALANKAN MIGRATION ─────────────────────────────────
php artisan migrate --force # --force wajib di production
# ── JALANKAN SEEDER (jika diperlukan) ─────────────────
php artisan db:seed --class=ProductionSeeder --force
# ── BUAT SYMBOLIC LINK STORAGE ─────────────────────────
php artisan storage:link
# ── SET PERMISSION ─────────────────────────────────────
sudo chown -R deploy:www-data /var/www/devpath.id
sudo chmod -R 755 /var/www/devpath.id
sudo chmod -R 775 /var/www/devpath.id/storage
sudo chmod -R 775 /var/www/devpath.id/bootstrap/cache
# ── OPTIMASI LARAVEL UNTUK PRODUCTION ─────────────────
# Cache konfigurasi (config/*.php → satu file cache)
php artisan config:cache
# Cache route (routes/*.php → satu file cache)
php artisan route:cache
# Cache view Blade (precompile semua template)
php artisan view:cache
# Cache event listeners
php artisan event:cache
# Atau jalankan semua sekaligus:
php artisan optimize
# ── VERIFIKASI OPTIMASI ────────────────────────────────
php artisan about
# Menampilkan info aplikasi termasuk status cache
# ── PENTING: CLEAR CACHE SAAT DEPLOY ULANG ────────────
# Saat ada perubahan kode, clear dulu baru cache ulang:
php artisan optimize:clear
php artisan optimize
Langkah 4: Konfigurasi Nginx
Nginx berperan sebagai web server yang menerima semua request dari internet dan meneruskannya ke PHP-FPM untuk diproses oleh Laravel. Konfigurasi Nginx yang benar sangat penting untuk keamanan, performa, dan fungsionalitas aplikasi.
# /etc/nginx/sites-available/devpath.id
server {
listen 80;
listen [::]:80;
server_name devpath.id www.devpath.id;
# Redirect HTTP ke HTTPS (akan diupdate Certbot)
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name devpath.id www.devpath.id;
# SSL — akan diisi Certbot
ssl_certificate /etc/letsencrypt/live/devpath.id/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/devpath.id/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Document root ke folder public Laravel
root /var/www/devpath.id/public;
index index.php;
# Charset
charset utf-8;
# Ukuran upload maksimal
client_max_body_size 20M;
# Sembunyikan versi Nginx
server_tokens off;
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# ── ROUTING LARAVEL ───────────────────────────────
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# ── PHP-FPM ───────────────────────────────────────
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_hide_header X-Powered-By;
# Timeout untuk proses yang panjang
fastcgi_read_timeout 300;
}
# ── CACHE STATIC FILES ────────────────────────────
location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|css|js|woff|woff2|ttf|eot)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# ── AMANKAN FILE SENSITIF ─────────────────────────
location ~ /\.ht {
deny all;
}
location ~ /\.(env|git) {
deny all;
}
# ── LOGGING ───────────────────────────────────────
access_log /var/log/nginx/devpath.id_access.log;
error_log /var/log/nginx/devpath.id_error.log;
# ── GZIP COMPRESSION ─────────────────────────────
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml application/json
application/javascript application/xml+rss
application/atom+xml image/svg+xml;
}
# ── AKTIFKAN KONFIGURASI NGINX ─────────────────────────
# Buat symbolic link ke sites-enabled
sudo ln -s /etc/nginx/sites-available/devpath.id \
/etc/nginx/sites-enabled/
# Hapus konfigurasi default jika tidak diperlukan
sudo rm -f /etc/nginx/sites-enabled/default
# Test konfigurasi — WAJIB sebelum reload
sudo nginx -t
# nginx: configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
# Reload Nginx
sudo systemctl reload nginx
Langkah 5: SSL dengan Let's Encrypt
HTTPS adalah keharusan di production — bukan hanya untuk keamanan, tapi juga untuk SEO dan kepercayaan pengguna. Let's Encrypt menyediakan sertifikat SSL gratis yang dipercaya semua browser, dan Certbot mengotomasi seluruh proses instalasi dan renewal.
# ── INSTALL CERTBOT ────────────────────────────────────
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# ── DAPATKAN SERTIFIKAT SSL ────────────────────────────
# Certbot otomatis modifikasi konfigurasi Nginx
sudo certbot --nginx -d devpath.id -d www.devpath.id
# Ikuti prompt:
# - Masukkan email untuk notifikasi expiry
# - Setujui Terms of Service
# - Pilih apakah ingin redirect HTTP→HTTPS (pilih 2: Redirect)
# ── VERIFIKASI AUTO-RENEWAL ────────────────────────────
sudo systemctl status snap.certbot.renew.timer
# Test renewal (dry run — tidak benar-benar renew)
sudo certbot renew --dry-run
# "Congratulations, all simulated renewals succeeded."
# ── TEST HTTPS ─────────────────────────────────────────
curl -I https://devpath.id
# HTTP/2 200
# Cek SSL grade di: https://ssllabs.com/ssltest/
# Target: Grade A
Langkah 6: Setup Queue Worker dengan Supervisor
Queue worker adalah proses yang berjalan di background untuk memproses job yang antri — seperti pengiriman email, resize gambar, atau notifikasi push. Tanpa Supervisor, queue worker akan berhenti saat terminal ditutup atau saat terjadi error. Supervisor memastikan queue worker selalu berjalan dan otomatis restart jika berhenti.
# ── INSTALL SUPERVISOR ─────────────────────────────────
sudo apt install supervisor -y
sudo systemctl enable supervisor
sudo systemctl start supervisor
# ── BUAT KONFIGURASI SUPERVISOR ────────────────────────
sudo nano /etc/supervisor/conf.d/laravel-worker.conf
; /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/devpath.id/artisan queue:work redis \
--sleep=3 \
--tries=3 \
--max-time=3600 \
--max-jobs=1000
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=deploy
numprocs=2 ; Jalankan 2 worker process
redirect_stderr=true
stdout_logfile=/var/www/devpath.id/storage/logs/worker.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backups=5
stopwaitsecs=3600
# ── AKTIFKAN KONFIGURASI SUPERVISOR ───────────────────
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*
# ── CEK STATUS WORKER ─────────────────────────────────
sudo supervisorctl status
# laravel-worker:laravel-worker_00 RUNNING pid 12345, uptime 0:00:05
# laravel-worker:laravel-worker_01 RUNNING pid 12346, uptime 0:00:05
# ── PERINTAH SUPERVISOR BERGUNA ───────────────────────
sudo supervisorctl stop laravel-worker:* # Hentikan semua worker
sudo supervisorctl start laravel-worker:* # Jalankan semua worker
sudo supervisorctl restart laravel-worker:* # Restart semua worker
# Setelah deploy baru, restart worker agar pickup kode terbaru:
sudo supervisorctl restart laravel-worker:*
Langkah 7: Task Scheduler dengan Cron
Laravel Task Scheduler memungkinkan kamu mendefinisikan tugas berulang langsung di kode PHP — mengirim laporan harian, membersihkan file temporary, memperbarui cache, dan lainnya. Untuk menjalankan scheduler ini, kamu perlu satu entri cron di server yang menjalankan perintah Artisan setiap menit.
# ── TAMBAHKAN CRON UNTUK LARAVEL SCHEDULER ────────────
crontab -e -u deploy
# Tambahkan baris ini:
* * * * * cd /var/www/devpath.id && php artisan schedule:run >> /dev/null 2>&1
# ── DEFINISIKAN SCHEDULED TASKS DI LARAVEL ────────────
# routes/console.php (Laravel 11+) atau app/Console/Kernel.php
<?php
// routes/console.php — Definisi scheduled tasks
use Illuminate\Support\Facades\Schedule;
// Kirim laporan harian pukul 08.00
Schedule::command('reports:daily')->dailyAt('08:00');
// Bersihkan file temporary setiap hari tengah malam
Schedule::command('storage:clean-temp')->daily();
// Hapus token expired setiap minggu
Schedule::command('sanctum:prune-expired --hours=168')->weekly();
// Backup database setiap hari pukul 01.00
Schedule::command('backup:run')->dailyAt('01:00');
// Perbarui sitemap setiap 6 jam
Schedule::command('sitemap:generate')->everySixHours();
// Cek status external services setiap 5 menit
Schedule::call(function () {
// Logika pengecekan
})->everyFiveMinutes();
// ── VERIFIKASI SCHEDULER BERJALAN ─────────────────────
// php artisan schedule:list → Lihat semua task terjadwal
// php artisan schedule:run → Jalankan manual sekali
// php artisan schedule:work → Jalankan scheduler secara lokal (development)
Langkah 8: Otomasi Deploy dengan GitHub Actions
Deploy manual — SSH ke server, git pull, composer install, migrate, optimize — adalah proses yang repetitif dan rawan lupa langkah. GitHub Actions memungkinkan kamu mengotomasi seluruh proses ini: setiap kali ada push ke branch main, test dijalankan otomatis, dan jika semua test lulus, kode di-deploy ke server secara otomatis.
Buat script shell yang berisi semua perintah deploy — git pull, composer install, npm build, migrate, optimize, restart worker. Script ini yang akan dipanggil oleh GitHub Actions via SSH.
GitHub Actions perlu akses SSH ke server untuk menjalankan deploy script. Buat SSH key pair khusus untuk deployment, tambahkan public key ke authorized_keys server, dan simpan private key sebagai GitHub Secret.
Buat file .github/workflows/deploy.yml yang mendefinisikan kapan workflow berjalan, apa yang dilakukan (test dulu, baru deploy), dan bagaimana cara deploy ke server via SSH.
# ── BUAT DEPLOY SCRIPT DI SERVER ──────────────────────
nano /var/www/devpath.id/deploy.sh
#!/bin/bash
# /var/www/devpath.id/deploy.sh
# Script deploy otomatis — dipanggil oleh GitHub Actions
set -e # Hentikan jika ada error
APP_DIR="/var/www/devpath.id"
cd $APP_DIR
echo "🚀 Memulai deployment..."
# ── MAINTENANCE MODE ───────────────────────────────────
echo "📴 Aktifkan maintenance mode..."
php artisan down --secret="bypass-token-rahasia"
# ── PULL KODE TERBARU ──────────────────────────────────
echo "📥 Pull kode terbaru dari GitHub..."
git pull origin main
# ── INSTALL DEPENDENCIES ───────────────────────────────
echo "📦 Install PHP dependencies..."
composer install \
--no-dev \
--optimize-autoloader \
--no-interaction \
--prefer-dist
# ── BUILD FRONTEND ─────────────────────────────────────
echo "🎨 Build frontend assets..."
npm ci
npm run build
# ── DATABASE ───────────────────────────────────────────
echo "🗃️ Jalankan migration..."
php artisan migrate --force
# ── CLEAR DAN CACHE ULANG ─────────────────────────────
echo "⚡ Optimasi cache..."
php artisan optimize:clear
php artisan optimize
# ── RESTART SERVICES ───────────────────────────────────
echo "🔄 Restart queue workers..."
sudo supervisorctl restart laravel-worker:*
# ── KELUAR MAINTENANCE MODE ────────────────────────────
echo "✅ Keluar dari maintenance mode..."
php artisan up
echo "🎉 Deployment selesai!"
# Buat script executable
chmod +x /var/www/devpath.id/deploy.sh
# ── SETUP SUDO TANPA PASSWORD UNTUK SUPERVISOR ────────
# Deploy user perlu restart supervisor tanpa password
sudo visudo -f /etc/sudoers.d/deploy
# Tambahkan:
# deploy ALL=(ALL) NOPASSWD: /usr/bin/supervisorctl
# ── BUAT SSH KEY UNTUK GITHUB ACTIONS ─────────────────
# Di KOMPUTER LOKAL:
ssh-keygen -t ed25519 -C "github-actions-deploy" -f ~/.ssh/github_actions_deploy
# Copy public key ke server:
ssh-copy-id -i ~/.ssh/github_actions_deploy.pub deploy@IP_VPS -p 2222
# Salin isi private key untuk GitHub Secret:
cat ~/.ssh/github_actions_deploy
# ── TAMBAHKAN GITHUB SECRETS ──────────────────────────
# Di GitHub → Repository → Settings → Secrets and variables → Actions:
# SSH_PRIVATE_KEY = isi file github_actions_deploy (private key)
# SSH_HOST = IP address VPS
# SSH_USER = deploy
# SSH_PORT = 2222
# .github/workflows/deploy.yml
name: Test & Deploy to Production
on:
push:
branches: [main]
jobs:
# ── JOB 1: JALANKAN TEST ──────────────────────────────
test:
name: Run Tests
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: laravel_test
ports: ['3306:3306']
options: --health-cmd="mysqladmin ping" --health-interval=10s
redis:
image: redis
ports: ['6379:6379']
options: --health-cmd="redis-cli ping" --health-interval=10s
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, pdo_mysql, redis, gd, zip
coverage: none
- name: Cache Composer dependencies
uses: actions/cache@v3
with:
path: vendor
key: composer-${{ hashFiles('composer.lock') }}
- name: Install Dependencies
run: composer install --no-interaction --prefer-dist
- name: Setup Environment
run: |
cp .env.example .env
php artisan key:generate
env:
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: laravel_test
DB_USERNAME: root
DB_PASSWORD: password
- name: Run Migrations
run: php artisan migrate --force
env:
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_DATABASE: laravel_test
DB_USERNAME: root
DB_PASSWORD: password
- name: Run Tests
run: php artisan test --parallel
env:
DB_CONNECTION: mysql
DB_HOST: 127.0.0.1
DB_DATABASE: laravel_test
DB_USERNAME: root
DB_PASSWORD: password
REDIS_HOST: 127.0.0.1
# ── JOB 2: DEPLOY (hanya jika test lulus) ────────────
deploy:
name: Deploy to Production
runs-on: ubuntu-latest
needs: test # Hanya jalan jika job 'test' berhasil
if: success() # Hanya jika semua job sebelumnya sukses
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
port: ${{ secrets.SSH_PORT }}
script: |
cd /var/www/devpath.id
bash deploy.sh
- name: Notify deployment success
if: success()
run: echo "✅ Deployment to production successful!"
- name: Notify deployment failure
if: failure()
run: echo "❌ Deployment failed! Check logs."
💡 Dengan setup ini, workflow deployment kamu sepenuhnya otomatis: push ke branch main → GitHub Actions menjalankan semua test → jika test lulus, kode otomatis di-deploy ke production → server masuk maintenance mode, pull kode baru, install dependencies, build assets, migrate, optimize, restart worker, lalu kembali online. Jika test gagal, deployment tidak terjadi sehingga production selalu dalam kondisi yang sudah terverifikasi.
Monitoring dan Logging Production
Aplikasi yang sudah live perlu dipantau secara aktif. Masalah di production sering tidak terlihat sampai ada pengguna yang mengeluh — dengan monitoring yang baik, kamu bisa mendeteksi dan mengatasi masalah sebelum berdampak luas ke pengguna.
# ── LOG LARAVEL ────────────────────────────────────────
# Log tersimpan di: storage/logs/laravel.log
# Ikuti log secara realtime:
tail -f /var/www/devpath.id/storage/logs/laravel.log
# Filter hanya error:
grep -i "error\|exception" /var/www/devpath.id/storage/logs/laravel.log
# ── KONFIGURASI LOG DI .ENV ────────────────────────────
# LOG_CHANNEL=daily ← Log per hari (direkomendasikan)
# LOG_LEVEL=error ← Hanya log error di production
# LOG_DEPRECATIONS_CHANNEL=null
# ── KONFIGURASI LARAVEL LOGGING (config/logging.php) ──
# Stack 'daily' otomatis rotate log per hari dan
# simpan 14 hari terakhir
# ── LOG NGINX ──────────────────────────────────────────
# Access log:
tail -f /var/log/nginx/devpath.id_access.log
# Error log:
tail -f /var/log/nginx/devpath.id_error.log
# Cari 404 errors:
grep " 404 " /var/log/nginx/devpath.id_access.log | tail -20
# Cari 500 errors:
grep " 500 " /var/log/nginx/devpath.id_access.log | tail -20
# ── MONITORING RESOURCE ────────────────────────────────
# CPU dan Memory realtime:
htop
# Disk usage:
df -h
# Queue monitoring via Artisan:
php artisan queue:monitor redis --max=100
# ── SETUP UPTIMEROBOT (gratis) ─────────────────────────
# Daftar di uptimerobot.com
# Tambahkan monitor: https://devpath.id
# Alert via email/Telegram jika down
# Cek setiap 5 menit
# ── LARAVEL TELESCOPE (debugging di staging) ───────────
# composer require laravel/telescope --dev
# php artisan telescope:install
# php artisan migrate
# Akses: /telescope (hanya untuk admin)
Checklist Deployment Production
Gunakan checklist ini setiap kali melakukan deployment besar atau pertama kali launch aplikasi ke production. Urutan ini dirancang untuk meminimalkan risiko downtime dan memastikan tidak ada langkah penting yang terlewat.
─── CHECKLIST SEBELUM LAUNCH PRODUCTION ─────────────────
SERVER SETUP
□ VPS sudah diamankan (user non-root, SSH key, firewall UFW)
□ Fail2ban aktif
□ PHP 8.3, Nginx, MySQL, Redis, Composer, Node.js terinstal
□ PHP-FPM dikonfigurasi dengan benar (memory limit, upload size)
APLIKASI
□ Repository ter-clone di /var/www/namadomain.com
□ File .env production sudah dikonfigurasi
□ APP_ENV=production
□ APP_DEBUG=false
□ APP_KEY sudah di-generate
□ Database credentials benar
□ Redis dikonfigurasi untuk cache, session, dan queue
□ Mail credentials aktif
□ composer install --no-dev berjalan tanpa error
□ npm run build berhasil
□ php artisan migrate --force berhasil
□ php artisan storage:link sudah dijalankan
□ Permission folder storage dan bootstrap/cache benar (775)
□ php artisan optimize sudah dijalankan
NGINX DAN SSL
□ Konfigurasi Nginx valid (nginx -t)
□ Domain sudah diarahkan ke IP VPS (DNS propagated)
□ SSL certificate terpasang via Certbot
□ HTTP otomatis redirect ke HTTPS
□ Security headers sudah ditambahkan
SERVICES
□ Supervisor aktif dan queue worker berjalan
□ Cron job untuk Laravel scheduler aktif
□ Redis server aktif
MONITORING
□ UptimeRobot / monitoring aktif
□ Log rotation dikonfigurasi (LOG_CHANNEL=daily)
□ Backup database terjadwal
CICD
□ GitHub Actions workflow berfungsi
□ Test semua lulus di CI
□ Deploy script sudah ditest
AKHIR
□ Test semua halaman utama di browser
□ Test form submission dan upload file
□ Test login, register, dan reset password
□ Test API endpoint dengan Postman
□ Cek SSL grade di ssllabs.com (target: A)
□ Cek performa di pagespeed.web.dev (target: 80+)
□ Simpan semua kredensial di password manager
⚠️ Tiga hal yang paling sering menyebabkan masalah saat deployment pertama: (1) permission folder storage dan bootstrap/cache yang salah — pastikan kedua folder ini writable oleh web server (chmod 775, owner deploy:www-data), (2) lupa menjalankan php artisan storage:link sehingga file upload tidak bisa diakses via URL, dan (3) APP_DEBUG=true tertinggal di production yang mengekspos stack trace dan konfigurasi sensitif ke pengguna. Selalu periksa ketiga hal ini pertama kali jika ada masalah setelah deploy.
Penutup: Perjalanan yang Telah Kita Tempuh
Selamat! Kamu telah menyelesaikan seluruh seri Belajar Laravel dari Nol — empat belas bagian yang membawamu dari instalasi pertama hingga aplikasi Laravel yang berjalan di production dengan CI/CD yang terautomasi. Ini adalah perjalanan yang luar biasa. Kamu sudah mempelajari Routing, Controller, Blade Templating, Migration, Eloquent ORM, Relasi Antar Model, Form dan Validasi, Authentication, Authorization, File Upload, REST API dengan Sanctum, Testing, dan terakhir Deployment ke Production.
🚀 Langkah selanjutnya setelah seri ini: perdalam Laravel dengan topik lanjutan seperti Event & Listener, Broadcasting (WebSocket dengan Laravel Reverb), Advanced Eloquent, Laravel Octane untuk performa tinggi, dan Multi-tenancy. Yang terpenting adalah terus membangun proyek nyata — setiap project mengajarkan hal yang tidak bisa didapat dari tutorial. Komunitas Laravel Indonesia sangat aktif dan siap membantu. Selamat berkarya!