Panduan Deploy Laravel di Ubuntu dengan Nginx, PHP-FPM, dan PostgreSQL
Membuat aplikasi Laravel berjalan lancar di laptop itu satu hal. Membuatnya online dan aman di server Ubuntu adalah hal lain. Artikel ini membahas langkah demi langkah cara deploy Laravel ke VPS Ubuntu memakai Nginx, PHP-FPM, dan PostgreSQL, lengkap dengan HTTPS gratis, queue worker, serta daftar error yang paling sering muncul beserta solusinya.
Gambaran Arsitektur
Sebelum mengetik perintah apa pun, pahami dulu bagaimana satu request diproses:
- Browser mengirim request ke domain kamu.
- Nginx menerima request dan menyajikan file statis (CSS, JS, gambar) langsung dari folder
public. - Untuk file
.php, Nginx meneruskan request ke PHP-FPM melalui sebuah unix socket. - PHP-FPM menjalankan Laravel, yang berbicara dengan PostgreSQL untuk data.
Kalau salah satu mata rantai ini putus atau salah alamat, hasilnya biasanya error 502 atau 500. Memahami alur ini akan sangat membantu saat troubleshooting.
Prasyarat
- VPS dengan Ubuntu 22.04 atau 24.04 dan akses
sudo. - Domain atau subdomain yang record DNS-nya (A record) sudah mengarah ke IP server.
- Project Laravel yang sudah ada di repository Git.
- Port 80 dan 443 terbuka di firewall server maupun di panel penyedia VPS.
Langkah 1: Update Server dan Install Paket Dasar
sudo apt update && sudo apt upgrade -y
sudo apt install -y nginx git unzip curlLangkah 2: Install PHP dan Ekstensinya
Cek versi PHP yang dibutuhkan project di composer.json. Laravel 11 dan 12 membutuhkan PHP 8.2 atau lebih baru. Kalau versi yang kamu butuhkan tidak tersedia di repository bawaan, tambahkan PPA:
sudo add-apt-repository ppa:ondrej/php -y && sudo apt updateInstall PHP-FPM beserta ekstensi yang umum dibutuhkan Laravel. Contoh di bawah memakai PHP 8.3, ganti angka versinya sesuai versi yang kamu pakai:
sudo apt install -y php8.3-fpm php8.3-cli php8.3-pgsql php8.3-mbstring \
php8.3-xml php8.3-curl php8.3-zip php8.3-bcmath php8.3-intl php8.3-gdPaket php-pgsql adalah driver untuk PostgreSQL. Tanpanya, Laravel akan menampilkan error could not find driver.
Cek hasilnya:
php -v
php -m | grep -i pgsqlHarus muncul pdo_pgsql dan pgsql.
Langkah 3: Install Composer
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer
composer --versionLangkah 4: Install dan Siapkan PostgreSQL
sudo apt install -y postgresql postgresql-contrib
sudo systemctl enable --now postgresqlMasuk ke shell PostgreSQL, lalu buat user dan database:
sudo -u postgres psqlCREATE USER laravel_user WITH PASSWORD 'password_kuat';
CREATE DATABASE article OWNER laravel_user ENCODING 'UTF8';
GRANT ALL PRIVILEGES ON DATABASE article TO laravel_user;
\qPada PostgreSQL 15 ke atas, user yang bukan owner database tidak otomatis boleh membuat tabel di schema public. Karena database di atas dibuat dengan OWNER laravel_user, hal ini aman. Kalau database dibuat dengan owner lain, jalankan:
sudo -u postgres psql -d article -c "GRANT ALL ON SCHEMA public TO laravel_user;"Uji koneksinya sebelum lanjut:
psql -h 127.0.0.1 -U laravel_user -d articleKalau muncul prompt article=>, berarti user, password, dan host sudah benar.
Langkah 5: Ambil Project dari Git
cd /var/www
sudo git clone https://github.com/username/repo-kamu.git nama-project
sudo chown -R $USER:www-data /var/www/nama-project
cd nama-project
composer install --no-dev --optimize-autoloaderJika project memakai Vite atau Tailwind, install Node.js lalu build asetnya:
npm ci && npm run buildLangkah 6: Konfigurasi .env
cp .env.example .env
php artisan key:generate
nano .envNilai yang wajib diperiksa untuk production:
APP_ENV=production
APP_DEBUG=false
APP_URL=https://domainkamu.comDB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=article
DB_USERNAME=laravel_user
DB_PASSWORD="password_kuat"
Dua hal penting di sini. Pertama, APP_DEBUG harus false di production, karena true akan menampilkan detail error (bahkan bisa membocorkan isi konfigurasi) ke siapa pun. Kedua, kalau password mengandung karakter khusus seperti #, $, spasi, atau tanda kutip, bungkus dengan tanda kutip agar tidak terbaca salah.
Setelah itu jalankan migrasi dan cache konfigurasi:
php artisan migrate --force
php artisan storage:link
php artisan config:cache
php artisan route:cache
php artisan view:cacheLangkah 7: Atur Permission
Hanya dua folder yang perlu bisa ditulis oleh web server:
sudo chown -R www-data:www-data storage bootstrap/cache
sudo chmod -R 775 storage bootstrap/cacheHindari chmod 777. Itu membuka akses tulis untuk semua user di server dan bukan praktik yang aman.
Langkah 8: Konfigurasi Nginx
Buat file konfigurasi, misalnya untuk subdomain article.example.com:
sudo nano /etc/nginx/sites-available/article.example.comserver {
listen 80;
server_name article.example.com;
root /var/www/nama-project/public; index index.php;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}
Ada dua baris yang paling sering jadi sumber masalah:
rootharus mengarah ke folderpublic, bukan ke root project. Kalau salah, file seperti.envbisa terekspos ke internet.fastcgi_passharus sama persis dengan nama socket PHP-FPM yang ada di server, termasuk nomor versinya.
Aktifkan situs dan muat ulang Nginx:
sudo ln -s /etc/nginx/sites-available/article.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginxPerintah nginx -t selalu dijalankan sebelum reload. Kalau ada salah ketik di konfigurasi, kamu tahu sebelum situs mati.
Langkah 9: Pasang HTTPS dengan Let's Encrypt
Pastikan DNS sudah mengarah ke server, lalu:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d article.example.comCertbot akan mengubah file konfigurasi Nginx secara otomatis: menambahkan blok listen 443 ssl, lokasi sertifikat, dan redirect dari HTTP ke HTTPS. Sertifikat diperpanjang otomatis. Kamu bisa mengujinya dengan:
sudo certbot renew --dry-runLangkah 10: Scheduler dan Queue Worker (Opsional)
Kalau aplikasi memakai task scheduling, tambahkan satu entri cron untuk user www-data:
sudo crontab -u www-data -e* * * * * cd /var/www/nama-project && php artisan schedule:run >> /dev/null 2>&1Kalau aplikasi memakai queue, jalankan worker lewat Supervisor supaya otomatis hidup kembali saat mati atau server reboot:
sudo apt install -y supervisor
sudo nano /etc/supervisor/conf.d/laravel-worker.conf[program:laravel-worker]
command=php /var/www/nama-project/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=www-data
stdout_logfile=/var/www/nama-project/storage/logs/worker.logsudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start laravel-worker:*Langkah 11: Firewall
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enablePastikan aturan OpenSSH ditambahkan sebelum ufw enable, supaya kamu tidak terkunci dari server sendiri.
Deploy Ulang Setelah Ada Perubahan Kode
Setelah deploy pertama, update berikutnya cukup mengikuti urutan ini:
cd /var/www/nama-project
php artisan down
git pull origin main
composer install --no-dev --optimize-autoloader
npm ci && npm run build # jika memakai Vite
php artisan migrate --force
php artisan optimize:clear
php artisan optimize
sudo supervisorctl restart laravel-worker:* # jika memakai queue
php artisan upphp artisan down menampilkan halaman maintenance selama proses berjalan, dan php artisan up mengembalikan situs ke normal.
Troubleshooting: Error yang Paling Sering Muncul
502 Bad Gateway
Artinya Nginx hidup, tetapi tidak bisa menghubungi PHP-FPM. Ini error paling umum saat deploy pertama. Langkah diagnosanya:
sudo tail -n 20 /var/log/nginx/error.log
ls /var/run/php/
sudo systemctl status php8.3-fpmPenyebab yang paling sering ditemukan adalah ketidakcocokan versi PHP di konfigurasi Nginx. Contoh nyata: log menampilkan pesan seperti connect() to unix:/var/run/php/php8.3-fpm.sock failed (2: No such file or directory). Itu berarti Nginx mencari socket PHP 8.3, padahal server hanya menjalankan PHP 8.2. Solusinya, samakan baris fastcgi_pass dengan socket yang benar-benar ada, lalu reload:
sudo nginx -t && sudo systemctl reload nginxIngat juga bahwa perubahan konfigurasi Nginx baru berlaku setelah di-reload. Log lama di error.log tetap berisi error sebelum perbaikan, jadi pantau dengan sudo tail -f /var/log/nginx/error.log sambil me-refresh halaman supaya yang kamu lihat adalah error terbaru.
could not find driver
Driver database untuk PHP belum terpasang, atau PHP-FPM belum di-restart. Install paketnya sesuai versi PHP dan database yang dipakai (misalnya php8.2-pgsql), lalu:
sudo systemctl restart php8.2-fpmPerhatikan bahwa PHP CLI dan PHP-FPM bisa berjalan di versi yang berbeda. Cek keduanya dengan php -v dan systemctl list-units | grep php.
500 Internal Server Error
Lihat log aplikasi di storage/logs/laravel.log. Penyebab umum: .env belum diisi benar, APP_KEY kosong, atau folder storage dan bootstrap/cache tidak bisa ditulis (cek lagi Langkah 7).
password authentication failed
Password di .env salah, atau konfigurasi lama masih ter-cache. Jalankan php artisan config:clear lalu uji login manual dengan psql.
permission denied for schema public
Terjadi pada PostgreSQL 15 ke atas saat user bukan owner database. Jalankan perintah GRANT ALL ON SCHEMA public seperti di Langkah 4.
Semua halaman selain beranda menghasilkan 404
root Nginx tidak mengarah ke /public, atau blok try_files di location / belum benar.
Perubahan .env tidak terbaca
Karena config:cache menyimpan konfigurasi, perubahan .env tidak berlaku sampai kamu menjalankan php artisan config:clear dan, kalau perlu, php artisan config:cache lagi.
Catatan Soal Request Aneh di Log
Begitu domain baru online, log Nginx biasanya langsung dipenuhi request ke path seperti /wp-config.php, /backup.sql, atau /config.xml. Itu bot scanner yang memeriksa semua alamat di internet, dan hal ini normal. Selama root mengarah ke public dan tidak ada file sensitif di dalamnya, request tersebut tidak berbahaya. Kalau mau mengurangi kebisingan, kamu bisa memasang Fail2ban.
Checklist Sebelum Go Live
APP_ENV=productiondanAPP_DEBUG=false.APP_KEYsudah di-generate.rootNginx mengarah ke folderpublic.- Versi PHP di
fastcgi_passcocok dengan socket yang ada. - Ekstensi PHP yang dibutuhkan (terutama
pgsql) terpasang. storagedanbootstrap/cachebisa ditulis olehwww-data.- HTTPS aktif dan
certbot renew --dry-runberhasil. - Firewall aktif dan SSH tetap bisa diakses.
- Cache konfigurasi, route, dan view sudah dibuat.
- Backup database terjadwal (misalnya dengan
pg_dumplewat cron).
Penutup
Deploy Laravel di Ubuntu pada dasarnya adalah menyambungkan beberapa komponen dengan benar: Nginx, PHP-FPM, database, dan permission. Hampir semua error saat deploy pertama berasal dari satu hal yang sama, yaitu ada komponen yang namanya, versinya, atau path-nya tidak cocok dengan yang dituliskan di konfigurasi. Kebiasaan sederhana seperti membaca error.log, menjalankan nginx -t sebelum reload, dan memeriksa versi PHP yang benar-benar terpasang akan menghemat banyak waktu. Setelah semuanya berjalan, simpan langkah-langkah ini sebagai catatan atau skrip, dan deploy berikutnya akan jauh lebih cepat.