OPS-006
Keep the config file out of every release you ship
A sample committed, the real one ignored, the release built by exclusion, and a web server rule that refuses to serve either.
A configuration file containing database credentials and API keys ends up in a public archive more often than anyone admits. It happens because the release is built by zipping the working directory, and the working directory is where the real config lives.
Three habits remove the possibility. Commit only a sample, never the real file. Build the release by excluding it explicitly rather than remembering to delete it. And have the site refuse to start with a clear message when the config is missing, so a fresh install fails with instructions rather than a stack trace containing paths.
Add a server rule that denies the file over HTTP as well. If PHP is ever misconfigured and stops executing, the fallback is the file being served as plain text.
# .gitignore — the real config is never committed
config.php
# Build the release by EXCLUSION, so it cannot be forgotten.
rsync -a --exclude 'config.php039; --exclude 039;.git039; src/ release/app-v1.0.0/
zip -rq app-v1.0.0.zip app-v1.0.0
# Verify before shipping. This must print 0, and the build should stop if it does not.
count=$(unzip -l app-v1.0.0.zip | grep -c 'config\.php$039;)
if [ "$count" != "0" ]; then
echo "REFUSING TO SHIP: config.php is in the archive"
exit 1
fi
echo "clean release: no config.php"
Using it
Make the verification step part of the build script rather than something you remember to run. A build that refuses to continue removes the human from the loop entirely.
Have the application fail with instructions when the config is absent, so a fresh install shows config.php is missing. Copy config.sample.php to config.php and fill it in. rather than a stack trace containing your filesystem paths.
Ship the sample with every key present and commented, so nobody has to guess what a missing setting was called.
What bites people
Deny both files over HTTP in .htaccess — the real config and the sample. If PHP is ever misconfigured and stops executing, the fallback is your credentials being served as plain text. The sample also reveals your key names and structure.
A settings table is not a place for database credentials. They have to exist before the table can be read.
Excluding by name in the archive step is safer than deleting the file afterwards. Deletion is a step that can be skipped; exclusion is the default.