Pada bagian sebelumnya, kita telah membahas dua fondasi penting: bagaimana Laravel Octane bekerja bersama FrankenPHP, serta tantangan arsitektur in-memory seperti stale data, memory leak, dan manajemen service yang benar. Sekarang saatnya masuk ke tahap yang paling sering ditanyakan: bagaimana cara benar-benar menjalankan FrankenPHP untuk aplikasi Laravel, lalu mendeploy-nya ke server.
Di artikel ini, kita akan mengurangi teori dan lebih banyak fokus ke langkah implementasi. Target akhirnya sederhana: Anda punya aplikasi Laravel yang berjalan di atas FrankenPHP, dikemas dengan Docker, lalu bisa di-upload dan dijalankan di server Linux dengan pola deployment yang cukup aman untuk production.
Contoh pada artikel ini menggunakan pendekatan Docker + FrankenPHP + Laravel Octane karena paling praktis untuk deployment modern, mudah direproduksi, dan meminimalkan perbedaan antara lingkungan lokal dan server.
1. Persiapan Aplikasi Laravel
Pastikan proyek Laravel Anda sudah memiliki Octane dan FrankenPHP. Jika belum, jalankan:
composer require laravel/octane
php artisan octane:installSaat installer bertanya server yang digunakan, pilih frankenphp.
Setelah itu, cek file konfigurasi utama berikut:
config/octane.php.envbootstrap/app.phpbila Anda punya penyesuaian middleware atau exception handling
Tambahkan beberapa environment variable yang umum dipakai di production:
APP_NAME="MyApp"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://domainanda.com
LOG_CHANNEL=stack
LOG_LEVEL=info
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=app_db
DB_USERNAME=app_user
DB_PASSWORD=secret
CACHE_STORE=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379Jika Anda memakai Octane di production, sebaiknya hindari menyimpan state request ke properti statis atau singleton yang tidak di-reset. Pada tahap deploy, bug semacam ini sering baru terlihat setelah server menerima trafik nyata.
2. Menjalankan FrankenPHP Secara Lokal Sebelum Deploy
Sebelum membungkus aplikasi ke Docker, pastikan aplikasi memang berjalan normal dengan FrankenPHP di lokal:
php artisan octane:start --server=frankenphp --host=127.0.0.1 --port=8000Untuk development, gunakan mode watch:
php artisan octane:start --server=frankenphp --watchJika aplikasi gagal naik, periksa beberapa hal berikut:
- Apakah file
.envvalid dan tidak ada variabel yang hilang. - Apakah koneksi database dan Redis bisa diakses.
- Apakah ada service singleton yang menyimpan state request.
- Apakah package pihak ketiga kompatibel dengan Octane.
Setelah lokal stabil, baru masuk ke packaging untuk server.
3. Struktur Deployment dengan Docker
Pendekatan yang paling praktis adalah membuat container terpisah untuk:
- app: Laravel + FrankenPHP + Octane
- queue: worker untuk job queue
- scheduler: menjalankan scheduler Laravel
- db: MySQL/PostgreSQL bila Anda ingin satu stack penuh
- redis: cache, queue, session
Untuk production, sering kali database dikelola terpisah. Tetapi untuk memudahkan pembelajaran, kita buat contoh yang lengkap.
Contoh Dockerfile untuk FrankenPHP
Buat file Dockerfile di root proyek:
FROM dunglas/frankenphp:php8.3
RUN install-php-extensions \
pdo_mysql \
bcmath \
pcntl \
opcache \
redis \
intl \
zip
WORKDIR /app
COPY . /app
RUN cp .env.example .env || true
RUN composer install --no-dev --optimize-autoloader --no-interaction
RUN php artisan config:cache || true
RUN php artisan route:cache || true
RUN php artisan view:cache || true
RUN chown -R www-data:www-data /app/storage /app/bootstrap/cache
EXPOSE 8000
CMD ["php", "artisan", "octane:start", "--server=frankenphp", "--host=0.0.0.0", "--port=8000"]Ada beberapa poin penting dari Dockerfile ini:
- Menggunakan image resmi
dunglas/frankenphp. - Menginstal extension PHP yang umum dibutuhkan Laravel.
- Menjalankan
composer installdengan--no-devuntuk production. - Melakukan cache konfigurasi agar bootstrap lebih ringan.
- Menjalankan server dengan host
0.0.0.0supaya bisa diakses dari luar container.
Jika aplikasi Anda menggunakan frontend Vite, Anda bisa menambahkan proses build asset di tahap image build. Misalnya dengan multi-stage build.
Contoh Dockerfile dengan Build Asset
FROM node:20 AS frontend
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM dunglas/frankenphp:php8.3
RUN install-php-extensions pdo_mysql bcmath pcntl opcache redis intl zip
WORKDIR /app
COPY . /app
COPY --from=frontend /app/public/build /app/public/build
RUN composer install --no-dev --optimize-autoloader --no-interaction
RUN php artisan config:cache || true
RUN php artisan route:cache || true
RUN php artisan view:cache || true
RUN chown -R www-data:www-data /app/storage /app/bootstrap/cache
EXPOSE 8000
CMD ["php", "artisan", "octane:start", "--server=frankenphp", "--host=0.0.0.0", "--port=8000"]4. Menambahkan docker-compose untuk Lingkungan Server
Selanjutnya buat file docker-compose.yml:
version: '3.9'
services:
app:
build: .
container_name: laravel_app
restart: unless-stopped
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- redis
- db
queue:
build: .
container_name: laravel_queue
restart: unless-stopped
command: php artisan queue:work --sleep=3 --tries=3 --timeout=90
env_file:
- .env
depends_on:
- redis
- db
scheduler:
build: .
container_name: laravel_scheduler
restart: unless-stopped
command: sh -c "while true; do php artisan schedule:run --verbose --no-interaction; sleep 60; done"
env_file:
- .env
depends_on:
- redis
- db
redis:
image: redis:7-alpine
container_name: laravel_redis
restart: unless-stopped
db:
image: mysql:8.0
container_name: laravel_db
restart: unless-stopped
environment:
MYSQL_DATABASE: app_db
MYSQL_USER: app_user
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: rootsecret
ports:
- "3306:3306"
volumes:
- dbdata:/var/lib/mysql
volumes:
dbdata:Dengan komposisi ini, Anda sudah punya stack yang cukup lengkap. Untuk menjalankannya:
docker compose up -d --buildLalu jalankan migrasi:
docker compose exec app php artisan migrate --forceJika Anda perlu membuat application key:
docker compose exec app php artisan key:generate5. Konfigurasi Reverse Proxy di Server
Meskipun FrankenPHP sudah berbasis Caddy, dalam banyak deployment nyata Anda tetap bisa menaruhnya di belakang reverse proxy seperti Nginx atau Traefik, terutama jika satu server menjalankan banyak aplikasi.
Contoh konfigurasi Nginx sederhana:
server {
listen 80;
server_name domainanda.com www.domainanda.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}Jika Anda mengaktifkan HTTPS dengan Certbot pada Nginx, maka Nginx menangani SSL, sementara FrankenPHP fokus menjalankan aplikasi.
Namun jika Anda ingin memanfaatkan kemampuan Caddy/FrankenPHP secara langsung, Anda bisa mengekspose port 80 dan 443 dari container lalu menggunakan konfigurasi Caddyfile. Pendekatan ini bagus untuk instalasi yang lebih minimalis, tetapi perlu perencanaan lebih hati-hati jika satu server memuat banyak layanan.
6. Langkah Deploy ke Server Linux
Misalkan Anda memakai VPS Ubuntu. Alur deploy yang umum adalah sebagai berikut.
1. Instal Docker dan Compose Plugin
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo $VERSION_CODENAME) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin2. Upload Source Code ke Server
Anda bisa memakai git clone langsung di server:
cd /var/www
sudo git clone https://github.com/username/nama-repo.git myapp
cd myappAtau upload melalui CI/CD. Jika deployment masih manual, minimal gunakan branch yang stabil dan hindari edit langsung di server.
3. Siapkan File Environment
Buat file .env production:
cp .env.example .env
nano .envIsi variabel penting seperti:
APP_ENV=productionAPP_DEBUG=falseAPP_URL=https://domainanda.com- kredensial database
- konfigurasi Redis, mail, dan queue
4. Build dan Jalankan Container
docker compose up -d --build5. Generate Key dan Migrasi
docker compose exec app php artisan key:generate
docker compose exec app php artisan migrate --force6. Optimasi Laravel
docker compose exec app php artisan optimize
php artisan event:cacheJika menjalankan perintah kedua, sebaiknya jalankan juga melalui container:
docker compose exec app php artisan event:cache7. Update Aplikasi Tanpa Banyak Downtime
Untuk deployment pembaruan kode, pola minimumnya:
git pull origin main
docker compose up -d --build
docker compose exec app php artisan migrate --force
docker compose exec app php artisan optimizeUntuk aplikasi dengan trafik lebih tinggi, Anda bisa mengarah ke strategi blue-green deployment atau rolling update lewat orchestrator seperti Docker Swarm atau Kubernetes. Namun untuk banyak aplikasi Laravel skala kecil sampai menengah, alur di atas sudah cukup layak jika waktu build image tidak terlalu lama.
Jika Anda ingin worker Octane di-restart setelah update konfigurasi atau kode:
docker compose restart appJangan lupa bahwa Octane menjalankan aplikasi secara persisten di memori. Jadi perubahan kode tidak akan aktif sampai proses di-restart atau container dibangun ulang.
8. File .dockerignore yang Sering Terlupa
Agar image lebih kecil dan build lebih cepat, buat file .dockerignore:
.git
node_modules
vendor
storage/logs
storage/framework/cache
storage/framework/sessions
storage/framework/views
.env
Dockerfile
docker-compose.ymlIni penting agar context build tidak terlalu besar, terutama pada proyek dengan direktori node_modules yang berat.
9. Logging, Debugging, dan Masalah Umum
Melihat log container
docker compose logs -f app
docker compose logs -f queueMasuk ke shell container
docker compose exec app shMasalah umum yang sering terjadi
- Permission error pada
storageataubootstrap/cache. Solusinya pastikan owner dan permission benar saat image dibangun. - Perubahan kode tidak muncul. Ini normal pada Octane jika proses belum di-restart.
- Queue tidak jalan. Pastikan service queue aktif dan
QUEUE_CONNECTIONsesuai. - Koneksi database gagal. Periksa host DB. Dalam Docker Compose, host biasanya nama service, misalnya
db, bukan127.0.0.1. - Aplikasi lambat setelah deploy. Cek apakah cache Laravel sudah dibuat, dan cek query lambat atau bottleneck eksternal seperti API pihak ketiga.
10. Kapan Perlu Supervisor?
Jika Anda tidak memakai Docker, maka Supervisor sangat berguna untuk menjaga proses FrankenPHP, queue worker, dan scheduler tetap hidup. Contoh konfigurasi Supervisor untuk Octane:
[program:laravel-octane]
process_name=%(program_name)s
command=php /var/www/myapp/artisan octane:start --server=frankenphp --host=127.0.0.1 --port=8000
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-octane.logLalu untuk queue worker:
[program:laravel-queue]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/myapp/artisan queue:work --sleep=3 --tries=3 --timeout=90
autostart=true
autorestart=true
numprocs=1
user=www-data
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-queue.logJika Anda sudah menggunakan Docker dengan restart policy yang baik, Supervisor di dalam container biasanya tidak diperlukan. Sebaiknya satu container menjalankan satu proses utama agar lifecycle-nya lebih mudah dikelola.
Kesimpulan
FrankenPHP sangat menarik untuk aplikasi Laravel modern karena proses setup-nya relatif sederhana, performanya baik, dan sangat cocok dipadukan dengan Laravel Octane. Namun, manfaat sebenarnya baru terasa ketika workflow deployment Anda juga rapi: image bisa dibangun ulang dengan konsisten, service queue dan scheduler dipisahkan, environment production jelas, dan proses restart aplikasi bisa diprediksi.
Di artikel ini, kita tidak hanya menjalankan FrankenPHP secara lokal, tetapi juga membawanya sampai ke server menggunakan Docker, lengkap dengan contoh Dockerfile, docker-compose.yml, reverse proxy, langkah upload ke VPS, dan debugging dasar. Untuk tahap berikutnya, Anda bisa melanjutkan dengan otomatisasi CI/CD, health check, monitoring, serta strategi deployment tanpa downtime yang lebih matang.
Jika fondasi ini sudah stabil, maka FrankenPHP bukan sekadar eksperimen performa, melainkan bisa menjadi bagian dari stack production Laravel Anda sehari-hari.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!