Lab 8.6 - Stop a Service
Objectives
By the end of this lab, you will be able to:
- Identify a process using a specific port
- Find the systemd service associated with a process
- Understand why
killalone is not sufficient to stop a service - Use
systemctl stopanddisableto permanently stop a service - Automate the identification of a service via a bash script
- Use advanced methods to diagnose services
Prerequisites
- Have a running Wiki.js site
- Have nginx installed
- Ubuntu 24.04 installed
- Sudo/root access
- Open terminal
Installing Nginx (if necessary)
sudo apt update
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
sudo systemctl status nginx
Context
Mr. Eric, a system administrator, is trying to install and run an application named Wiki.js on an Ubuntu server. The application is supposed to listen on port 3000, but it is not working. After several unsuccessful attempts, Eric undertakes a series of investigations to identify and resolve the issue.
Step 1 – Checking the Port in Use
Eric starts by checking if port 3000 is already used by another service. He uses the following command:
lsof -i :3000
Result obtained:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 9744 wikijs 22u IPv4 59242 0t0 TCP *:3000 (LISTEN)
A node process is listening on port 3000. He notes the PID: 9744.
Analysis
- COMMAND:
node- The process is a Node.js application - PID:
9744- Process identifier - USER:
wikijs- The user running the process - PORT:
3000- The port in listening
Step 2 – Attempt to Free the Port with kill
Eric attempts to manually stop the process:
# Attempt a graceful stop (SIGTERM)
kill -15 9744
# If that doesn't work, force stop (SIGKILL)
kill -9 9744
Verification
After executing these commands, Eric checks again:
lsof -i :3000
Result:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
node 9842 wikijs 22u IPv4 59243 0t0 TCP *:3000 (LISTEN)
Conclusion: The process is automatically restarted. A new PID (9842) appears. Another entity (probably a systemd service) is restarting it.
Why does the process restart?
The process restarts automatically because it is managed by a systemd service with the Restart=always option in its configuration. Even if you kill the process, systemd immediately restarts it.
Step 3 – Searching for the systemd Service
Eric suspects a systemd service. He therefore seeks to identify its exact name.
Commands Used
# List all services
systemctl list-units --type=service
# List stopped services
systemctl list-units --type=service --state=exited
# List running services
systemctl list-units --type=service --state=running
# Filter to find Wiki services
systemctl list-units --type=service --state=running | grep -i wiki
Searching in Service Files
# List service files by modification date
ls -l --sort=time /etc/systemd/system/
# Filter to find Wiki services
ls -l /etc/systemd/system/ | grep wiki
Cross Searches
# Search in network connections
sudo ss | grep -i wiki
sudo ss | grep -i 3000
# Search Node.js processes
ps aux | grep node
# Search services containing "node"
systemctl | grep node
Winning Commands
The most effective commands to identify the service are:
# Find running Wiki services
systemctl list-units --type=service --state=running | grep -i wiki
# Search Wiki service files
ls -l /etc/systemd/system/ | grep wiki
# View Node.js processes
ps aux | grep node
# Search services containing "node"
systemctl | grep node
Hypothesis confirmed: A service called wikijs.service seems to be responsible for the process.
Step 4 – Verification of the Correlation Between Process, Port, and Service
Eric manually establishes the link between the node process, port 3000, and the service in question:
Identify the Process on the Port
# View the process listening on port 3000
lsof -i :3000
# View all Node.js processes and their ports
sudo lsof -i -P -n | grep node
# View all Wiki.js processes
sudo lsof -i -P -n | grep wiki
Identify the Service File
# Search for the service file
ls -l /etc/systemd/system/ | grep wiki
File identified: wikijs.service
Verify the Service
# View the service status
sudo systemctl status wikijs.service
# View the service logs
sudo journalctl -u wikijs.service --no-pager --lines=50
Step 5 – Definitive Stopping of the Service and Port Release
Eric properly stops the service and disables its automatic restart:
Stop the Service
# Stop the service
sudo systemctl stop wikijs.service
Disable Automatic Restart
# Disable the service at startup
sudo systemctl disable wikijs.service
Final Verification
# Verify that the port is released
lsof -i :3000
# Verify the service status
sudo systemctl status wikijs.service
Result: Port 3000 is now released. The service will no longer restart automatically.
Bonus Step – Complete Scan of Open Ports (Optional)
To ensure the overall state of the server, Eric uses the nmap tool:
# Install nmap
sudo apt install nmap -y
# Scan open ports on localhost
sudo nmap -sT -O localhost
# Scan a specific port
sudo nmap -p 3000 localhost
Reflection Questions
-
Why was port 3000 still blocked despite using
kill?- Explain the role of systemd in service management
- Why is
killalone not enough?
-
What method allows identifying the name of the service using a specific port?
- Describe the method step by step
- Which commands are the most effective?
-
What command could be used to search for all services containing the word
wikiin their name or description?- Propose several approaches
-
Propose a bash script to automate this investigation.
- The script should automatically identify the service associated with a port
Appendix 1: More Advanced Methods
The described method (manual search from the port with lsof, ps, systemctl, etc.) is reliable but artisanal. There are more advanced and automated methods, useful for complex environments, such as production servers or clusters.
1. systemd-cgls or systemd-cgtop
These tools allow visualizing the hierarchy of services and processes controlled by systemd.
# View the complete hierarchy
systemd-cgls
# Filter for Wiki.js
systemd-cgls | grep -i wiki
# Filter for PostgreSQL
systemd-cgls | grep -i postgres
# Filter for Nginx
systemd-cgls | grep -i nginx
# View the hierarchy of a specific service
systemd-cgls /system.slice/wikijs.service
# List the cgroups
ls /sys/fs/cgroup/system.slice/ | grep wiki
# View Wiki processes
ps -ef | grep wiki
2. systemctl status Combined with --property
You can query all services and request to see their MainPID, then cross-check with the port:
# View all MainPID of services
systemctl show --all --property=MainPID --no-pager
# For a specific service
systemctl show wikijs.service --property=MainPID
Then:
# View the PID using port 3000
sudo lsof -i :3000
And you compare the MainPID to the PID using the port.
3. Use fuser to Directly Kill the Process by Port
# Kill the process associated with port 3000
sudo fuser -k 3000/tcp
Warning: This method does not disable the service, so it may restart. It is useful in a temporary script.
4. With ss --processes
# View the process listening on port 3000
sudo ss -lptn 'sport = :3000'
This directly shows:
- the port,
- the protocol,
- the process,
- and sometimes the service name if well configured.
5. Use netstat with --program (if available)
# Install net-tools if necessary
sudo apt update
sudo apt install net-tools
# View the process on port 3000
sudo netstat -tulnp | grep 3000
Allows directly identifying the program using a port. You can cross-check with systemctl:
# View process details
ps -p <PID> -o pid,cmd
6. Via systemd Logs
If the service has started well by systemd, you can do:
# View the service logs
journalctl -u wikijs.service
# View logs in real-time
journalctl -u wikijs.service -f
# View the last lines
journalctl -u wikijs.service --no-pager --lines=50
This shows you the execution history, including the listened port.
Appendix 2: Automate the Identification of the Service
Bash Script: Identify the systemd Service Behind a Port
Create a file recherche_service_port.sh:
#!/bin/bash
# Prompt the user to enter the port number
read -p "Enter the port number (e.g., 3000): " PORT
# Step 1: Get the PID of the process listening on this port
PID=$(sudo lsof -i :$PORT -sTCP:LISTEN -t)
# Check if a PID was found
if [ -z "$PID" ]; then
echo "No process seems to be listening on port $PORT."
exit 1
fi
echo "Process detected on port $PORT: PID = $PID"
# Step 2: Display information about the process
echo "Command related to this PID:"
ps -p $PID -o pid,cmd
# Step 3: Search for the systemd service to which this PID belongs
echo ""
echo "Searching for the corresponding systemd service..."
# Method 1: Search via systemctl
SERVICE=$(systemctl | grep $PID | awk '{print $1}')
# Method 2: If not found, search in service files
if [ -z "$SERVICE" ]; then
echo "Searching in service files..."
# Search the PID in cgroups
for service_file in /etc/systemd/system/*.service; do
if [ -f "$service_file" ]; then
service_name=$(basename "$service_file")
# Check if the service is active and matches the PID
main_pid=$(systemctl show "$service_name" --property=MainPID --value 2>/dev/null)
if [ "$main_pid" = "$PID" ]; then
SERVICE="$service_name"
break
fi
fi
done
fi
# Method 3: Search via cgroup
if [ -z "$SERVICE" ]; then
cgroup=$(cat /proc/$PID/cgroup 2>/dev/null | grep system.slice | cut -d: -f3)
if [ -n "$cgroup" ]; then
SERVICE=$(basename "$cgroup" .service)
fi
fi
if [ -z "$SERVICE" ]; then
echo "No systemd service automatically found for PID $PID."
echo "Manual verification possible with:"
echo " systemctl status <service_name>"
echo "or search in /etc/systemd/system/"
echo ""
echo "Useful commands:"
echo " ps -p $PID -o pid,cmd"
echo " systemctl list-units --type=service | grep -i wiki"
echo " ls -l /etc/systemd/system/ | grep wiki"
else
echo "Detected systemd service: $SERVICE"
echo ""
echo "Service status:"
systemctl status $SERVICE --no-pager -l
echo ""
echo "To stop the service:"
echo " sudo systemctl stop $SERVICE"
echo " sudo systemctl disable $SERVICE"
fi
Usage
- Save the script in a file:
nano recherche_service_port.sh
- Make it executable:
chmod +x recherche_service_port.sh
- Run it:
./recherche_service_port.sh
What You Have Learned
- How to link a port to a process (
lsof) - How to trace back to the service via
systemctlandgrep - How to automate a network diagnostic in Bash
- How to use cgroups to identify services
Summary of Important Commands
| Command | Description |
|---|---|
lsof -i :3000 | View the process listening on port 3000 |
kill -15 PID | Graceful stop of the process (SIGTERM) |
kill -9 PID | Force stop of the process (SIGKILL) |
systemctl list-units --type=service --state=running | List active services |
systemctl stop wikijs.service | Stop a service |
systemctl disable wikijs.service | Disable a service at startup |
systemctl status wikijs.service | View the status of a service |
journalctl -u wikijs.service | View the logs of a service |
sudo ss -lptn 'sport = :3000' | View the process on a port with ss |
sudo fuser -k 3000/tcp | Kill the process on a port |
Final Verification
Ensure you have succeeded in:
- Identifying the process using port 3000
- Understanding why
killalone is not enough - Finding the responsible systemd service
- Properly stopping and disabling the service
- Verifying that the port is released
- Using advanced diagnostic methods
- Creating and using the automation script
- Answering the reflection questions
Next Steps
- Lab 8.1: Managing systemd Services (review)
- Lab 8.5: Multiple Wiki.js Instances (creating multiple instances)
- TP 3: systemd and Process Examination (assessment)
Lab created on: December 2024