I'm hosting several WordPress sites on a LEMP VPS.

  • Each site has its own Wordpress install (located under /srv/http/domain/wordpress), its own user account (site-user) and its own php-fpm pool running as site-user.
  • Nginx is running under the http account and all files under /srv/http/domain/wordpress have site-user:http ownership with 0640 (files) and 2750 (directories) permissions.

So, each user has full RW access to their own files/directories, but no access to other site's files/directories. Nginx has R-only access to every site's files/directories.

I'm using the setgid bit to force new directories created under /srv/http/domain/wordpress to inherit the http group so Nginx has read access to these. This works as expected when files are created via SFTP.

This seems sane to me and I can update plugins, themes and WordPress successfully through the wp-admin interface. However, anytime I execute a task that requires WordPress to create new files/directories -- basically anytime I install or update a plugin/theme or update Wordpress itself -- the resulting file ownership is site-user:site-user. What I'd like is to have the newly created files/directories respect the setgid bit and create files/directories with site-user:http ownership so Nginx can read these files without my intervention.

I set the following in each site's wp-config.php file:

  • define( 'FS_CHMOD_DIR', ( 02750 & ~ umask() ) );
  • define( 'FS_CHMOD_FILE', ( 0640 & ~ umask() ) );

This forces the permissions to what I want but doesn't have any effect on ownership.

I've read this and this but the "solution" requires modifying PHP code to avoid using move_uploaded_file() which is fine if you're writing your own PHP code, but I'm not going to start modifying WordPress PHP files. I'm not even certain this is the source of my issue.

Also, I understand I could loosen permissions and set them to 755 (directories) and 644 (files) so that Nginx could read files regardless of whether it had group ownership over them, but for security reasons I'm trying to avoid world-readable files on a shared server.

How to I control ownership of files created by WordPress/PHP?

  • Please read the wordpress tag you included. You are asking an off-topic question. See On Topic. Questions about wordpress.com belong on Web Applications. Questions about installing and maintaining WordPress belong on WordPress Development – DavidPostill Nov 24 '17 at 22:11
  • This is arkward. I'm reading this as a filesystem/permissions issue. Possibly to do with the webserver. I'm reopening for now, Having talk with @DavidPostill over how to proceed then if its off topic here, move it to the appropriate site. – Journeyman Geek Nov 25 '17 at 0:24
  • I’ve done similar things with Apache and basically you need to set Nginx to have http group ownership. More details here. – JakeGould Nov 25 '17 at 0:56
  • @JakeGould - Nginx worker threads are running under http:http user/group as stated in the original post. The issue is making files newly-created by Wordpress (actually PHP) to have http group ownership so Nginx can read them. – chr0mag Nov 25 '17 at 15:08
  • @DavidPostill - Apologies David. I don't actually think this is a Wordpress-specific issue, but more to do with PHP and how to setup your LEMP stack in general, including Linux file permissions. – chr0mag Nov 25 '17 at 15:09

I've found a couple of solutions to this:

  1. New files created by Wordpress (actually PHP) are dicated by the user an group directives in the php-fpm pool configuration file under which PHP executes. So to force newly created files to site-user:http ownership as I was originally hoping you could just set user=site-user and group=http in your site-specific php-fpm pool configuration file. This works in that newly created files have the group ownership I was looking for. However, from a security point of view this partly defeats the purpose of create separate php-fpm pools for each site as any site-user could potentially create PHP files that would have read access to another site's files/directories.

  2. Simpler, and more secure than #1 above is to have all of a site's files/directories owned by site-user:site-user (instead of site-user:http as I had originally planned), and then add the http user to the site-user group. With 640 (files) and 750 (folders) permissions on all sites, this effectively gives nginx read-only access to every site's files as required, while still disallowing any user to read any other site's files except their own.

Option #2 above doesn't require any use of the setgid bit which simplifies things but it does require adding the following in your wp-config.php file:

  • define( 'FS_CHMOD_DIR', ( 0750 & ~ umask() ) );
  • define( 'FS_CHMOD_FILE', ( 0640 & ~ umask() ) );

Without the above lines WordPress/PHP will create world-readable files (644) and folders (755).

  • Great self-answered question!!! – JakeGould Nov 25 '17 at 17:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.