PHP-FPM #
PHP masih mendominasi web — WordPress, Laravel, Drupal, Magento, dan ribuan aplikasi lain dibangun dengan PHP. Caddy mendukung PHP melalui FastCGI protocol dengan direktif php_fastcgi yang sangat mudah dikonfigurasi dibanding Nginx.
Cara Kerja PHP di Caddy #
Browser → HTTPS Request → Caddy
│
├─ Static files (CSS, JS, images) → Caddy langsung
│
└─ PHP files → FastCGI → PHP-FPM → PHP → Response
Instalasi PHP-FPM #
# Ubuntu/Debian
sudo apt install php8.3-fpm php8.3-mysql php8.3-curl \
php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip \
php8.3-redis php8.3-imagick
# Start dan enable
sudo systemctl enable --now php8.3-fpm
sudo systemctl status php8.3-fpm
# Socket PHP-FPM (lebih cepat dari TCP)
ls /run/php/
# php8.3-fpm.sock
Konfigurasi Dasar PHP #
example.com {
root * /var/www/html
# Aktifkan PHP via FastCGI socket
php_fastcgi unix//run/php/php8.3-fpm.sock
# Sajikan file statis secara langsung
file_server
}
WordPress #
wordpress.example.com {
root * /var/www/wordpress
encode gzip zstd
# Security: Blokir akses ke file sensitif
@blocked {
path /wp-admin/includes/*
path /wp-includes/theme-compat/*
path /wp-includes/js/tinymce/langs/*
path *.sql
path */.git/*
path */.env*
path */xmlrpc.php
}
respond @blocked 403
# WordPress pretty permalinks
php_fastcgi unix//run/php/php8.3-fpm.sock
file_server
# Rewrite untuk pretty URLs (WordPress Rewrite Rules)
@notFound `!{path} =~ "^/wp-"`
try_files {path} {path}/ /index.php?{query}
}
Laravel #
laravel.example.com {
# Laravel serve dari direktori public/
root * /var/www/laravel/public
encode gzip zstd
# Security headers
header {
-Server
-X-Powered-By
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
}
# Semua request yang bukan file statis → index.php
php_fastcgi unix//run/php/php8.3-fpm.sock
file_server
# Laravel front controller pattern
try_files {path} {path}/ /index.php?{query}
}
Keamanan File Sensitif PHP #
example.com {
root * /var/www/html
# Blokir akses ke file konfigurasi
@sensitive {
path /.env
path /.env.*
path /config.php
path /wp-config.php
path /.git*
path /.htaccess
path /composer.json
path /composer.lock
path /package.json
path /package-lock.json
path *.sql
path *.bak
path *.log
}
respond @sensitive 403
# Hanya izinkan PHP dieksekusi dari root, bukan subdirektori upload
@phpInUpload path /uploads/*.php /media/*.php
respond @phpInUpload 403
php_fastcgi unix//run/php/php8.3-fpm.sock
file_server
}
Upload File Besar #
{
# Global: izinkan request body besar untuk upload
servers {
max_header_size 1mb
}
}
uploads.example.com {
root * /var/www/uploads-app
encode gzip zstd
# Tingkatkan timeout untuk upload besar
php_fastcgi unix//run/php/php8.3-fpm.sock {
read_timeout 300s # 5 menit untuk upload besar
dial_timeout 10s
}
# Batasi ukuran upload di level Caddy juga
request_body {
max_size 100mb # Tolak request > 100MB
}
file_server
}
; php.ini settings yang diperlukan
; /etc/php/8.3/fpm/php.ini
upload_max_filesize = 100M
post_max_size = 105M
max_execution_time = 300
max_input_time = 300
memory_limit = 256M
Multiple PHP Version #
# PHP 8.3 untuk aplikasi modern
app-modern.example.com {
root * /var/www/modern-app
php_fastcgi unix//run/php/php8.3-fpm.sock
file_server
try_files {path} {path}/ /index.php?{query}
}
# PHP 7.4 untuk aplikasi legacy
app-legacy.example.com {
root * /var/www/legacy-app
php_fastcgi unix//run/php/php7.4-fpm.sock
file_server
try_files {path} {path}/ /index.php?{query}
}
# Install PHP 7.4 di samping PHP 8.3
sudo apt install php7.4-fpm php7.4-mysql php7.4-curl
# Keduanya berjalan di socket berbeda
ls /run/php/
# php7.4-fpm.sock
# php8.3-fpm.sock
PHP-FPM Pool Tuning #
; /etc/php/8.3/fpm/pool.d/www.conf
[www]
user = www-data
group = www-data
; Socket (lebih cepat dari TCP untuk koneksi lokal)
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Dynamic process management
pm = dynamic
pm.max_children = 50 ; Maksimal worker process
pm.start_servers = 5 ; Worker saat startup
pm.min_spare_servers = 5 ; Minimum worker idle
pm.max_spare_servers = 35 ; Maksimum worker idle
pm.max_requests = 500 ; Restart worker setelah N request (cegah memory leak)
; Logging
php_admin_value[error_log] = /var/log/php8.3-fpm/error.log
php_admin_flag[log_errors] = on
; Keamanan
php_admin_value[open_basedir] = /var/www/html:/tmp
php_admin_value[disable_functions] = exec,passthru,shell_exec,system,proc_open,popen
Caching dengan OPcache #
; /etc/php/8.3/fpm/conf.d/10-opcache.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60 ; Production: 60, Development: 0
opcache.fast_shutdown=1
opcache.enable_cli=0
# Verifikasi OPcache aktif
php -r "var_dump(function_exists('opcache_get_status'));"
# Harus output: bool(true)
Monitoring PHP-FPM #
# Status PHP-FPM pool
# Aktifkan pm.status_path di pool.d/www.conf:
# pm.status_path = /fpm-status
curl http://localhost/fpm-status
# Output: pool info, process manager stats, slow request count
# Cek error log FPM
sudo tail -f /var/log/php8.3-fpm.log
# Lihat proses PHP-FPM yang berjalan
ps aux | grep php-fpm | grep -v grep
# Slow log — query yang memakan waktu > N detik
# slowlog = /var/log/php8.3-fpm/slow.log
# request_slowlog_timeout = 5s
Ringkasan #
- Direktif
php_fastcgi unix//run/php/php8.3-fpm.sockadalah semua yang dibutuhkan untuk PHP dasar — jauh lebih simple dari konfigurasi Nginx+PHP.- Selalu blokir akses ke file sensitif (
.env,.git,wp-config.php) sebelum deploy ke production.- Gunakan Unix socket (
unix//run/php/php8.3-fpm.sock) bukan TCP untuk performa lebih baik pada server yang sama.- OPcache wajib diaktifkan di production — bisa meningkatkan performa PHP 3-5x dengan meng-cache bytecode.
- Untuk WordPress dan Laravel, gunakan
try_files {path} {path}/ /index.php?{query}untuk mendukung URL rewriting.- Bind PHP-FPM hanya ke socket atau localhost — jangan expose port PHP-FPM ke internet karena tidak ada autentikasi.
← Sebelumnya: Node.js App Berikutnya: Python WSGI →
PHP dengan Redis Session #
# Install PHP Redis extension
sudo apt install php8.3-redis
# Konfigurasi session di Redis
; /etc/php/8.3/fpm/conf.d/redis-session.ini
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=your-redis-password"
session.gc_maxlifetime = 7200
Menggunakan Redis untuk session memungkinkan multiple server PHP-FPM berbagi session — penting untuk horizontal scaling di mana beberapa server menjalankan instance PHP yang sama.
Magento / E-commerce PHP #
shop.example.com {
root * /var/www/magento/pub
encode gzip zstd
# Magento security
@blocked {
path /app/*
path /var/*
path /lib/*
path /dev/*
path /phpunit.xml
path /.git*
path /composer.*
}
respond @blocked 403
# Magento front controller
php_fastcgi unix//run/php/php8.2-fpm.sock {
# Magento butuh timeout lebih panjang (report generation, dll.)
read_timeout 300s
}
file_server
# Magento URL rewriting
try_files {path} {path}/ /index.php?{query}
}
PHP Debugging di Development #
# Development: nonaktifkan cache dan aktifkan error detail
localhost:8080 {
root * /var/www/myapp
# Matikan HTTPS di development
# (Caddy di localhost otomatis pakai self-signed cert)
php_fastcgi unix//run/php/php8.3-fpm.sock {
env PHP_XDEBUG_MODE debug
env PHP_XDEBUG_CLIENT_HOST host.docker.internal
}
file_server
try_files {path} {path}/ /index.php?{query}
}
; /etc/php/8.3/fpm/conf.d/xdebug.ini (development only!)
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=127.0.0.1
xdebug.client_port=9003
Tuning PHP-FPM untuk Caddy #
Caddy sangat efisien dalam menangani koneksi ke PHP-FPM. Beberapa tips tuning:
# Cek berapa worker PHP-FPM yang aktif saat ini
ps aux | grep "php-fpm: pool www" | grep -v grep | wc -l
# Monitor PHP-FPM pool status secara real-time
watch -n 2 'curl -s http://localhost/fpm-status | grep -E "(idle|active|total)"'
# Hitung kebutuhan memory per worker
# Cek usage memory PHP-FPM process:
ps -eo pid,pmem,rss,comm | grep php-fpm | awk '{print $3}' | \
awk 'BEGIN{s=0}{s+=$1}END{print s/1024 " MB total, " NR " workers, " s/NR/1024 " MB avg"}'
Gunakan hasil perhitungan ini untuk mengkonfigurasi pm.max_children secara tepat. Aturan praktis: pm.max_children = (RAM tersedia untuk PHP) / (rata-rata memory per worker).