To secure a Windows RDP server, start with four things: let only your own IP address reach Remote Desktop (or put it behind a VPN), give the Administrator account a long, unique password, turn on an account lockout policy, and keep Network Level Authentication and Windows Update on. Moving RDP off port 3389 cuts log noise, but it is not protection.
The checklist below applies to Windows Server 2025, 2022 and 2019 and is ordered by impact. The first two steps stop almost all password guessing; the rest limit the damage if something still gets through. It is the Windows counterpart of our SSH hardening guide.
- Firewall: RDP is reachable from your IP address only.
- No public port: better still, RDP runs through WireGuard or an SSH tunnel.
- Passwords: long and unique, with an account lockout policy that also covers Administrator.
- NLA: on.
- Everyday account: a standard user in Remote Desktop Users.
- Updates: installed every month, restart included.
- Logs: failed logons (event 4625) checked now and then.
- Automatic blocking where you cannot restrict by IP.
- Redirection: drives and clipboard off when you do not need them.
What attacks hit an exposed RDP server?
Two kinds, and they need different defences.
- Password guessing. Scanners sweep the whole internet for port 3389 without pause, and a new Windows server usually sees its first login attempts within hours. They try
Administrator,admin,userand lists of leaked passwords, around the clock. A weak or reused password eventually falls. A long random one does not, but the attempts still flood your logs and can lock accounts. - Bugs that need no password. RDP has had pre-authentication vulnerabilities. BlueKeep (CVE-2019-0708) hit Windows 7, Server 2008 and Server 2008 R2. A few months later, CVE-2019-1181 and CVE-2019-1182 reached every supported Windows 10 version, Windows Server 2019 included. Microsoft rated all three wormable, patched them, and named NLA as a partial mitigation.
Both are answered by the same two habits: do not leave RDP open to everyone, and install updates.
1. How do I allow RDP only from my IP address?
Narrow the built-in Remote Desktop firewall rules to your own address. A bot that is not on the list never reaches the login screen, so there is nothing left for it to guess. This one change matters more than everything else on this page.
First find the address the server sees you connecting from. Run this inside your current RDP session, in PowerShell as Administrator (use your own port if you moved RDP):
Get-NetTCPConnection -LocalPort 3389 -State Established |
Select-Object -ExpandProperty RemoteAddress -UniqueThen restrict the rules, with that address in place of YOUR_IP. On an English Windows Server they sit in the display group Remote Desktop; on a Windows in another language, use the group’s resource ID instead.
# the built-in rules and whether they are enabled
Get-NetFirewallRule -DisplayGroup "Remote Desktop" | Format-Table DisplayName, Enabled, Profile
# admit only your address; list several with commas, or a range such as 198.51.100.0/24
Set-NetFirewallRule -DisplayGroup "Remote Desktop" -RemoteAddress YOUR_IP
# non-English Windows: the same group by its resource ID
Set-NetFirewallRule -Group "@FirewallAPI.dll,-28752" -RemoteAddress YOUR_IPIf you already moved RDP to another port with rules of your own, as in our port guide, narrow those rules by their display name instead — its restrict section has the two lines. Do not add a separate “block everyone” rule next to your allow rule: in Windows Firewall a block rule beats an allow rule, so it would block you too.
Now prove it from somewhere else, for example a phone hotspot, with your server’s address in place of 203.0.113.10. The test must fail:
Test-NetConnection 203.0.113.10 -Port 3389nc -vz -w 5 203.0.113.10 3389nc -vz -G 5 203.0.113.10 3389Windows should report TcpTestSucceeded : False, and nc should time out after five seconds. On the Mac, -G is the connect timeout; the macOS nc ignores -w while connecting.
No second network at hand? The open port checker connects from our server, which is not on your list, so after this step it must report no answer on the RDP port.
A home connection whose address changes every few days is the weak spot of this method. Allowing your ISP’s whole range is better than nothing, but it still admits everyone else on that ISP. The clean answer is the next step.
2. Should RDP sit behind a VPN?
If you can manage it, yes. With RDP reachable only through a tunnel, the internet sees no RDP port at all, a changing home IP stops mattering, and an RDP bug would have to get through the tunnel first. There are two practical routes.
- WireGuard. Run a small WireGuard server, make both your computer and the Windows server peers, and connect RDP to the Windows server’s tunnel address. The configuration for both sides is in using a VPN on a Windows RDP server.
- An SSH tunnel. Windows Server 2019 and 2022 include OpenSSH Server as an optional feature; on Windows Server 2025 it is already installed, and you only start the
sshdservice. Forward a local port to127.0.0.1:3389on the server and point the RDP client atlocalhost— set up in the tunnel section of the port guide.
Once the WireGuard path works, scope the RDP rules to the tunnel network rather than a public address, and make sure the rules cover the network profile Windows gives the tunnel adapter (usually Public):
Set-NetFirewallRule -DisplayGroup "Remote Desktop" -RemoteAddress 10.8.0.0/24With the SSH route you can disable the Remote Desktop rules entirely, because the tunnelled connection arrives over the loopback interface, which Windows Firewall does not filter. SSH is then the exposed door, so log in with a key and turn password login off in C:\ProgramData\ssh\sshd_config.
3. How do I stop brute-force attempts on the password?
Give Administrator a long random password from a password manager — you paste it anyway, so twenty characters cost you nothing — and never use it anywhere else. Then make guessing expensive with an account lockout policy.
What a server starts with depends on when it was set up. The old default lockout threshold for a stand-alone server is 0: accounts never lock, however many passwords a bot tries. Since October 2022, a machine installed from media that already contained that month’s cumulative update starts with Microsoft’s recommended values instead, but one installed earlier and updated later keeps 0, and a provider’s template may be either. So check yours, then set a limit. The values below are the 10/10/10 that Microsoft recommends in KB5020282: lock after 10 failures within 10 minutes, for 10 minutes. The lockout duration must not be shorter than the window.
net accounts # "Lockout threshold: Never" means no lockout at all
net accounts /lockoutthreshold:10 /lockoutwindow:10 /lockoutduration:10There is a catch. The built-in Administrator account — the one you log in with on most hosted Windows servers — was traditionally exempt from lockout. Since the October 2022 cumulative updates there is a separate policy for it, Windows Server 2019 and 2022 included. Open secpol.msc, go to Security Settings → Account Policies → Account Lockout Policy, and set Allow Administrator account lockout to Enabled. According to Microsoft’s KB5020282, this lockout only applies to network logons such as RDP. Console logons still work while the account is locked.
4. What is Network Level Authentication, and is it on?
With Network Level Authentication (NLA), the client has to prove the password before the server creates a Windows session and draws a login screen. Without it, anyone who can reach the port gets a logon screen built for them. NLA means less code exposed to strangers and less load per bot, and Microsoft named it a partial mitigation for the wormable RDP bugs above. It is the default when you enable Remote Desktop on current Windows Server versions, so the job is to check that nobody turned it off.
In the GUI, run SystemPropertiesRemote.exe: “Allow connections only from computers running Remote Desktop with Network Level Authentication” should be ticked. In PowerShell:
$rdp = 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp'
(Get-ItemProperty -Path $rdp).UserAuthentication # 1 = NLA required, 0 = not required
# switch it on
Set-ItemProperty -Path $rdp -Name UserAuthentication -Value 1If a Group Policy sets “Require user authentication for remote connections by using Network Level Authentication”, it overrides this value. Every current client supports NLA: Remote Desktop Connection (mstsc), Microsoft’s Windows App, FreeRDP and Remmina.
5. Should I log in as Administrator every day?
Better not. Create a standard account for daily work and add it to Remote Desktop Users. When something needs admin rights, Windows asks for the Administrator password through a UAC prompt. A hijacked session of a standard user can do far less than a hijacked admin session. Put the new account’s name in place of USERNAME:
$pw = Read-Host -AsSecureString "Password for USERNAME"
New-LocalUser -Name "USERNAME" -Password $pw
Add-LocalGroupMember -Group "Remote Desktop Users" -Member "USERNAME"
# who may log in over RDP at all (members of Administrators can by default)
Get-LocalGroupMember -Group "Remote Desktop Users"
Get-LocalGroupMember -Group "Administrators"You will often read that you should rename Administrator. It does take you off the lists of bots that only try that name, but check first whether your provider’s panel depends on it. If the panel’s password reset targets the account named Administrator, a rename quietly breaks that reset. In that case keep the name and let the firewall rule and the lockout policy do the work.
6. How do I keep Windows Server updated?
BlueKeep was patched in May 2019, months before the first attacks were seen in the wild; the machines at risk were the ones that never installed the fix. Microsoft publishes security updates on the second Tuesday of every month, and an update only protects you once the server has restarted.
# text menu on Server Core and Desktop Experience alike; it has an updates entry
sconfig
# when were updates last installed?
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 5 HotFixID, InstalledOnOn a server with the desktop, Settings → Windows Update does the same job. If the last entry is more than a month or two old, start there.
7. How do I see failed RDP logins?
Windows writes them to the Security event log. Three event IDs are worth knowing:
- 4625 — a failed logon. With NLA on, failed RDP attempts show logon type 3 (network), because the password is checked before any session exists.
- 4624 — a successful logon. An RDP session is logon type 10 (RemoteInteractive).
- 4740 — an account was locked out.
In Event Viewer that is Windows Logs → Security → Filter Current Log. In PowerShell, this lists who is knocking and who actually got in:
function Get-LogonEvents($Id, $Days) {
Get-WinEvent -ErrorAction SilentlyContinue -FilterHashtable @{
LogName = 'Security'; Id = $Id; StartTime = (Get-Date).AddDays(-$Days)
} | ForEach-Object {
$e = $_
$f = @{}
([xml]$e.ToXml()).Event.EventData.Data | ForEach-Object { $f[$_.Name] = $_.'#text' }
[pscustomobject]@{ Time = $e.TimeCreated; User = $f.TargetUserName; From = $f.IpAddress; Type = $f.LogonType }
}
}
# failed logons in the last 24 hours, counted per source address
Get-LogonEvents 4625 1 | Group-Object From | Sort-Object Count -Descending |
Select-Object -First 10 Count, Name
# successful RDP sessions in the last 7 days
Get-LogonEvents 4624 7 | Where-Object Type -eq '10' | Format-Table Time, User, FromIf the From column shows - for many failures, Windows did not record the address in those 4625 events, which happens with NLA and NTLM logons. The Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational log then helps: its event 140 names the client IP address of a failed connection.
Hundreds of failures from addresses you do not know mean RDP is still open to the world. A successful type 10 logon from an address you do not know means it is time to change passwords and look at what that session did.
8. Can Windows block an IP after failed RDP logins?
Not out of the box. Account lockout locks the account, not the attacker’s address, and Windows has no built-in equivalent of fail2ban. The approach is the same as on Linux: watch for event 4625, and once one address fails a set number of times within a window, add it to a firewall block rule. Because block rules beat allow rules in Windows Firewall, the ban holds even while the RDP port is open to everyone.
You do not have to script that yourself. IPBan is an open-source tool under the MIT licence that does exactly this on Windows and Linux; its maker also sells a Pro edition. Whatever you use, treat it as noise reduction. It cannot stop a slow attack spread over thousands of addresses, which is why step 1 comes first. If RDP is already limited to your own IP, you can skip this step.
Should I turn off drive and clipboard redirection?
By default an RDP session can map your local drives into the server and share your clipboard. That is handy for copying a file across, but it also means malware on the server can read the drives you shared and whatever you copy on your own computer, for as long as the session is open. If you do not need either, switch them off on the server for every client:
$ts = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services'
if (-not (Test-Path $ts)) { New-Item -Path $ts -Force | Out-Null }
New-ItemProperty -Path $ts -Name fDisableCdm -PropertyType DWord -Value 1 -Force | Out-Null # drives
New-ItemProperty -Path $ts -Name fDisableClip -PropertyType DWord -Value 1 -Force | Out-Null # clipboardThese are the registry values behind two Group Policy settings, “Do not allow drive redirection” and “Do not allow Clipboard redirection”, under Computer Configuration → Administrative Templates → Windows Components → Remote Desktop Services → Remote Desktop Session Host → Device and Resource Redirection. They apply from the next connection. On your own computer, the Local Resources tab in mstsc decides what you offer in the first place.
Can I add two-factor authentication to RDP?
Not with Windows alone. A local account on a stand-alone server has no built-in second factor for Remote Desktop; Microsoft’s own multi-factor options for RDP are built around Microsoft Entra ID and Remote Desktop Gateway, not a single rented server. Two practical routes remain:
- Let the tunnel be the second factor. With RDP reachable only through WireGuard or SSH (step 2), an attacker needs your tunnel key before the Windows password is worth anything. For one administrator that is usually enough.
- A credential provider on the server. Tools such as Duo Authentication for Windows Logon and RDP add a push or code prompt after the password and work with local accounts. Its installer can limit the prompt to RDP logons; choose that, so the provider’s console stays a way in if the second factor ever fails.
What about moving RDP off port 3389?
Worth doing, for a narrow reason: most bots only knock on 3389, so a different port makes your logs readable again. It is not a defence. A full port scan finds the new number quickly, and a weak password is just as weak on port 13389. Do it after the steps above, not instead of them — changing the RDP port walks through it without locking yourself out.
How do I check my RDP server in two minutes?
# 1. firewall: should list your IP or tunnel range, not "Any"
Get-NetFirewallRule -DisplayGroup "Remote Desktop" | Get-NetFirewallAddressFilter |
Select-Object -ExpandProperty RemoteAddress
# 3. lockout: threshold should be a number, not "Never"
net accounts
# 4. NLA: should print 1
(Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp').UserAuthentication
# 6. updates: the newest entry should be recent
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 1If you are still choosing between a shared RDP account and a Windows server of your own, RDP vs VPS explains the difference. A Windows RDP server from VMHeaven is a KVM machine in Amsterdam (Netherlands RDP) or Frankfurt (Germany RDP) with Windows Server 2022 or 2019 that you log in to as Administrator, and its VNC console stays reachable whatever the firewall says — so you can tighten every rule on this page without betting the server on it.
Frequently asked
Is changing the RDP port enough to secure a Windows server?
No. Moving RDP off port 3389 cuts the automated noise, because most bots only try the default port, but a port scan finds the new one quickly. The protection comes from allowing RDP only from your own IP address or through a VPN, a long unique password with an account lockout policy, and keeping NLA and Windows Update on.
What is NLA, and should it be on?
Network Level Authentication makes the client prove the password before Windows creates a session and draws a login screen. Keep it on: it is the default on current Windows Server, every modern RDP client supports it, and Microsoft names it a partial mitigation for wormable RDP bugs such as CVE-2019-1181. The registry value UserAuthentication under HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp is 1 when it is on.
How do I see failed RDP logins?
In the Windows Security event log. Event 4625 is a failed logon; with NLA on, failed RDP attempts are logged as logon type 3. Event 4624 with logon type 10 is a successful RDP session, and 4740 means an account was locked out. In PowerShell, Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625} lists the failures.
Should RDP go through a VPN?
If you can, yes. Behind WireGuard or an SSH tunnel the RDP port is not exposed to the internet at all, a changing home IP address stops mattering, and an RDP vulnerability would have to get through the tunnel first. If a VPN is not practical, restrict the Remote Desktop firewall rules to your own IP address.