Skip to main content

Lab 8.5 - Supplementary Exercise: Create 3 New Wiki.js Services and Test Different Ways to Stop Them

Objectives​

By the end of this lab, you will be able to:

  • Master the creation of additional instances from a systemd template (wikijs@.service)
  • Compare several "shutdown" commands and identify which ones work correctly (and why)
  • Use systemd templates to manage multiple instances of the same application
  • Identify and stop Node.js processes in different ways
  • Understand the differences between stop, disable, kill, and other shutdown methods

Prerequisites​

  • Ubuntu 24.04 installed
  • Sudo/root access
  • Wiki.js already installed (at least one instance)
  • Basic knowledge of systemd and MariaDB
  • Open terminal

Overview​

In this lab, you will create 3 new Wiki.js instances (stage, qa, demo) using a systemd template. Then, you will test different methods to stop these services and understand why some work and others do not.

Instance Architecture:

EnvironmentLinux AccountDirectoryPortMariaDB Database
stagewikijs_stage/var/www/stage.site13003wikidb_stage
qawikijs_qa/var/www/qa.site13004wikidb_qa
demowikijs_demo/var/www/demo.site13005wikidb_demo

Part 1: Preparing the systemd Template​

Step 1: Create the systemd Template​

If you do not already have a template, create it:

sudo nano /etc/systemd/system/wikijs@.service

Template Content:

[Unit]
Description=Wiki.js Instance %i
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/node server
Restart=always
User=wikijs_%i
Environment=NODE_ENV=production
WorkingDirectory=/var/www/%i.site1

[Install]
WantedBy=multi-user.target

Explanation:

  • %i is replaced by the instance (stage, qa, demo)
  • wikijs_%i becomes wikijs_stage, wikijs_qa, wikijs_demo
  • /var/www/%i.site1 becomes /var/www/stage.site1, etc.

Step 2: Reload systemd​

sudo systemctl daemon-reload

Part 2: Creating the Three New Instances​

Step 1: Create System Users​

# Create users for each instance
sudo adduser --system --group wikijs_stage
sudo adduser --system --group wikijs_qa
sudo adduser --system --group wikijs_demo

# Allow login with bash
sudo usermod -s /bin/bash wikijs_stage
sudo usermod -s /bin/bash wikijs_qa
sudo usermod -s /bin/bash wikijs_demo

Step 2: Create Directories​

# Create directories for each instance
sudo mkdir -p /var/www/stage.site1
sudo mkdir -p /var/www/qa.site1
sudo mkdir -p /var/www/demo.site1

# Set ownership
sudo chown -R wikijs_stage:wikijs_stage /var/www/stage.site1
sudo chown -R wikijs_qa:wikijs_qa /var/www/qa.site1
sudo chown -R wikijs_demo:wikijs_demo /var/www/demo.site1

Step 3: Create MariaDB Databases​

# Connect to MariaDB
sudo mysql -u root -p

In the MariaDB shell:

-- Create databases
CREATE DATABASE wikidb_stage;
CREATE DATABASE wikidb_qa;
CREATE DATABASE wikidb_demo;

-- Create users
CREATE USER 'wikidb_stage_user'@'localhost' IDENTIFIED BY 'password_stage';
CREATE USER 'wikidb_qa_user'@'localhost' IDENTIFIED BY 'password_qa';
CREATE USER 'wikidb_demo_user'@'localhost' IDENTIFIED BY 'password_demo';

-- Grant privileges
GRANT ALL PRIVILEGES ON wikidb_stage.* TO 'wikidb_stage_user'@'localhost';
GRANT ALL PRIVILEGES ON wikidb_qa.* TO 'wikidb_qa_user'@'localhost';
GRANT ALL PRIVILEGES ON wikidb_demo.* TO 'wikidb_demo_user'@'localhost';

FLUSH PRIVILEGES;
EXIT;

Step 4: Download and Install Wiki.js for Each Instance​

For Stage (port 3003)​

# Log in as wikijs_stage
sudo su - wikijs_stage

# Go to the directory
cd /var/www/stage.site1

# Download Wiki.js
wget https://github.com/Requarks/wiki/releases/latest/download/wiki-js.tar.gz

# Extract
tar xzf wiki-js.tar.gz

# Remove the archive
rm wiki-js.tar.gz

