Permission Unix Socket PHP-FPM - Biarkan Nginx Menjangkau PHP Tanpa Membuka Akses untuk Semua
Nginx mengembalikan response 502, lalu error log menyebut Unix socket yang dipakai PHP-FPM. Ada godaan untuk membuat socket itu writable bagi semua user dan segera melanjutkan pekerjaan. Namun, 502 hanyalah kegagalan boundary yang terlihat. Socket mungkin tidak ada, Nginx dan PHP-FPM mungkin menunjuk path yang berbeda, parent directory mungkin menghalangi traversal, atau worker Nginx mungkin tidak memiliki izin untuk terhubung.
Perbaikan yang berguna dimulai dengan mengenali kondisi mana yang benar-benar terjadi. Artikel ini menyusun langkah diagnosis untuk Nginx dan PHP-FPM yang berjalan pada host Linux yang sama. Setelah itu, perbaikannya ditempatkan dalam konfigurasi pool PHP-FPM agar tetap berlaku ketika socket dibuat ulang, bukan bergantung pada satu kali chmod.
Nama app, www-data, dan /run/php/app.sock di bawah ini hanyalah placeholder. User, group, nama service, nama binary, dan path aktif berbeda antar sistem dan package; periksa semuanya sebelum mengubah apa pun.
Mulai dari Boundary, Bukan Pesan di Browser
Dalam susunan ini, PHP-FPM bertindak sebagai listener dan Nginx sebagai client. Pool PHP-FPM membuat endpoint lokal melalui directive listen. Nginx mengirim request ke endpoint tersebut melalui fastcgi_pass. Manual konfigurasi PHP-FPM menerima alamat IP dan port atau path Unix socket untuk listen. Modul FastCGI Nginx juga menerima Unix-domain socket:
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/app.sock;
}
Kedua sisi harus menunjuk endpoint yang sama. Nama yang terlihat mirip tetap merupakan path berbeda. Konfigurasi /run/php/app.sock tidak akan menjangkau /run/php/app-fpm.sock, dan service PHP-FPM yang sedang berjalan tidak membuktikan bahwa pool atau socket tertentu yang diharapkan Nginx tersedia.
Karena itu, bukti pertama sebaiknya berasal dari error log Nginx di sekitar satu request yang dikendalikan. Pertahankan operasi, path, dan error dari sistem operasi secara persis. “No such file or directory”, “connection refused”, dan “permission denied” mengarah ke penyelidikan yang berbeda. Ketiganya tidak seharusnya disederhanakan menjadi “PHP mati”.
Periksa Keberadaan Sebelum Mengubah Izin
Sebelum mengubah ownership atau mode, pastikan socket yang diharapkan ada dan terdapat proses yang listen. Command berikut memeriksa keadaan tanpa mengubahnya:
systemctl list-units --type=service --all 'nginx.service' 'php*-fpm.service'
ss -xl
stat -Lc 'type=%F owner=%U group=%G mode=%a path=%n' /run/php/app.sock
Wildcard membantu menemukan unit PHP-FPM yang memakai versi dalam namanya, tetapi penamaan unit tetap bergantung pada package. Kegagalan stat bukan diagnosis permission. Temuan itu lebih dulu memunculkan pertanyaan apakah path keliru, pool gagal dimulai, parent directory tidak tersedia, atau unit service lain memiliki listener tersebut.
Bandingkan konfigurasi Nginx yang aktif dengan konfigurasi pool yang aktif, bukan dengan tutorial atau sample file yang tidak dipakai:
; PHP-FPM pool
listen = /run/php/app.sock
# Nginx PHP location
fastcgi_pass unix:/run/php/app.sock;
Nginx dapat mencetak konfigurasi yang dimuat melalui nginx -T, tetapi output itu mungkin memuat pengaturan sensitif yang tidak berkaitan dan tidak seharusnya ditempel ke tiket publik tanpa pemeriksaan. Command untuk menguji konfigurasi PHP-FPM dan nama binary berbeda menurut package. Gunakan binary serta dokumentasi dari package yang terpasang, bukan menebak command dengan nomor versi.
Kenali Proses yang Memerlukan Akses
Identitas proses efektif lebih berguna daripada label konfigurasi. Dalam susunan master-worker yang umum, master Nginx mungkin dimulai dengan privilege tinggi, sedangkan worker yang menangani request berjalan sebagai akun tanpa privilege. Worker itulah yang perlu terhubung. PHP-FPM juga memisahkan identitas worker pool dari metadata yang diterapkan pada listening socket.
Daftar proses yang luas dapat memperlihatkan identitas tersebut tanpa mengasumsikan namanya:
ps -eo user,group,pid,ppid,comm,args
Filter dan baca baris Nginx serta PHP-FPM yang relevan secara lokal. Periksa juga directive user milik Nginx serta directive user, group, dan listen.* milik pool. User proses pool menjawab “akun mana yang mengeksekusi code PHP?” Owner, group, dan mode socket menjawab “proses lokal mana yang boleh menjangkau listener ini?” Kedua pertanyaan itu berkaitan, tetapi tidak sama.
Seluruh Path Harus Dapat Dilalui
Pathname socket mengikuti pemeriksaan permission filesystem. Manual Linux unix(7) menyatakan bahwa pembuatan pathname socket memerlukan izin write dan search pada directory-nya. Di Linux, koneksi ke stream socket memerlukan izin write pada socket tersebut. Client juga harus mampu melintasi path menuju socket.
Detail terakhir itu menjelaskan mengapa socket dapat terlihat memiliki ownership yang benar, tetapi koneksi masih gagal. Periksa setiap komponen, bukan hanya baris terakhir:
namei -l /run/php/app.sock
stat -Lc 'owner=%U group=%G mode=%a path=%n' /run /run/php /run/php/app.sock
namei mungkin tidak terpasang pada semua sistem, sehingga rangkaian stat menjadi fallback yang cukup portabel untuk path pendek ini. Directory membutuhkan izin search bagi worker Nginx sepanjang rute. Menambahkan izin write pada parent directory hanya untuk mengizinkan traversal tidak diperlukan dan memberikan akses lebih luas daripada yang dibutuhkan.
Tempatkan Permission Persisten di Pool
PHP-FPM menyediakan tiga directive untuk Unix socket di Linux: listen.owner, listen.group, dan listen.mode. Manual mendokumentasikan mode default 0660, sedangkan owner dan group secara default mengikuti user yang menjalankan proses. Konfigurasi dari package dapat menetapkan nilai eksplisit yang berbeda, sehingga file aktif tetap menjadi acuan utama.
Misalkan hasil pemeriksaan menunjukkan pool aplikasi berjalan sebagai app dan worker Nginx berjalan dengan group www-data. Konfigurasi pool dengan cakupan sempit dapat berbentuk:
[app]
user = app
group = app
listen = /run/php/app.sock
listen.owner = app
listen.group = www-data
listen.mode = 0660
Contoh ini memberikan bit read/write kepada owner dan group tanpa memberikan bit socket kepada akun lokal lain. Di Linux, bit write untuk group memungkinkan worker dalam www-data terhubung. Owner dan group yang tepat harus mengikuti identitas yang ditemukan pada host tujuan. Group khusus untuk akses FastCGI dapat mempersempit izin ketika beberapa web server atau pool berada pada satu host. Namun, penambahannya juga mengharuskan pengelolaan supplementary group dan restart proses terkait agar proses menerima membership baru.
Template pool PHP-FPM dari upstream mendokumentasikan pemisahan yang sama antara identitas worker pool dan metadata socket. Template itu juga mendokumentasikan listen.acl_users dan listen.acl_groups untuk sistem yang mendukung POSIX ACL. Ketika opsi ACL tersebut ditetapkan, listen.owner dan listen.group diabaikan. ACL dapat mengekspresikan akses tanpa berbagi group, tetapi mencampur kedua mekanisme tanpa menyadari urutan prioritasnya membuat diagnosis semakin sulit.
Mengapa chmod Cepat Bukan Perbaikan
Command yang mengubah socket aktif dapat dipakai sebagai eksperimen sementara: jika akses mulai bekerja setelah perubahan metadata yang dipilih dengan hati-hati, hasil itu menjadi bukti tentang penyebab kegagalan. Namun, itu belum menjadi konfigurasi yang tahan lama. PHP-FPM membuat pathname socket ketika pool mengikat listener. Saat endpoint dihapus dan dibuat ulang dalam siklus hidup service, metadata yang diterapkan secara manual dapat ikut hilang bersama object filesystem lama.
Karena itu, sumber konfigurasi yang tahan lama adalah konfigurasi pool, ditambah mekanisme apa pun yang digunakan sistem operasi atau package untuk membuat dan melindungi parent directory. Mekanisme terakhir berbeda-beda: jangan berasumsi bahwa directory yang dibuat manual di bawah /run akan bertahan setelah reboot.
Mode 0666 sangat lemah bila dijadikan jawaban default. Mode itu memberi setiap akun lokal akses write ke endpoint, padahal client yang diketahui hanya satu identitas web server. Error mungkin hilang, tetapi boundary yang seharusnya diberikan oleh permission socket ikut dibuang. Sebaliknya, mode 0600 hanya bekerja jika worker yang terhubung memenuhi syarat sebagai owner; “lebih ketat” tidak berguna apabila justru mengecualikan client yang dituju.
Validasi, Terapkan, dan Uji secara Bertahap
Setelah mengedit, validasi konfigurasi setiap daemon dengan command yang disediakan oleh package terpasang. Jangan me-restart kedua service secara membabi buta: jika pengujian gagal, biarkan service yang masih bekerja tetap berjalan dan perbaiki syntax terlebih dahulu.
Setelah validasi lulus, terapkan perubahan PHP-FPM agar socket dibuat ulang, lalu reload atau restart Nginx hanya jika konfigurasinya berubah. Ulangi pemeriksaan:
stat -Lc 'type=%F owner=%U group=%G mode=%a path=%n' /run/php/app.sock
namei -l /run/php/app.sock
Terakhir, request route PHP yang tidak berbahaya melalui Nginx, lalu periksa hasil HTTP dan log terbaru. Pemeriksaan end-to-end ini penting karena metadata yang terlihat benar tidak membuktikan bahwa Nginx memuat server block yang diharapkan, PHP-FPM memuat pool yang diharapkan, atau kebijakan mandatory access control mengizinkan koneksi.
Urutan troubleshooting yang ringkas adalah:
- Catat error Nginx dan path socket secara persis dari satu request.
- Pastikan listener ada dan pool PHP-FPM berjalan.
- Pastikan Nginx dan PHP-FPM menunjuk endpoint yang sama.
- Kenali user dan group efektif worker Nginx.
- Periksa socket dan setiap parent directory.
- Ubah pengaturan
listen.*milik pool, bukan hanya socket aktif. - Validasi konfigurasi, terapkan, periksa kembali metadata, dan uji melalui Nginx.
Kenali Batas Baseline Ini
Permission filesystem diskresioner hanyalah satu lapisan. SELinux, AppArmor, sandbox systemd, chroot, atau boundary container dapat menolak koneksi meskipun bit mode numerik terlihat cukup. Artikel ini tidak menyarankan untuk menonaktifkan kontrol tersebut. Jika path dan identitas sudah benar tetapi akses tetap ditolak, periksa log kebijakan dan confinement service yang relevan alih-alih terus memperlebar mode socket.
Perilaku Linux juga bukan aturan universal untuk seluruh Unix. Dokumentasi PHP dan unix(7) sama-sama mencatat bahwa sebagian sistem turunan BSD memperlakukan permission pathname socket secara berbeda. Terakhir, pool PHP-FPM terpisah dapat meningkatkan pemisahan operasional, tetapi manual PHP secara eksplisit mengingatkan bahwa pool bukan mekanisme keamanan yang lengkap; resource seperti satu instance OPcache masih dapat digunakan bersama.
Perbaiki Kontrak di Antara Proses
Socket PHP-FPM adalah kontrak kecil antara dua proses. PHP-FPM memilih lokasi endpoint dan metadata yang diterimanya. Nginx harus menyebut endpoint yang sama dan terhubung dengan identitas yang diizinkan oleh path. Parent directory dan setiap lapisan confinement tambahan juga ikut menentukan hasilnya.
Model tersebut lebih berguna daripada menganggap setiap 502 sebagai permintaan untuk memperlebar permission. Pastikan apakah endpoint ada, bandingkan kedua konfigurasi, periksa identitas nyata dan seluruh path, lalu nyatakan akses minimum yang bekerja di dalam pool. Tujuannya bukan sekadar membuat halaman dapat dimuat satu kali, melainkan membuat koneksi yang memang dimaksudkan mudah dipahami dan dapat direproduksi ketika socket dibuat lagi.
