Cara Deploy Laravel ke VPS Ubuntu dengan Nginx + SSL

Kalau trafik aplikasi Laravel Anda mulai naik, shared hosting sering terasa lambat dan terbatas. Solusinya: pindah ke VPS. Artikel ini memandu Anda deploy Laravel ke VPS Ubuntu mem...

Cara Deploy Laravel ke VPS Ubuntu dengan Nginx + SSL
Iklan

Kalau trafik aplikasi Laravel Anda mulai naik, shared hosting sering terasa lambat dan terbatas. Solusinya: pindah ke VPS. Artikel ini memandu Anda deploy Laravel ke VPS Ubuntu memakai Nginx dan PHP-FPM, langkah demi langkah, cocok untuk yang baru pertama kali memakai VPS.

Panduan ini tidak berhenti di "aplikasi sudah bisa dibuka". Kita juga membahas hal yang sering terlewat saat pertama kali deploy: membuat database MySQL, build aset Vite, menjalankan queue worker dan scheduler, memasang firewall, serta cara meng-update aplikasi tanpa repot. Di akhir ada tabel troubleshooting dan FAQ untuk error yang paling sering muncul.

Gambaran Arsitektur: Bagaimana Nginx, PHP-FPM, dan Laravel Bekerja

Sebelum mengetik perintah, ada baiknya paham alurnya dulu, karena hampir semua error deploy berasal dari salah satu mata rantai ini:

Iklan
  1. Browser mengirim request ke domain Anda. DNS mengarahkannya ke IP VPS.
  2. Nginx menerima request di port 80 (HTTP) atau 443 (HTTPS). File statis seperti CSS, JS, dan gambar langsung dilayani Nginx tanpa melibatkan PHP.
  3. Untuk request selain file statis, Nginx meneruskannya ke PHP-FPM lewat socket Unix (misalnya /var/run/php/php8.3-fpm.sock).
  4. PHP-FPM menjalankan public/index.php, yaitu pintu masuk Laravel, yang lalu memproses route, controller, database, dan mengembalikan HTML atau JSON.

Dari sini kelihatan kenapa dua hal paling krusial adalah root Nginx yang harus menunjuk ke folder public, dan fastcgi_pass yang harus cocok dengan socket PHP-FPM yang benar-benar ada. Salah satu meleset, hasilnya 403, 404, atau 502.

Prasyarat

  • VPS dengan Ubuntu dan akses SSH root/sudo. Disarankan Ubuntu 24.04 LTS, karena PHP bawaannya sudah 8.3. Ubuntu 22.04 juga bisa, tetapi PHP bawaannya 8.1 (lihat catatan di Langkah 2).
  • Domain yang sudah diarahkan (A record) ke IP VPS.
  • Project Laravel Anda (idealnya sudah ada di repository Git).
  • RAM minimal sekitar 1 GB sudah cukup untuk aplikasi kecil. Jika di bawah itu, pertimbangkan menambah swap agar composer install dan npm run build tidak gagal karena kehabisan memori.

Pastikan juga Anda sudah terbiasa dengan Git dasar, karena alur deploy di artikel ini mengandalkan git clone dan git pull.

Langkah 1: Update Server & Install Paket Dasar

sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx git unzip curl

Sebaiknya jangan bekerja terus-menerus sebagai root. Buat user biasa dengan akses sudo, lalu login SSH memakai user tersebut:

adduser deploy
usermod -aG sudo deploy
usermod -aG www-data deploy

Aktifkan firewall (UFW)

Buka hanya port yang memang diperlukan: SSH, HTTP, dan HTTPS. Pastikan aturan OpenSSH ditambahkan sebelum mengaktifkan firewall, supaya koneksi SSH Anda tidak terputus.

Iklan
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status

Langkah 2: Install PHP & Ekstensi Laravel

Pasang PHP-FPM beserta ekstensi yang dibutuhkan Laravel:

sudo apt install -y php-fpm php-cli php-mysql php-mbstring \
    php-xml php-bcmath php-curl php-zip php-gd

Cek versi PHP untuk dipakai di konfigurasi Nginx nanti:

php -v
ls /var/run/php/

Perintah kedua menampilkan nama socket PHP-FPM, misalnya php8.3-fpm.sock. Catat namanya, karena akan dipakai di Langkah 8.

