Back to tutorials
Tutorial

VPS Security Audit Tutorial (2026): Verify SSH, Firewall, DNS, Mail Ports, and Risky Services Without Downtime

VPS security audit tutorial for 2026: scan open ports, verify SSH, DNS, mail, and lock down risky services without downtime.

By Anurag Singh
Updated on Sep 04, 2026
Category: Tutorial
Share article
VPS Security Audit Tutorial (2026): Verify SSH, Firewall, DNS, Mail Ports, and Risky Services Without Downtime

Most server compromises don’t start with “advanced hacking.” They start with an open port you forgot about, an admin panel exposed to the internet, or SSH still accepting passwords. This VPS security audit tutorial gives you a repeatable, low-risk checklist.

You’ll confirm what’s reachable from the outside. Then you’ll verify what’s actually listening on the server.

You can do it without taking your websites, DNS, or email offline.

You can use this on Ubuntu 24.04/26.04 LTS, Debian 12/13, AlmaLinux 9/10, Rocky 9/10, or CentOS Stream VPS instances.

If you host client sites or run a busy WordPress stack, run it monthly. Also run it after every migration.

What you’ll need (and what we’re auditing)

  • Shell access as root or sudo.
  • A second machine to scan from (your laptop or a small “auditor” VPS).
  • 10–20 minutes for a baseline audit; longer if you find surprises.

We’ll check five areas that drive real hosting risk:

  • Internet exposure: open ports and unexpected services
  • SSH access posture (keys, root login, allowed users, rate limits)
  • Firewall reality (rules that match your hosted services)
  • DNS and email ports (only open if you truly provide those services)
  • Persistence checks: cron/systemd/autostart surprises and recent auth events

If you want the base hardening and ongoing maintenance handled for you, a managed VPS hosting plan from HostMyCode keeps the fundamentals consistent.

If you prefer full control, start with a HostMyCode VPS and run the audit below.

Step 1: Snapshot first (so you can undo fast)

An audit shouldn’t break production. The changes you make afterward can.

Before you touch SSH or networking, take a snapshot in your provider panel or run a quick backup.

If you already use restic, trigger a manual backup now.

If you want a proven offsite workflow, follow our VPS backup automation tutorial and make restore tests part of your routine.

Step 2: Do an outside-in port scan (what attackers see)

Run this from a different network than the server. Substitute your server IP.

export TARGET=203.0.113.10
nmap -Pn -sS -sV -p- --reason --open $TARGET

Now do a second pass that’s “aggressive but safe.” Limit it to the ports you saw open.

nmap -Pn -sC -sV -O -p 22,80,443,25,465,587,110,143,993,995 $TARGET

How to read the results on a hosting VPS:

  • 22/tcp (SSH) is expected.
  • 80/443 are expected for web hosting.
  • 25/465/587 and 110/143/993/995 should only be open if the server actually provides SMTP/IMAP/POP.
  • Unexpected ports (e.g., 2375 Docker API, 3306 MySQL, 5432 Postgres, 9200 Elasticsearch, 11211 Memcached) are almost always mistakes on a hosting VPS.

Quick rule: for every internet-reachable port, you should be able to answer: “Which customers depend on this, and why does it need to be public?”

If you can’t, close it.

Step 3: Confirm listeners on the server (what’s really bound)

SSH into the VPS and list what’s listening.

This catches a classic mistake: a service bound to 0.0.0.0 (public) instead of 127.0.0.1 (local-only).

sudo ss -lntup | awk 'NR==1 || /LISTEN/'

If you want a clearer mapping from port to process:

sudo lsof -nP -iTCP -sTCP:LISTEN

What “normal” often looks like on a basic web VPS:

  • Nginx or Apache on 80/443
  • SSH on 22
  • Database bound to localhost only (e.g., 127.0.0.1:3306)

If a port is open externally but missing from ss/lsof, look at your firewall/NAT path.

If you see a listener you don’t recognize, identify it before removing anything.

Step 4: Map each open port to a business requirement

This step keeps “security work” from turning into downtime.

Make a simple table and keep it with your ops notes.

PortServiceNeeded?Who uses it?Scope
22SSHYesAdmins/AutomationRestricted by IP where possible
80/443HTTP/HTTPSYesAll sitesPublic
25/587/465SMTPMaybeMailboxes / outbound mailPublic (or relay-only)

If you host mail on the same VPS, do it on purpose.

If you only need WordPress transactional mail, a relay is usually the safer option.

