Apache랑 PHP-FPM 사이에서 /home이 read-only로 보이던 문제를 한 번 정리해봤다. 결론부터 말하면, 커널이나 LVM, ext4가 문제가 아니라 systemd httpd 서비스의 Protect 옵션들이 /home을 읽기 전용으로 바꿔놓고 있었다.
상황 정리 – CLI에선 되는데, 웹에서만 안 된다
워드프레스 마이그레이션 후 플러그인 업데이트를 누르니 FTP 자격 증명을 물어본다.
권한 문제 같아서 퍼미션을 열어도 해결이 안 돼서, 직접 PHP로 쓰기 테스트를 했다.
<?php
$file = __DIR__ . '/' . time() . '.txt';
var_dump($file);
var_dump(@file_put_contents($file, "test\n"));
웹에서 호출하면 이렇게 나온다.
PHP Warning: file_put_contents(/home/abc/pub/text.txt): Failed to open stream: Read-only file system …
CLI에서는 같은 디렉터리에서 잘 써진다.sudo -u httpd touch …, php -r 'file_put_contents(...)' 둘 다 정상.findmnt /home으로 보면 /home은 rw, ext4, relatime 딱 보기 좋은 상태다.
그런데 httpd 프로세스 입장에서 /home을 다시 보니까 느낌이 확 온다.
ps aux | grep httpd | head
cat /proc/1912/mounts | grep ' /home '
/dev/mapper/home_vg-home_lv /home ext4 ro,relatime 0 0
커널 전체에서는 rw인데, Apache 프로세스가 붙어 있는 mount namespace에서만 /home이 ro로 마운트되어 있었다.
systemd Protect 옵션 확인
httpd 서비스가 어떻게 띄워져 있는지부터 본다.
systemctl show httpd | egrep 'PrivateTmp|PrivateMounts|ProtectSystem|ProtectHome'
PrivateTmp=yes
PrivateTmpEx=connected
PrivateMounts=no
ProtectHome=read-only
ProtectSystem=yes
PrivateTmp=yes는 /tmp 분리라 괜찮다.PrivateMounts=no인데도/proc/<httpd-pid>/mounts에서 /home이 ro로 잡혀 있다.- 결정적으로
ProtectHome=read-only,ProtectSystem=yes가 걸려 있다.
즉, httpd는 자기 전용 mount 네임스페이스 안에서 /home을 읽기 전용으로 다시 붙이고 있었고, 그 안에서 돌아가는 PHP는 자연스럽게 “Read-only file system”을 맞고 있었다.
재미있는 건 php-fpm 쪽이다.
ps aux | grep 'php-fpm: pool' | head
nsenter -t 997 -m -u -i -n -p mount | grep ' /home '
/dev/mapper/home_vg-home_lv on /home type ext4 (rw,relatime)
php-fpm 프로세스가 바라보는 /home은 rw다.
그러니까 커널/FS/LVM은 멀쩡하고, httpd 서비스만 따로 보호 설정에 걸려 있었던 것.
fix – httpd override에서 보호 해제
원인은 알았으니, httpd 쪽에서 /home에 대한 read-only 보호를 일단 풀어버렸다.
먼저 /home을 한 번 전체적으로 rw로 remount:
mount -o remount,rw /home
그 다음 httpd 서비스 override를 수정한다.
vi /etc/systemd/system/httpd.service.d/override.conf
내용은 최소한 이렇게 맞췄다.
[Service]
PrivateMounts=no
ProtectSystem=off
ProtectHome=off
그리고 reload + restart:
systemctl daemon-reload
systemctl restart httpd
다시 Apache 워커 하나 골라서 확인:
cat /proc/$(pgrep -n httpd)/mounts | grep ' /home '
/dev/mapper/home_vg-home_lv /home ext4 rw,relatime 0 0
이제 웹에서 다시 호출하면, 파일 작성이 가능해진다.
워드프레스도 FTP 자격 증명 팝업 없이 플러그인/코어 업데이트가 잘 올라간다.
정리
- CLI/ssh에서는 잘 되는데 웹에서만
Read-only file system이면, 퍼미션보다 먼저 서비스별 mount 네임스페이스를 의심해 볼 만하다. /home이 rw로 보이는데도 PHP가 ro라고 우길 때는/proc/<pid>/mounts를 직접 보는 게 제일 빠르다.- systemd 기반 서비스라면
ProtectSystem,ProtectHome,PrivateMounts같은 옵션이 의도치 않게 데이터 디렉터리를 read-only로 만들 수 있다. - 보호 수준을 낮출 땐 최소한 필요한 범위에서만 풀고, 왜 처음에 그렇게 설정되어 있었는지(보안 정책, 호스팅 템플릿 등)도 같이 한 번 돌아봐야 한다.
이번 건은 httpd만 따로 ro 네임스페이스를 타고 있었던 게 원인이라, override 하나로 깔끔하게 정리됐다.