# Copy the configuration file
cp config.sample.yml config.yml

# Edit the configuration
nano config.yml

Configuration for stage:

port: 3003
bindIP: 0.0.0.0
db:
type: mariadb
host: localhost
port: 3306
user: wikidb_stage_user
pass: password_stage
db: wikidb_stage
ssl: false

Save and exit. Then:

exit

For QA (port 3004)​

sudo su - wikijs_qa
cd /var/www/qa.site1
wget https://github.com/Requarks/wiki/releases/latest/download/wiki-js.tar.gz
tar xzf wiki-js.tar.gz
rm wiki-js.tar.gz
cp config.sample.yml config.yml
nano config.yml

Configuration for qa:

port: 3004
bindIP: 0.0.0.0
db:
type: mariadb
host: localhost
port: 3306
user: wikidb_qa_user
pass: password_qa
db: wikidb_qa
ssl: false

Save and exit. Then:

exit

For Demo (port 3005)​

sudo su - wikijs_demo
cd /var/www/demo.site1
wget https://github.com/Requarks/wiki/releases/latest/download/wiki-js.tar.gz
tar xzf wiki-js.tar.gz
rm wiki-js.tar.gz
cp config.sample.yml config.yml
nano config.yml

Configuration for demo:

port: 3005
bindIP: 0.0.0.0
db:
type: mariadb
host: localhost
port: 3306
user: wikidb_demo_user
pass: password_demo
db: wikidb_demo
ssl: false

Save and exit. Then:

exit

Step 5: Enable and Start the Services​

# Enable and start the three instances
sudo systemctl enable --now wikijs@stage
sudo systemctl enable --now wikijs@qa
sudo systemctl enable --now wikijs@demo

Step 6: Control​

# Check the status of each instance
sudo systemctl status wikijs@stage --no-pager
sudo systemctl status wikijs@qa --no-pager
sudo systemctl status wikijs@demo --no-pager

# Check that the ports are listening
sudo ss -tlnp | grep -E '3003|3004|3005'

Part 3: Identify Processes and Ports​

Appendix 1: Commands to Identify Node.js Processes​

1. Display All Node Processes with the systemd Unit​

ps -eo pid,user,unit,cmd | grep -w node

2. Compact Version: PID + Command Line​

pgrep -a node

3. Loop: For Each Node PID, Show the Ports It Listens To​

for pid in $(pgrep node); do lsof -Pan -p "$pid" -i; done

4. Directly Display All Open Node Sockets​

ss -tlnp | grep node

5. For a Specific PID​

# Replace 1234 with the actual PID
systemctl status --pid=1234
cat /proc/1234/cgroup | grep system.slice

Part 4: Test Different Shutdown Methods​

Shutdown Methods to Test​

Command A – Proper Shutdown via systemd​

# Proper shutdown of the stage instance
sudo systemctl stop wikijs@stage

Analysis: This command properly stops the service via systemd. It is the recommended method.

Command B – Logical Error: Disables for Later, Does Not Stop​

# Disables the service but does not stop it immediately
sudo systemctl disable wikijs@qa

Analysis: This command disables the service at startup but does not stop it if it is already running. The service continues to run until the next reboot.

Command C – ⚠️ Very Risky: Kills All "wikijs" Processes​

# Kills all processes named "wikijs"
sudo killall wikijs

Analysis: This command is risky because it kills all processes matching the name, indiscriminately. It can affect unrelated processes.

Command D – Indirect Shutdown via the Demo Instance Port (3005)​

# Kills the process listening on port 3005
sudo fuser -k 3005/tcp

Analysis: This command identifies and kills the process using port 3005. It works but is less clean than systemctl.

Command E – Forced Shutdown of QA (port 3004) via lsof + kill -9​

# Finds the PID listening on 3004 and kills it
sudo lsof -ti:3004 | xargs sudo kill -9

Analysis: This command finds the PID of the process listening on port 3004 and forcefully kills it. It works but uses SIGKILL (brute force).

Command F – Reload ≠ Stop: Does Not Cut the Service​

# Reloads the configuration but does not cut the service
sudo systemctl reload wikijs@demo

Analysis: This command reloads the service configuration but does not stop it. The service continues to run.

Correct Answers Only​

The commands that actually stop the services are:

# Command A - Proper shutdown
sudo systemctl stop wikijs@stage

