Why Your Linux Service Won't Start: Missing Environment Variables
A service that crashes immediately on startup - with no port listening - is most often missing a required environment variable. The app fails before it binds, the log says exactly which variable, and the fix is a one-liner export. Here's how to work through it.
Why services fail silently on a new server
"It worked on my machine" is almost always an environment problem. The developer's
shell had INVENTORY_DB (or DATABASE_URL, SECRET_KEY, etc.) exported from a
previous session. The production server was freshly provisioned and never had it.
The app crashes before it binds the port, so from the outside it looks like the network is down - but the real error is in the logs.
Step 1: confirm nothing is listening and read the log
ps aux | grep app.py # is the process running at all?
ss -ltnp | grep 8080 # is port 8080 open?
cat /var/log/flask/app.log # what did it say when it tried to start?
If the process is absent and the port is closed, the app exited on startup. The log is the first place to look.
Step 2: start it manually to see the raw error
python3 app.py
A missing environment variable surfaces immediately:
KeyError: 'INVENTORY_DB'
Python's os.environ['INVENTORY_DB'] raises KeyError (not a default) when the
variable is absent. os.getenv('INVENTORY_DB') returns None silently, which
usually causes a crash a few lines later. Either way, the error names the variable.
Step 3: confirm what the app expects
Open the source to verify the variable name and what it's used for:
import os
DB_NAME = os.environ['INVENTORY_DB'] # crashes here if unset
conn = psycopg2.connect(dbname=DB_NAME, user='postgres', host='localhost')
This tells you the exact key and confirms a safe value to set.
Step 4: export the variable and restart
export INVENTORY_DB=inventory
python3 app.py > /var/log/flask/app.log 2>&1 &
Then verify the service is answering:
curl http://localhost:8080/health
curl http://localhost:8080/products
Making the fix permanent
An export in your current shell is lost on reboot or a new session. For a
long-lived service, set the variable where the process manager will pick it up:
- systemd unit - add
Environment=INVENTORY_DB=inventoryunder[Service]and runsystemctl daemon-reload && systemctl restart app /etc/environment- machine-wide, picked up by PAM-started sessions- A
.envfile loaded by your app or an init script
The goal is that the variable is present regardless of who restarts the service.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Reading process logs and using ps/ss to confirm a service is not running
- Running an app manually to expose the raw startup error
- Exporting a missing environment variable and verifying the service comes up
FAQ
How do I find out which environment variable is causing a crash?
Start the process manually in a terminal (python3 app.py) and read the raw error output. A KeyError or similar will name the missing variable directly. The application log often has the same message.
How do I set an environment variable so a Linux service keeps it after reboot?
For a systemd service, add Environment=VAR=value inside the [Service] section of the unit file, then run systemctl daemon-reload and restart the service. A plain export in your shell is lost when the session ends.
Why does a Python app crash with KeyError when an env var is missing?
os.environ['VAR'] raises KeyError if the variable is not set - it does not return a default. Use os.getenv('VAR') if you want None on miss, or guard with a startup check that exits with a clear error message listing every missing variable.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →