Updated

Was my Linux server hacked? Read-only checks for suspicious logins and processes

Your cloud provider flags an "unusual login" or "possible crypto-mining", the CPU is pinned for no obvious reason, or your login records are full of IP addresses you've never seen. The question on your mind is whether someone already has control of the machine. This guide gives developers and site owners who run their own servers a set of read-only checks to tell "someone is trying" apart from "someone may have got in", so you can decide whether to escalate.

The limits come first:

The commands below work on common Linux distributions. Log paths and service names vary, so adjust them to your system.

0. Before you start: preserve the evidence

1. Someone trying, or someone in?

Start with successful logins. Ubuntu/Debian usually log to /var/log/auth.log; RHEL, CentOS, Rocky and similar use /var/log/secure. If neither exists (for example on journald-only systems), query the journal:

sudo grep -E 'Accepted (password|publickey)' /var/log/auth.log | tail -n 50
sudo journalctl -u ssh -u sshd --since "7 days ago" --no-pager | grep -E 'Accepted|Failed password|Invalid user' | tail -n 50

Summarize successful logins by method, user and source IP (use the log path that exists on your system):

sudo grep -hoE 'Accepted [a-z-]+ for [^ ]+ from [^ ]+' /var/log/auth.log | sort | uniq -c | sort -rn

Then look at failed attempts and who is logged in right now:

sudo grep -hoE 'Failed password for (invalid user )?[^ ]+ from [^ ]+' /var/log/auth.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -n 20
who
last -a -n 30
sudo lastb -a -n 30

What this does not tell you: logs rotate and only cover a limited window; logs can be edited; and finding no suspicious Accepted line doesn't mean nobody got in. Attackers don't have to come through SSH. A web application bug or a leaked key works just as well.

While you're here, check the SSH authentication settings actually in effect. You'll need this for hardening decisions later (read-only, requires root):

sudo sshd -T | grep -E '^(permitrootlogin|passwordauthentication|pubkeyauthentication) '

passwordauthentication yes means password logins are allowed, which gives brute-force attempts a chance to succeed. permitrootlogin without-password (the same as prohibit-password) means root can only log in with a key.

2. Unusual processes and outbound connections

ps -eo pid,ppid,user,lstart,cmd --sort=-%cpu | head -n 15
sudo ss -tnp state established
sudo ss -ltnup

For a suspicious PID, check its executable and working directory (replace PID with the number):

sudo ls -l /proc/PID/exe /proc/PID/cwd

An executable in /tmp, /var/tmp or /dev/shm, or one marked (deleted) (the file was removed after the program started), deserves serious attention.

What this does not tell you: high CPU can be legitimate workload, and well-hidden malware may not appear in ps or ss output at all.

3. Signs of a way back in

sudo crontab -l
crontab -l
sudo ls -la /var/spool/cron/ /var/spool/cron/crontabs/ 2>/dev/null
sudo ls -la /etc/cron.d/ /etc/cron.hourly/ /etc/cron.daily/
cat /etc/crontab
systemctl list-timers --all --no-pager
sudo find /etc/systemd/system -type f -newermt '2026-09-01' -ls

Then accounts and keys:

awk -F: '$3 == 0 {print $1}' /etc/passwd
awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $6, $7}' /etc/passwd
sudo find /root /home -name authorized_keys -exec ls -l --time-style=long-iso {} \;
sudo ls -la /etc/sudoers.d/
ls -l /etc/ld.so.preload

What this does not tell you: modification times can be faked, and finding nothing doesn't mean nothing is there.

4. What to do with what you found

Only failed attempts, no suspicious successful logins or processes: that's normal background noise for a public server. Hardening is worth considering, but every item is a change you decide on: key-only authentication, no root password logins, restricting port 22 to your own IP in the security group, a tool such as fail2ban. When you edit the SSH config, keep one logged-in session open, run sudo sshd -t to check the syntax, and test a fresh login from a new window. If something breaks, use the open session to revert. Your cloud console's VNC or serial access is the last-resort way back in. Afterwards, consider adding "spike in failed logins" and "new listening port" to your routine read-only checks; see the small-team VPS monitoring checklist.

Treat it as a likely compromise if you see any of these: a successful login you can't explain, an unknown UID 0 account or authorized_keys entry, an executable running from a temp directory or already deleted, or a malicious-activity alert your cloud provider has confirmed. Then:

  1. Snapshot the disk if you didn't in step 0, to preserve evidence.

  2. If you need to contain damage, restrict inbound and outbound traffic with security group rules in the cloud console rather than deleting files or killing processes on the machine. That's a change too: record the existing rules so you can restore them, and make sure you still have console access.

  3. Contact your cloud provider's security support or a security professional.

  4. Rebuilding from a clean image and restoring data from a known-good backup taken before the compromise is usually the safer route. Deleting the miner and carrying on leaves you unable to confirm every backdoor is gone.

  5. From a clean device, rotate every credential the machine touched: SSH keys, database passwords, API keys in your app config. If you ever logged into this machine with a password, treat that password as exposed too.

Running these checks in OpsMate

OpsMate puts the SSH terminal and AI on the same page. You can type every command above yourself, or ask the AI in plain language to help. It proposes troubleshooting commands, and beyond the auth logs it can use ps, ss and journalctl for checks. After a command has run, click Analyze to get a summary of sources, users and a timeline. The commands and output stay in the terminal for you to check (see AI and SSH commands in one workspace).

Illustrative example

Illustrative example (not a real customer case): the cloud provider sends a "possible crypto-mining" alert. ps shows a process with a random-looking name using all the CPU, and /proc/PID/exe points at a file in /tmp marked (deleted). ss shows it holding a long-lived connection to an unfamiliar external address. The auth log has a 3 a.m. password login for user deploy from 203.0.113.45, sshd -T shows password authentication enabled, and that user's crontab downloads and runs a script every 10 minutes. Together this strongly suggests the machine is under someone else's control, though it's still not a formal verdict. The sensible path is to snapshot, isolate at the security-group level, contact the provider's security team, rebuild from a clean image and rotate all credentials. Killing the process, deleting the crontab line and carrying on would likely leave behind a backdoor nobody has found. (The IP address is from a range reserved for documentation.)

AI diagnostic prompt

I'm worried about suspicious logins on this server. Without changing anything, check the sources, users and timing of successful and failed SSH logins over the last 7 days, the top CPU processes and their executable paths, established external connections, cron jobs and systemd timers, accounts with UID 0, and the modification times of authorized_keys files. List only what you observe and what deserves attention. Do not conclude that the server is "compromised" or "safe", and tell me what information is missing. Do not delete files, kill processes, change configuration or reboot. If you recommend any change, explain its risks and rollback first and wait for my approval.

Try OpsMate

500 free AI calls per month and unlimited servers. The desktop app keeps your SSH credentials on your own machine by default.

Need help interpreting the evidence?

OpsMate helps developers and operators investigate with AI. Review the evidence. After you click Analyze, the command output is sent to cloud AI for analysis; redact sensitive information first.

Start free Desktop with local credentials

Troubleshooting guides