# Command D - Shutdown via port
sudo fuser -k 3005/tcp

# Command E - Forced shutdown via port
sudo lsof -ti:3004 | xargs sudo kill -9

Verification of Shutdown​

# Verify that no service is still active
sudo systemctl status wikijs@stage
sudo systemctl status wikijs@qa
sudo systemctl status wikijs@demo

# See if any ports are still being listened to
sudo ss -tlnp | grep node

# Check Node.js processes
ps aux | grep node

Part 5: Extension (Optional)​

Properly Restart All Instances​

# Restart all instances in one command
sudo systemctl restart wikijs@{stage,qa,demo}

Review All Currently Active Node.js Ports​

# See all Node.js ports being listened to
sudo lsof -iTCP -sTCP:LISTEN | grep node

Verify that All Ports Are Freed After a Shutdown​

# Stop all instances
sudo systemctl stop wikijs@{stage,qa,demo}

# Verify that the ports are free
sudo ss -tlnp | egrep '3003|3004|3005'

Appendix 2: Useful Commands for Service Management​

CommandComment / Purpose
sudo ss -tulnDisplays open TCP/UDP ports (listening), without DNS resolution (fast).
sudo lsof -i -P -nDisplays all ports and the programs using them.
sudo lsof -i -P -n | grep nodeFilters to see only Node.js processes.
sudo netstat -tulnpOld command equivalent to ss, also shows PIDs.
sudo apt install net-toolsInstalls netstat (necessary on modern Ubuntu).
ps aux | grep nodeLists all processes containing "node".
sudo lsof -i :3000Displays the process specifically listening on port 3000.
sudo apt install nmapInstalls nmap, a port scanner.
sudo nmap -sT -O localhostScans open TCP ports on the local machine.

2. Node.js Service Management with systemd​

CommandComment / Purpose
systemctl | grep nodeSearches for services containing "node".
systemctl list-units --type=serviceLists all running services.
ls /etc/systemd/system/Lists manually installed .service files.
sudo systemctl stop service-nameProperly stops a service (e.g., wikijs.service).
sudo systemctl disable service-namePrevents the service from starting at the next boot.
sudo rm /etc/systemd/system/service-name.serviceDeletes the service file.
sudo systemctl daemon-reexecFully reloads systemd.
sudo systemctl daemon-reloadReloads .service files.
systemctl list-units --type=service | grep -i nodeLists Node.js services (case insensitive).
systemctl list-units --type=service | grep 3100Searches for services associated with port 3100.
sudo systemctl reset-failedResets the state of failed services.

3. Manually Stopping a Process (if not a service)​

CommandComment / Purpose
sudo kill 1064738Attempts to kill the process (PID 1064738) properly.
sudo kill -9 1064738Forcefully kills the process (SIGKILL).
ps -fp 1072723Displays details of process 1072723 (extended format).
sudo ls -l /proc/1072723/exeShows the actual binary executed by the process.
sudo cat /proc/1072723/cmdline | tr '\0' ' 'Displays the exact command that launched the process.

4. Detection and Stopping of Processes Managed by PM2​

CommandComment / Purpose
which pm2Checks if pm2 is installed.
pm2 listLists applications managed by PM2.
pm2 stop allStops all PM2 applications.
pm2 delete allDeletes all references to applications.
pm2 unstartupDisables PM2 auto-start at boot.

5. Complete Removal of a systemd Service​

CommandComment / Purpose
ls /etc/systemd/system/ | grep -i wikiFilters .service files related to "wiki".
sudo systemctl stop wikijs.serviceStops the service before deletion.
sudo systemctl disable wikijs.serviceDisables the service.
sudo rm /etc/systemd/system/wikijs.serviceDeletes the service file.
sudo systemctl daemon-reloadReloads the systemd config.
sudo systemctl reset-failedResets systemd errors.
systemctl list-units --type=service | grep wikiChecks if the service has disappeared.
systemctl status wikijs.serviceChecks if the service still exists.
ls -l /etc/systemd/system/Complete list for manual verification.
grep -r ExecStart /etc/systemd/system/Searches for start lines in all services.

Appendix 3: Comprehensive List of Commands​

Commands to View Ports​

