I'm trying to set up the private files directory and I'm getting the following error.

The backup file could not be saved to 'private://backup_migrate/' because the directory could not be created or cannot be written to. Please make sure your private files directory is writable by the web server.

Could someone help correct my misstep? I've scoured scads of pages of documentation, and oddly I don't seem to be able to find a reliable path to a solution. Lots of conflicting info and lots of missing details.

Here's my setup:

  1. bitnami drupal image (centos)
  2. path to Drupal /root/apps/drupal/htdocs
  3. I've connected as root via ssh

Here are the exact steps I've followed, and which best reflect my understanding so far of what I should do:

  1. # cd /root/apps/drupal/ to go to directory that contains the web root directory
  2. # mkdir private-files
  3. # drush dl file_permissions --destination=~/.drush to download the contributed file_permissions utility, which says it handles all necessary permissions changes
  4. # nano sites/default/settings.php to tell Drupal where to find the directory, set $settings['file_private_path'] = '/root/apps/drupal/private-files';
  5. # drush cr to clear Drupal and Drush caches
  6. # drush fp to run the file_permissions utility; it responds:

    Your httpd user: daemon [status]
    Your httpd group: daemon [status]
    You will be prompted for admin password to be able to change [warning]
    permissions with sudo command.
    Security warning: Couldn't write .htaccess file. Please create a [error]
    .htaccess file inyour private:// directory which contains the
    following lines: <pre><code># Deny all requests from Apache 2.4+.
    <IfModule mod_authz_core.c>
    Require all denied

    # Deny all requests from Apache 2.0-2.2.
    <IfModule !mod_authz_core.c>
    Deny from all
    # Turn off all options we don't need.
    Options -Indexes -ExecCGI -Includes -MultiViews

    # Set the catch-all handler to prevent scripts from being executed.
    SetHandler Drupal_Security_Do_Not_Remove_See_SA_2006_006
    # Override the handler again if we're run later in the evaluation list.
    SetHandler Drupal_Security_Do_Not_Remove_See_SA_2013_003
    # If we know how to do it safely, disable the PHP engine entirely.
    <IfModule mod_php5.c>
    php_flag engine off

  7. # drush cr to clear Drupal and Drush caches

  8. # ls -al to see permissions; it shows:

    total 8628
    drwxr-xr-x 7 root root 134 Jul 23 12:04 .
    drwxr-xr-x 5 root root 53 Jun 7 13:52 ..
    lrwxrwxrwx 1 root root 14 Jun 7 13:55 .bitnamimeta -> ../../var/meta
    -r-xr--r-- 1 root root 8826689 Jun 7 13:31 bnconfig
    drwxr-xr-x 4 root root 146 Jun 7 13:51 conf
    drwxr-xr-x 12 root root 4096 Jun 7 13:51 drush
    drwxr-x--- 9 root daemon 4096 Jul 18 13:46 htdocs
    drwxr-xr-x 2 root root 25 Jun 7 13:51 licenses
    drwxrwsr-x 2 daemon daemon 23 Jul 23 13:45 private-files
    lrwxrwxrwx 1 root root 33 Jun 7 13:54 updateip -> /opt/bitnami/apps/drupal/bnconfig

  9. # ls -al private-files/ to see permissions; it shows:

    total 4
    drwxrwsr-x 2 daemon daemon 23 Jul 23 13:45 .
    drwxr-xr-x 7 root root 134 Jul 23 12:04 ..
    -rw-r--r-- 1 root daemon 687 Jul 23 13:47 .htaccess

Needless to say, pretty frustrating since I've spent at least 4 hrs on what I imagine must be simple for someone already familiar with all the components.

Since I am new to servers as well as to Drupal, please break out actual steps vs merely invoking (vague-to-me) concepts such as 'change user group' or the like.

  • 1
    Are you running drush as root? That's not going to help because any files created by drush will not be writable by the webserver. Better to run it as the daemon user to reduce the chance of file ownership issues. Jul 23, 2018 at 14:59
  • 1
    Sorry but that would be much too broad for a single question in this format. There are many different environments with many different considerations, too many to cover in a couple of paragraphs. File permissions are file permissions at the end of the day - Drupal just needs to be able to write to two folders (public and private), and read from the rest of the docroot. How you get that to happen across multiple platforms isn't something that Drupal is concerned with, it only cares about the result, and nothing in and of Drupal itself will teach you *nix file permissions
    – Clive
    Jul 24, 2018 at 12:16
  • 1
    To put it succinctly: this is a file permission problem, not unique to Drupal, and we wouldn't teach you what you want us to teach you here (how to manage generic file permissions on any platform). It's been made specific to your current environment, in an attempt to avoid it being closed as "too broad" or otherwise off topic, because the knowledge you need is not unique to Drupal, but there\s an outside chance that there might be something unique to Bitnami that can be identified and addressed to help you and future users of the same platform
    – Clive
    Jul 24, 2018 at 12:18
  • 1
    Ok I give :) I've edited into the more generic version - like I said before, I can't promise that's not going to make it attract "too broad" close votes (if I wasn't a mod and didn't have a binding vote I'd be voting it as such if I'm honest). Good luck getting it sorted anyway
    – Clive
    Jul 24, 2018 at 13:01
  • 1
    Thanks Clive - I appreciate your efforts, and those of other long-time users, in keeping quality here high. There do seem to be unknown/unstated specifics regarding the private-files directory, and as you acknowledge, some holes in official documentation. I plan to help edit the Drupal docs page once I have a bit more clarity (ideally with similar help in making sure my edits are accurate and useful).
    – lacuna
    Jul 24, 2018 at 13:06

