Configurar Windows Server en un VPS: los primeros pasos
La lista de comprobación posterior al aprovisionamiento, en el orden correcto: licencia, contraseña, zona horaria, actualizaciones, firewall, asegurar RDP, discos y roles. Incluidos los puntos donde suele torcerse.
Un Windows Server recién aprovisionado parece terminado: RDP responde, aparece el escritorio, arranca el Administrador del servidor. Justo ahí está la trampa. Entre "RDP responde" y "listo para producción" hay unos veinte minutos de trabajo, y el orden de esos pasos decide si después vas a poder seguir entrando.
Aquí tienes los pasos en el orden en el que hay que hacerlos, cada uno con su comando de comprobación y con los mensajes de error citados literalmente.
Aclarar la licencia primero, no al final
Windows Server no está incluido en el precio del servidor. KernelHost no es partner de Microsoft SPLA y no alquila licencias de Windows. Aquí Windows funciona bajo el modelo Bring Your Own License: la licencia se obtiene de un partner certificado de Microsoft o directamente de Microsoft, y la aporta el cliente.
Para pruebas, evaluaciones y ensayos de migración existe la versión de evaluación gratuita de Microsoft, con 180 días de vigencia. Es completa, solo está limitada en el tiempo y no está pensada para producción.
Lo primero de todo es comprobar qué se está ejecutando realmente en el servidor:
slmgr /dlv
slmgr /xpr
slmgr /dlv muestra el nombre de la edición. Si ahí pone ServerStandardEval o ServerDatacenterEval, se está ejecutando una evaluación. slmgr /xpr indica la fecha de caducidad en texto claro. Ambos comandos abren una ventana emergente, algo que molesta en Server Core. Allí usa en su lugar cscript C:\Windows\System32\slmgr.vbs /dlv.
Qué pasa cuando se acaban los 180 días
El servidor sigue funcionando, pero el Windows License Monitoring Service lo apaga después de aproximadamente una hora de actividad, una y otra vez. Abajo a la derecha aparece una marca de agua que avisa de que la licencia de Windows ha caducado. Quien ve esto por primera vez suele pasarse horas buscando un fallo de hardware o de controladores, porque el patrón se parece al de un watchdog.
La salida limpia es pasar a una licencia real. Se puede hacer sin reinstalar:
DISM /Online /Set-Edition:ServerStandard /ProductKey:XXXXX-XXXXX-XXXXX-XXXXX-XXXXX /AcceptEula
Tres puntos en los que esto falla con frecuencia:
- Solo funciona de Eval a la versión completa del mismo nombre, o hacia arriba. DISM no te lleva de Datacenter Evaluation de vuelta a Standard.
- La clave tiene que ser Retail, MAK o KMS. Si no encaja, DISM informa de Error: 1168, o el servicio de licencias devuelve 0xC004F050 indicando que la clave de producto no es válida. Eso casi nunca significa "clave falsificada", sino "tipo de clave equivocado para esta vía".
- Un controlador de dominio no se puede pasar de Evaluation a Retail. Si ya has ejecutado
Install-ADDSForestsobre la evaluación, primero tienes que degradar el rol otra vez. Es el error más caro de este artículo, y por eso la cuestión de la licencia está aquí arriba del todo y no al final.
Un apunte sobre el origen de instalación: en KernelHost no se pueden subir imágenes ISO propias, Windows viene del catálogo de imágenes del área de cliente. La licencia la aportas tú, la imagen ya está ahí.
Cambiar la contraseña de administrador sin dejarte fuera
La contraseña que te entregan viene en el correo de aprovisionamiento y hay que sustituirla de inmediato. La vía habitual con net user Administrator * funciona, pero tiene el inconveniente de devolver un mensaje muy escueto cuando se incumple alguna directiva. Mejor así:
$pw = Read-Host -AsSecureString -Prompt "Nueva contraseña"
Set-LocalUser -Name "Administrator" -Password $pw
Si aparece La contraseña no cumple los requisitos de complejidad de contraseñas, está actuando la directiva local: al menos ocho caracteres y tres de las cuatro clases de caracteres. Los valores en vigor los puedes consultar con net accounts.
Más útil que renombrar la cuenta es crear una segunda cuenta de administrador con nombre propio. Así tienes una vía de vuelta si una de las cuentas queda bloqueada:
$pw = Read-Host -AsSecureString -Prompt "Contraseña para svcadmin"
New-LocalUser -Name "svcadmin" -Password $pw -PasswordNeverExpires
Add-LocalGroupMember -SID "S-1-5-32-544" -Member "svcadmin"
¿Por qué el SID y no el nombre del grupo? Porque el grupo de administradores se llama Administradores en un sistema en español y Administrators en uno en inglés. Los scripts que fijan el nombre en duro se rompen en el primer cambio de idioma con El grupo local especificado no existe. S-1-5-32-544 es el mismo en cualquier Windows.
La trampa del bloqueo que sí existe en Windows Server 2025
Hasta Windows Server 2019 incluido, la cuenta de administrador integrada no se podía bloquear mediante inicios de sesión por red. Desde una actualización acumulativa para Server 2022, y de forma predeterminada en Windows Server 2025, esto ha cambiado: el bloqueo de cuenta actúa a partir de cinco intentos fallidos, y también alcanza al administrador integrado.
En un VPS con el puerto 3389 abierto eso significa algo muy concreto: los intentos de inicio de sesión de los escáneres automatizados te bloquean la cuenta antes de que llegues tú. Escribes una contraseña correcta y aun así obtienes La cuenta de usuario a la que se hace referencia está bloqueada actualmente y no se puede usar para iniciar sesión.
La forma de salir cuando ya ha ocurrido:
- Inicia sesión por la consola del área de cliente en lugar de usar RDP.
- Levanta el bloqueo, ya sea esperando a que pase la duración del bloqueo (
net accountsla muestra, el valor predeterminado son diez minutos) o directamente:
$u = [ADSI]"WinNT://$env:COMPUTERNAME/Administrator,user"
$u.IsAccountLocked = $false
$u.SetInfo()
La solución duradera no es subir el umbral de bloqueo, sino limitar desde dónde se puede llegar a RDP. Eso viene más abajo. Solo después se puede volver a relajar el umbral, porque para entonces ya no llegan intentos ajenos.
Configurar zona horaria y hora antes de que se registre nada
Las imágenes de Windows están casi siempre en UTC o en una zona americana. Nadie se da cuenta hasta que el primer certificado TLS se rechaza como "todavía no válido" o hasta que los registros de eventos ya no se pueden cruzar con los de otros sistemas.
Get-TimeZone
Get-TimeZone -ListAvailable | Where-Object { $_.Id -like "*Europe*" }
Set-TimeZone -Id "W. Europe Standard Time"
"W. Europe Standard Time" cubre Viena, Berlín y Zúrich, incluido el cambio de hora de verano. La hora en sí viene del servicio de tiempo, y ahí está la verdadera diferencia entre una máquina bare metal y un servidor virtual:
w32tm /query /source
w32tm /query /status
Si como origen aparece Local CMOS Clock, el servidor no está tomando la hora de la red en absoluto. En un sistema virtualizado el reloj se desvía entonces de forma visible, a veces varios segundos al día. Configura un origen real:
w32tm /config /manualpeerlist:"time.windows.com,0x9 at.pool.ntp.org,0x9" /syncfromflags:manual /update
Set-Service w32time -StartupType Automatic
Restart-Service w32time
w32tm /resync /force
La prueba de que ha funcionado: w32tm /query /source nombra ahora uno de los servidores configurados, y w32tm /query /status muestra un valor Stratum menor que 10 junto con una hora plausible de la última sincronización. Si en cambio w32tm /resync devuelve El equipo no se volvió a sincronizar porque no había datos de hora disponibles, lo normal es que el firewall esté bloqueando el puerto UDP 123 saliente, o que el servicio todavía no estuviera en marcha.
Si el servidor se une más tarde a un dominio: entonces el controlador de dominio asume la distribución de la hora y la lista manual de pares tiene que desaparecer, porque si no acabas con dos orígenes de tiempo compitiendo.
Actualizaciones de Windows, y qué hacer cuando se quedan colgadas
Aplica los parches antes de instalar roles, no después. Si no, instalas roles a partir de un estado antiguo y luego los vuelves a pasar una segunda vez por el ciclo de actualizaciones.
En Server Core de esto se encarga sconfig, opción 6 del menú. Con interfaz de escritorio se hace desde la configuración. Y se puede automatizar con el módulo PSWindowsUpdate:
Install-PackageProvider -Name NuGet -Force
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
Install-Module PSWindowsUpdate -Force
Import-Module PSWindowsUpdate
Get-WindowsUpdate
Si la descarga desde la PowerShell Gallery falla con No se encontró ninguna coincidencia para los criterios de búsqueda especificados o con un corte de conexión, en versiones antiguas (Server 2016 y 2019) casi siempre es cosa de TLS. Ejecuta esto antes, en la misma sesión:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Para la primera pasada conviene mantener el reinicio bajo tu control:
Install-WindowsUpdate -AcceptAll -IgnoreReboot
Get-WURebootStatus -Silent
La primera tanda de parches sobre una imagen nueva tarda entre 30 y 60 minutos según la antigüedad de esa imagen y necesita dos o tres reinicios. Eso es normal. Lo que no es normal es el mensaje Error al configurar las actualizaciones de Windows. Revirtiendo cambios durante el arranque. Las dos causas más habituales en un VPS: poco espacio libre en C: (por debajo de unos 10 GB la cosa se pone justa) o un reinicio brusco en plena fase de configuración. Comprueba el espacio con Get-Volume y restablece el almacén de actualizaciones: detén los servicios wuauserv y bits, renombra C:\Windows\SoftwareDistribution y vuelve a arrancar los servicios.
Al margen: para Windows Server 2025 existe el hotpatching, es decir, actualizaciones de seguridad sin reinicio. Desde mayo de 2026 ya no cuesta nada, pero requiere una conexión con Azure Arc. Para un VPS suelto suele ser más trabajo que beneficio.
Firewall: el perfil importa más que la regla
El firewall de Windows se queda activado. Siempre. El consejo habitual de "desactívalo un momento para probar" acaba con frecuencia, en un servidor accesible desde Internet, en que se queda desactivado para siempre.
Get-NetFirewallProfile | Select-Object Name, Enabled
Get-NetConnectionProfile
El malentendido de firewall más frecuente con diferencia en Windows: la regla existe, está activada, y aun así el acceso se bloquea. La causa casi siempre es que la regla vale para el perfil Privado o Dominio, mientras que la tarjeta de red está en el perfil Público. Un VPS con IP pública directa acaba justo ahí muy a menudo después del aprovisionamiento. Comprueba de forma explícita a qué perfil pertenece una regla:
Get-NetFirewallRule -Name "RemoteDesktop-UserMode-In-TCP" | Select-Object Name, Enabled, Profile, Action
Y echa un vistazo a qué está permitido de entrada en general:
Get-NetFirewallRule -Enabled True -Direction Inbound -Action Allow | Select-Object DisplayName, Profile | Sort-Object DisplayName
Lo que no pinta nada en un VPS expuesto a Internet es compartir archivos e impresoras en el TCP 445. Si necesitas SMB, hazlo pasar por un túnel en lugar de dejarlo abierto. Un túnel WireGuard es la vía más directa, y la configuración del otro extremo está descrita en Instalar un servidor VPN WireGuard.
El eco ICMP, en cambio, deberías permitirlo, porque si no tu monitorización dará el servidor por muerto:
New-NetFirewallRule -DisplayName "ICMPv4 Echo entrante" -Protocol ICMPv4 -IcmpType 8 -Direction Inbound -Action Allow
Asegurar RDP no significa mover el puerto
Otro puerto reduce el ruido en los registros y nada más. Si aun así quieres cambiarlo, se puede hacer sin reiniciar, y está descrito en Cambiar el puerto RDP sin reiniciar. El endurecimiento de verdad consiste en otras tres cosas.
Primero: forzar la autenticación a nivel de red. Sin NLA, Windows monta la sesión antes de que nadie se haya identificado. Esa es exactamente la superficie de ataque que no quieres.
$rdp = "HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp"
Get-ItemProperty -Path $rdp -Name UserAuthentication, SecurityLayer
Set-ItemProperty -Path $rdp -Name UserAuthentication -Value 1
Set-ItemProperty -Path $rdp -Name SecurityLayer -Value 2
UserAuthentication = 1 significa NLA activo, SecurityLayer = 2 fuerza TLS para el establecimiento de la conexión.
Segundo: restringir la IP de origen. Es la medida con mayor efecto, y cabe en una sola línea. Corta por completo los ataques de contraseña, y con ellos el problema de bloqueo de cuenta de más arriba.
Set-NetFirewallRule -Name "RemoteDesktop-UserMode-In-TCP" -RemoteAddress "203.0.113.10"
Set-NetFirewallRule -Name "RemoteDesktop-UserMode-In-UDP" -RemoteAddress "203.0.113.10"
El nombre de regla es a propósito el -Name interno y no el grupo de visualización, porque ese se llama "Escritorio remoto" o "Remote Desktop" según el idioma. Varias direcciones o una red entera funcionan igual de bien, por ejemplo -RemoteAddress @("203.0.113.10","198.51.100.0/24").
Y aquí va la precaución importante: ejecuta esto desde una sesión RDP existente y deja abierta en paralelo una segunda sesión. Si te equivocas al teclear tu propia IP, la conexión desaparece al instante. La vía de vuelta es entonces la consola del área de cliente. Si en casa tienes una IP cambiante, sáltate este paso y haz que RDP solo sea accesible por VPN.
Tercero: ajustar el umbral de bloqueo a un valor razonable, una vez cerrado el firewall:
net accounts /lockoutthreshold:10 /lockoutduration:15 /lockoutwindow:15
Los tres errores de RDP que la gente busca de verdad
- Se ha producido un error de autenticación. No se admite la función solicitada. Es el caso de CredSSP de CVE-2018-0886: el cliente está parcheado, el servidor no. La solución correcta es el nivel de parches en el servidor. El apaño de registro que circula por ahí,
AllowEncryptionOracle = 2en el cliente, vuelve a abrir justo ese agujero y, si acaso, solo debería quedarse puesto hasta terminar la tanda de parches y eliminarse después. - El equipo remoto requiere autenticación a nivel de red, que su equipo no admite. Aparece con clientes muy antiguos. Aquí el servidor está bien configurado: actualiza el cliente en lugar de desactivar NLA.
- Escritorio remoto no puede conectarse al equipo remoto por alguno de estos motivos: ... Este mensaje es un cajón de sastre. Acota el problema en el servidor comprobando si hay algo escuchando siquiera:
Get-Service TermService
Get-NetTCPConnection -LocalPort 3389 -State Listen
Si vuelve una línea con 0.0.0.0:3389, el servicio está bien y el fallo está en el firewall o en el camino hasta él. Si no vuelve nada, es el servicio o un puerto cambiado. Si el servidor deja de responder por completo bajo carga y el ICMP también se queda mudo, merece la pena mirar hacia un posible ataque, y para eso encaja Proteger el servidor frente a ataques DDoS.
Añadir discos adicionales
Un segundo disco no aparece solo en el Explorador después de asignarlo. Está en bruto y hay que inicializarlo.
Get-Disk
Get-Disk | Where-Object PartitionStyle -eq 'RAW' | Initialize-Disk -PartitionStyle GPT
New-Partition -DiskNumber 1 -UseMaximumSize -DriveLetter D | Format-Volume -FileSystem NTFS -NewFileSystemLabel "Datos" -Confirm:$false
Get-Volume
GPT en lugar de MBR, siempre. MBR se queda corto en 2 TB, y el cambio posterior no le apetece a nadie. Cuatro puntos donde se tropieza:
- Disco sin conexión o protegido contra escritura.
Initialize-Diskinforma entonces de El disco está sin conexión o El disco está protegido contra escritura. Solución:Set-Disk -Number 1 -IsOffline $falseySet-Disk -Number 1 -IsReadOnly $false. - La letra D: está ocupada. En muchas imágenes ahí está montada la unidad virtual con el origen de instalación.
New-Partitionaborta con La letra de unidad especificada no está disponible. Comprueba conGet-Volumey pásate a E:, o mueve antes la unidad virtual. - Número confundido.
-DiskNumber 1no es necesariamente el disco nuevo. Compara el tamaño yPartitionStyleenGet-Diskantes de formatear. Un formateo sobre el número 0 va contra el disco del sistema. - Después de ampliar el almacenamiento, C: no crece solo. El espacio adicional queda sin particionar detrás:
Update-HostStorageCache
$max = (Get-PartitionSupportedSize -DriveLetter C).SizeMax
Resize-Partition -DriveLetter C -Size $max
Si Resize-Partition devuelve aquí El tamaño especificado no se admite o Size Not Supported, es que entre C: y el espacio libre hay una partición de recuperación. Primero hay que eliminarla o moverla al final, eso no se hace con un solo comando y no debería hacerse sin un backup.
Instalar roles y características
Solo ahora, con el nivel de parches y el firewall en su sitio, llegan los roles. Un vistazo al estado actual:
Get-WindowsFeature | Where-Object Installed | Select-Object Name, DisplayName
Un servidor web cabe en una línea:
Install-WindowsFeature -Name Web-Server -IncludeManagementTools
Get-Service W3SVC
Invoke-WebRequest http://localhost -UseBasicParsing | Select-Object StatusCode
Si vuelve StatusCode 200, IIS funciona en local. Eso todavía no dice que sea accesible desde fuera: para ello hacen falta la regla de firewall correspondiente y una comprobación desde un segundo sistema.
El clásico entre los fallos es .NET Framework 3.5. No está en el sistema en ejecución, hay que cargarlo desde el origen de instalación. Sin una imagen montada aparece:
Error: 0x800f081f
No se encontraron los archivos de origen.
En un VPS sin ISO propia tienes dos caminos: configurar la directiva para que Windows pueda descargar los archivos directamente de Windows Update, o copiar al servidor la carpeta sources\sxs de una imagen con el mismo número de compilación y apuntar a ella con -Source. Otro número de compilación no funciona, aunque pertenezca a la misma versión de Windows.
Dos puntos más sobre los roles: Uninstall-WindowsFeature -Name Web-Server -Remove no solo quita el rol, también borra sus archivos del disco. Eso ahorra espacio, pero hace que la reinstalación posterior vuelva a depender de un origen, con el mismo 0x800f081f. Y quien instale Active Directory debería subir un momento hasta el principio: sobre una licencia de evaluación eso es un callejón sin salida.
Cómo saber que todo está en su sitio
Para terminar, una ronda de comandos de comprobación. Cada uno tiene una respuesta esperada, y si alguna no encaja, el servidor todavía no está listo.
slmgr /xpr
Get-TimeZone
w32tm /query /source
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 5
Get-NetFirewallProfile | Select-Object Name, Enabled
Get-NetFirewallRule -Name "RemoteDesktop-UserMode-In-TCP" | Get-NetFirewallAddressFilter
Get-LocalUser | Select-Object Name, Enabled, PasswordLastSet
Get-Volume | Where-Object DriveLetter
Get-WindowsFeature | Where-Object Installed | Measure-Object
Lo que se espera: una fecha de caducidad o "activado de forma permanente", la zona horaria europea, un origen de tiempo real en lugar del reloj local, actualizaciones de hoy o de ayer, los tres perfiles de firewall en True, una restricción RemoteAddress en lugar de Any, una fecha de contraseña reciente en el administrador y todas las unidades con letra.
Después merece la pena un último paso que se olvida a menudo: no cortes la sesión cerrando la ventana sin más, cierra sesión como es debido. Las sesiones desconectadas siguen ahí con su consumo de memoria, y en un VPS pequeño eso se va sumando a lo largo de las semanas hasta el punto en que ya no es posible ningún inicio de sesión nuevo.
Si en paralelo estás montando un servidor Linux, Configurar un servidor root nuevo: la lista de comprobación cubre los mismos temas para el otro lado, y Asegurar SSH y configurar el acceso por clave es allí el equivalente al apartado sobre RDP.
Preguntas frecuentes
¿La licencia de Windows Server está incluida en el precio del servidor?
¿Qué pasa cuando se acaban los 180 días de la versión de evaluación?
¿Por qué me quedo fuera de mi propio servidor una y otra vez?
¿Cómo añado un segundo disco en Windows Server?
¿Qué significa el mensaje de que no se admite la función solicitada?
¿Por qué bloquea el firewall de Windows si la regla existe?
2026 KernelHost GmbH. Todos los derechos reservados. Esta guía está protegida por derechos de autor. Su publicación en otros sitios web, aunque sea de forma parcial o modificada, no está permitida sin nuestro consentimiento por escrito. Las citas con indicación de la fuente y un enlace son muy bienvenidas.

