How to Turn Off Standalone Services in Linux: Complete Service Disabling and Security Hardening Guide

how to turn off standalone services in linux

Every server I’ve ever inherited from someone else has had at least one service running that nobody could explain. Cups printing support on a headless server. Bluetooth on a rack-mounted machine that will never be within thirty feet of a Bluetooth device. An NFS client stack fully loaded on a box that’s never touched an NFS share. Turning off standalone services you don’t need isn’t just tidiness — it directly reduces attack surface, and it’s one of the highest-value, lowest-risk hardening steps available on any Linux system.

What “Standalone Service” Means

A standalone service, in this context, is a daemon that runs continuously and independently, managed directly by the init system (systemd on virtually every current distro) — as opposed to a service launched on-demand by a super-server like xinetd, or spun up transiently by socket activation. Standalone services are the persistent background processes you’d see with systemctl list-units --type=service.

Step 1: Inventory What’s Actually Running

Before disabling anything, know your baseline.

systemctl list-units --type=service --state=running

For a full list including inactive/disabled services:

systemctl list-unit-files --type=service

Cross-reference with what’s actually listening on the network — a strong signal for what’s worth scrutinizing first:

sudo ss -tulnp

Example output:

Netid  State   Local Address:Port   Process
tcp    LISTEN  0.0.0.0:22           sshd
tcp    LISTEN  0.0.0.0:631          cupsd
udp    LISTEN  0.0.0.0:5353         avahi-daemon

If this is a headless server, cupsd (printing) and avahi-daemon (mDNS/Bonjour-style service discovery) are both classic examples of services that add attack surface for zero operational benefit.

Step 2: Understand the Difference Between Stop, Disable, and Mask

This distinction trips people up constantly, so it’s worth being precise:

sudo systemctl stop SERVICE      # stops it right now, but it will start again on next boot if enabled
sudo systemctl disable SERVICE   # prevents it from starting on boot, but doesn't stop it if currently running
sudo systemctl mask SERVICE      # prevents it from being started at all, even manually or as a dependency of another unit

For genuinely turning off a service you don’t need, you typically want both stop and disable together:

sudo systemctl stop cups
sudo systemctl disable cups

Or in one command:

sudo systemctl disable --now cups

mask is the strongest option — it symlinks the unit file to /dev/null, so nothing can start it even accidentally as a dependency of something else. Reach for this when a service is not just unwanted but something you want to guarantee can never come back without deliberate intervention:

sudo systemctl mask cups

To reverse a mask later:

sudo systemctl unmask cups

Step 3: Verify a Service Is Actually Stopped

systemctl status cups

Confirm it’s no longer listening:

sudo ss -tulnp | grep cups

Confirm it won’t reappear on next boot:

systemctl is-enabled cups
# should print: disabled  (or "masked" if you masked it)

Common Services Worth Reviewing on a Server

This isn’t a “disable all of these blindly” list — it’s a starting point for asking “do I actually need this here”:

ServiceTypical purposeUsually needed on a headless server?
cups/cups-browsedPrinting supportRarely
avahi-daemonmDNS/Bonjour service discoveryRarely
bluetoothBluetooth stackAlmost never on server hardware
ModemManagerCellular/modem managementAlmost never
rpcbind/nfs-serverNFS/RPC servicesOnly if actually serving/mounting NFS
postfix/sendmailLocal mail transfer agentOnly if the box actually sends mail (many distros install one by default for system notifications)
telnet/rsh/vsftpd (anonymous)Legacy plaintext remote accessEssentially never — should be SSH/SFTP instead
snapdSnap package managementDepends on whether you use snap packages at all

Check what a given service actually is before disabling it if you’re unsure:

systemctl status SERVICE
man SERVICE 2>/dev/null

Disabling Multiple Services at Once

sudo systemctl disable --now cups avahi-daemon bluetooth ModemManager

Auditing and Disabling Legacy Standalone Daemons (Non-systemd Remnants)

On systems with SysV init compatibility scripts still present (common on older RHEL/CentOS systems even under systemd), you might also encounter services managed through /etc/init.d/ and chkconfig:

chkconfig --list
sudo chkconfig SERVICE off
sudo service SERVICE stop

Modern systemd transparently wraps most of these, so systemctl disable --now SERVICE typically works even for these legacy-style services, but chkconfig --list is still useful for surfacing what’s actually configured to run.

A Practical Server Hardening Pass

