1

What user, group and permissions of files and folders I need for core updates?

Test setups

I tried everything the manual recommended me to. Here are some test setups I used, the setup was recursively used on the WordPress installation.

  • Case A: The owner has read/write permissions.
  • Case B: The owner and group have read/write permissions.

Every permission case above was tried with the following user and group setup.

  1. Owner: Apache | Group: Apache
  2. Owner: Apache | Group: FTPuser
  3. Owner: FTPuser | Group: FTPuser
  4. Owner: FTPuser | Group: Apache

Test results

  • 1A:

    Could not create directory.
    

  • 1B:

    Could not create directory
    

  • 2A:

    Could not create directory.
    

  • 2B:

    The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.: wp-admin/includes/update-core.php
    

  • 3A:

    Warning: touch(): Unable to create file /home/FTPuser/domains/domain.name/public_html/wordpress/wp-content/uploads/wordpress-4.tmp because Permission denied in /home/FTPuser/domains/domain.name/public_html/wordpress/wp-admin/includes/file.php on line 155
    Warning: unlink(/home/FTPuser/domains/domain.name/public_html/wordpress/wp-content/uploads/wordpress-4.tmp): No such file or directory in /home/FTPuser/domains/domain.name/public_html/wordpress/wp-admin/includes/file.php on line 457
    Download failed.: Destination directory for file streaming does not exist or is not writable.
    

  • 3B:

    Warning: touch(): Unable to create file /home/FTPuser/domains/domain.name/public_html/wordpress/wp-content/uploads/wordpress-4.tmp because Permission denied in /home/FTPuser/domains/domain.name/public_html/wordpress/wp-admin/includes/file.php on line 155
    Warning: unlink(/home/FTPuser/domains/domain.name/public_html/wordpress/wp-content/uploads/wordpress-4.tmp): No such file or directory in /home/FTPuser/domains/domain.name/public_html/wordpress/wp-admin/includes/file.php on line 457
    Download failed.: Destination directory for file streaming does not exist or is not writable.
    

  • 4A:

    Warning: touch(): Unable to create file /home/FTPuser/domains/domain.name/public_html/wordpress/wp-content/uploads/wordpress-4.tmp because Permission denied in /home/FTPuser/domains/domain.name/public_html/wordpress/wp-admin/includes/file.php on line 155
    Warning: unlink(/home/FTPuser/domains/domain.name/public_html/wordpress/wp-content/uploads/wordpress-4.tmp): No such file or directory in /home/FTPuser/domains/domain.name/public_html/wordpress/wp-admin/includes/file.php on line 457
    Download failed.: Destination directory for file streaming does not exist or is not writable.
    

  • 4B:

    The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.: wp-admin/includes/update-core.php
    

These updates always have been a big issue for WordPress, I would like to clarify this let's find a general solution! The installation is hosted on a CentOS 6.6 server running with DirectAdmin.

EDIT:

The custom configuration at wp-config.php I used for these tests, contain the following:

$root='public_html';
define('FTP_USER','username');
define('FTP_PASS','password');

$addr=$_SERVER['SERVER_ADDR'];
$name=$_SERVER['SERVER_NAME'];
$host=$_SERVER['HTTP_HOST'];
$https=$_SERVER['HTTPS'];
$protocol=(!empty($https)&&$https!=='off'||$_SERVER['SERVER_PORT']===443)?'https://':'http://';
$abspath=(strpos(getcwd(),'/wp-admin')!==FALSE)?substr(getcwd(),0,strrpos(getcwd(),'/wp-admin')):getcwd();
$relpath=substr($abspath,strrpos($abspath,$root)+strlen($root));
define('WP_HOME',$protocol.$host.$relpath);
define('WP_SITEURL',$protocol.$name.$relpath);
define('FS_CHMOD_DIR',(02755&~umask())); //FOR CASE A
define('FS_CHMOD_FILE',(0664&~umask())); //FOR CASE A
define('FS_CHMOD_DIR',(02775&~umask())); //FOR CASE B
define('FS_CHMOD_FILE',(0664&~umask())); //FOR CASE B
define('FS_METHOD','ftpext');
define('FTP_BASE',$abspath);
define('FTP_HOST',$addr);
4
  • Is PHP running as CGI or an Apache module? Feb 4, 2015 at 11:53
  • @TheDeadMedic The Server API is "Apache 2.0 Handler".
    – luukvhoudt
    Feb 4, 2015 at 12:19
  • @TheDeadMedic Why is this important? I've added my config maybe this will narrow it down.
    – luukvhoudt
    Feb 5, 2015 at 12:59
  • 1
    It's important if you're using direct for FS_METHOD, as CGI will need suPHP or similar. Have you tried direct? So long as PHP can run as the same owner as your files, direct is always the most reliable & efficient filesystem method. Feb 5, 2015 at 13:43