Catatan versi: Laravel 11 dan 12 membutuhkan PHP minimal 8.2, sedangkan Laravel 10 masih bisa berjalan di PHP 8.1. Jika Anda memakai Ubuntu 22.04 (PHP bawaan 8.1) dan aplikasinya Laravel 11 ke atas, Anda perlu memasang PHP yang lebih baru, misalnya lewat PPA ondrej/php:

Iklan
sudo add-apt-repository ppa:ondrej/php
sudo apt update
sudo apt install -y php8.3-fpm php8.3-cli php8.3-mysql php8.3-mbstring \
    php8.3-xml php8.3-bcmath php8.3-curl php8.3-zip php8.3-gd

Langkah 3: Install Composer

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --version

Perintah terakhir memastikan Composer sudah bisa dipanggil dari folder mana pun.

Langkah 4: Siapkan Database MySQL

Banyak tutorial melewatkan langkah ini, padahal tanpa database perintah migrasi di Langkah 6 pasti gagal. Install MySQL server, lalu buat database dan user khusus untuk aplikasi. Jangan memakai user root MySQL untuk aplikasi.

sudo apt install -y mysql-server
sudo mysql

Di dalam prompt MySQL, jalankan:

CREATE DATABASE laravel_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'laravel_user'@'localhost' IDENTIFIED BY 'GantiDenganPasswordKuat!';
GRANT ALL PRIVILEGES ON laravel_db.* TO 'laravel_user'@'localhost';
EXIT;

Dengan host localhost, user ini hanya bisa login dari VPS itu sendiri, sehingga database tidak terbuka ke internet. Jika Anda lebih suka MariaDB, ganti mysql-server dengan mariadb-server; perintah SQL di atas tetap sama.

Iklan

Langkah 5: Ambil Kode Aplikasi

cd /var/www
sudo git clone https://github.com/user/project.git laravel_app
cd laravel_app
composer install --optimize-autoloader --no-dev

Opsi --no-dev membuat package khusus development (seperti PHPUnit atau Laravel Pint) tidak ikut terpasang, dan --optimize-autoloader membuat autoload class lebih cepat. Jika repository bersifat private, cara yang paling rapi adalah membuat SSH key di VPS (ssh-keygen -t ed25519) lalu menambahkan public key-nya sebagai deploy key di pengaturan repository, kemudian clone memakai URL SSH (git@github.com:user/project.git).

Build aset frontend (Vite)

Proyek Laravel modern memakai Vite untuk CSS dan JavaScript. Jika folder public/build tidak ada di server, halaman akan menampilkan error "Vite manifest not found". Ada dua pilihan: build di lokal lalu ikut di-upload, atau install Node.js di VPS dan build di sana. Untuk opsi kedua, pakai versi LTS dari NodeSource:

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
npm ci
npm run build

Jika error manifest tetap muncul, pastikan file public/build/manifest.json benar-benar ada setelah build dan tidak ikut di-ignore saat upload.

Langkah 6: Konfigurasi .env

cp .env.example .env
php artisan key:generate
nano .env   # isi APP_URL, DB_DATABASE, DB_USERNAME, DB_PASSWORD, dll

Set APP_ENV=production dan APP_DEBUG=false. Contoh bagian penting .env untuk server produksi:

Iklan
APP_NAME="Aplikasi Saya"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://domainanda.com

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_db
DB_USERNAME=laravel_user
DB_PASSWORD=GantiDenganPasswordKuat!

APP_DEBUG=false itu wajib di produksi. Jika dibiarkan true, halaman error akan menampilkan detail stack trace dan konfigurasi yang bisa dibaca siapa saja. Lalu jalankan migrasi:

php artisan migrate --force
php artisan storage:link

Opsi --force diperlukan karena Laravel meminta konfirmasi saat migrasi dijalankan di environment production. Perintah storage:link membuat symlink public/storage, yang dibutuhkan jika aplikasi Anda menampilkan file hasil upload.

Langkah 7: Atur Permission

Beri kepemilikan folder ke user Nginx (www-data) dan izin tulis pada folder yang diperlukan:

sudo chown -R www-data:www-data /var/www/laravel_app
sudo chmod -R 775 /var/www/laravel_app/storage /var/www/laravel_app/bootstrap/cache

Cara di atas paling sederhana dan langsung berhasil. Kekurangannya, Anda harus memakai sudo atau user www-data setiap kali menjalankan git pull atau composer. Alternatif yang lebih rapi untuk jangka panjang: biarkan user deploy sebagai pemilik file, dan beri grup www-data akses tulis hanya ke folder yang perlu ditulis:

