How to Harden SSH Access on Your Dedicated Server

A layered, command-level walkthrough that takes your dedicated server from default SSH settings to a hardened, automated defence — key authentication first, daemon tuning second, Fail2Ban last — so each control amplifies the one before it.
Save This Article
A man walks through a server room with a laptop and a coffee cup.
At a Glance

Default SSH configurations are an open invitation: standard ports, password authentication, and no automated response to repeated failures leave a dedicated server exposed to the most routine scanning tools available. Addressing each weakness in the right order transforms isolated settings into a self-reinforcing defence.

This article walks you through generating and deploying key-based authentication, tuning the SSH daemon to eliminate low-hanging attack vectors, and configuring Fail2Ban to automate blocking — so you leave with a complete, maintainable hardening sequence grounded in concrete commands.

0 out of 5

Three controls that compound — and why sequence determines how well they hold

Save This Article

About the Author

Written by Kristian

Freelance web developer & digital marketer

About the Author

Written by Kristian

Freelance web developer & digital marketer

Table of Contents

SSH is the primary administrative gateway to your dedicated server — and it is also the most consistently targeted entry point by automated scanners and brute-force tools. A freshly provisioned server with default SSH settings will typically see login attempts within minutes of coming online. The question is not whether attackers will probe that port; it is whether your configuration gives them anything to work with.

The good news is that three layered controlskey-based authentication, daemon hardening, and automated intrusion response — dramatically reduce that attack surface without excessive operational complexity. Each control reinforces the next: cryptographic keys eliminate the credential-guessing problem, a hardened daemon configuration removes the fallback paths attackers rely on, and a tool like Fail2Ban converts repeated failure patterns into automatic, time-limited bans.

Applied in sequence, these measures shift the effort required to breach your server well beyond what automated tooling can sustain. This guide walks through that sequence in order, explaining what each control does, why the order matters, and what a misconfigured step looks like before it becomes a real incident.

Why Default SSH Settings Put Your Dedicated Server at Risk

Default SSH settings create a predictable, well-documented attack surface that automated scanning tools are specifically built to exploit. Three configurations are responsible for most of the exposure where enabled by the provider image: password-based authentication, direct root login, and the standard port 22. Each one alone is a manageable risk; together, they form a combination that requires almost no sophistication to abuse.

Password authentication is the most consequential default. When SSH accepts a username and password, every login attempt is a valid credential test. Automated tools cycle through millions of common username-password pairs in hours, requiring no human involvement. A with a publicly routable IP address and port 22 open will attract this traffic almost immediately — not because it is specifically targeted, but because it is reachable.

Any publicly reachable SSH service can be scanned regardless of whether it runs on or a VM. Exposure depends on routing and firewall policy, not on virtualization type.

Root login compounds the problem significantly. If an attacker successfully authenticates as root, there is no privilege escalation step, no additional barrier — the compromise is immediate and total. Allowing direct root login over SSH is the equivalent of leaving a master key in the front lock. Many providers ship servers with root login enabled because it simplifies initial provisioning access, but that convenience becomes a liability the moment the server is live.

Port 22 adds a third layer of predictability. Every scanner probing the internet for SSH services checks port 22 first. Changing the port does not stop a determined attacker, but it removes much of the lowest-effort automated traffic. The combination of all three defaults — password auth, root login, port 22 — is precisely what a layered hardening sequence is designed to dismantle, step by step.

A well-configured dedicated server removes each of these footholds before real traffic ever arrives.

A person is working on a network server with yellow cables.

Replacing password prompts with cryptographic key pairs eliminates the most common credential-based attack vector targeting remote servers.

How to Generate and Deploy SSH Key Pairs for Key-Based Authentication

Key-based authentication replaces the password prompt entirely: your server accepts a login only when the connecting client can prove it holds the private half of a key pair that matches the public key stored on the server. No password means no credential to guess, and no credential to guess means automated brute-force tools have nothing to work with. This single change eliminates the most common SSH attack vector before any other daemon setting is touched.

Start by generating the key pair on your local machine, not on the server. The Ed25519 algorithm is the right choice here: it produces shorter keys than RSA while offering equivalent or stronger security, and it is supported by all modern SSH implementations. Run the generation command, accept the default file location, and set a strong passphrase. That passphrase protects your private key file locally — if the file is ever copied from your machine, it is substantially harder to misuse without the passphrase.

