Run an application
Store environment values and secrets
Keep production configuration outside the repository and make secret files readable only by the service account.
8 minute lesson
Production configuration belongs outside the release directory. This lets the same code run in several environments and prevents a code rollback from restoring old credentials.
Create a root-managed environment file that the service group can read:
sudo install -m 640 -o root -g notes-app /dev/null /etc/notes-app.env
sudoedit /etc/notes-app.env
Use simple NAME=value entries:
NODE_ENV=production
PORT=3000
DATABASE_URL=replace-with-the-real-secret
Do not add export. A systemd EnvironmentFile is not an interactive shell script. When a value contains spaces or special characters, check systemd’s environment-file quoting rules and test the application rather than guessing.
Verify ownership and mode without printing the contents:
sudo stat -c '%U %G %a %n' /etc/notes-app.env
sudo -u notes-app test -r /etc/notes-app.env && echo readable
sudo -u deploy test -r /etc/notes-app.env && echo readable-by-deploy
The first command should report root notes-app 640. The service should be able to read the file. Decide deliberately whether the deployment account belongs to the notes-app group and can read production secrets.
Never put the file in Git, a frontend bundle, process arguments, screenshots, or command output. Also avoid diagnostic commands that dump the complete service environment into logs or chat.
A common failure is making the file readable only by root while the service runs as notes-app. The service then starts without required values or fails with Permission denied. Fix the group and mode; do not run the application as root.
Secret rotation is a deployment. Update the provider credential first when possible, update the environment file, restart the service, verify health, then revoke the old credential. Keep a rollback window when the provider supports two active credentials.
Your action is to create the file with placeholder values, prove its permissions with stat and test, and write a separate .env.example containing names but no real values in the application repository.
Lesson completed