RDP brute-force traffic is relentless and largely automated. An exposed Windows Server on a public IP will typically see its first credential-guessing attempts within hours of going live, and the pattern is repetitive: a few thousand attempts against Administrator from a handful of /24s, then a pause, then a shift to the RDP port if that proves unreachable. The defences that actually reduce the volume are, in order of effectiveness: not exposing RDP at all, requiring Network Level Authentication so unauthenticated clients cannot even reach the login prompt, and then rate limiting and lockout for whatever still arrives. This article covers each layer with the concrete settings.
The Baseline: Measure Before You Change Anything
Before hardening, record what the server is seeing. The two log sources that matter are the Security log on the target (events 4625 for failed logon, 4624 for success, 4776 for credential validation) and any logs from your provider’s edge firewall. A quick count over the last seven days gives you a baseline to compare against after the changes:
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddDays(-7)} | Measure-Object
Then break it down by source address and target account. If the top talkers are a small set of IPs hitting Administrator, that is generic scanning. If the source set is large and distributed, you are the target of a coordinated credential-stuffing run, and per-IP blocking will not help much — account lockout policy and MFA will.
Layer One: Do Not Expose 3389
The single most effective RDP hardening step costs nothing in software: stop publishing TCP 3389 to the internet. The options, roughly in order of preference for a VPS:
- VPN first. Put the VPS on a WireGuard or OpenVPN endpoint and connect to RDP over the tunnel. The RDP listener binds to the private interface only.
- RD Gateway. Expose only HTTPS 443 on the gateway and keep the session hosts on a private network. This is the correct enterprise answer and works well on a two-node VPS estate.
- IP allowlist. Restrict 3389 to your office and home ranges at both the provider firewall and Windows Firewall. Cheap, but brittle when your ISP changes your address.
- Non-standard port. Reduces log noise from broad scans by a large factor but is not a security control; treat it as tidying, not defence.
If you must expose RDP directly, do it with NLA enforced and with the allowlist as narrow as you can tolerate. The secure RDP setup walkthrough for Windows Server covers the firewall scoping and certificate steps for that configuration.
Layer Two: Network Level Authentication
NLA moves authentication to the connection phase, before a session is allocated and before the login screen is drawn. It uses CredSSP and requires a Kerberos or NTLM handshake, which means most brute-force scripts cannot reach the stage where they submit passwords. On Windows Server it is enabled by default, but it can be disabled by group policy or by a misconfigured remote app.
Confirm it is required, not merely supported:
Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' -Name UserAuthentication
A value of 1 means NLA is required. 0 means it is not, and the server will accept unauthenticated connections that land directly on the logon screen. Also check the policy path Computer Configuration → Administrative Templates → Windows Components → Remote Desktop Services → Remote Desktop Session Host → Security → Require user authentication for remote connections by using Network Level Authentication, because group policy will overwrite the local registry setting on the next refresh.
Layer Three: Account Lockout Without Locking Yourself Out
Account lockout is a blunt instrument, and it is also the fastest way to lock yourself out of your own VPS. The settings that trade brute-force resistance against availability are threshold, duration, and observation window. A reasonable starting point for a small server is a threshold of 5 failed attempts, a 15-minute duration, and a 15-minute observation window — enough to blunt a password spray against a single account without turning a typo into a support incident.
The critical safeguard is a second, unprivileged-except-for-RDP path in: a break-glass local account with a long random password stored offline, allowed to log on via RDP but not a member of Domain Admins. Verify it works before you enable lockout. Then verify it again after a group policy refresh.
Layer Four: Rate Limiting the Source, Not the Account
Account lockout punishes the target. Rate limiting punishes the source, and that is what you want against a distributed spray. Linux operators reach for fail2ban; on Windows the equivalent patterns are Windows Firewall dynamic rules, a PowerShell watchdog, or the built-in Block-RdpConnection-style approaches in third-party tools. A minimal, dependency-free watchdog is a scheduled task that runs every five minutes, parses the last window of 4625 events, and adds a Windows Firewall block rule for any source address that exceeded a threshold.
Pseudo-code for that job: query Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddMinutes(-10)}, extract IpAddress from each event’s XML, group and count, then for any address over the limit check whether a rule named RDP-Block-<ip> already exists and create it with New-NetFirewallRule -Direction Inbound -RemoteAddress $ip -Action Block if not. Expire rules older than 24 hours on the same schedule.
Two cautions. First, use a threshold high enough that a legitimate user fumbling a password twice is not blocked — 30+ failures in 10 minutes is a reasonable floor. Second, never block a range that includes your own management address; a static egress IP for your office and a documented exception list prevent the worst outcome.
Layer Five: Make the Credential Useless
The layers above reduce the number of guesses reaching the authentication stack. The final layer makes a successful guess worthless. Rename or disable the built-in Administrator account and use named administrative accounts instead; require long passwords (16+ characters) for any account permitted to RDP; and enable MFA at the RDP layer using an RD Gateway with Azure MFA/NPS extension or a third-party credential provider. For a single-admin VPS, the 80% solution is a renamed admin account, a 20-character password in a password manager, NLA enforced, and RDP reachable only from a VPN or allowlist.
| Control | Effort | Effect on brute-force volume |
|---|---|---|
| Remove public 3389 (VPN / allowlist) | Medium | Near-total |
| Require NLA | Low | High — blocks pre-auth attempts |
| Account lockout 5/15/15 | Low | Medium against single-account spray |
| Source rate-limit watchdog | Medium | High against distributed attempts |
| MFA / RD Gateway | High | Very high — defeats valid passwords |
Verification and Ongoing Monitoring
After each change, re-run the 4625 baseline and compare. You should see the absolute count fall sharply once NLA and network restrictions are in place, and the surviving events should be concentrated on the accounts you deliberately left reachable. Alert on successful logons (4624 type 10) from addresses outside your expected set; that is the signal that matters more than the noise.
Keep the whole configuration in version control as a PowerShell script so a rebuild reproduces it. Hardening that lives only in a GUI is hardening you will lose the first time the instance is replaced. If you are standing up a new instance and want the RDP path correct from the first boot, the Windows VPS hosting options page describes the standard network configurations, and the hosting support team can confirm whether your provider firewall can do the allowlisting for you.

