
You can run a tight firewall and still get burned by a loose SSH setup. SSH is the front door to your VPS or dedicated server. Risky defaults like password logins, wide-open access, and minimal logging often stay unchanged for years. This SSH lockdown tutorial shows how to harden OpenSSH on Ubuntu/Debian and RHEL-family systems without locking yourself out.
The order matters. You’ll create a separate admin user, install and test keys, and keep a safety session open.
Then you’ll tighten sshd settings in small increments, add rate limiting with Fail2Ban, and finish with a rollback plan you can use under pressure.
If you’d rather have these steps handled end-to-end with guardrails, managed VPS hosting from HostMyCode is designed for exactly this kind of operational hardening.
What you’ll secure (and what you won’t break)
- Stop password guessing: move to SSH keys and (optionally) 2FA.
- Reduce blast radius: limit who can log in and narrow where logins can come from.
- Keep access stable: validate changes safely and keep an easy rollback path.
- Improve visibility: cleaner logs and more predictable failure behavior.
Prerequisites and a “don’t lock yourself out” checklist
Set up your safety net before you edit anything. Most SSH lockouts happen the same way: someone edits sshd_config, reloads, and only then tries to log in.
- Open two SSH sessions to the server. Leave one untouched as your lifeline.
- Confirm your distro and OpenSSH version:
cat /etc/os-release
sshd -V 2>&1 | head -n1
- Know where your SSH config lives: typically
/etc/ssh/sshd_config, plus drop-ins under/etc/ssh/sshd_config.d/*.conf(common on newer Ubuntu/Debian). - Make sure you have console access or rescue mode access through your provider.
- If this is production with no out-of-band access, schedule a maintenance window before you harden anything.
If you’re doing a bigger move (shared hosting to VPS, or VPS to VPS), align SSH hardening with your migration runbook.
This internal guide complements the steps below: server migration tutorial with DNS, SSL, email, and rollback.
Step 1: Create a separate admin user (stop using root directly)
You want a privileged account for day-to-day administration. It stays useful even if you later disable root SSH logins (recommended). It also improves audit trails.
Ubuntu/Debian
adduser adminops
usermod -aG sudo adminops
AlmaLinux/Rocky/RHEL
useradd -m adminops
passwd adminops
usermod -aG wheel adminops
Test sudo immediately (use your second SSH session):
su - adminops
sudo -v
Step 2: Install SSH keys properly (and test them before disabling passwords)
On your laptop/workstation (not the server), generate a modern key. In 2026, Ed25519 is still the default choice for most environments.
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/hostmycode_adminops
Copy the public key to the new user:
ssh-copy-id -i ~/.ssh/hostmycode_adminops.pub adminops@YOUR_SERVER_IP
Test key-based login explicitly:
ssh -i ~/.ssh/hostmycode_adminops adminops@YOUR_SERVER_IP
On the server, fix permissions. If ownership or modes are wrong, OpenSSH may ignore your key.
When that happens, it often falls back to password auth.
sudo chmod 700 /home/adminops/.ssh
sudo chmod 600 /home/adminops/.ssh/authorized_keys
sudo chown -R adminops:adminops /home/adminops/.ssh
Step 3: Back up SSH config and validate changes safely
Back up your SSH config before the first edit. If something goes sideways, this is your fastest recovery.
sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F-%H%M)
After every change, validate syntax before you reload anything:
sudo sshd -t
If validation passes, reload instead of restarting when you can:
sudo systemctl reload ssh
# or on some distros
sudo systemctl reload sshd
Why reload? New settings apply only to new sessions. Your existing sessions stay connected. That makes reload the safest way to harden SSH.
Step 4: Apply a practical hardening baseline in sshd_config
Edit /etc/ssh/sshd_config (or add a drop-in like /etc/ssh/sshd_config.d/99-hardening.conf).
Make changes in a controlled sequence. Do a little, test, then proceed.
Example baseline (fits most VPS hosting setups):
# /etc/ssh/sshd_config.d/99-hardening.conf
# Keep it boring and predictable
Protocol 2
# Listen on IPv4 and IPv6 by default
Port 22
# Disable direct root access (use your sudo user)
PermitRootLogin no
# Only allow key-based auth
PasswordAuthentication no
KbdInteractiveAuthentication no
ChallengeResponseAuthentication no
# Keys only
PubkeyAuthentication yes
# Reduce exposure
X11Forwarding no
AllowTcpForwarding no
PermitTunnel no
# Tighten timeouts to reduce brute-force attempts
LoginGraceTime 20
MaxAuthTries 3
MaxSessions 3
# Optional: limit who can log in via SSH
AllowUsers adminops
# Logging that’s actually useful
LogLevel VERBOSE
Validate and reload:
sudo sshd -t
sudo systemctl reload ssh || sudo systemctl reload sshd
Then test again from a fresh terminal on your laptop:
ssh -i ~/.ssh/hostmycode_adminops adminops@YOUR_SERVER_IP
Pitfall: locking out automation or control panels
If you run cPanel/WHM, Plesk, DirectAdmin, or agent-based monitoring, be cautious with AllowUsers. Some tools rely on service accounts.
In those environments, AllowGroups sshusers is usually easier to manage and audit.
Group-based allowlist example:
sudo groupadd sshusers
sudo usermod -aG sshusers adminops
# /etc/ssh/sshd_config.d/99-hardening.conf
AllowGroups sshusers
Step 5: Optional but useful—move SSH off port 22 (only after keys work)
A non-standard port doesn’t “secure” SSH by itself. It mainly reduces drive-by scans and noisy logs.
If you change the port, document it. Then update every tool that connects.
- Pick a port (example:
2222). - Update config:
# /etc/ssh/sshd_config.d/99-hardening.conf
Port 2222
Reload SSH, then test from your laptop:
sudo sshd -t
sudo systemctl reload ssh || sudo systemctl reload sshd
ssh -p 2222 -i ~/.ssh/hostmycode_adminops adminops@YOUR_SERVER_IP
Important: keep port 22 enabled until you’ve confirmed 2222 works from where you actually operate. Once you’re sure, remove port 22 and reload again.
Step 6: Add Fail2Ban for SSH brute-force blocking (practical settings)
Fail2Ban doesn’t replace your firewall. It watches logs and bans IPs that behave like credential-stuffing bots or brute-force scanners.
Install Fail2Ban
# Ubuntu/Debian
sudo apt update
sudo apt install -y fail2ban
# AlmaLinux/Rocky (EPEL usually required)
sudo dnf install -y epel-release
sudo dnf install -y fail2ban
Create a local jail configuration. Avoid editing the default file so upgrades don’t overwrite your changes:
sudo tee /etc/fail2ban/jail.d/sshd.local >/dev/null <<'EOF'
[sshd]
enabled = true
port = 22,2222
backend = systemd
maxretry = 4
findtime = 10m
bantime = 6h
ignoreip = 127.0.0.1/8
EOF
Enable and start:
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
sudo fail2ban-client status sshd
If you want a more alert-driven setup (SSH plus web login endpoints), follow this internal guide: VPS log monitoring tutorial with Fail2Ban, Logwatch, and actionable alerts.
Step 7: Add SSH 2FA (TOTP) for human admins (without breaking automation)
2FA makes sense for interactive admin sessions. It’s usually a poor fit for non-interactive automation.
If you need both, design for it. Use separate accounts, dedicated keys, and explicit bypass rules.
A common approach is PAM + Google Authenticator compatible TOTP. On Ubuntu/Debian:
sudo apt update
sudo apt install -y libpam-google-authenticator
On RHEL-family systems, the package name can differ depending on repos.
After installation, enroll as the admin user:
su - adminops
google-authenticator
Answer prompts to:
- Use time-based tokens
- Disallow multiple uses of the same token
- Enable rate limiting
Edit PAM SSH configuration:
# Ubuntu/Debian
sudo nano /etc/pam.d/sshd
auth required pam_google_authenticator.so nullok
Keep nullok at first so accounts without TOTP configured can still log in while you roll this out.
Remove it after every admin has enrolled and confirmed access.
Now enable challenge-response prompts for SSH (required for TOTP):
# /etc/ssh/sshd_config.d/99-hardening.conf
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
Validate and reload. Then test a new login. After key auth succeeds, you should get a verification code prompt.
If you run cPanel/WHM, you may prefer enforcing 2FA at the control panel layer for panel users instead of SSH. This internal guide walks through that: cPanel two-factor authentication setup.
Step 8: Restrict SSH by IP (simple, effective, easy to undo)
If your admins connect from known networks (office IPs, a VPN egress IP), IP restrictions are one of the highest-value controls you can add.
You can do this inside SSH with Match Address. In practice, it’s usually cleaner at the network layer.
Use your provider’s security groups if available, or add a minimal rule in your host firewall tooling.
A practical pattern is to allow SSH only from your VPN egress IP. If you don’t have a VPN yet, this is one place where managed hosting can help. HostMyCode can implement safe access controls as part of managed VPS hosting.
Step 9: Quick diagnostics—confirm your SSH posture
After hardening, don’t rely on “it seems fine.” Run a short set of checks you can repeat later. It’s especially useful after OS or OpenSSH updates.
- Confirm effective SSH settings:
sudo sshd -T | egrep 'port|permitrootlogin|passwordauthentication|kbdinteractiveauthentication|authenticationmethods|allowusers|allowgroups|maxauthtries|loglevel'
- Confirm which ports are actually listening:
sudo ss -lntp | egrep '(:22|:2222)'
- Check recent SSH auth activity:
# systemd journal
sudo journalctl -u ssh -S "2 hours ago" --no-pager | tail -n 80
# or
sudo journalctl -u sshd -S "2 hours ago" --no-pager | tail -n 80
- Verify Fail2Ban is actively protecting SSH:
sudo fail2ban-client status sshd
For a broader scan of exposed services and risky ports (without downtime), use this internal walkthrough: VPS security audit tutorial.
Step 10: Safe rollback plan (what to do if you lock yourself out)
Mistakes happen. A rollback plan turns a bad reload into a quick fix instead of an outage.
If you still have one SSH session open
- Restore the backup config:
sudo cp -a /etc/ssh/sshd_config.bak.YYYY-MM-DD-HHMM /etc/ssh/sshd_config
- Remove the hardening drop-in if that’s where the problem is:
sudo mv /etc/ssh/sshd_config.d/99-hardening.conf /root/99-hardening.conf.disabled
- Validate and reload:
sudo sshd -t
sudo systemctl reload ssh || sudo systemctl reload sshd
If you are fully locked out
- Use your provider’s console/rescue mode to get filesystem access.
- Revert
sshd_configand any drop-ins. - Reboot if required (some rescue environments need it).
On critical systems, it can be worth choosing a hosting plan where recovery paths are part of the service.
A HostMyCode VPS gives you VPS flexibility with predictable access tooling. You can also step up to managed options when you want the hardening handled for you.
Summary: your hardened SSH baseline for production hosting
If you only implement five changes from this SSH lockdown tutorial, make them these: key-based auth, disable root login, restrict access with users/groups, add Fail2Ban, and keep a tested rollback path.
That set blocks the most common SSH compromise patterns on hosting VPS and dedicated servers.
Once SSH is under control, the rest of your security work gets easier. TLS, mail reputation, and panel access all depend on trusted server administration.
For hosting-grade help with secure builds, migrations, and ongoing maintenance, choose managed VPS hosting or start on a flexible HostMyCode VPS and harden it with the steps above.
If you’re locking down SSH because you’re stepping into real server ownership, HostMyCode is a practical starting point. Pick a HostMyCode VPS for full control, or choose managed VPS hosting if you want a team to manage security baselines, updates, and incident-safe changes.
FAQ
Should I disable password authentication immediately?
No. First, confirm key logins work from at least two networks (your primary connection and a backup like a mobile hotspot). Disable passwords only after those tests succeed.
Is changing the SSH port worth it in 2026?
It’s useful for reducing scan noise and log volume. It doesn’t replace real controls like keys, allowlists, and Fail2Ban.
Will SSH 2FA break deployments and Git pulls?
It can if your automation uses interactive SSH. Keep automation on dedicated accounts and keys, and enforce 2FA only for human admin logins.
What’s the safest way to enforce “only these admins can SSH”?
Use AllowGroups with a dedicated group (like sshusers) and manage membership explicitly. It’s easier to review than a long AllowUsers list.
How do I confirm my server is no longer accepting passwords?
Try logging in without specifying a key and confirm SSH doesn’t offer a password prompt. Also verify sudo sshd -T | grep passwordauthentication returns no.