First of all, I am a developer not a security expert. I do have some experience and expertise in setting up a windows server that does what I need it to do. I figured I could set out some of what I am up to whilst I am knee deep in migrations. Take the information included here as a suggestion or insight, however, YMMV.
Use as long a password as you can reasonably remember and type correctly for the admin account, a 15+ character gleeked phrase is a good place to start.
If possible, disable the default Administrator account and use a non-standard logon name (keep 'em guessing).
Once you're in, set the GPO to hide the last windows user.
Use tzutil to set your appropriate timezone, this will help you cross reference log timestamps properly.
When it comes time to install windows features, if you plan to install .Net 3.5 (it's actually supported until 2029!!!) You'll need either the DVD or an ISO of the particular version of the OS you are using. In theory you can also try DISM, but I've had mixed results using this. If you have MSDN, you can simply download an ISO, if you do not, Microsoft does provide Evaluation ISOs for download, which are a sufficient source for the supporting features. The one proviso here is that you have an already properly licensed OS and the use of those downloaded ISOs is to simply provide the required files for the associated feature. You can sometimes request that the hosting provider mount the installation media or obtain an internal network share path.
There are several ways to get the right files onto the server. For me, the easiest is to extract the ISO locally, set my RDP connection to see my local drives. Local drives are accessible on the remote system using \\tsclient\<drive letter>. I generally use the windows role/feature wizard to first install everything but .Net 3.5. To install 3.5, I use an elevated powershell command. Once that is done, I return to the wizard and finish anything else that required 3.5.
Two examples, one is a locally mounted ISO using VirtualCloneDrive, the other is a locally extracted location, both methods have worked for me.
Install-WindowsFeature -Name "NET-Framework-Core" -Source "\\tsclient\V\SxS" Install-WindowsFeature -Name "NET-Framework-Core" -Source "\\tsclient\D\Server Prep\Server22\sources\sxs"
If to want to try DISM:
DISM /Online /Enable-Feature /FeatureName:NetFx3 /All
I install almost everything for IIS, depending on what I am actually hosting, but NEVER WebDav. In the long long ago, when I used shared hosting, I had my website defaced more than once, by way of WebDav (as evidenced by IIS Logs).
When creating any service accounts, be sure to deny their local logon ability. This reduces vectors someone could use to logon to your system but still permit scheduled tasks, app pool security contexts etc.
Disable/block any firewall ports you do not need. Pay attention to your hosting provider's instructions as some have agents to provide health checks, and disabling some ports may cause that monitoring to fail. If it's something for your needs only, consider IP restricting the port(s).
This next bit is important, folks will be trying to get in, either to make your server a zombie to send spam or mine bitcoin, or worse. You want to install SOMETHING that can watch for failed logons on your various services and block after X attempts. Creating a policy to lock the account after X logons isn't a bad idea, but with all the bots out there, you'll most likely just get yourself locked out when someone else's attempts fail.
I use a combination of EvlWatcher and some other tools to monitor my system(s), as well as leveraging feeds like IPsum. EvlWatcher (a fail2ban clone for Windows) essentially performs that lock out on bad tries, but based on the originating IP address. It creates a firewall block for the failed IP (see above regarding the password length). This has worked pretty well for me, but YMMV. And this is important: before you walk away, make sure your home/office IP/subnet is whitelisted in the tool(s) so if you fat finger your password, you don't cut yourself off from your server.
If you have a server inside your local network, or just a computer you leave on all the time, you can install Cygwin (or if you use something like FreeNas/TrueNas/Synology, these are Linux native) and set up rsync - it just works. Unless you need SSH open in general, this is one of those times you want to limit the port to specific IP ranges like the above listed home/office computer. Hosting providers can and will remind you about "user agreed to be responsible for their site backups" if something happens to their backups, and it's just a good peace of mind in case you accidentally blow something away, or your hosted server crashes with no viable backups.
And yeah, you can install PHP, but this is a Windows server, so why would you add that attack vector? My logs are FULL of folks trying to exploit php and Wordpress and it's been three servers ago now (over nine years) since I last had any PHP installed.
If you're migrating to a new server, you can easily export/import your IIS config. I have used this technique to move from 2008 R2 -> 2012 R2, from 2008 R2 -> 2016, and 2012 R2 -> 2022. Be sure to review the XML files prior to import to remove or re-number existing sites/app pools you may have already configured ex: the Default site on the new server.
If you're using SQL server, you can perform a bulk backup and restore following techniques like these:
And of course, once you've got it set up, do some SSL magic