3 Answers 3


Your Drupal folder is owned by daemon:daemon and your private files directory is owned by root:root.

Fix it by making your private files directory at least owned by the same group:

$ chown -R daemon:daemon /root/apps/drupal/private-files

Sorry, I reread your ls -la output again, this time on a bigger screen, and it seems to be the other way around. Your private files folder is already owned by daemon:daemon where in this setup it should be root:root instead:

$ chown -R root:root /root/apps/drupal/private-files

After reading through this thread from 2013 https://community.bitnami.com/t/how-in-bitnami-cloud-drupal-set-up-a-secure-private-file-system-path-folder/9652 it seems your files and folders ownership got messed. Seems that all your Drupal including private files should indeed recursively be owned by daemon:daemon. Generally, logging in as root should be avoided.

  • I have recursively set owner and group to daemon:daemon using $ chown -R daemon:daemon /root/apps/drupal/ --unfortunately the issue persists (I've confirmed all Drupal files/directories have that ownership and cleared caches several times with $ drush cr). I'm editing my original question to include this info.
    – lacuna
    Jul 24, 2018 at 12:00
  • Hi Clive - I notice you rolled back my edits, and I understand your doubts about this question broadly. Seems useful to me to include the changes mentioned here as an update to my question. Would doing so still be in keeping with the guidelines of the community?
    – lacuna
    Jul 24, 2018 at 13:03
  • @OwnSourcingstudent – I'm considering it, or to update the docs on drupal.org. But I guess I won't have the time until later this day or tomorrow.
    – leymannx
    Jul 24, 2018 at 14:07

I would not create the folder as root, let the site create its own folder. Just set the path in your settings.php and then go to 'File system' in the Drupal site (configuration). You can see your path reflected here. Then just save the form and Drupal will create the folders with right permissions.

  • Yeah, that's what I tried first. It reflects the correct path in the file system ("Private file system path /root/apps/drupal/private-files") but I still get the error.
    – lacuna
    Jul 23, 2018 at 16:16
  • How should that ever work when your private files path exists outside Drupal's web root in a directory where Drupal has no write permission for?
    – leymannx
    Jul 23, 2018 at 20:10
  • @leymannx it does work, you can fill in ../private and have Drupal create a folder on it's own, even if it's outside of the webroot.
    – brace110
    Jul 25, 2018 at 15:00

Your configuration looks like this:

Your httpd user: daemon [status]
Your httpd group: daemon [status]

# ls -al /root/apps/drupal/private-files
total 4
drwxrwsr-x 2 daemon daemon 23 Jul 23 13:45 .
drwxr-xr-x 7 root root 134 Jul 23 12:04 ..
-rw-r--r-- 1 root daemon 687 Jul 23 13:47 .htaccess

On a vanilla *nix system, that is all it takes to give daemon full access to the private-files directory. I.e. when the Drupal Backup and Migrate tries to create 'private://backup_migrate/ it should be allowed to to so. As indicated by the error message you've posted, it is not.

Finding: You're not running a vanilla *nix system.
So what can be wrong?

There is no way of knowing without knowing a lot more about your server configuration, but given that you're running CentOS, I suspect that you're having an issue with something known as "SELinux". Btw. SELinux is great! But it imposes an extra layer of security that sometimes comes as an surprise to the uninitiated.

Basically, if SELinux is in use, to fix permissions – in addition to the mod-bits – you also you need to make sure that the security policy for your private-files directory allows daemon to create subdirectories there.

First navigate to the the Drupal configuration directory (sites/default) and inspect the security context label for the public file upload directory:

$ ls -Z .
drwxrwxr x. daemon daemon unconfined_u:object_r:httpd_sys_rw_content_t:s0 files

The label here is httpd_sys_rw_content_t.

Then make sure that private-filesis tagged with the same label. Navigate to /root/apps/drupal and a give command similar to this (use the label used on your configuration):

$ sudo chcon -R -t httpd_sys_rw_content_t private-files

(Source: http://heim.ifi.uio.no/gisle/staging2/drupalprimer/drupal/cf_files.html#f_selinux)

  • Thanks for this detail, @free-radical. Great explanation, and strikes me as a likely explanation, but # sestatus returns SELinux status: disabled. I'd guess it's consequently no surprise that # ls -Z sites/default/ returns a question mark for the security context label for the public file upload dir: drwxrwsr-x daemon daemon ? files. Interested whether there's another buried detail that similarly bears checking.
    – lacuna
    Aug 3, 2018 at 10:38
  • I agree: SELinux is disabled. That rules out SELinux as the culprit. Unfortunately, I cannot think of any other things that may cause this. Things to try: 1) Contact bitnami support and user forums; 2) Go over your configuration again, look for spelling errors and other trivial mistakes; 3) ditch your vhost - start from scratch. Going over your description agian, I see nothing wrong in the way you've tried to set this up. Aug 3, 2018 at 14:06

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.