1 Answer 1

0

Yeahh! I finally found a solution!

The trick was to set all files and folders their ownership and group to the apache user. Make sure you've an directory for temporary storage and you need to have the ../wp-content/upgrade/ directory as well. Than at your wp-config.php this is the only thing I'm not aware about of the compatibility of it. But you'll need constant FS_METHOD set to direct like @TheDeadMedic suggested.

To make live easier I created a bash script what is pretty easy to use, it will get everything into place except the wp-config.php you'll have to add the following to this file by yourself.

// Some static information, so fill this in correctly.
$root='public_html';
define('FTP_USER','<username>');
define('FTP_PASS','<password>');

// This is dynamically configured. You won't have to edit.
$addr=$_SERVER['SERVER_ADDR'];
$name=$_SERVER['SERVER_NAME'];
$host=$_SERVER['HTTP_HOST'];
$https=$_SERVER['HTTPS'];
$protocol=(!empty($https)&&$https!=='off'||$_SERVER['SERVER_PORT']===443)?'https://':'http://';
$abspath=(strpos(getcwd(),'/wp-admin')!==FALSE)?substr(getcwd(),0,strrpos(getcwd(),'/wp-admin')):getcwd();
$relpath=substr($abspath,strrpos($abspath,$root)+strlen($root));
$tmppath=substr($abspath,0,-(strlen($relpath)+strlen($root))).'tmp';
define('WP_HOME',$protocol.$host.$relpath);
define('WP_SITEURL',$protocol.$name.$relpath);  
define('FS_CHMOD_DIR',(02755&~umask()));
define('FS_CHMOD_FILE',(0644&~umask()));
define('WP_TEMP_DIR', $tmppath);
define('FS_METHOD','direct');
define('FTP_BASE',$abspath);
define('FTP_HOST',$addr);

Than the bash script, this works as following: bash script.sh $1 $2

  • $1: Choose an action to run
    • help: Show how to use this script.
    • config: Configure an already existing WP installation correctly, one what is installed in the CURRENT directory.
    • new: Install a new WP CMS in the CURRENT directory and than configure it correctly.
  • $2: the public directory name, so we can detect from where files are private. The default and also most common is public_html leave this parameter empty if your server uses this as default as well.

And now the bash script itself! :D

# If requested install WP
if [ "$1" = new ]; then
    wget https://wordpress.org/latest.tar.gz
    tar -xvf latest.tar.gz
    mv -f wordpress/* .
    rm -rf wordpress/ latest.tar.gz
fi
if [[ "$1" = help || -z "$1" ]]; then
    echo "Usage: install.sh \$1 \$2"
    echo "\$1: default=config, new=install new WP."
    echo "\$2: default=public_html, *=root folder (must be a parent)."
else
    # Define root directory
    if [ ! -z "$2" ]; then
        root=$2
    else 
        root='public_html'
    fi

    # Define root path
    dir=`pwd -P`
    tmp=${dir%%$root*}"tmp"

    # Define apache user
    APACHE_USER=$(ps axho user,comm|grep -E "httpd|apache"|uniq|grep -v "root"|awk 'END {if ($1) print $1}')

    # Create missing directories
    if [ ! -d "$tmp" ]; then
        mkdir "$tmp"
        chown -R "$APACHE_USER":"$APACHE_USER" "$tmp"
    fi
    if [ ! -d wp-content/upgrade ]; then
        mkdir -p wp-content/upgrade
    fi

    # Setup group and ownership for the installation
    chown -R "$APACHE_USER":"$APACHE_USER" wp-* index.php xmlrpc.php .htaccess

    # Make sure the chmoding is correct
    find wp-* index.php xmlrpc.php .htaccess -type f -exec chmod 644 {} \;
    find wp-* -type d -exec chmod 755 {} \;

    # Remove unwanted WP files
    rm -f license.txt readme.html
fi

TIP: To make it available everywhere on the system, then just put it in /usr/local/bin/ when that's done you're able to just run $ <script name> **$1 $2**. Make sure the "script name" is unique.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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