Iklan
sudo chown -R deploy:www-data /var/www/laravel_app
sudo chmod -R 775 /var/www/laravel_app/storage /var/www/laravel_app/bootstrap/cache

Hindari chmod -R 777. Memang membuat error permission hilang, tetapi siapa pun di server bisa menulis ke folder tersebut, termasuk proses yang tidak seharusnya.

Langkah 8: Buat Server Block Nginx

Buat file konfigurasi baru:

sudo nano /etc/nginx/sites-available/laravel_app

Isi dengan konfigurasi berikut (sesuaikan domain dan versi PHP-FPM):

server {
    listen 80;
    server_name domainanda.com www.domainanda.com;
    root /var/www/laravel_app/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-Content-Type-Options "nosniff";

    index index.php;
    charset utf-8;
    client_max_body_size 20M;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_hide_header X-Powered-By;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

Perhatikan baris root menunjuk ke folder public, dan fastcgi_pass harus cocok dengan versi PHP-FPM Anda. Jika ls /var/run/php/ menampilkan php8.1-fpm.sock atau php8.2-fpm.sock, ganti angkanya sesuai yang ada.

Iklan

Beberapa baris tambahan di atas punya fungsi masing-masing:

  • try_files ... /index.php?$query_string meneruskan semua URL yang bukan file nyata ke Laravel. Tanpa baris ini, semua route selain halaman utama akan 404.
  • client_max_body_size menaikkan batas ukuran upload Nginx (default-nya 1 MB). Sesuaikan juga upload_max_filesize dan post_max_size di php.ini milik FPM jika aplikasi menerima file besar.
  • location ~ /\.(?!well-known).* memblokir akses ke file tersembunyi seperti .env dan .git, kecuali folder .well-known yang dibutuhkan Let's Encrypt.
  • fastcgi_hide_header X-Powered-By menyembunyikan versi PHP dari header respons.

Langkah 9: Aktifkan Situs & Reload Nginx

sudo ln -s /etc/nginx/sites-available/laravel_app /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default   # opsional: matikan halaman default Nginx
sudo nginx -t          # tes konfigurasi
sudo systemctl reload nginx

Aplikasi Anda kini seharusnya bisa diakses lewat domain. Selalu jalankan nginx -t sebelum reload. Jika ada salah ketik, Nginx akan memberi tahu baris mana yang bermasalah tanpa mematikan situs yang sedang berjalan.

Dapatkan Update Terbaru

Berlangganan gratis. Artikel & tutorial coding terbaru langsung ke email kamu. Tanpa spam.

Langkah 10: Pasang HTTPS Gratis (Let's Encrypt)

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d domainanda.com -d www.domainanda.com

Certbot otomatis mengatur sertifikat SSL, menambahkan blok listen 443 ssl ke konfigurasi Nginx, dan memasang timer untuk memperbarui sertifikat secara berkala. Untuk memastikan perpanjangan otomatis berjalan, uji dengan:

sudo certbot renew --dry-run

Setelah HTTPS aktif, pastikan APP_URL di .env sudah memakai https://, lalu bersihkan cache konfigurasi (Langkah 11). Jika tidak, URL yang dibuat Laravel bisa tetap http:// dan memicu peringatan mixed content di browser.

Iklan

Langkah 11: Optimasi Production

php artisan config:cache
php artisan route:cache
php artisan view:cache

Ketiga perintah ini membuat Laravel tidak perlu membaca ulang file konfigurasi, route, dan template Blade di setiap request. Di Laravel 11 dan 12, perintah php artisan optimize menjalankan cache untuk config, event, route, dan view sekaligus. Satu hal penting: setelah config:cache, fungsi env() yang dipanggil di luar folder config akan mengembalikan null. Pastikan kode Anda membaca nilai lewat config('...'), bukan env() langsung.

Tips performa lain yang layak diaktifkan adalah OPcache (biasanya sudah aktif bawaan di paket PHP Ubuntu), memakai Redis untuk cache dan session bila trafik besar, serta eager loading untuk menghindari query N+1. Pembahasan lengkapnya ada di 8 cara optimasi performa Laravel.

Langkah 12: Jalankan Scheduler & Queue Worker

Jika aplikasi Anda memakai task scheduler (misalnya kirim laporan harian) atau queue (kirim email di background), keduanya tidak berjalan sendiri. Anda perlu mendaftarkannya di server.

Scheduler lewat cron

Buka crontab milik user web:

Iklan
sudo crontab -u www-data -e

Tambahkan satu baris berikut. Laravel akan menentukan sendiri task mana yang jatuh tempo setiap menitnya:

* * * * * cd /var/www/laravel_app && php artisan schedule:run >> /dev/null 2>&1

Penjelasan detail tentang cara mendefinisikan jadwal ada di cara setting cron job dan task scheduler di Laravel.

Queue worker dengan Supervisor

Perintah queue:work harus terus hidup. Jika dijalankan manual di terminal, ia mati begitu SSH ditutup. Supervisor menjaga proses ini tetap berjalan dan menyalakannya ulang bila crash.

sudo apt install -y supervisor
sudo nano /etc/supervisor/conf.d/laravel-worker.conf
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/laravel_app/artisan queue:work --sleep=3 --tries=3 --max-time=3600
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
user=www-data
numprocs=1
redirect_stderr=true
stdout_logfile=/var/www/laravel_app/storage/logs/worker.log
stopwaitsecs=3600
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start "laravel-worker:*"

Cara Update Aplikasi Setelah Live

Deploy pertama memang paling panjang. Untuk update berikutnya, cukup jalankan urutan yang sama setiap kali. Simpan sebagai skrip deploy.sh di root project agar tidak ada langkah yang terlupa:

Iklan
#!/bin/bash
set -e

cd /var/www/laravel_app

php artisan down || true
git pull origin main
composer install --optimize-autoloader --no-dev
npm ci && npm run build
php artisan migrate --force
php artisan optimize
php artisan queue:restart
php artisan up

sudo systemctl reload php8.3-fpm

Beberapa catatan: set -e membuat skrip berhenti jika ada perintah yang gagal, sehingga Anda tidak menyalakan aplikasi dalam keadaan setengah ter-update. php artisan down menampilkan halaman maintenance selama proses berjalan. queue:restart memberi sinyal ke worker agar memuat kode baru setelah job yang sedang jalan selesai. Reload PHP-FPM membersihkan OPcache supaya kode lama tidak tertahan di memori. Jalankan skrip ini sebagai user pemilik file (misalnya deploy) agar tidak muncul masalah permission.

Shared Hosting vs VPS: Mana yang Cocok?

AspekShared Hosting (cPanel)VPS Ubuntu + Nginx
AksesTerbatas, biasanya tanpa rootPenuh (root/sudo)
Versi PHP & ekstensiTergantung penyediaBebas pilih
Queue worker & SupervisorUmumnya tidak tersediaBisa
Composer & SSHKadang tersedia, kadang tidakSelalu bisa
Perawatan serverDiurus penyediaTanggung jawab Anda sendiri
Cocok untukWebsite kecil, belajarAplikasi produksi yang terus berkembang

Jika anggaran atau waktu belum memungkinkan untuk mengurus server sendiri, shared hosting masih pilihan masuk akal. Langkahnya berbeda cukup jauh, dan sudah dibahas di cara deploy Laravel ke shared hosting cPanel.

Troubleshooting Singkat

  • 502 Bad Gateway: path fastcgi_pass salah. Cek nama socket PHP-FPM (ls /var/run/php/) dan pastikan servisnya berjalan (sudo systemctl status php8.3-fpm).
  • 500 / layar putih: cek permission storage & log di storage/logs/laravel.log.
  • 403 Forbidden: pastikan root menunjuk ke folder public, bukan root project.
  • 404 di semua route kecuali halaman utama: baris try_files di blok location / hilang atau salah ketik.
  • Halaman default "Welcome to nginx!" yang muncul: server block Anda belum aktif, atau server_name tidak cocok dengan domain. Cek symlink di sites-enabled.
  • 413 Request Entity Too Large saat upload: naikkan client_max_body_size di Nginx.
  • Perubahan .env tidak berpengaruh: konfigurasi masih ter-cache. Jalankan php artisan config:clear lalu php artisan config:cache lagi.

Untuk membedah error 500 lebih jauh, ikuti langkah di cara mengatasi error 500 internal server error Laravel. Log Nginx juga sering memberi petunjuk; lihat /var/log/nginx/error.log.

Kesalahan Umum Saat Pertama Kali Deploy

  • Mengarahkan root Nginx ke folder project, bukan public. Selain memicu 403, ini berbahaya karena file seperti .env berpotensi bisa diunduh orang lain.
  • Lupa APP_DEBUG=false. Pesan error lengkap, termasuk potongan konfigurasi, tampil ke publik.
  • Memakai user root MySQL di .env. Jika aplikasi terkena SQL injection, penyerang mendapat akses ke seluruh server database.
  • Menjalankan composer atau artisan sebagai root lalu lupa memperbaiki permission. File log atau cache baru jadi milik root dan PHP-FPM tidak bisa menulisnya, hasilnya error 500.
  • Tidak ada backup. Jadwalkan mysqldump rutin dan simpan hasilnya di luar VPS.

Kesimpulan

Deploy Laravel ke VPS Ubuntu dengan Nginx memberi Anda performa dan kontrol jauh lebih besar dibanding shared hosting. Kuncinya: install PHP-FPM + ekstensi dengan versi yang sesuai Laravel Anda, siapkan database dengan user khusus, arahkan root Nginx ke folder public, atur permission, lalu pasang HTTPS. Setelah itu lengkapi dengan scheduler, queue worker, dan skrip deploy. Sekali terbiasa, proses ini bisa diselesaikan dalam 15โ€“20 menit untuk deployment berikutnya.

Iklan

FAQ

Ubuntu versi berapa yang paling cocok untuk Laravel?

Ubuntu 24.04 LTS adalah pilihan paling praktis saat ini karena PHP bawaannya 8.3, sudah memenuhi syarat Laravel 11 dan 12. Ubuntu 22.04 tetap bisa dipakai, tetapi untuk Laravel 11 ke atas Anda perlu memasang PHP 8.2 atau lebih baru dari PPA.

Apakah wajib menginstal Node.js di VPS?

Tidak wajib. Node.js hanya dipakai untuk build aset Vite. Anda bisa menjalankan npm run build di komputer lokal lalu mengunggah folder public/build. Namun build di server membuat alur deploy lebih sederhana karena cukup dari git pull.

Kenapa muncul 502 Bad Gateway setelah upgrade PHP?

Nama socket PHP-FPM berubah mengikuti versi, misalnya dari php8.1-fpm.sock menjadi php8.3-fpm.sock. Perbarui baris fastcgi_pass di server block, jalankan sudo nginx -t, lalu reload Nginx.

Bisakah satu VPS dipakai untuk beberapa aplikasi Laravel?

Bisa. Buat folder terpisah di /var/www, database dan user MySQL terpisah, serta satu file server block per domain di sites-available. Masing-masing aplikasi juga butuh baris cron dan konfigurasi Supervisor sendiri jika memakai scheduler atau queue.

Iklan

Apakah perlu menjalankan php artisan optimize setiap kali update?

Ya, sebaiknya. Cache config dan route menyimpan kondisi lama, jadi perubahan route atau konfigurasi baru tidak akan terbaca sampai cache dibuat ulang. Karena itu perintah ini dimasukkan ke skrip deploy.sh di atas.

Iklan
deploy laravel vps laravel nginx ubuntu cara deploy laravel ke vps setup laravel vps ubuntu laravel php-fpm nginx
Rekomendasi

Hosting Cepat untuk Website & Laravel

Butuh hosting yang ngebut dan stabil untuk deploy website atau aplikasi Laravel-mu? Ini rekomendasi yang saya pakai.

Lihat Rekomendasi Hosting
Yudhi
Ditulis oleh

Yudhi

Web Developer

Web developer yang sehari-hari berkutat dengan PHP, Laravel, JavaScript, dan MySQL. Terbiasa membangun aplikasi web dari nol โ€” merancang database, menulis fitur, memburu bug, hingga deploy ke server โ€” lalu menuangkan solusi dan tutorialnya di DhieCoderWeb agar lebih mudah diikuti developer lain.

Bagikan artikel
Kembali

Komentar (0)

Punya pertanyaan atau tambahan? Tulis di bawah โ€” tak perlu login.

Membalas komentarโ€ฆ batal

Belum ada komentar. Jadilah yang pertama!

๐Ÿš€ Partner Recommendation

Butuh Source Code & Aplikasi Premium?

Download aplikasi Laravel, POS, Sekolah, Klinik, ERP, dan source code siap pakai di GudangCode.

GudangCode
  • โœ” Source Code Premium
  • โœ” Sistem Siap Pakai
  • โœ” Lifetime Update
  • โœ” Membership Lifetime
  • โœ” Update Aplikasi Harian
Daftar Membership โ†’
Iklan
Iklan