sudo ss -tuln
sudo lsof -i -P -n
sudo lsof -i -P -n | grep node
sudo netstat -tulnp
sudo apt install net-tools
ps aux | grep node
sudo lsof -i :3000
sudo apt install nmap
sudo nmap -sT -O localhost

systemd Commands​

systemctl | grep node
systemctl list-units --type=service
ls /etc/systemd/system/
sudo systemctl stop service-name
sudo systemctl stop wikijs.service
sudo systemctl disable service-name
sudo rm /etc/systemd/system/service-name.service
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
systemctl | grep 3100
systemctl | grep node
sudo systemctl stop wikijs.service

kill Commands​

sudo kill 1064738
sudo kill -9 1064738
sudo ss -tuln | grep 3100
sudo lsof -i :3100

PM2 Commands​

which pm2 && pm2 list
pm2 stop all
pm2 delete all
pm2 unstartup

Diagnostic Commands​

sudo systemctl list-units --type=service | grep -i node
ps aux | grep node
ps -fp 1072723
sudo ls -l /proc/1072723/exe
sudo cat /proc/1072723/cmdline | tr '\0' ' '
ls /etc/systemd/system/ | grep -i wiki
ls /lib/systemd/system/ | grep -i wiki
grep -r 3100 /etc/systemd/system/

Removal Commands​

sudo systemctl stop name.service
sudo systemctl disable name.service
sudo systemctl daemon-reload
sudo systemctl reset-failed
ls /etc/systemd/system/
ls /etc/systemd/system/ | grep -i wiki
sudo systemctl stop wikijs.service
sudo systemctl disable wikijs.service
sudo rm /etc/systemd/system/wikijs.service
sudo systemctl daemon-reload
sudo systemctl reset-failed
systemctl list-units --type=service | grep wiki
systemctl status wikijs.service
ls -l /etc/systemd/system/
grep -r ExecStart /etc/systemd/system/

Practical Exercises​

Exercise 1: Create and Start the 3 Instances​

  1. Create the 3 instances (stage, qa, demo) following the steps above
  2. Verify that all instances are active
  3. Verify that ports 3003, 3004, 3005 are listening

Exercise 2: Test the Shutdown Methods​

For each shutdown method (A, B, C, D, E, F):

  1. First restart the concerned instance
  2. Execute the shutdown command
  3. Verify if the service is really stopped
  4. Document the result in a table

Exercise 3: Comparison of Methods​

Create a comparative table:

MethodCommandWorks?Why?Recommended?
Asystemctl stop???
Bsystemctl disable???
Ckillall wikijs???
Dfuser -k port/tcp???
Elsof -ti:port | xargs kill -9???
Fsystemctl reload???

Reflection Questions​

  1. Why does systemctl disable not stop a service that is already running?

    • Explain the difference between stop and disable
  2. What are the risks of using killall to stop services?

    • Provide an example scenario where this could cause problems
  3. Why does systemctl reload not cut the service?

    • Explain the difference between reload and restart
  4. What is the difference between kill and kill -9?

    • In which cases would you use each of these commands?
  5. Why use a systemd template (wikijs@.service) rather than creating 3 separate service files?

    • What are the advantages and disadvantages of each approach?

Summary of Shutdown Methods​

  1. systemctl stop wikijs@instance - Proper shutdown via systemd
  2. fuser -k port/tcp - Shutdown via port (works but less clean)
  3. lsof -ti:port \| xargs kill -9 - Forced shutdown (last resort)

Methods to Avoid ❌​

  1. systemctl disable - Does not stop, only disables at startup
  2. systemctl reload - Reloads config but does not cut
  3. killall wikijs - Too risky, can affect other processes

Final Verification​

Ensure you have successfully:

  • Created the systemd template wikijs@.service
  • Created the 3 system users (wikijs_stage, wikijs_qa, wikijs_demo)
  • Created the 3 directories and installed Wiki.js in each
  • Created the 3 MariaDB databases
  • Configured the config.yml files with the correct ports
  • Enabled and started the 3 instances
  • Verified that ports 3003, 3004, 3005 are listening
  • Tested all shutdown methods
  • Understood why some methods work and others do not
  • Answered the reflection questions

Next Steps​

  • Lab 8.1: systemd Service Management (review)
  • Lab 8.2: Custom Services (deep dive)
  • TP 2: NGINX Reverse Proxy (to expose instances via a reverse proxy)

Lab created on: December 2024