Here’s the sequence I actually run when hardening a fresh server image:

# See what's running and listening
systemctl list-units --type=service --state=running
sudo ss -tulnp

# Disable common unnecessary services on a headless box (review this list per your actual use case first!)
sudo systemctl disable --now cups cups-browsed avahi-daemon bluetooth ModemManager 2>/dev/null

# Confirm nothing unexpected is still listening afterward
sudo ss -tulnp

# Check for any remaining SysV-style legacy services
chkconfig --list 2>/dev/null

I always run the ss -tulnp check both before and after — the “after” check confirms the disabling actually took effect and nothing else quietly restarted the service as a dependency.

Handling Services That Restart Themselves

Some services get re-triggered by socket activation, timers, or another unit’s dependency chain, even after you’ve disabled them. Diagnose with:

systemctl status SERVICE
journalctl -u SERVICE --since "10 minutes ago"

Look specifically for “Triggered by” or dependency information in the status output — if another unit (like a .socket or .path unit) is what’s actually starting it, you need to disable that unit as well:

systemctl list-dependencies SERVICE --reverse
sudo systemctl disable --now SERVICE.socket

Automating This as Part of Provisioning

For fleets of servers, doing this by hand every time doesn’t scale. A simple hardening script:

#!/bin/bash
UNWANTED_SERVICES=(cups cups-browsed avahi-daemon bluetooth ModemManager)

for svc in "${UNWANTED_SERVICES[@]}"; do
    if systemctl list-unit-files | grep -q "^${svc}.service"; then
        systemctl disable --now "$svc" 2>/dev/null
        echo "Disabled: $svc"
    fi
done

For configuration management at scale, tools like Ansible make this declarative and idempotent:

- name: Disable unnecessary services
  ansible.builtin.systemd:
    name: "{{ item }}"
    state: stopped
    enabled: false
  loop:
    - cups
    - avahi-daemon
    - bluetooth

Understanding systemd Unit Dependency Chains Before You Disable Anything

The single most common mistake in a service-disabling pass isn’t disabling something genuinely needed — it’s disabling something that a different, more important service quietly depends on, and only discovering that dependency when the important thing breaks later. Before disabling anything you’re not already confident about, check its reverse dependencies:

systemctl list-dependencies --reverse cups

This shows what would be affected if cups stopped — if the output includes something you actually care about, that’s your signal to investigate further before proceeding, rather than a green light to disable freely.

It’s also worth understanding the different kinds of unit relationships systemd tracks, since not all of them mean “requires”:

  • Requires= — a hard dependency; if the required unit fails, the dependent unit is stopped too.
  • Wants= — a soft dependency; the wanted unit is started alongside, but its failure doesn’t stop the dependent unit.
  • After=/Before= — pure ordering, with no dependency implication at all — a unit can be ordered after another without requiring it to even be running.
systemctl show cups -p Requires -p Wants -p RequiredBy -p WantedBy

Reading these fields directly, rather than guessing from the service name alone, is the difference between a confident disabling decision and one you’ll be debugging at an inconvenient hour later.

Socket-Activated and Path-Activated Services: A Special Case

Some services aren’t started directly at boot at all — they’re started on-demand the first time something connects to a socket or a watched file/path changes, via a corresponding .socket or .path unit. Disabling the .service unit alone in these cases often has no effect, because it’s the socket/path unit doing the actual triggering.

systemctl list-units --type=socket --state=active
systemctl list-units --type=path --state=active

If you disable cups.service but cups.socket remains enabled, the very next print-related connection attempt will start cups.service right back up, regardless of its own enabled/disabled state — the socket unit’s activation bypasses that check. The fix is to disable both:

sudo systemctl disable --now cups.socket cups.path cups.service 2>/dev/null

This is a genuinely common source of “I disabled it but it keeps coming back” confusion, and checking for a same-named .socket or .path unit is the first thing worth doing whenever a disable doesn’t stick.

A More Thorough Server Hardening Checklist

Beyond the handful of commonly-cited services (cups, avahi, bluetooth), a more thorough pass through a fresh server image worth walking through explicitly:

# Full inventory of enabled services, sorted for readability
systemctl list-unit-files --type=service --state=enabled | sort

# Cross-reference against what's actually listening
sudo ss -tulnp

# Check for services that are running but weren't part of the base image
# (useful after inheriting a server someone else configured)
rpm -qa --last | head -20     # RHEL — recently installed packages, oldest install activity first
grep " install " /var/log/dpkg.log | tail -20   # Debian equivalent

