
“My server is acting weird” isn’t actionable. In hosting, minutes matter. You need a repeatable flow that stops damage first, preserves evidence second, and restores service third. This VPS incident response tutorial gives you a practical playbook for Ubuntu/Debian and AlmaLinux/Rocky hosting servers—without turning your night into a forensic research project.
Your job is simple to state and hard to do: keep customer sites and email from getting worse. At the same time, collect enough facts to explain what happened and prevent a repeat.
What you’ll need (and what to avoid doing)
- Out-of-band access: your VPS provider console or rescue mode. If SSH is compromised, don’t assume it’s safe.
- A clean admin workstation with SSH keys and a simple notes file.
- Disk space for evidence (1–2 GB is often enough for logs and snapshots).
Avoid these common mistakes:
- Don’t reboot immediately. You’ll wipe volatile clues: running processes, live network connections, and active footholds.
- Don’t “just run updates” first. Patching can overwrite evidence and won’t remove persistence by itself.
- Don’t trust a single scanner. Treat tool output as leads, not final answers.
If you’re running customer workloads and want predictable performance under pressure, start on a plan with headroom and reliable console access.
A HostMyCode VPS is a good fit for hands-on server admins. If you’d rather offload patching and baseline hardening, look at managed VPS hosting.
Step 1: Confirm the incident (fast triage checklist)
Start with signals you can verify in under 10 minutes. You’re answering two questions: “is this real?” and “what’s affected?” Root cause can wait.
Quick indicators
- Unexpected CPU spikes or load averages with no traffic change
- New listening ports (especially high ports) or a surprise reverse proxy
- Outbound email spikes, queue backlogs, or blacklisting reports
- Suspicious new cron jobs, systemd timers, or unknown services
- New users, new SSH keys, or sudoers changes
Commands (Ubuntu/Debian + RHEL-family)
# Who is logged in, and from where?
who
w
last -a | head -n 30
# Recent auth activity
sudo journalctl -u ssh --since "2 hours ago" --no-pager | tail -n 200
sudo grep -E "Failed password|Accepted|Invalid user" /var/log/auth.log 2>/dev/null | tail -n 200
sudo grep -E "Failed password|Accepted|Invalid user" /var/log/secure 2>/dev/null | tail -n 200
# What is listening on the network?
sudo ss -lntup
# Top processes
ps auxf --sort=-%cpu | head -n 25
ps auxf --sort=-%mem | head -n 25
# Quick disk check (compromise often comes with droppers/log flood)
df -h
sudo du -xhd1 /var 2>/dev/null | sort -h | tail -n 15
If SSH is getting hammered and you need a focused path to stop lockouts and spot real logins, pair this guide with this SSH brute-force troubleshooting tutorial.
Step 2: Contain first (stop the bleeding without breaking everything)
Containment limits movement and outbound abuse. It also keeps the box stable enough to investigate.
Your best move depends on your stack (web, email, control panels). It also depends on how confident you are that the host is compromised.
Option A (recommended): Restrict access at the firewall, keep SSH for your IP only
If you can still authenticate safely, lock management access to your office/home IP. Keep web ports open only if you must maintain uptime.
# UFW example (Ubuntu/Debian)
# Replace 203.0.113.10 with your real admin IP
sudo ufw status verbose
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp
sudo ufw deny 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw reload
# nftables systems (AlmaLinux/Rocky using firewalld)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" port protocol="tcp" port="22" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload
If you want a safer, fuller firewall approach that avoids accidental lockouts, keep this UFW firewall configuration tutorial open while you work.
Option B: Kill outbound email abuse (common on compromised hosting VPS)
If you see spam signals (queue growth, lots of outbound connections on 25/587), stop mail egress temporarily. This protects your IP reputation and buys you time.
# Block outbound SMTP quickly (UFW)
sudo ufw deny out 25/tcp
sudo ufw deny out 587/tcp
sudo ufw deny out 465/tcp
sudo ufw reload
# Postfix: freeze deliveries without deleting the queue
sudo postfix stop
sudo postqueue -p | head
Option C: Snapshot before deep changes
If your platform supports snapshots, take one now. You get rollback and a clean reference point for later analysis.
For a HostMyCode VPS, you can build a repeatable snapshot/restore habit with this snapshot backup tutorial.
Step 3: Preserve evidence (without buying forensic software)
You’re running a hosting server, not building a courtroom case. Still, you need enough evidence to answer three questions: what changed, how did they get in, and what did they touch?
Create an incident folder
sudo mkdir -p /root/ir-$(date +%F)
sudo chmod 700 /root/ir-$(date +%F)
IRDIR=/root/ir-$(date +%F)
Capture system state (processes, sockets, users)
# Processes and network
ps auxfww > $IRDIR/ps-auxf.txt
ss -pant > $IRDIR/ss-pant.txt
ss -lntup > $IRDIR/ss-listen.txt
# Accounts and keys
getent passwd > $IRDIR/passwd.txt
getent group > $IRDIR/group.txt
grep -R "^sudo" -n /etc/group /etc/sudoers /etc/sudoers.d 2>/dev/null > $IRDIR/sudo-config.txt
find /root /home -maxdepth 3 -name authorized_keys -print -exec ls -la {} \; > $IRDIR/authorized-keys-inventory.txt
Copy logs you’re likely to need
# Auth logs (paths vary by distro)
cp -a /var/log/auth.log* $IRDIR/ 2>/dev/null
cp -a /var/log/secure* $IRDIR/ 2>/dev/null
# Web logs (adjust for Nginx/Apache)
cp -a /var/log/nginx $IRDIR/ 2>/dev/null
cp -a /var/log/apache2 $IRDIR/ 2>/dev/null
cp -a /var/log/httpd $IRDIR/ 2>/dev/null
# System journal export
journalctl --since "48 hours ago" > $IRDIR/journal-48h.txt
If you already centralize logs, building a timeline is much easier. It also helps if an attacker wipes local files.
See this log shipping tutorial for a practical rsyslog+TLS setup.
Step 4: Find the entry point (the “how did they get in?” loop)
Most hosting VPS compromises come from a short list. The usual causes are weak SSH, exposed admin panels, vulnerable web apps/plugins, leaked credentials, or insecure file uploads.
Check SSH logins for “first known good” vs “first known bad”
# Identify successful SSH logins and their source IPs
sudo grep "Accepted" /var/log/auth.log 2>/dev/null | tail -n 200
sudo grep "Accepted" /var/log/secure 2>/dev/null | tail -n 200
# If you use journalctl
sudo journalctl -u ssh | grep "Accepted" | tail -n 200
Flag logins at odd hours. Also flag logins from places you don’t operate in. Treat any “shouldn’t SSH” account as suspect.
Check web entry patterns: suspicious POSTs, upload endpoints, plugin probes
# Nginx access log quick scan
sudo awk '$6 ~ /POST/ {print $1, $4, $7, $9}' /var/log/nginx/access.log | tail -n 200
# Search for common webshell markers in requests
sudo grep -R "base64" -n /var/log/nginx/access.log /var/log/apache2/access.log 2>/dev/null | head
sudo grep -R "wp-admin/admin-ajax.php" -n /var/log/nginx/access.log 2>/dev/null | tail
If the server hosts a lot of WordPress, include plugin and theme auditing in the incident. After recovery, use this WordPress security hardening tutorial for a clean baseline.
Check for stolen credentials and persistence
- New SSH keys in
/root/.ssh/authorized_keysor user home directories - New users in
/etc/passwdwith UID 0 or sudo access - New cron jobs in
/etc/cron.*,/var/spool/cron, or user crontabs - New systemd units in
/etc/systemd/system/
# Cron and timers
sudo ls -la /etc/cron.* /etc/crontab
sudo find /etc/cron.* -type f -maxdepth 2 -print -exec sed -n '1,200p' {} \; 2>/dev/null
sudo systemctl list-timers --all > $IRDIR/systemd-timers.txt
# Systemd units recently changed
sudo find /etc/systemd/system -type f -mtime -7 -ls > $IRDIR/systemd-unit-changes-7d.txt
Step 5: Identify what was modified (and what must be rebuilt)
Now decide: clean in place, or rebuild from known-good backups. In hosting, a rebuild is often faster and safer once root compromise looks likely.
Fast file integrity checks
# Recently modified binaries in common paths (last 7 days)
sudo find /bin /sbin /usr/bin /usr/sbin -type f -mtime -7 -ls 2>/dev/null | head -n 200
# Recently modified web roots (adjust paths)
sudo find /var/www -type f -mtime -7 -ls 2>/dev/null | head -n 200
Package verification (best-effort)
On Debian/Ubuntu, dpkg helps. On RHEL-family, rpm helps. This won’t catch everything, but it can highlight tampered system files.
# Ubuntu/Debian
sudo dpkg -V > $IRDIR/dpkg-verify.txt
# AlmaLinux/Rocky
sudo rpm -Va > $IRDIR/rpm-verify.txt
If you see widespread changes in system binaries, treat this as a rebuild event.
Step 6: Eradication plan (choose one of these paths)
Pick one path and commit to it. Switching strategies mid-stream is how compromises survive.
Path 1: Suspected web-only compromise (no root), clean + patch + rotate credentials
- Disable write access where possible (uploads still need writes): lock down permissions in
/var/www. - Remove unknown PHP files in upload directories and scan for common webshell functions.
- Update CMS core, plugins, themes. Remove unused plugins/themes entirely.
- Rotate passwords (WordPress admin, database user, SFTP/SSH for site users).
- Deploy WAF rules if you can (ModSecurity/OWASP CRS) and rate-limit login endpoints.
Path 2: Root compromise likely, rebuild from scratch (recommended for hosting)
If you find new SSH keys for root, unknown systemd units, suspicious listening daemons, or tampered binaries, plan a rebuild.
- Take a snapshot (if available) and preserve your
/root/ir-YYYY-MM-DDfolder off-server. - Provision a fresh VPS/dedicated server.
- Restore websites and databases from backups taken before the intrusion window.
- Rotate every credential that ever touched the old server.
- Do a controlled DNS cutover with low TTL and rollback readiness.
If you need a clean, low-downtime move plan, use this VPS migration tutorial alongside the rebuild workflow.
Step 7: Recovery steps (restore service safely)
Recovery isn’t “the server boots.” Recovery is “the server is trustworthy and stays stable.” Work in this order.
1) Re-enable only required services
# List enabled services
sudo systemctl list-unit-files --type=service --state=enabled
# Check what is actually listening
sudo ss -lntup
If you see an unexpected port, stop and investigate before you proceed.
2) Restore from known-good backups (and test the restore)
Whatever tool you use, test the restore on a staging path first. For file-based sites, restore to /var/www-staging and validate.
For full-server approaches, you can also run a rehearsal using the ideas in this VPS restore drill tutorial.
3) Rotate credentials (don’t skip this)
- SSH keys: remove unknown keys; rotate known keys if you suspect workstation compromise.
- All hosting panel logins (WHM/cPanel/DirectAdmin/Plesk) and reseller accounts.
- Database passwords used by apps.
- SMTP credentials and API keys (mail providers, payment gateways, backups).
4) Rebuild DNS and SSL cleanly
Incidents often leave DNS half-changed. Verify A/AAAA, MX, and TXT records.
For low-downtime DNS changes, follow the TTL discipline in this DNS propagation tutorial. If SSL renewals fail after the move, keep this SSL renewal troubleshooting guide handy.
Step 8: Post-incident hardening checklist (so it doesn’t repeat)
Now you make the server boring again. That’s the goal.
- Patch cadence: enable unattended security updates (Ubuntu) or dnf-automatic (Alma/Rocky) and schedule reboots.
- SSH policy: keys only, disable root login, restrict by IP where possible.
- Firewall baseline: only 22 (restricted), 80/443, and mail ports if you truly run mail.
- Least privilege: separate deploy users from admin users; remove stale accounts.
- Backups with restore tests: retention + encrypted offsite + monthly restore drill.
- Log centralization: off-server logs make it harder to rewrite history.
- WAF/abuse controls: rate-limit login endpoints and block common exploit paths.
If you want a tight baseline for new servers, the steps in Server Hardening Tutorial: Lock Down a New Ubuntu VPS pair well with this incident response flow.
Hands-on mini playbook: 30-minute “contain + capture” sequence
Use this when you’re under pressure and need a clean order of operations.
- Open a timestamped notes file: record what you do and when.
- Restrict SSH to your IP (firewall or provider console rules).
- Capture state:
ps,ss,who,last, auth logs. - Copy logs to
/root/ir-YYYY-MM-DDand then off-server. - Check persistence: cron, systemd units, authorized_keys.
- Decide: web-only clean vs rebuild.
Common pitfalls during hosting incidents
- Mixing cleanup and investigation: if you delete artifacts before you understand them, you lose the thread.
- Assuming “no log entries” means “no compromise”: logs may be rotated, deleted, or never collected.
- Forgetting outbound abuse: even if sites look fine, spam and botnet traffic can burn your IP quickly.
- Restoring from backups taken after compromise: you may restore the backdoor right along with the site.
If you want incident response to feel like a checklist instead of a fire drill, start with infrastructure you can snapshot, rebuild, and secure quickly. A HostMyCode VPS gives you the control you need for hands-on containment, and managed VPS hosting is a practical option if you’d rather outsource patching and baseline hardening.
FAQ
Should I rebuild the VPS after a compromise?
If you suspect root compromise (new root SSH keys, unknown services, tampered binaries), rebuild is usually the safest and often the fastest path for hosting.
Is it safe to keep serving websites during investigation?
Sometimes. If you can contain access (restrict admin ports, block outbound spam, keep only 80/443), you can maintain uptime while you capture evidence. If you see active malware serving, take sites offline.
What logs matter most for a hosting incident?
SSH/auth logs, web access/error logs, mail logs (if applicable), and systemd journal entries for the incident window. Off-server log shipping helps a lot.
How do I prevent the same attack from coming back after restore?
Patch the entry point (plugin/app vuln, weak SSH, exposed admin panel), rotate all credentials, and add guardrails: firewall policy, least-privilege users, and tested offsite backups.
Summary: a calm, repeatable incident response loop
This VPS incident response tutorial follows one rule: contain first, investigate second, restore third. Practice the 30-minute contain+capture sequence and keep clean backups. Then an ugly incident becomes a controlled maintenance window.
For production hosting where rebuilds and migrations are normal operations, consider running on a HostMyCode VPS (or step up to managed VPS hosting if you want tighter operational support). HostMyCode’s tagline still applies during incidents: Affordable & Reliable Hosting.