Never transfer your private key to the server; it stays on the client side at all times.

Once the key pair exists, copy the public key to the server using the ssh-copy-id utility or by appending its contents manually to the authorized_keys file in the target user’s home directory. Verify the file permissions immediately: the .ssh directory should be set to mode 700, and the authorized_keys file itself to mode 600. Incorrect permissions cause SSH to silently reject the key, which is one of the most common reasons key-based login appears to fail during setup.

Before changing a single daemon setting, open a second terminal session and confirm that key-based login works end to end. This verification step is not optional. Every subsequent hardening change — disabling password authentication, restricting root login, moving the port — depends on this foundation being solid. Locking yourself out by disabling passwords before confirming key access is a recoverable situation on a dedicated server with out-of-band console access, but it is an avoidable delay.

Establish the key, confirm the login, then proceed.

How to Disable Password Authentication and Root Login in sshd_config

The SSH daemon configuration file — usually /etc/ssh/sshd_config — should make key login the only path. A minimal, reviewable block looks like this:

bash
PasswordAuthentication no

KbdInteractiveAuthentication no

PubkeyAuthentication yes

PermitRootLogin no

MaxAuthTries 3

Exact names and defaults vary by OpenSSH version and distribution — before reloading, run sudo sshd -t and inspect the intended effective settings with sudo sshd -T. After reloading, verify the listening socket and open a fresh session. Setting these correctly is what converts your server from "probably secure" to structurally resistant to credential guessing.

A daemon reload protects existing sessions while enforcing new rules on every connection that follows.

The order of operations is critical. Change these directives only after you have verified that key-based login succeeds in a live session. Do not close that session while editing the file. Work in a second, separate terminal window so that if a syntax error or misconfiguration prevents the daemon from restarting cleanly, your original session remains open and you can correct the file without needing out-of-band console access.

Setting PasswordAuthentication no disables all password-based logins immediately upon daemon reload. Setting KbdInteractiveAuthentication no closes a secondary path that some systems leave open even when the main password directive is disabled — both directives must be addressed together. Setting PermitRootLogin no removes the root account as a valid SSH target entirely, forcing all administrative access through a named user account with sudo privileges.

After saving the file, reload the daemon rather than restarting it outright. A reload applies the new configuration to new connections while leaving existing sessions intact — a meaningful safety net during hardening work. Once the reload completes, attempt a fresh login from a third terminal window before closing your working sessions. This confirms the new configuration is active and functional.

One practical consideration worth noting: dedicated server environments with remote console or access give you a recovery path if something goes wrong, which is a meaningful operational advantage over virtual environments where out-of-band access may not offer equivalent recovery options. That safety net makes it reasonable to apply these changes decisively rather than incrementally.

A desk with a notebook, metal plates, tags, and a pen.

Relocating the SSH daemon away from its default port dramatically reduces the volume of automated login attempts your server must absorb every day.

How to Move SSH Off Port 22 and Harden SSH Daemon Exposure

A public server with no extra filtering will typically accumulate thousands of port-22 probe attempts within its first 24 hours online, each one consuming daemon resources and inflating log noise that can obscure genuine intrusion signals. Moving the daemon off port 22 mainly reduces scan noise and log clutter — it does not replace key-based auth, account limits, or a firewall.

Port selection mainly reduces automated noise; treat it as hygiene, not a primary control. Choose a port above 1024 — the range below is reserved for privileged services — and avoid well-known alternates such as 2222 or 8022, which appear in many scanning scripts as secondary targets. Any free, documented non-default port works; the goal is less scan noise, not secrecy.

Before changing the Port directive in sshd_config and reloading the daemon, update your firewall to allow the new port and explicitly block port 22. The sequence is non-negotiable: open the new port first, reload the daemon second, verify a successful login on the new port third, then remove the port 22 rule. Reversing that order risks a lockout.

Beyond the port change, three additional sshd_config directives complete the exposure reduction. AllowUsers restricts SSH access to an explicit list of named accounts — any account not listed is silently rejected at the daemon level, regardless of credentials. LoginGraceTime sets the maximum seconds the daemon waits for a completed authentication sequence; reducing it from the default 120 seconds to 30 seconds shortens the window each unauthenticated connection holds open. MaxAuthTries limits failed authentication attempts per connection before the daemon closes it; a value of 2 or 3 is appropriate once key-based login is confirmed as reliable.

