Table of Contents

Running "npm start" App As a Systemd Service

If you have a npm app that is launched with “npm start” and want to run it as a systemd service in the background without a user, this is how.
Please keep in mind this is really a tutorial how I personally set this up to run Stickybot. I have no idea what I'm doing with systemd so this setup might not be ideal or secure. But it does work.
Example of full stickybot.service will be at the end of this article.

This is also on a Debian based system, I have no idea how Arch or Fedora would do this. I know it works on Ubuntu Server 20.04 and Debian 11
Update August 2024: This guide has since been confirmed to work on AlmaLinux9. Guide is identical, just replace “APT” with “DNF” for installing system packages.

Using a Service File

  1. Create a text file called myapp.service (in this case stickybot.service) with following content
    [Unit]
    Description=appname
    
    [Service]
    ExecStart=/path/to/main.js
    Restart=always
    User=nobody
    # Note Debian/Ubuntu uses 'nogroup', RHEL/Fedora uses 'nobody'
    Group=nogroup
    Environment=PATH=/usr/bin:/usr/local/bin
    Environment=NODE_ENV=production
    WorkingDirectory=/path/to/
    
    [Install]
    WantedBy=multi-user.target 
  2. Copy this file to /etc/systemd/system
     sudo cp myapp.service /etc/systemd/system 
  3. Edit your main.js to include to contain
     #!/usr/bin/env node 

    on the very first line

  4. (Optional but recommended) Convert this file to Unix format. This should prevent incompatibles from different carriage return behaviors between Windows and Linux
    1. Install dos2unix
       sudo apt install dos2unix
    2. Convert the file
       sudo dos2unix /path/to/main.js 
  5. Start your app
     sudo systemctl start myapp.service 
  6. See status of your app
     sudo systemctl status myapp.service 

Stickybot example

cat /etc/systemd/system/stickybot.service
[Unit]
Description=Stickybot

[Service]
ExecStart=/etc/stickybot/src/main.js
Restart=always
User=nobody
# Note Debian/Ubuntu uses 'nogroup', RHEL/Fedora uses 'nobody'
Group=nogroup
Environment=PATH=/usr/bin:/usr/local/bin
Environment=NODE_ENV=production
WorkingDirectory=/etc/stickybot/

[Install]
WantedBy=multi-user.target

Head of main.js

#!/usr/bin/env node
require('dotenv').config();

const Discord = require('discord.js');
const {Client} = Discord;
const client = new Client();
const fs = require('fs');

dustojnikhummer 2022/12/31 22:10