Our SMTP relay setup guide walks through a clean setup that helps reduce reputation problems.

Step 5: VPS security audit tutorial — SSH audit (keys, root login, and “who can get in”)

Start by checking the effective SSH configuration and a week of auth events.

That gives you “what should happen” and “what is happening.”

sudo sshd -T | egrep 'port|permitrootlogin|passwordauthentication|pubkeyauthentication|allowusers|allowgroups'
sudo journalctl -u ssh --since "7 days ago" | egrep -i 'failed|invalid user|accepted'

A solid hosting baseline for 2026:

  • Disable password auth after you confirm key-based login works.
  • Disable direct root login; use sudo from an admin user.
  • Limit access with AllowUsers or AllowGroups.

Edit /etc/ssh/sshd_config (or use a drop-in at /etc/ssh/sshd_config.d/99-hardening.conf on systemd-based distros):

sudo nano /etc/ssh/sshd_config.d/99-hardening.conf
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AllowUsers adminops

Validate, then reload without dropping existing connections:

sudo sshd -t
sudo systemctl reload ssh

Keep your current SSH session open until you’ve opened a second session and confirmed key-based login works.

If you want a key workflow that reduces lockout risk, follow our SSH key setup guide.

Step 6: Audit your firewall by intent (not by tool)

You don’t need a full firewall rebuild to get value here.

Confirm two things:

  • Which rules are active
  • Whether they match the “required ports” table you built in Step 4

On Ubuntu/Debian (UFW or nftables)

sudo ufw status verbose
sudo nft list ruleset | sed -n '1,160p'

On AlmaLinux/Rocky (firewalld)

sudo firewall-cmd --state
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all

Checks that catch common hosting mistakes:

  • SSH open to the world even though you could restrict it to office/VPN IPs.
  • Databases exposed publicly (3306/5432). In hosting environments, they should almost always be localhost-only.
  • Mail ports open even though the VPS doesn’t host mail.
  • Admin panels exposed (e.g., 10000 Webmin, 9090 Cockpit) without IP restrictions.

If you want a hosting-safe ruleset pattern (rate limits, persistence, and NAT considerations), reference our IPTables firewall configuration tutorial and adapt it to your distro.

Step 7: Web stack exposure checks (Nginx/Apache/cPanel)

Most compromises in hosting start at the web tier.

The quickest wins usually come from reducing info leaks and tightening TLS and headers.

7.1 Confirm your server isn’t advertising versions

From your laptop:

curl -I https://example.com | egrep -i 'server:|x-powered-by:'

Recommendation: remove or minimize these headers.

On Nginx, set:

server_tokens off;

On Apache, make sure ServerTokens Prod and ServerSignature Off are set (often in /etc/apache2/conf-available/security.conf on Debian/Ubuntu).

7.2 Verify TLS posture quickly

Run:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -issuer -subject

Then use a scanner (or your internal standard) to confirm allowed TLS versions and ciphers.

For specific hardening steps, use our TLS hardening tutorial.

7.3 Add security headers that don’t break apps

Security headers are easy to botch, especially with copy/pasted CSPs.

Start with reasonable defaults, then test.

Our security headers setup guide includes working snippets for Nginx, Apache, and cPanel.

Step 8: DNS and mail: verify you’re not running an accidental mail server

A lot of VPS owners don’t mean to run mail.

Images and packages can still leave mail ports open. That’s a quick way to inherit spam and reputation issues.

8.1 Check if SMTP/IMAP/POP services are running

sudo ss -lntup | egrep ':(25|465|587|110|143|993|995)\b' || echo "No common mail ports listening"

If you see Postfix/Exim/Dovecot and it wasn’t planned, pick a direction and act:

  • Remove/disable mail services and use an SMTP relay for outbound app mail.
  • Commit to mail hosting and configure SPF/DKIM/DMARC, rDNS, and strong auth.

If you do host mail, plan for ongoing maintenance.

Start with deliverability basics in our email deliverability troubleshooting tutorial and verify rDNS with our rDNS setup tutorial.

Step 9: Look for persistence: cron, systemd, and unexpected startup jobs

If your port review turned up something odd, persistence checks help you see how it starts.

They also help you spot extra hooks.

9.1 Systemd services and timers

sudo systemctl list-units --type=service --state=running
sudo systemctl list-timers --all | head -n 40

If something looks unfamiliar:

sudo systemctl status suspicious.service
sudo systemctl cat suspicious.service

