Skip to content

Powered by Grav

Database credentials — cloaking

Database credentials — cloaking

Open a hosted Drupal or Backdrop site's sites/<uri>/settings.php and you will not find a database password. You will find this instead:

PHP
'password' => $_SERVER['db_passwd'],

That is credential cloaking: the file names the credentials rather than containing them, and something outside the file supplies the values at the moment they are needed. It is on by default.

Why the password is not in that file

Each Octopus instance runs one PHP-FPM pool, as the instance's own web user (oN.<php>.web, in group www-data). Every site in that instance is served by that pool — and so is the instance's own Ægir panel. For any of them to be served, settings.php has to be readable by that shared web user; it ships 0440 owned oN:www-data precisely so it can be.

That makes settings.php the wrong place to keep a secret. Anything running as the pool user can read every one of them, and the panel's own database account is far more privileged than a single site's. Cloaking removes the value from the file the web user can read, and keeps it in files the web user cannot.

The isolation between Octopus accounts rests on separate Unix users, separate pools and, since the per-instance group, separate groups on the files — each site's database account is in any case granted rights over its own database and nothing else. Cloaking closes the one channel that sat inside an instance, where the sharing is by design.

Where the credentials actually live

Holder Mode Read by
The site's Nginx vhost, as fastcgi_param db_* 0600 oN:<account group> Nginx, which passes the values into PHP as $_SERVER
sites/<uri>/drushrc.php 0440 oN:<account group> Drush and the account's shell identities (oN, oN.ftp)
A site backup archive inside the archive see Backups below

The common thread is the group. settings.php carries group www-data because the web server must read it. Both on-disk holders carry the account's own group instead — the per-instance group oN, whose only members are that account's identities; users, the old box-wide group, on an instance not yet converted — and the web pool user is a member of neither. So a web request can obtain the credentials for the site it is serving, the account's own shell identities can read them for Drush, and nothing else on the box can read them off disk. The Ægir site alias in ~/.drush/ is not a credential holder: it records db_server and the site's other context, and Drush takes the credentials themselves from drushrc.php.

The two paths

A web request arrives through the site's vhost, which passes the six db_* values to PHP-FPM. settings.php reads them from $_SERVER, builds the connection, and the request proceeds normally. Nothing about this is visible to the site's code beyond the connection itself.

The command line has no vhost, so $_SERVER is empty. settings.php therefore falls back to reading the values out of the sibling drushrc.php, which the shell identities can read. This is what keeps ordinary Drush, site-local Drush and vdrush in the limited shell working exactly as before — including updatedb and cache rebuilds on Drupal 10 and 11, which run through a site-local Drush of their own. The values are read back as the var_export() literals drushrc.php is written with, so a password carrying an apostrophe or a backslash — an adopted site's, typically — arrives intact; the file is parsed, never executed.

You do not have to do anything to get either path. Both are wired by Provision when it writes the site.

Backups keep the real credentials

A backup is deliberately not cloaked. Before the archive is written the credentials are put back into settings.php in full, and restored to their cloaked form immediately afterwards. Without that, an archive would be useless anywhere except a server that already had a matching vhost — which would defeat the point of an off-site backup.

So an archive from ~/backups, or one opened with boa-restore, contains a working settings.php with real credentials. Treat those archives as secrets, which is the same rule that already applied to the database dump inside them.

Where cloaking does not apply

Textpattern keeps its credentials in the site's own sites/<uri>/private/config.php (mode 0440, group www-data, the same terms as an uncloaked settings.php), and Grav sites have no database at all. Neither participates in cloaking. Nothing is weakened by that: those sites hold only their own database account, scoped to their own database, exactly as a Drupal site's is.

Reading a site's credentials as an operator

When you need the values — to open a client's database by hand, for instance — take them from drushrc.php, or let the tooling do it:

BASH
drush @<site-alias> sql-connect

The database GUI tools and sqlmagic work through the site's Drush alias rather than by reading settings.php, so they are unaffected.

Advanced — turning it off

Cloaking is a property of the HTTP service, resolved per site when Provision writes settings.php:

PHP
$this->cloaked = drush_get_option('provision_db_cloaking', ->cloaked_db_creds());

The Nginx service returns TRUE, so cloaking is the default for every site on the server. A single Provision command can be overridden:

BASH
drush @<site-alias> provision-verify --provision_db_cloaking=0

That re-renders one site's settings.php with literal credentials, and the next ordinary Verify puts it back. There is no reason to run it in normal operation; it exists for the backup path described above and for debugging. Turning cloaking off server-wide means editing the Provision service and is not supported as a configuration choice.

© 2026 BOA Documentation. All rights reserved.