Nginx Sensitive-File Leak Protection in Practice: Blocking .git and .env
Hands-on Nginx config to block high-risk paths including .git, .env, and backup archives, while preserving .well-known for certificate validation. Includes access-log triage and a post-leak credential-rotation playbook.
Sensitive-file leak protection is the most overlooked piece of web security. Attackers mass-scan /.git/config, /.env, /backup.zip, and similar paths. A hit yields full source or database credentials and often a full takeover. This article gives a complete Nginx sensitive-file deny config, plus verification and post-leak incident response.
Applicable Scenarios
- Site tree is Git-managed;
.gitships into the web root at deploy time - Leftover
.env,config.php.bak,*.sql, and other debug files in the project root - Ops habit of dropping backup archives temporarily under the web root
- Pre-launch security baseline: need a uniform reduction of file exposure
Prerequisites
- Nginx 1.x, with permission to edit config and reload
- Know the path of the site's
serverblock config - Local curl or a browser for verification
How It Works
Automated scanners probe these high-risk paths. Hitting any one can be severe:
/.git/HEAD,/.git/config: tools such as git-dumper can reconstruct the full repo, including passwords and API keys accidentally committed in history/.env: Laravel and similar framework env files, typically holding database, Redis, and mail credentials*.sql,*.bak,*.zip: DB dumps and code backups, direct download of data/.svn/entries: SVN metadata leak/phpinfo.php: exposes server paths, extensions, environment variables, and other sensitive info
The defense: deny at the Nginx layer. Even if the file exists, the attacker cannot read it. Return 404 rather than 403 so scanners do not confirm the target exists.
Procedure
1. Block Hidden Directories and VCS Directories
Add the following to the site server block. Use a (?!well-known) negative lookahead to preserve /.well-known/; otherwise Let's Encrypt certificate validation breaks:
location ~ /\.(?!well-known) {
deny all;
return 404;
}
2. Block High-Risk Extensions and Backup Files
location ~* \.(env|sql|bak|old|swp|conf|ini|tar|gz|tgz|zip|7z|rar)$ {
deny all;
return 404;
}
If the site has a legitimate archive-download flow, change the rule to deny only files under the web root and explicitly allow the download directory:
location ~* ^/downloads/.*\.(zip|tar\.gz)$ {
allow all;
}
location ~* \.(env|sql|bak|old|swp|conf|ini|tar|tgz|zip|7z|rar)$ {
deny all;
return 404;
}
Nginx location regex matches in order. The allow rule must come first.
3. Disable Directory Listing
Confirm autoindex is off so directory structure is not exposed:
autoindex off;
4. Disable PHP Execution in Upload Directories
Hardening extra: do not execute PHP under upload dirs. Cuts off direct use of a dropped WebShell:
location ~* ^/(uploads|files)/.*\.php$ {
deny all;
}
5. Reload Config
nginx -t && systemctl reload nginx
Verification
Request the following paths in order. Expect 404 on all:
curl -I https://helixcyber.ai/.env
curl -I https://helixcyber.ai/.git/config
curl -I https://helixcyber.ai/db_backup.sql
curl -I https://helixcyber.ai/site.zip
Also verify /.well-known/ is not blocked (certificate renewal depends on it):
curl -I https://helixcyber.ai/.well-known/acme-challenge/test
FAQ
FAQ 1: Blocking .zip breaks legitimate downloads?
Per step 2, use a more precise location to allow the download directory (e.g. /downloads/) and put the allow rule before the deny rule; or restrict the deny rule to paths matching ^(?!/downloads/). Prefer object storage over the web root for business files so you do not false-positive at all.
FAQ 2: Files were already scanned and downloaded. How to recover?
First establish exposure window: search access logs for scan traces: grep -E '\.(env|git|sql|bak)' /var/log/nginx/access.log. Then run a three-step response: ① rotate every leaked credential immediately—database passwords, Redis passwords, third-party API keys, mail auth codes; ② if .git was accessed, treat all history as leaked; scrub sensitive files with BFG Repo-Cleaner and reset every credential; ③ physically delete .env, backup archives, and similar files from the web root. Config is a backstop, not a root fix.
Summary
Sensitive-file leaks are a classic low-cost, high-impact bug: attack cost is near zero; a hit can take over the site. Nginx-layer deny is deploy-once, long-lived, but must be paired with source control—do not publish VCS dirs to production, do not drop backups in the web root, rotate credentials on a schedule. Put the curl checks above on the launch checklist.