9.2 Cron and user scheduled tasks

sudo ls -la /etc/cron.*
sudo crontab -l 2>/dev/null || true
sudo ls -la /var/spool/cron /var/spool/cron/crontabs 2>/dev/null || true

9.3 SSH authorized_keys review

sudo find /home -maxdepth 2 -name authorized_keys -type f -print -exec sed -n '1,3p' {} \;

Remove keys you can’t tie back to a person or a deployment system.

If you manage shared or reseller environments, keep an access register.

Track which key belongs to whom and what it’s used for.

Step 10: Quick vulnerability hygiene checks (patches and exposed admin UIs)

This isn’t a full vulnerability management program.

It’s a quick “are we obviously behind?” pass. It blocks a lot of low-effort compromises.

10.1 Confirm updates and reboot needs

Ubuntu/Debian:

sudo apt update
apt list --upgradable | head
sudo reboot --check 2>/dev/null || true

AlmaLinux/Rocky/CentOS Stream:

sudo dnf check-update || true
sudo needs-restarting -r 2>/dev/null || true

10.2 Check control panels are not world-exposed

If you run cPanel/WHM, Plesk, or DirectAdmin, treat those admin ports like production credentials.

Restrict them by IP (office/VPN) wherever you can.

  • cPanel/WHM: 2083/2087
  • Plesk: 8443
  • DirectAdmin: 2222

If you can’t fully IP-restrict (travel, dynamic IPs), at least enable 2FA and tighten root access policies.

Our cPanel 2FA setup guide is a practical baseline for shared hosting and reseller servers.

Step 11: Document results and convert them into permanent guardrails

Audits don’t help if the results vanish into terminal scrollback.

Capture what you found, what you changed, and what should never change back.

  • Save scan output: nmap results, listener list, firewall state.
  • Create a “required ports” policy for this VPS.
  • Add alerts for new open ports and auth spikes.

If you want a simple way to catch regressions, add external checks plus an on-server health endpoint.

Our uptime monitoring tutorial shows a pragmatic setup that fits hosting workloads.

Step 12: A practical “pass/fail” checklist you can reuse monthly

  • Ports: Only required ports are open externally; no accidental admin ports are public.
  • SSH: Keys only, root login disabled, users/groups restricted; recent failures reviewed.
  • Firewall: Matches your port mapping; databases are not public; admin UIs IP-restricted.
  • Web: TLS is current; security headers are present; version headers minimized.
  • Mail/DNS: Mail ports open only if you host mail; rDNS/SPF/DKIM correct if you do.
  • Persistence: systemd/cron reviewed; unknown services investigated.
  • Updates: Security updates applied; reboots scheduled if required.
  • Backups: You have a recent restore test, not just “a backup job.”

Summary: turn an audit into a safer hosting baseline

A good audit doesn’t chase perfection. It reduces surprises.

If your external scan matches your intent, SSH is keys-only, and only the services you provide are public, you’ve removed the usual entry points.

If you want consistent patching, monitoring, and security hygiene for production hosting, consider HostMyCode’s managed VPS hosting.

If you’re moving into heavier workloads or multi-tenant hosting, stepping up to a dedicated server can simplify isolation and capacity planning.

If you run client sites or revenue-critical WordPress stores, make audits part of normal operations. HostMyCode offers VPS hosting when you want full control, and managed VPS hosting when you’d rather have the platform maintained and the baseline hardening kept consistent.

FAQ

How often should I run this VPS security audit?

Monthly is a realistic cadence for most hosting workloads.

Also run it after migrations, control panel installs, major plugin/theme changes, or any incident involving suspicious logins.

Is it safe to close ports if I’m not sure what they do?

Close ports only after you map them to a service and confirm no customer workflow depends on them.

If you’re unsure, restrict the port to your IP first, then remove it once you’ve confirmed stability.

Should I expose my database port to the internet for remote access?

Usually no.

Bind the database to localhost and use SSH tunnels or a VPN for admin access. Public database ports are a common breach path on hosting servers.

Do I need to run mail on the same VPS as my websites?

Not necessarily.

If you only need outbound mail from WordPress/apps, an SMTP relay reduces deliverability and reputation risk. Run full mail services only if you’re prepared to maintain them.

What’s the fastest way to spot “new” exposure between audits?

Keep a saved “known-good” nmap output and compare it monthly.

Add monitoring that alerts you when a new port becomes reachable or SSH failures spike.