Systemd Masterclass

Most tutorials just say "paste this code." This guide explains why things break and how to deploy production-grade services that are secure, reliable, and auto-restarting.

What is Systemd?

It's the "Manager" of your Linux server. It starts your bot/website when the server turns on, restarts it if it crashes, and captures all logs. It's the standard for 99% of Linux servers.

1. Security: The "No Root" Rule

CRITICAL WARNING

Never run your code as root. If your code has a bug or gets hacked, the attacker gains full control of your server (they can delete everything). Always create a specific user.

Step 1: Create a System User

Run this command on your VPS. It creates a user named my-app that cannot login (safer) but can run scripts.

sudo useradd -r -s /bin/false my-app

Step 2: Add to Group (Optional)

If your app needs to write logs, sometimes adding it to the www-data group helps (common for web servers).

sudo usermod -aG www-data my-app

2. Permissions & Ownership

One of the most common errors is Permission Denied (Exit Code 203 or 1). This happens because you uploaded files as root, but your service tries to run as my-app.

Fix Ownership

Give your new user ownership of the project folder:

# Syntax: chown -R user:group /path/to/folder
sudo chown -R my-app:my-app /var/www/my-project

Make Scripts Executable

If you are running a shell script (`.sh`) or a binary (like Go app), you must mark it executable:

chmod +x /var/www/my-project/start.sh

3. Language Specific Guides

Python (Virtual Environments)

Never use /usr/bin/python3 directly if you installed packages with pip. You must point to the python binary inside your virtual environment.

WRONG ❌ (Module Not Found Error)

ExecStart=/usr/bin/python3 main.py

CORRECT ✅

ExecStart=/var/www/bot/venv/bin/python main.py

Node.js (NVM Issue)

Systemd does not know about NVM. If you installed Node via NVM, you must find the absolute path to the node binary.

Run which node in your terminal to find it. It usually looks like:

/root/.nvm/versions/node/v18.16.0/bin/node

Use that full path in your ExecStart.

4. Managing Secrets (.env)

Do not hardcode passwords in your code. You have two ways to pass secrets:

Method A: Inline (Good for 1-2 vars)

Add this to the [Service] section:

Environment="PORT=8080"
Environment="DATABASE_URL=postgres://..."

Method B: Environment File (Best Practice)

If you already have a .env file, you can tell Systemd to read it.

# Loads all variables from this file automatically
EnvironmentFile=/var/www/my-project/.env

Note: Systemd does not support quotes in .env files very well. Ensure your .env looks like `KEY=value`, not `KEY="value"`.

5. Binding Port 80/443

By default, Linux prevents non-root users from opening ports below 1024 (like HTTP port 80). If you try, you'll get EACCES.

Instead of running as root, simply grant the "Capability" to bind ports:

[Service]
# Allows 'my-app' user to bind Port 80/443
AmbientCapabilities=CAP_NET_BIND_SERVICE

6. The Developer Cheat Sheet

Memorize these commands. You will use them every time you deploy.

Command Description
systemctl daemon-reload Run this every time you modify a .service file.
systemctl enable my-app Make it start automatically when VPS reboots.
systemctl start my-app Turn it on right now.
systemctl restart my-app Stop and Start immediately (for updates).
systemctl status my-app Check if it's running or crashed.
journalctl -u my-app -f View live logs (like tail -f). Ctrl+C to exit.

7. Error Decoder

Service failed? Check the status code.

Exit Code Likely Cause & Fix
203 / EXEC Path Error. Systemd cannot find your executable. Check ExecStart. Does that file exist? Is the path absolute?
126 / 127 Permission Denied. Your User cannot execute the script. Run chmod +x on your script.
1 / FAILURE App Error. Your application crashed. Run journalctl -u my-app -n 50 to see the Python/Node stack trace.