Hardcoding database passwords, API keys, and other secrets directly into application code is a common and serious security mistake. This guide covers proper environment variable management across different deployment approaches.
Why This Matters
- Hardcoded secrets end up in version control history, even if later removed
- Different environments (development, staging, production) need different values
- Separating configuration from code follows standard software deployment practices
Method 1 — .env Files (Most Common for PHP/Node.js/Python Apps)
nano .env
DB_HOST=localhost
DB_PASSWORD=change_me_strong_password
API_KEY=your_api_key_here
Always exclude it from version control:
echo ".env" >> .gitignore
Commit a .env.example with variable names but no real values, so team members know what's required.
Method 2 — System Environment Variables via systemd
For applications run as a systemd service, set variables directly in the unit file:
[Service]
Environment="DB_PASSWORD=change_me"
Environment="API_KEY=your_key"
ExecStart=/usr/bin/node /opt/myapp/index.js
Or reference a separate environment file:
EnvironmentFile=/etc/myapp/myapp.env
ExecStart=/usr/bin/node /opt/myapp/index.js
sudo chmod 600 /etc/myapp/myapp.env
Method 3 — Shell Profile (Not Recommended for Secrets)
Setting variables in ~/.bashrc works for non-sensitive configuration but isn't ideal for secrets, since it's tied to a specific user session rather than the specific service.
Method 4 — Docker/Docker Compose
See Docker Compose .env Files and Environment Variables Explained for the full Docker-specific approach.
Reading Environment Variables in Code
PHP:
$dbPassword = getenv('DB_PASSWORD');
Node.js:
const dbPassword = process.env.DB_PASSWORD;
Python:
import os
db_password = os.environ.get('DB_PASSWORD')
Setting Correct File Permissions on Secret Files
chmod 600 .env
chown deploy:deploy .env
Only the application's own user should be able to read it — never world-readable.
Rotating Secrets
When rotating a compromised or routinely-expiring secret:
- Generate the new credential at the source (database, API provider)
- Update the
.envfile or systemd environment configuration - Restart the application to pick up the new value
- Revoke the old credential once confirmed working
Common Errors
Variable shows as undefined in the application — confirm the application actually loads the .env file (most frameworks require a library like dotenv for PHP/Node.js), and that the app was restarted after any change.
Secrets accidentally committed to Git — beyond removing the file going forward, the credential should be treated as compromised and rotated immediately, since Git history retains it even after deletion.
Best Practices
- Never commit real secret values to version control, ever
- Set restrictive file permissions (600) on any file containing secrets
- Use different credentials per environment (development, staging, production)
- Rotate secrets immediately if accidentally exposed
Related Articles
- Docker Compose .env Files and Environment Variables Explained
- How to Manage Services with systemd and systemctl
- VPS Security Checklist for Beginners
