chmod -R 777 supaya semuanya bisa ditulis. Website memang jalan lagi. Masalahnya, sekarang semua file bisa diubah oleh proses apa pun di server, termasuk script yang masuk lewat plugin bermasalah. Di sini kita bahas cara mengecek owner dan permission yang benar, lalu memperbaikinya tanpa membuat update plugin dari dashboard berhenti berfungsi.
Kenapa owner file berubah setelah migrasi
rsync -ayang dijalankan sebagai root menyimpan UID (nomor user) dari server asal. Kalau user dengan UID itu tidak ada di VPS,ls -lhanya menampilkan angka, bukan nama.- Arsip
.tar.gzyang diekstrak sebagai root biasanya mempertahankan owner asli. Arsip.zipyang diekstrak sebagai root umumnya menghasilkan file milik root. - File yang di-upload lewat SFTP dengan login root otomatis jadi milik root.
www-data atau user yang kamu buat sendiri. Hasilnya, PHP masih bisa membaca file karena permission 644 mengizinkan siapa pun membaca. Tapi PHP tidak bisa menulis, sehingga upload dan update gagal.
Sedikit pengingat soal angka permission. Tiga digit itu berlaku untuk owner, group, dan others (semua user lain). Nilai r=4, w=2, x=1 dijumlahkan, jadi 755 artinya owner bisa baca, tulis, dan masuk folder, sedangkan yang lain hanya baca dan masuk. 777 artinya semua user bisa melakukan semuanya. Sebagian handler seperti suPHP bahkan menolak menjalankan file yang group-writable atau world-writable, tergantung setting-nya. Jadi 777 tidak selalu membuat situs jalan.
Cari tahu dulu siapa yang menjalankan PHP
BASH
# User yang menjalankan worker PHP-FPM (kolom pertama)
ps -eo user,group,args | grep '[p]hp-fpm'
# User yang diset di konfigurasi pool
# Path ini untuk Debian/Ubuntu. Keluarga RHEL biasanya di /etc/php-fpm.d/
grep -RE '^(user|group|listen\.owner|listen\.group)\s*=' /etc/php/*/fpm/pool.d/
# User web server, untuk perbandingan
ps -eo user,args | grep -E '[n]ginx|[a]pache2|[h]ttpd|[l]itespeed'define('FS_METHOD', 'direct'); di wp-config.php memang menghilangkan form itu, tapi akar masalahnya tetap ada. File baru akan dimiliki user PHP, sedangkan file lama tetap milik root, sehingga kepemilikannya jadi campur aduk.
Audit kondisi sekarang dengan stat dan find
siteuser, kita lihat kondisi file saat ini. Semua perintah di bawah hanya membaca, jadi aman dijalankan kapan saja. Variabel WP sengaja ditulis tanpa tanda kutip. Kalau path kamu mengandung spasi, bungkus $WP dengan tanda kutip ganda.
BASH
WP=/var/www/example.com/public_html
# Owner, group, permission oktal, dan nama untuk titik-titik penting
stat -c '%U:%G %a %n' WPWP/wp-config.php WP/wp-contentWP/wp-content/uploads
# File dengan UID/GID yatim (sisa dari server lama)
find $WP \( -nouser -o -nogroup \) | head
# File atau folder yang owner-nya bukan user PHP
find $WP ! -user siteuser | wc -l
# Apa pun yang bisa ditulis others (sisa chmod 777), symlink dikecualikan
find $WP ! -type l -perm -o+w | wc -l
# contoh format output stat (bukan dari server nyata):
# root:root 777 /var/www/example.com/public_html
# root:root 777 /var/www/example.com/public_html/wp-config.phpstat menampilkan root:root atau angka seperti 1005:1005, owner belum sesuai. Kalau perintah find ! -user mengembalikan angka selain nol, masih ada file yang bukan milik user PHP. Perintah -perm -o+w mencari bit tulis untuk others. Pada situs WordPress yang sehat, hasilnya seharusnya nol.
Symlink sengaja dikecualikan karena di Linux symlink selalu tampil dengan permission 777. Itu normal dan tidak berarti apa-apa.
Target owner dan permission yang masuk akal
siteuser, dan PHP-FPM untuk situs itu berjalan sebagai siteuser. Update dari dashboard berjalan normal. Kekurangannya, kalau ada plugin yang bisa dieksploitasi, penyerang juga bisa mengubah file core dan plugin karena PHP punya hak tulis di semua tempat.
Model kedua lebih ketat. File dimiliki user deploy, sedangkan PHP hanya diberi hak tulis di wp-content/uploads dan folder cache. Model ini lebih aman, tapi update plugin dari dashboard tidak akan berjalan. Update harus dilakukan lewat WP-CLI sebagai user deploy atau lewat pipeline deploy.
Untuk sebagian besar VPS yang dikelola sendiri dan masih mengandalkan update dari dashboard, model pertama adalah titik awal yang realistis. Targetnya kira-kira seperti ini:
| Bagian | Owner:group | Permission | Catatan |
|---|---|---|---|
| Semua folder | siteuser:siteuser | 755 | Bit x pada folder diperlukan agar bisa dimasuki |
| Semua file | siteuser:siteuser | 644 | Web server tetap bisa membaca file statis |
| wp-config.php | siteuser:siteuser | 640 atau 600 | Berisi password database, others tidak perlu membaca |
| wp-content/uploads | siteuser:siteuser | 755 | Cukup karena PHP adalah owner, tidak perlu 775 atau 777 |
640 aman untuk wp-config.php di model ini karena file itu dibaca oleh PHP sebagai owner. Nginx tidak perlu membacanya karena Nginx hanya meneruskan request PHP ke PHP-FPM. Kalau PHP ternyata berjalan sebagai user lain, permission ini akan membuat situs langsung error. Karena itu, langkah identifikasi user PHP tadi tidak boleh dilewati.
Memperbaiki tanpa merusak update plugin
WP menunjuk ke path yang salah, misalnya /var/www atau /, owner file sistem bisa ikut berubah dan kondisinya sulit dikembalikan. Sebelum menjalankan perintah ini:
- Pastikan
echo $WPmenampilkan folder situs yang benar. - Simpan dulu permission lama dengan
getfaclsebagai titik balik. - Jalankan perubahan.
BASH
WP=/var/www/example.com/public_html
echo $WP
# 1. Simpan permission lama. Pulihkan dengan: setfacl --restore=/root/wp-perms-backup.acl
getfacl -R -p $WP > /root/wp-perms-backup.acl
# 2. Kembalikan owner ke user PHP
chown -R siteuser:siteuser $WP
# 3. Folder 755, file 644, wp-config.php 640
find $WP -type d -exec chmod 755 {} +
find $WP -type f -exec chmod 644 {} +
chmod 640 $WP/wp-config.phpfind ... -exec ... {} + memisahkan folder dan file. Cara ini lebih aman daripada chmod -R 755, yang akan memberi bit execute ke semua file. Secara default, chown -R juga tidak menelusuri symlink, sehingga folder di luar situs tidak ikut terubah.
Setelah itu, verifikasi ulang dari sisi PHP, jangan dari sesi root:
- Jalankan lagi dua perintah
finddari bagian audit.find $WP ! -user siteuser | wc -ldan pencarian-perm -o+wseharusnya sama-sama menghasilkan nol. - Uji hak tulis sebagai user PHP dengan
sudo -u siteuser touch $WP/wp-content/uploads/.tes-tulis, lalu hapus file itu. Kalau perintahnya gagal, berarti masih ada folder induk yang owner-nya keliru. - Jalankan
sudo -u siteuser wp plugin list --path=$WPuntuk memastikan WP-CLI bisa membaca instalasi sebagai user yang benar. Kalau WP-CLI belum terbiasa kamu pakai untuk troubleshooting, ada catatan di Cara Cek Plugin Penyebab White Screen WordPress Lewat WP-CLI Tanpa Buka Admin. - Coba update satu plugin kecil dari dashboard. Form permintaan FTP seharusnya tidak muncul lagi.
find $WP/wp-content/uploads -name '*.php'. Kalau ada yang mencurigakan, langkah pembersihannya lebih panjang dari sekadar ganti password, seperti dibahas di Mengira Ganti Password Admin Cukup Setelah WordPress Dibobol.
Pegangan praktisnya: setiap selesai migrasi, cari tahu dulu user yang menjalankan PHP, lalu samakan owner file dengan user itu. Pakai 755 untuk folder, 644 untuk file, dan 640 untuk wp-config.php. Setelah itu, jalankan audit find yang sama sampai hasilnya nol. Kalau dashboard meminta FTP saat update, periksa owner file, bukan permission-nya, dan jangan menjadikan chmod 777 atau FS_METHOD sebagai solusi permanen.