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:
| Environment | Linux Account | Directory | Port | MariaDB Database |
|---|---|---|---|---|
| stage | wikijs_stage | /var/www/stage.site1 | 3003 | wikidb_stage |
| qa | wikijs_qa | /var/www/qa.site1 | 3004 | wikidb_qa |
| demo | wikijs_demo | /var/www/demo.site1 | 3005 | wikidb_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:
%iis replaced by the instance (stage, qa, demo)wikijs_%ibecomeswikijs_stage,wikijs_qa,wikijs_demo/var/www/%i.site1becomes/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
1. See All Active Ports and Related Processes
| Command | Comment / Purpose |
|---|---|
sudo ss -tuln | Displays open TCP/UDP ports (listening), without DNS resolution (fast). |
sudo lsof -i -P -n | Displays all ports and the programs using them. |
sudo lsof -i -P -n | grep node | Filters to see only Node.js processes. |
sudo netstat -tulnp | Old command equivalent to ss, also shows PIDs. |
sudo apt install net-tools | Installs netstat (necessary on modern Ubuntu). |
ps aux | grep node | Lists all processes containing "node". |
sudo lsof -i :3000 | Displays the process specifically listening on port 3000. |
sudo apt install nmap | Installs nmap, a port scanner. |
sudo nmap -sT -O localhost | Scans open TCP ports on the local machine. |
2. Node.js Service Management with systemd
| Command | Comment / Purpose |
|---|---|
systemctl | grep node | Searches for services containing "node". |
systemctl list-units --type=service | Lists all running services. |
ls /etc/systemd/system/ | Lists manually installed .service files. |
sudo systemctl stop service-name | Properly stops a service (e.g., wikijs.service). |
sudo systemctl disable service-name | Prevents the service from starting at the next boot. |
sudo rm /etc/systemd/system/service-name.service | Deletes the service file. |
sudo systemctl daemon-reexec | Fully reloads systemd. |
sudo systemctl daemon-reload | Reloads .service files. |
systemctl list-units --type=service | grep -i node | Lists Node.js services (case insensitive). |
systemctl list-units --type=service | grep 3100 | Searches for services associated with port 3100. |
sudo systemctl reset-failed | Resets the state of failed services. |
3. Manually Stopping a Process (if not a service)
| Command | Comment / Purpose |
|---|---|
sudo kill 1064738 | Attempts to kill the process (PID 1064738) properly. |
sudo kill -9 1064738 | Forcefully kills the process (SIGKILL). |
ps -fp 1072723 | Displays details of process 1072723 (extended format). |
sudo ls -l /proc/1072723/exe | Shows 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
| Command | Comment / Purpose |
|---|---|
which pm2 | Checks if pm2 is installed. |
pm2 list | Lists applications managed by PM2. |
pm2 stop all | Stops all PM2 applications. |
pm2 delete all | Deletes all references to applications. |
pm2 unstartup | Disables PM2 auto-start at boot. |
5. Complete Removal of a systemd Service
| Command | Comment / Purpose |
|---|---|
ls /etc/systemd/system/ | grep -i wiki | Filters .service files related to "wiki". |
sudo systemctl stop wikijs.service | Stops the service before deletion. |
sudo systemctl disable wikijs.service | Disables the service. |
sudo rm /etc/systemd/system/wikijs.service | Deletes the service file. |
sudo systemctl daemon-reload | Reloads the systemd config. |
sudo systemctl reset-failed | Resets systemd errors. |
systemctl list-units --type=service | grep wiki | Checks if the service has disappeared. |
systemctl status wikijs.service | Checks 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
- Create the 3 instances (stage, qa, demo) following the steps above
- Verify that all instances are active
- Verify that ports 3003, 3004, 3005 are listening
Exercise 2: Test the Shutdown Methods
For each shutdown method (A, B, C, D, E, F):
- First restart the concerned instance
- Execute the shutdown command
- Verify if the service is really stopped
- Document the result in a table
Exercise 3: Comparison of Methods
Create a comparative table:
| Method | Command | Works? | Why? | Recommended? |
|---|---|---|---|---|
| A | systemctl stop | ? | ? | ? |
| B | systemctl disable | ? | ? | ? |
| C | killall wikijs | ? | ? | ? |
| D | fuser -k port/tcp | ? | ? | ? |
| E | lsof -ti:port | xargs kill -9 | ? | ? | ? |
| F | systemctl reload | ? | ? | ? |
Reflection Questions
-
Why does
systemctl disablenot stop a service that is already running?- Explain the difference between
stopanddisable
- Explain the difference between
-
What are the risks of using
killallto stop services?- Provide an example scenario where this could cause problems
-
Why does
systemctl reloadnot cut the service?- Explain the difference between
reloadandrestart
- Explain the difference between
-
What is the difference between
killandkill -9?- In which cases would you use each of these commands?
-
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
Recommended Methods ✅
systemctl stop wikijs@instance- Proper shutdown via systemdfuser -k port/tcp- Shutdown via port (works but less clean)lsof -ti:port \| xargs kill -9- Forced shutdown (last resort)
Methods to Avoid ❌
systemctl disable- Does not stop, only disables at startupsystemctl reload- Reloads config but does not cutkillall 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.ymlfiles 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