Tired of manually restarting your server every time your SSH session drops? Whether you're running a Node.js backend, a Python script, or a Rust-powered microservice, systemd can make your app run like a first-class citizen on Linux. This blog breaks down the steps to get your service running with systemd, handle environment variables like a pro, and debug it without losing your mind.
Introduction
Systemd is the init system and service manager used by most modern Linux distributions. It allows you to define, control, and manage services with precision and reliability. Think of it as a smarter cron
, nohup
, and tmux
all rolled into one, but built into the OS and designed for real services.
If you're still SSHing into your server and running your backend with node dist/index.js
, it's time to upgrade your game.
Step 1: Create Your Service File
Your backend is located at ~/backend/dist/index.js
. Let's make it run like a daemon.
- Create a new systemd service file:
sudo nano /etc/systemd/system/myserver.service
- Paste this configuration (change
your_username
accordingly):
[Unit] Description=My Node.js Server After=network.target [Service] Type=simple User=your_username WorkingDirectory=/home/your_username/backend ExecStart=/usr/bin/node /home/your_username/backend/dist/index.js Restart=on-failure EnvironmentFile=/etc/ternarysearch.env StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target
- Reload systemd and enable your service:
sudo systemctl daemon-reexec sudo systemctl daemon-reload sudo systemctl enable myserver sudo systemctl start myserver
Step 2: Handle Environment Variables the Right Way
Avoid hardcoding values or messing with .env
in your code. Instead, create a system-wide env file:
sudo nano /etc/ternarysearch.env
Add your variables like:
NODE_ENV=production PORT=3000 DB_URL=postgres://user:pass@localhost:5432/db
Make sure it's readable:
sudo chmod 644 /etc/ternarysearch.env
This file works for both systemd and manual shell loading. You can even symlink it as .env
in your project if you want dev tools to pick it up:
ln -s /etc/ternarysearch.env .env
Step 3: Running in Dev Mode
Want to run it manually for development using the same env file?
set -o allexport source /etc/ternarysearch.env set +o allexport node dist/index.js
Or wrap it in a script like run-dev.sh
:
#!/bin/bash ENV_FILE=${ENV_FILE:-/etc/ternarysearch.env} set -o allexport source "$ENV_FILE" set +o allexport exec node dist/index.js
Make it executable:
chmod +x run-dev.sh
Run it:
./run-dev.sh
Step 4: Logging and Debugging
Check the logs for your service:
journalctl -u myserver
Follow logs in real time:
journalctl -u myserver -f
Want to start fresh?
sudo systemctl restart myserver
If it's broken:
journalctl -u myserver -xe
Step 5: Bonus Tips
- Use
tmux
orscreen
for development if you're on a remote VM - Make different env files for staging, dev, prod and use symlinks
- Reload systemd with
sudo systemctl daemon-reload
after any service file change - Use
Restart=always
if you want it to auto-respawn like a cockroach
Conclusion
Once you've got systemd set up, your app becomes a real service, not just a script you're babysitting. It's clean, restartable, loggable, and production-ready. Use this setup for anything from a web server to a custom scraper.
Welcome to the grown-up table.