
Most VPS compromises still start the same way: someone gets SSH access. Then they fan out into your sites, mail, backups, and billing hooks. This SSH lockdown tutorial gives you a practical hardening baseline for a hosting VPS or dedicated server in 2026—without “securing” yourself into an outage.
You’re not chasing maximum security. You’re aiming for predictable access.
That means the right users, from the right networks, using the right auth methods, with logs that tell the truth.
What you’ll build (and what you’ll need)
By the end, your server will use:
- SSH keys only (no passwords), with a safe “break-glass” path
- Restricted users and groups, plus per-user rules
- IP allowlisting (UFW + optional provider firewall)
- Optional 2FA for SSH via PAM (TOTP)
- Auditing: useful logs + basic anomaly checks
Assumptions: Ubuntu 24.04 LTS or Debian 12/13, OpenSSH 9.x, and root access. Commands are shown for Ubuntu/Debian.
If you’re on AlmaLinux/Rocky, the approach is the same. Your firewall tooling and config paths will differ.
If you need a clean server to apply these controls, start on a HostMyCode VPS.
If you’d rather have someone review and lock down SSH as part of ongoing ops, managed VPS hosting is the better fit.
Step 0 — Don’t lock yourself out (console access and a rollback plan)
Before you touch SSH settings:
- Confirm you have out-of-band access (provider console/KVM) or, at minimum, a second SSH session already open.
- Write down your current SSH port and your public IP.
- Make sure key auth works before you disable passwords.
Open a second terminal and keep it logged in.
If something goes sideways, that session is your undo button.
# Check current SSH port and active config
ss -lntp | grep -E ':(22|2222)\s'
sshd -T | egrep 'port|passwordauthentication|pubkeyauthentication|permitrootlogin'
Step 1 — Create an admin user (and stop using root for daily work)
Root over SSH feels fast. It also makes attribution harder.
Use a dedicated admin account. Elevate with sudo.
adduser admin
usermod -aG sudo admin
On Debian, install sudo if needed:
apt update && apt install -y sudo
Tip for hosting servers: if multiple people need access, create one user per person. Shared accounts destroy audit trails.
Step 2 — Set up SSH keys correctly (and verify permissions)
On your local machine, generate a modern key if you don’t already have one.
In 2026, Ed25519 is the standard default.
# On your local machine
ssh-keygen -t ed25519 -a 64 -f ~/.ssh/id_ed25519_hosting_vps
Copy the public key to the server (replace IP/hostname):
ssh-copy-id -i ~/.ssh/id_ed25519_hosting_vps.pub admin@YOUR_SERVER_IP
Then verify ownership and permissions on the server:
sudo ls -ld /home/admin /home/admin/.ssh
sudo ls -l /home/admin/.ssh/authorized_keys
sudo stat -c '%a %U %G %n' /home/admin/.ssh /home/admin/.ssh/authorized_keys
Expected perms are typically 700 for .ssh and 600 for authorized_keys.
Fix anything that doesn’t match:
sudo chmod 700 /home/admin/.ssh
sudo chmod 600 /home/admin/.ssh/authorized_keys
sudo chown -R admin:admin /home/admin/.ssh
Step 3 — Harden sshd_config with safe, hosting-friendly defaults
On Ubuntu/Debian, edit /etc/ssh/sshd_config.
In 2026, a sane approach is to keep strong defaults. Then pin the settings that change your risk.
sudo nano /etc/ssh/sshd_config
Add (or update) the following lines. Adjust values to your environment:
# Network
Port 22
AddressFamily inet
ListenAddress 0.0.0.0
# Authentication
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
# Accounts and sessions
AllowUsers admin
MaxAuthTries 3
LoginGraceTime 20
ClientAliveInterval 300
ClientAliveCountMax 2
# Forwarding (often not needed on hosting nodes)
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
# Logging
LogLevel VERBOSE
Why these choices:
PermitRootLogin noblocks direct root logins. You still get admin rights viasudo.PasswordAuthentication noshuts down password guessing. This is the biggest single improvement.AllowUserschanges SSH from “any local account can try” to “only these accounts can even attempt.”LogLevel VERBOSElogs key fingerprints for successful key auth. That helps during incident review.
Validate the config, then reload SSH.
Don’t restart unless you have to.
sudo sshd -t
sudo systemctl reload ssh
Now test from a fresh terminal:
ssh -i ~/.ssh/id_ed25519_hosting_vps admin@YOUR_SERVER_IP
Once that works, you can close the older sessions.
Step 4 — Add IP allowlisting (UFW) without breaking web hosting
Keys stop credential attacks. They don’t reduce how often you get scanned.
An allowlist does. If you administer from a fixed IP (office VPN, static ISP IP), restrict SSH to it.
If you haven’t set up UFW yet, see our related guide: UFW Firewall Setup Tutorial (2026).
Example UFW rules for a typical hosting VPS (HTTP/HTTPS open, SSH allowlisted):
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Web hosting
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# SSH only from your admin IP
sudo ufw allow from YOUR_ADMIN_IP to any port 22 proto tcp
sudo ufw enable
sudo ufw status verbose
If your IP changes often: allowlist a VPN subnet you control. Or filter by country/ASN at the provider firewall level.
Avoid “allow SSH from anywhere” unless you truly need it.
Step 5 — Optional: move SSH to a non-default port (do it for noise reduction, not security)
Changing ports won’t stop a targeted attacker.
It will reduce bot traffic and clean up your logs.
If you do it, open the firewall first. That prevents lockouts.
# Allow the new port before changing sshd
sudo ufw allow from YOUR_ADMIN_IP to any port 2222 proto tcp
Edit /etc/ssh/sshd_config:
Port 2222
Reload and test from a new terminal:
sudo sshd -t && sudo systemctl reload ssh
ssh -p 2222 -i ~/.ssh/id_ed25519_hosting_vps admin@YOUR_SERVER_IP
After you confirm the new port works, remove the old SSH allow rule if you had one.
Step 6 — Add 2FA (TOTP) for SSH logins (practical for small teams)
For a small admin team, TOTP-based 2FA is a real upgrade.
The trade-off is friction. Automation and emergency access need more planning.
Set your break-glass path before you enforce 2FA.
Install Google Authenticator PAM module:
sudo apt update
sudo apt install -y libpam-google-authenticator
Run setup for each SSH user (as that user):
su - admin
google-authenticator
Answer the prompts.
For most hosting admins, “time-based tokens” and “disallow multiple uses” are good defaults.
Enable PAM for SSH. Edit /etc/pam.d/sshd and add near the top:
auth required pam_google_authenticator.so nullok
nullok allows users without a token to log in.
If you want mandatory 2FA for every allowed user, remove nullok after everyone enrolls.
Now adjust /etc/ssh/sshd_config.
You must allow keyboard-interactive for the OTP prompt, while still requiring a key:
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
Reload and test:
sudo sshd -t && sudo systemctl reload ssh
ssh -i ~/.ssh/id_ed25519_hosting_vps admin@YOUR_SERVER_IP
After the key is accepted, you should be prompted for a verification code.
Step 7 — Build a break-glass path you can live with
Hardening that blocks you is still a failure.
Pick one break-glass method, write it down, and test it once while you’re calm.
- Provider console/KVM: best option. Works even if networking is broken.
- Second admin user with a separate key: store the private key offline (password manager vault, hardware token).
- Time-limited firewall rule: temporarily open SSH from a wider IP range for 10 minutes during incidents.
Example: create a second emergency user and restrict it hard:
sudo adduser breakglass
sudo usermod -aG sudo breakglass
sudo mkdir -p /home/breakglass/.ssh
sudo nano /home/breakglass/.ssh/authorized_keys
sudo chmod 700 /home/breakglass/.ssh
sudo chmod 600 /home/breakglass/.ssh/authorized_keys
sudo chown -R breakglass:breakglass /home/breakglass/.ssh
Then allow it explicitly:
# /etc/ssh/sshd_config
AllowUsers admin breakglass
Policy suggestion: keep break-glass disabled day-to-day by removing it from AllowUsers.
Add it only during an incident.
Step 8 — Add brute-force controls that match SSH lockdown goals
Even with keys and allowlists, you’ll still see noisy traffic.
Auto-banning repeat offenders is worth it.
Fail2Ban remains a practical option for VPS hosting nodes.
We won’t repeat the full setup here. Use our guide: Fail2Ban Setup Tutorial (2026).
For an SSH-locked server, start with thresholds like these:
- findtime: 10m
- maxretry: 3
- bantime: 1h (or longer if you have static admin IPs)
Step 9 — Turn logs into a quick daily check (journal, auth logs, and suspicious patterns)
If nobody looks at logs, you won’t notice drift.
You also won’t catch the “temporary” account that never got removed.
This routine takes a couple minutes and catches most surprises.
On Ubuntu 24.04, SSH logs typically live in the systemd journal. Depending on your rsyslog setup, they may also appear in /var/log/auth.log.
# Last 200 sshd lines
sudo journalctl -u ssh --no-pager -n 200
# Failed logins and invalid users (if auth.log exists)
sudo grep -E "Failed password|Invalid user|authentication failure" /var/log/auth.log | tail -n 50
Check successful logins and which keys were used (enabled by LogLevel VERBOSE):
sudo journalctl -u ssh --no-pager | grep -E "Accepted publickey" | tail -n 30
If you’re running a hosting business, tie this to basic uptime and resource alerts.
CPU spikes that line up with access attempts are a clue. Our monitoring walkthrough is here: VPS Monitoring Tutorial (2026).
Step 10 — Tighten SSH for control panels (cPanel/WHM, Plesk, DirectAdmin)
Control panels expand your attack surface.
You get more services, more admins, and more “quick fixes” applied under pressure.
SSH is still your last-resort door. Keep it stricter than panel access.
- Keep SSH key-only even if the panel makes password resets easy.
- Use separate admin accounts for panel admins vs. SSH admins when possible.
- Don’t enable SSH access for every hosting customer unless you sell it as a feature with clear limits.
If you need reliable panel hosting on a clean VPS, start with a stable base node (adequate RAM, NVMe storage, and predictable networking).
That’s exactly the use case for HostMyCode VPS or a larger plan on dedicated servers when you’re packing in multiple accounts.
Step 11 — Quick troubleshooting: common SSH lockdown mistakes (and how to recover)
- “Permission denied (publickey)”
- Check you’re using the right key:
ssh -i ~/.ssh/key admin@IP - Check perms:
~/.sshmust be 700 andauthorized_keys600 - Inspect server logs:
sudo journalctl -u ssh -n 200
- Check you’re using the right key:
- SSH hangs after “Connecting…”
- Firewall rule missing for your IP/port. Confirm:
sudo ufw status verbose - Service not listening. Confirm:
ss -lntp | grep ssh
- Firewall rule missing for your IP/port. Confirm:
- 2FA prompts don’t appear
- Ensure
KbdInteractiveAuthentication yesandAuthenticationMethods publickey,keyboard-interactive - Check PAM config:
/etc/pam.d/sshd
- Ensure
- You changed ports and got locked out
- Use provider console to revert
Portand reload SSH. - Or temporarily allow both ports in UFW, then test.
- Use provider console to revert
SSH lockdown tutorial checklist (print this)
- At least one non-root admin user with sudo
- SSH key works for that user; correct file permissions
PermitRootLogin noandPasswordAuthentication noAllowUsers(orAllowGroups) explicitly set- Firewall allows SSH only from trusted IPs or VPN
- Optional 2FA enrolled for all admins
- Break-glass plan tested (console or emergency user)
- Logs reviewed and alerts enabled
Summary: a safer SSH posture you can operate
This SSH lockdown tutorial focused on controls that reduce real risk on hosting servers: keys-only auth, root login disabled, explicit user allowlists, IP allowlisting, optional 2FA, and logging you can actually use.
If you run multiple sites, email, cron jobs, and customer accounts on the same node, these steps protect the one access path that matters most.
If you want a stable place to implement this cleanly, deploy on a HostMyCode VPS.
If you’d rather keep SSH, patching, and monitoring handled by a team that does it daily, choose managed VPS hosting from HostMyCode.
If you’re standardizing SSH access across production websites, start with infrastructure you can depend on. HostMyCode offers VPS plans for hands-on admins and managed VPS hosting when you want security hardening and day-to-day ops handled by a team.
FAQ
Should I disable SSH passwords even if I use Fail2Ban?
Yes. Fail2Ban slows repeated attempts, but password auth still leaves a guessable surface exposed. Keys-only removes the entire password-guessing category.
Is changing the SSH port worth it in 2026?
It helps with noise reduction and log cleanup, not as a primary security control. Do it only after keys and firewall allowlisting are already in place.
Will 2FA break automation like rsync backups?
It can. For automation, use a dedicated SSH key restricted to a single command or host, and keep 2FA for human admin accounts only.
What’s the safest way to keep emergency access?
Out-of-band console/KVM access is the cleanest option. If you can’t get that, maintain a separate break-glass user and store its key offline.
How do I verify which SSH key was used for a login?
Set LogLevel VERBOSE in sshd_config, reload SSH, then search logs for Accepted publickey. The entry includes the key fingerprint.