These directives work as a layered system: each one removes a specific opportunity that an attacker would otherwise exploit in sequence. The full hardening workflow — including the interaction between these directives and the Fail2Ban rules covered in the next section — is detailed in our dedicated server recommendation guide.

A man is working on a computer with code on the screen.

Fail2Ban transforms passive login restrictions into active, real-time bans by monitoring authentication logs and blocking repeat offenders across multiple connections.

How to Install and Configure Fail2Ban to Block Brute-Force Attempts

Fail2Ban is the automated enforcement layer that turns your sshd_config rules into active, real-time blocking. MaxAuthTries closes a single connection after a fixed number of failures; Fail2Ban watches the authentication log across connections (a mistyped key passphrase is typically local and never appears as a server auth failure) and bans the source IP once a threshold is crossed — making repeated reconnection attempts from the same host less useful.

Installation is straightforward on most Debian- and Ubuntu-based distributions: the package is available in standard repositories and requires no compilation. The critical configuration step comes immediately after installation. Fail2Ban ships with a default jail configuration file, but you must create a local override file — conventionally named jail.local — rather than editing the distributed defaults. This separation ensures that a package update does not silently overwrite your tuned settings.

Inside that local file, declare an SSH jail that points to your authentication log path, references the correct filter, and specifies the custom listening port you set in the previous step. Set the jail’s port/action consistently with the actual SSH listener so the resulting firewall ban protects the correct port. Verify the jail with a controlled test.

Two threshold values determine how aggressively the jail responds. The first is maxretry, which defines how many failed authentication events from a single IP are permitted within the detection window before a ban is issued. A value of three to five strikes the right balance: low enough to catch credential-stuffing tools, which typically fire dozens of attempts in seconds, but high enough to tolerate occasional legitimate authentication failures (wrong key presented, or a mistyped account password if passwords are still briefly enabled during cutover).

The second is bantime, which controls how long a banned IP remains blocked. Starting at 3600 seconds — one hour — is reasonable for most environments; high-risk or compliance-bound deployments on a dedicated server often extend this to 24 hours or longer to reduce the operational burden of repeat offenders.

After reloading the service, verify the jail is active by checking its status directly in the Fail2Ban client. Confirm the correct port appears in the output, and trigger a test ban manually using a known safe IP to validate that the unban command also works before relying on the setup in production.

The Dedicated Server User Management – Sudo and Role-Based Access guide covers how to structure the admin accounts whose IPs you may want to whitelist in Fail2Ban's ignoreip directive, keeping your own access protected while enforcement runs automatically.

How to Verify Your SSH Hardening Controls Are Actually Enforced

AllowUsers (or equivalent allow-lists), structuring admin accounts, and whitelisting trusted IPs handle the access side of enforcement. The gap that remains is confirming the daemon itself is running the settings you wrote — a directive can be syntactically valid, absent from any error log, and still silently ignored if the daemon never reloaded cleanly, leaving enforcement gaps that neither Fail2Ban nor your firewall ruleset can compensate for.

Validate syntax with sudo sshd -t, inspect effective settings with sudo sshd -T, reload the service, then verify the listening socket and a fresh connection. A mismatch here is the clearest signal that a reload did not apply.

Keep your existing session open throughout and open a second terminal for each connection test; a failed attempt in that second window costs nothing, whereas losing your only session mid-hardening on a dedicated server — where no hypervisor layer exists to catch the error — can leave no recovery path short of an out-of-band console.

Run sshd -T to print the effective configuration that would be used when the daemon starts or reloads. Run sshd -t first to validate syntax.

  • Confirm the connection succeeds with no password prompt, proving the daemon reloaded the updated config
  • Force a password authentication attempt using the appropriate flag to confirm it is rejected
  • Test root login directly to verify that PermitRootLogin no is enforced and returns an access denied response
  • Check the active listening port with a network scan or ss command to confirm the daemon moved off port 22
  • Review the Fail2Ban jail status to confirm the SSH jail is active and processing the correct log file
  • Inspect the parsed effective configuration with sudo sshd -T, then verify the running listener separately with ss -lntp and a fresh connection

