A server should run only what it needs. Every extra package is something to patch, every extra service uses memory, and every listening port is something to attack. Ubuntu Server images are already fairly lean, but there’s usually more you can trim, especially on a small VPS. Here’s a careful approach.
Why minimal is better
- Security: fewer packages means fewer vulnerabilities, and fewer open ports.
- Resources: more free RAM and CPU for your applications on small plans.
- Simplicity: fewer moving parts to understand, update and debug.
- Faster updates and backups.
1. See what’s running and listening
systemctl list-units --type=service --state=running
ss -tulpn # listening ports and their programs
systemd-analyze blame | head # services slowing down boot
See ss and netstat and systemctl commands.
Every listening service should be one you intend to run. Typical expected ones: sshd, your web server, your database (bound to localhost), and systemd-resolved on 127.0.0.53.
2. See what’s installed
apt list --installed | wc -l
apt-mark showmanual # packages explicitly installed
dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -n | tail -20 # biggest packages
3. Common candidates to remove on a VPS
Review each one before removing it. What’s safe depends on your setup.
| Package / service | Why you might remove it |
|---|---|
snapd |
If you don’t use snaps (it runs a daemon and mounts loop devices). See snap packages |
ModemManager, wpasupplicant, bluez |
No modems, Wi-Fi or Bluetooth on a VPS |
multipath-tools |
Only for SAN multipath storage |
cups, avahi-daemon |
Printing and mDNS, not needed on servers |
apport, whoopsie |
Crash reporting to Canonical |
lxd-agent-loader, open-iscsi |
Only for specific environments |
| Old kernels | apt autoremove keeps the current and one previous |
sudo apt purge snapd ModemManager
sudo apt autoremove --purge
Don’t remove cloud-init without understanding your provider’s setup, nor openssh-server, systemd-*, networking packages (netplan.io), or ubuntu-minimal / ubuntu-server metapackages, without checking what they’d take with them. apt shows the list before removing: read it.
Stop a service without uninstalling: sudo systemctl disable --now avahi-daemon.
4. Install less in the future
APT installs recommended packages by default, which often pulls in extras. Skip them per command:
sudo apt install --no-install-recommends nginx
Or globally (more aggressive; some packages then lack optional features):
# /etc/apt/apt.conf.d/99norecommends
APT::Install-Recommends "false";
Prefer packages over tools that install entire stacks unless you need them, and use containers for apps with many dependencies. See Docker on a VPS.
5. Clean up
sudo apt autoremove --purge
sudo apt clean
sudo journalctl --vacuum-size=200M
dpkg -l | awk '/^rc/{print $2}' | xargs -r sudo dpkg --purge # leftover configs of removed packages
See disk full troubleshooting.
6. Keep it minimal
- Document what you install, and why (a README, or an Ansible playbook). See Ansible playbooks.
- Review
ss -tulpnandapt-mark showmanualevery few months. - Keep automatic security updates for what remains. See automatic security updates.
Before and after
Measure the effect: note free -h, the number of running services, and ss -tulpn output before you start, and compare afterwards. On a small 1–2 GB VPS, removing unneeded daemons often frees 100–300 MB of RAM, and the list of listening ports usually shrinks to exactly the services you meant to expose.
Quick reference
| Task | Command |
|---|---|
| Running services | systemctl list-units --type=service --state=running |
| Listening ports | ss -tulpn |
| Manually installed | apt-mark showmanual |
| Remove + config | apt purge <pkg> && apt autoremove --purge |
| No recommends | apt install --no-install-recommends … |
| Disable a service | systemctl disable --now <svc> |
Related: Ubuntu 24.04 initial server setup and Linux server hardening checklist.