Beyond the obvious desktop-oriented services, it’s worth specifically reviewing:

  • rpcbind — required for NFS and some legacy RPC-based services; if nothing on the box actually serves or mounts NFS, this can typically be disabled, closing off a service that’s had a long history of security advisories.
  • postfix/sendmail — many distros install a local MTA by default purely so system utilities and cron can send local notification mail; if nothing on the box actually needs to send external mail, consider configuring it in local-only mode rather than leaving it listening on all interfaces, or disabling it entirely if local mail delivery genuinely isn’t needed.
  • snapd — relevant primarily on Ubuntu; if you don’t use snap packages at all, this can often be removed rather than merely disabled.
  • cockpit — a web-based server management UI on some RHEL-family installs; convenient, but represents meaningful attack surface (a full web application and its own auth stack) if you’re not actually using it for management.

Handling Firmware/Hardware-Triggered Services Carefully

A category worth extra caution: services tied to physical hardware detection (like udisks2 for removable media, or various hardware-monitoring daemons). These are usually harmless to disable on a headless server that will never have removable media inserted, but on physical hardware (as opposed to a VM/cloud instance), some of these also feed into legitimate hardware health monitoring — disabling blindly on bare-metal without checking what depends on it can occasionally remove monitoring capability you actually wanted.

systemctl status smartd    # disk health monitoring — usually worth KEEPING on physical hardware
systemctl status lm-sensors 2>/dev/null    # temperature/voltage sensors — same caution applies

The general principle: services tied to network exposure (listening ports, discovery protocols) are almost always safe disable candidates on a server that doesn’t need them; services tied to local hardware health monitoring deserve a second look specifically on physical hardware, since disabling them trades away visibility rather than just reducing attack surface.

Automating the Audit Itself, Not Just the Disabling

Beyond the one-time disabling script shown earlier, it’s worth having a standing audit script that reports (without acting) on anything that’s changed since the last known-good baseline — useful for catching a service that got silently re-enabled by a package update or a colleague’s troubleshooting session:

#!/bin/bash
BASELINE="/etc/service-baseline.txt"
CURRENT=$(systemctl list-unit-files --type=service --state=enabled | sort)

if [ ! -f "$BASELINE" ]; then
    echo "$CURRENT" > "$BASELINE"
    echo "Baseline created."
    exit 0
fi

diff <(cat "$BASELINE") <(echo "$CURRENT")

Running this periodically (via cron or a configuration-management drift check) turns “turn off unnecessary services” from a one-time hardening pass into an ongoing, low-effort control rather than something that quietly erodes the first time someone installs a new package that pulls in an unwanted service as a dependency.

Troubleshooting

Disabled a service and something else broke — check reverse dependencies before disabling anything on a production system you don’t fully understand yet:

systemctl list-dependencies --reverse SERVICE

Service keeps coming back after disable — check for socket/path/timer units and any other unit that lists it as a dependency, as covered above.

Not sure if a service is safe to disable — check its actual resource usage and recent logs before deciding; a service that’s been silently running for years with zero connections and zero log activity is a much safer disable candidate than one with regular recent activity:

journalctl -u SERVICE --since "30 days ago" | tail -50

Security and Performance Implications

Every standalone service running is: additional code that could contain a vulnerability, additional listening ports that widen the network attack surface, additional memory and CPU consumed at idle, and additional complexity when auditing what a system actually does. None of that is hypothetical — unused services with old, unpatched code are a recurring theme in real-world compromises, precisely because nobody’s paying attention to a thing they forgot was even running. Disabling what you don’t use is one of the few security improvements that costs essentially nothing in terms of functionality lost.

Summary

Turning off standalone services in Linux comes down to three systemd commands — stop, disable, and mask — applied deliberately after actually auditing what’s running and what’s listening on the network. The habit worth building is doing this audit as a routine part of provisioning any new server, not as a one-time cleanup exercise, and always verifying with ss -tulnp and systemctl is-enabled that a change actually took effect and stuck across a reboot.

References

Total
4
Shares

Leave a Reply

Previous Post
gpg command in Linux and it perimeters

gpg Command in Linux: Complete Guide to GNU Privacy Guard Encryption and Parameters

Next Post
how to configure internet super server in linux

How to Configure Internet Super Server (xinetd) in Linux: Complete Service Management Guide

Related Posts