Begin with key-only login. Open a second terminal and attempt to connect using your private key. A successful connection without any password prompt confirms that key-based authentication is functioning and that the daemon has reloaded the updated configuration.

The server must refuse the attempt outright, returning an explicit permission denied message rather than a password prompt. If a prompt still appears, the Password Authentication directive has not taken effect, which means either the configuration file was not saved correctly or the daemon was not reloaded after the change.

The output should show your SSH jail as active, list the correct non-default port, and display a zero or low ban count if the server is newly provisioned. A jail that reports zero monitored connections is a warning sign: it often means the log path or port value in the local override file does not match the actual daemon configuration.

Cross-reference the authentication log directly to confirm that your test connection attempts — both successful and rejected — appear as expected entries.

Finally, verify that your custom listening port is the only one accepting SSH connections. A port scan from an external host against the old default port should return no response. This single check closes the most common gap: a misconfigured daemon that silently falls back to listening on multiple ports.

A dedicated server's full administrative access makes this confirmation sequence especially consequential — there is no hypervisor layer or provider abstraction to catch configuration errors before they affect production access.

A man in a safety vest uses an access control reader in front of a cage with switches and a key rotation checklist.

Maintaining strong SSH security requires ongoing attention to key audits, software updates, and configuration reviews as your team and threat landscape evolve.

How to Keep Your SSH Configuration Secure Over Time

SSH hardening is not a one-time task. The controls you put in place on day one will degrade unless you build deliberate maintenance habits around them. Team changes, software updates, and evolving threat patterns all create gaps that a static configuration cannot address on its own.

The most overlooked maintenance task is authorised key rotation. Every administrator who leaves your team — whether through role change, departure, or contract end — leaves behind a private key that still exists somewhere outside your control. Removing their public key from every relevant account on the server should happen on the same day access is revoked, not at the next scheduled overview.

After editing authorized_keys, test a fresh session before closing the current one.

A practical habit is to treat the authorised keys file as a living access list: audit it whenever your team roster changes, and schedule a full overview at least quarterly for stability.

Pair this with a log overview routine: Fail2Ban's ban log and the system authentication log together give you an early-warning signal for unusual login patterns, repeated failures from unfamiliar source addresses, or sudden spikes in blocked attempts that may indicate a targeted campaign rather than generic scanning noise.

Rotate keys when personnel, device ownership, cryptographic policy, or suspected compromise requires it. Maintain an inventory and revoke obsolete keys immediately.

For teams that want a structured, recurring approach to these checks, Automated Security Auditing on a Dedicated Server with Lynis covers how to schedule hardening audits as an automated loop rather than a manual checklist.

SSH Hardening Controls: Key Auth vs. Fail2Ban vs. SSH Daemon Config

Criterionatetcssh
Primary attack vector addressedRepeated failed logins triggering time-limited bansPredictable defaults: password auth, root login, port 22Credential guessing via password-based authentication
Configuration locationSeparate service config, typically /etc/fail2ban/SSH daemon file, typically /etc/ssh/sshd_configKey pair stored on client; public key on server
Protects against root compromiseIndirectly, by banning IPs before root credentials succeedDirectly, by disabling PermitRootLogin in daemon configDirectly, no password means no credential to guess
Blocks automated scannersBans source IPs after configurable failure thresholdNon-standard port removes highest-volume automated trafficEliminates credential-guessing loop entirely, no prompt offered
Requires ongoing maintenanceLog monitoring and jail rule review recommended periodicallyMinimal; settings persist unless daemon config is changedKey rotation and passphrase discipline on client side
Effective without other controlsPartial; still exposes password prompt if keys not enforcedPartial; daemon hardening alone does not stop all attemptsHigh; removes primary attack vector before other settings apply

Conclusion – One Hardened Entry Point, Significantly Smaller Attack Surface

For provider fit and procurement context, see our guide to choosing a dedicated server provider and the honest recommendation overview.

Prioritize key-based authentication and disabling password (and usually root) login first. A non-default port and Fail2Ban are complementary layers for noise reduction and leftover probes — not substitutes for strong auth. Each one raises the cost of unauthorized access: an attacker who bypasses generic port scanning still faces cryptographic authentication, and one who generates repeated failures triggers an automatic block before a meaningful attempt can be completed.

