Resolving “Read-only file system” Error in PHP When Writing Outside Webroot Directory on Arch Linux


10 views

While configuring Nextcloud on Arch Linux (ALARM) for Raspberry Pi 3, I encountered a peculiar permissions issue where PHP couldn't write to directories outside the webroot, despite having correct ownership and 777 permissions. The error manifested as:

Warning: fopen(/usr/share/webapps/nextcloud/test.txt): failed to open stream: Read-only file system

Before discovering the root cause, I performed these standard checks:

# Verify directory ownership
chown -R http:http /usr/share/webapps/nextcloud

# Set maximum permissions temporarily
chmod -R 777 /usr/share/webapps/nextcloud

# Check directory traversal permissions
ls -ld /usr /usr/share /usr/share/webapps

Interestingly, manual file creation worked when switching to the http user:

su -s /bin/bash http
echo test > /usr/share/webapps/nextcloud/test.txt  # Succeeded

The breakthrough came when examining systemd's service protections. Many modern Linux distributions, including Arch, implement strict filesystem protection through systemd. For PHP-FPM, this appears in the service unit:

[Service]
ProtectSystem=full

This setting makes several directories read-only, including /usr. The solution isn't to disable security completely, but to selectively allow write access to required paths.

The proper way to handle this is creating a systemd drop-in configuration:

systemctl edit php-fpm.service

[Service]
ReadWritePaths=/etc/webapps/nextcloud/config 
ReadWritePaths=/usr/share/webapps/nextcloud/apps
ReadWritePaths=/usr/share/webapps/nextcloud/data

After reloading systemd and restarting PHP-FPM, verify with:

systemctl daemon-reload
systemctl restart php-fpm

# Test with PHP script

Other potential solutions I evaluated before finding the systemd approach:

  1. Moving Nextcloud to /srv/http (breaks package management)
  2. Disabling ProtectSystem completely (security risk)
  3. Using bind mounts (complex maintenance)

When implementing this solution:

  • Keep the ReadWritePaths list minimal
  • Maintain strict ownership (http:http)
  • Consider setting appropriate SELinux/AppArmor policies if available

When configuring Nextcloud on an Arch Linux system with systemd, I encountered a frustrating permission error:

Warning: fopen(/usr/share/webapps/nextcloud/test.txt): failed to open stream: Read-only file system

Despite having proper permissions (777) and ownership (http:http), PHP processes couldn't write to directories outside the webroot. This behavior stems from systemd's security hardening.

Systemd services on modern Linux distributions often include these protections by default:

ProtectSystem=full
ProtectHome=true
ReadOnlyPaths=/

These security measures make critical system directories read-only to services. You can verify this with:

systemctl show php-fpm.service | grep -E 'ProtectSystem|ProtectHome'

Instead of disabling security features completely, create a systemd override file:

sudo systemctl edit php-fpm.service

Add these directives:

[Service]
ReadWritePaths=/usr/share/webapps/nextcloud
ReadWritePaths=/etc/webapps/nextcloud/config
ReadWritePaths=/var/lib/nextcloud/data
PrivateTmp=false

Create a test script to verify write permissions:

";
        unlink($file);
    } else {
        echo "Failed to write to $file
"; error_log("Write error: " . print_r(error_get_last(), true)); } } ?>

For more complex deployments, consider bind mounts in /etc/fstab:

/var/lib/nextcloud/data    /usr/share/webapps/nextcloud/data    none    bind    0 0

This maintains package manager compatibility while giving you control over storage locations.

After solving the write issue, remember to:

  • Restore proper permissions: chmod -R 750 /usr/share/webapps/nextcloud
  • Set correct ownership: chown -R http:http /usr/share/webapps/nextcloud
  • Configure SELinux/apparmor if present