Every running service uses memory and CPU, and every service that listens on a network port is something an attacker can probe. A fresh Ubuntu server already runs a few dozen services, and more accumulate as you install and try software. In this tutorial you will list what is running and listening on Ubuntu 24.04, decide what can go, check dependencies, and then stop, disable, mask or uninstall those services safely, with a way to undo each change.
Prerequisites
To follow this tutorial, you will need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS. The
systemctlcommands work the same on Debian 12 and Rocky Linux 9; only package names differ. - A non-root user with
sudoprivileges. - Access to the server console, in case you disable something required for networking or SSH.
Step 1 - Listing running and enabled services
Two lists matter: what is running now, and what will start at boot. Show running services:
systemctl list-units --type=service --state=running
UNIT LOAD ACTIVE SUB DESCRIPTION
cron.service loaded active running Regular background program processing daemon
dbus.service loaded active running D-Bus System Message Bus
ModemManager.service loaded active running Modem Manager
multipathd.service loaded active running Device-Mapper Multipath Device Controller
polkit.service loaded active running Authorization Manager
rsyslog.service loaded active running System Logging Service
ssh.service loaded active running OpenBSD Secure Shell server
systemd-journald.service loaded active running Journal Service
systemd-networkd.service loaded active running Network Configuration
systemd-resolved.service loaded active running Network Name Resolution
systemd-timesyncd.service loaded active running Network Time Synchronization
unattended-upgrades.service loaded active running Unattended Upgrades Shutdown
...
Show services enabled at boot:
systemctl list-unit-files --type=service --state=enabled
systemd can also start services on demand through socket units and on a schedule through timer units, so list those as well:
systemctl list-units --type=socket
systemctl list-timers
A service that is stopped but has an active socket (for example cups.socket or multipathd.socket) will start again as soon as something connects to it.
Step 2 - Finding services that listen on the network
Network-facing services are the most important to review. ss lists listening sockets and the process that owns each one:
sudo ss -tulpn
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.54:53 0.0.0.0:* users:(("systemd-resolve",pid=612,fd=16))
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=612,fd=14))
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:* users:(("systemd-resolve",pid=612,fd=15))
tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1043,fd=3),("systemd",pid=1,fd=112))
tcp LISTEN 0 4096 0.0.0.0:111 0.0.0.0:* users:(("rpcbind",pid=701,fd=4))
Addresses starting with 127. or [::1] are reachable only from the server itself. Anything bound to 0.0.0.0, [::] or a public IP is reachable from outside unless the firewall blocks it. In this example, rpcbind on port 111 is exposed and only needed for NFS, so it is a candidate for removal.
To find the unit behind a process, pass its PID to systemctl status:
systemctl status 701
Step 3 - Deciding what to disable
For each candidate, answer three questions: what does it do, does anything on this server use it, and is it listening on the network? Read the unit's description and documentation:
systemctl status ModemManager.service
systemctl cat ModemManager.service
Then check what depends on it. --reverse lists the units that would be affected:
systemctl list-dependencies --reverse ModemManager.service
ModemManager.service
● └─multi-user.target
If the only reverse dependency is a target such as multi-user.target, nothing else needs it; the target simply starts it at boot.
These services are commonly present on Ubuntu 24.04 servers and are safe to disable in the situations described. Keep anything you are not sure about.
| Unit | What it does | Disable when |
|---|---|---|
ModemManager.service | Manages 3G/4G/5G modems | Always, on a VPS or server without a modem |
multipathd.service and .socket | Multipath access to SAN storage | The server does not use iSCSI or Fibre Channel multipath storage |
udisks2.service | Automounting of removable disks for desktop tools | Nothing uses it (common on headless servers) |
rpcbind.service and .socket | Port mapper for NFS v3 and other RPC services | The server is not an NFS client or server |
cups.service and .socket | Printing | Always, on a server |
avahi-daemon.service and .socket | mDNS/Bonjour discovery on the local network | Always, on a server |
snapd.service and .socket | Snap packages | snap list shows no snaps you need |
Never disable these on a working server: ssh, systemd-journald, systemd-networkd (or NetworkManager where used), systemd-resolved, systemd-logind, dbus, cron, rsyslog, systemd-timesyncd or chrony, and unattended-upgrades, which installs security updates. On a VPS, also keep cloud-init and qemu-guest-agent if they are installed, since the platform may rely on them for provisioning and graceful shutdown.
Step 4 - Stopping and disabling a service
disable --now stops the service and removes it from boot in one command. Using ModemManager as the example:
sudo systemctl disable --now ModemManager.service
Removed "/etc/systemd/system/multi-user.target.wants/ModemManager.service".
Removed "/etc/systemd/system/dbus-org.freedesktop.ModemManager1.service".
For services that also have a socket unit, disable both, or the socket will start the service again on the next connection:
sudo systemctl disable --now multipathd.service multipathd.socket
Verify the result:
systemctl is-active ModemManager.service
systemctl is-enabled ModemManager.service
inactive
disabled
Step 5 - Masking services that keep coming back
A disabled service can still be started manually, by another unit that requires it, or through D-Bus activation. Masking links the unit to /dev/null so nothing can start it:
sudo systemctl mask --now cups.service cups.socket
Created symlink /etc/systemd/system/cups.service → /dev/null.
Created symlink /etc/systemd/system/cups.socket → /dev/null.
Attempts to start it now fail with a clear message:
sudo systemctl start cups.service
Failed to start cups.service: Unit cups.service is masked.
Use masking for services you have decided must never run. For everything else, disable is enough and easier to reason about.
Step 6 - Removing packages you do not need
If a service will never be used, removing its package is cleaner than disabling it: there is nothing left to patch or accidentally re-enable. Find the package that provides a unit:
dpkg -S /usr/lib/systemd/system/rpcbind.service
rpcbind: /usr/lib/systemd/system/rpcbind.service
Check what else would be removed before confirming:
sudo apt purge rpcbind
apt lists the packages that depend on it. If the list includes something you use, answer n and fall back to disabling the service instead.
For snapd, confirm first that no snaps are installed:
snap list
No snaps are installed yet. Try 'snap install hello-world'.
Then remove it:
sudo apt purge snapd
After removing packages, clean up dependencies that are no longer needed:
sudo apt autoremove --purge
Step 7 - Checking the result
Reboot so the change is tested under real boot conditions:
sudo reboot
After reconnecting, confirm that no services failed and review the listening ports again:
systemctl --failed
sudo ss -tulpn
UNIT LOAD ACTIVE SUB DESCRIPTION
0 loaded units listed.
You can also compare memory use and boot time with what you had before:
free -h
systemd-analyze
systemd-analyze blame | head -n 10
Undoing a change
Every step above is reversible:
sudo systemctl unmask cups.service cups.socket
sudo systemctl enable --now ModemManager.service
sudo apt install rpcbind
A reinstalled package enables its services again through its own post-install scripts, as on a fresh install.
Troubleshooting
- A disabled service is running again after reboot: another unit starts it, or its socket is still enabled. Run
systemctl list-dependencies --reverse name.serviceandsystemctl list-units --type=socket, then disable the socket or mask the service. Failed to disable unit: Unit file name.service does not exist: the name is wrong or the package is not installed. Check withsystemctl list-unit-files | grep -i name.- A disabled service is still listed as
static: static units have no[Install]section and are only started by other units. Disable or mask the unit that pulls it in instead. - Lost network or SSH after a change: log in through the server console and run
sudo systemctl enable --nowon the unit you disabled, for examplesystemd-networkdorssh.
Conclusion
Your server now runs only the services it needs, with fewer processes exposed on the network and a smaller set of software to keep updated. As next steps, restrict the remaining open ports with a firewall such as UFW, harden the SSH configuration, and repeat this audit whenever you install new software or change the server's role.