The discipline of maintaining this configuration over time — rotating keys, auditing access lists, and evaluating ban logs when team membership changes — is what separates a hardened server from one that was simply configured once and forgotten. On a dedicated server, where every setting applies directly to production hardware with no intermediary layer to absorb mistakes, that ongoing discipline carries real operational weight.

FAQ - Frequently Asked Questions

Key-based authentication eliminates the credential-guessing problem at its root — without it, changing the port or configuring Fail2Ban only slows attackers rather than blocking the attack vector entirely. Each subsequent control in the layered sequence assumes that password-based login is already disabled, so applying them out of order leaves exploitable fallback paths in place. Starting with cryptographic keys ensures every later control reinforces a foundation that automated scanners cannot brute-force.
Cryptographic keys remove the credential-guessing problem, a hardened daemon configuration eliminates the fallback paths — such as direct root login and password authentication — that attackers rely on when keys are enforced, and Fail2Ban converts repeated failure patterns into automatic bans that protect the remaining attack surface. Applied in that order, each layer assumes the previous one is already in place, so the combined effect is multiplicative rather than additive. Skipping or reordering a step breaks the dependency chain and leaves gaps that automated tooling is built to find.
Any publicly reachable SSH service can be scanned regardless of whether it runs on bare metal or a VM. Exposure depends on routing and firewall policy, not virtualization. On bare metal, every automated login attempt lands directly on your daemon, which is why a freshly provisioned server with default settings typically attracts brute-force traffic within minutes of coming online.
A common early warning is successful key authentication combined with an sshd_config that still permits PasswordAuthentication yes as a fallback, meaning an attacker who cannot use your key can still attempt credential stuffing. Another indicator is a port change applied without a corresponding firewall rule update, which can lock you out of your own server before any attacker is affected. Reviewing the daemon configuration with sshd -T and testing each change in a second terminal before closing the original session catches these misconfigurations before they escalate.
Fail2Ban should be configured after key-based authentication is enforced and the daemon is hardened, because its value is converting residual failure patterns — such as probes against a non-standard port or rare misconfigured clients — into time-limited bans rather than serving as the primary defence. If Fail2Ban is applied before password authentication is disabled, it becomes the only barrier against credential stuffing, which is a role it is not designed to carry alone. Positioning it last in the sequence means it reinforces controls that have already eliminated the highest-volume attack vectors.
Password-based authentication and direct root login drive most real SSH risk; port 22 mainly increases visibility and log noise rather than being a vulnerability by itself. Each is a manageable risk in isolation, but together they form a combination that requires almost no attacker sophistication to abuse — automated tools cycle through credential pairs against port 22 while targeting root directly to skip privilege escalation entirely. Hardening all three in the daemon configuration is the step that removes the fallback paths that remain even after key-based authentication is enabled.
Keep your original SSH session open and open a second, independent session to test each configuration change before applying it permanently — if the new session fails, you still have the original connection to revert the change. After a validated reload of the SSH daemon, confirm that key authentication succeeds, that password authentication is rejected, and that root login is denied before closing any session. Running sshd -T after each edit to sshd_config surfaces syntax errors and unintended effective values before a validated reload makes them active.
When an attacker authenticates as root, there is no privilege escalation step required — the compromise is immediate and total, granting unrestricted control over your dedicated server from the first moment of access. A standard user account, by contrast, forces an attacker to clear at least one additional barrier before achieving the same level of control. This distinction makes disabling direct root login a critical daemon configuration change, not a minor hardening preference.

Share this article

Save This Article
Kristian

About the Author

Kristian is a freelance web developer with years of hands-on experience building and hosting websites for real-world projects. On this site, he shares practical insights on dedicated server infrastructure and hosting to help readers choose the right setup for their needs.

Was This Article Helpful?

Your feedback helps us improve the quality, relevance, and usefulness of the content we publish.
0 out of 5 (0 ratings)

About This Article

Editorial Note
Affiliate Link Disclosure *
Report an Error

You May Also Like

This website uses cookies

We use cookies to personalize content, provide social media features, and analyze our traffic. We also share information about your use of our site with our analytics partners. You can change your preferences at any time. For more information, please see our Privacy Policy.