Windows Server Failover Clustering (WSFC) provides high availability for critical workloads by automatically failing over services between cluster nodes when hardware or software failures occur. This guide covers setting up a two-node failover cluster on Windows Server VPS instances.
Prerequisites
- Two or more Windows Server VPS instances with identical configurations
- Active Directory: All nodes must be domain-joined
- Shared storage: iSCSI SAN, Storage Spaces Direct, or shared disk
- Multiple NICs: Separate networks for cluster heartbeat and client traffic
- Same Windows Server version on all nodes
Install Failover Clustering Feature
# Install on ALL cluster nodes
Install-WindowsFeature -Name Failover-Clustering -IncludeManagementTools
# Verify
Get-WindowsFeature Failover-Clustering
Validate Cluster Configuration
# Run validation tests before creating the cluster
# This checks network, storage, and system configuration
Test-Cluster -Node "node1.corp.example.com", "node2.corp.example.com" `
-Include "System Configuration", "Network", "Storage"
# Review the validation report
# Located at: C:\Users\Administrator\AppData\Local\Temp\Validation Report*.html
# For VPS environments where shared storage may differ
Test-Cluster -Node "node1", "node2" -Include "System Configuration", "Network"
Create the Cluster
# Create a new failover cluster
New-Cluster -Name "MyCluster" `
-Node "node1.corp.example.com", "node2.corp.example.com" `
-StaticAddress 10.0.0.100 `
-NoStorage
# Verify cluster is running
Get-Cluster
Get-ClusterNode | Format-Table Name, State, NodeWeight
# Configure cluster quorum
# For 2-node clusters, use a file share witness or cloud witness
# File Share Witness
Set-ClusterQuorum -NodeAndFileShareMajority "\\fileserver\ClusterWitness"
# Cloud Witness (Azure Storage Account)
Set-ClusterQuorum -CloudWitness `
-AccountName "mystorageaccount" `
-AccessKey "YourAzureStorageKey"
Configure Cluster Networks
# View cluster networks
Get-ClusterNetwork | Format-Table Name, State, Role
# Rename networks for clarity
(Get-ClusterNetwork "Cluster Network 1").Name = "Client Network"
(Get-ClusterNetwork "Cluster Network 2").Name = "Heartbeat Network"
# Set network roles
# 0 = Not used by cluster
# 1 = Cluster only (heartbeat)
# 3 = Client and cluster
(Get-ClusterNetwork "Client Network").Role = 3
(Get-ClusterNetwork "Heartbeat Network").Role = 1
Add Clustered Roles
# Generic Service (e.g., for a custom application)
Add-ClusterGenericServiceRole -ServiceName "MyAppService" `
-Name "MyApp" `
-StaticAddress 10.0.0.101
# File Server Role
Add-ClusterFileServerRole -Name "ClusterFS" `
-Storage "Cluster Disk 1" `
-StaticAddress 10.0.0.102
# SQL Server Always On (after SQL is installed on both nodes)
# Enable Always On in SQL Server
Enable-SqlAlwaysOn -ServerInstance "node1" -Force
Enable-SqlAlwaysOn -ServerInstance "node2" -Force
# Hyper-V Virtual Machine (clustered VM)
Add-ClusterVirtualMachineRole -VMName "ImportantVM"
Test Failover
# Manual failover for testing
Move-ClusterGroup "MyApp" -Node "node2"
# Verify the role moved
Get-ClusterGroup "MyApp" | Select-Object Name, OwnerNode, State
# Move back
Move-ClusterGroup "MyApp" -Node "node1"
# Simulate node failure (careful in production!)
# Stop-ClusterNode "node1" # This will trigger automatic failover
# Check failover events
Get-ClusterLog -Destination C:\ClusterLogs -TimeSpan 60
Monitoring
# Check cluster health
Get-ClusterNode | Select-Object Name, State
Get-ClusterGroup | Select-Object Name, OwnerNode, State
Get-ClusterResource | Select-Object Name, OwnerGroup, State
# Cluster-aware updating (rolling patches)
$cau = New-CauOrchestrator
Invoke-CauRun -ClusterName "MyCluster" `
-MaxRetriesPerNode 3 `
-RequireAllNodesOnline `
-EnableFirewallRules `
-Force
# Cluster event monitoring
Get-WinEvent -LogName "Microsoft-Windows-FailoverClustering/Operational" `
-MaxEvents 20 | Format-Table TimeCreated, Message
Storage Spaces Direct (S2D) for VPS
# Enable Storage Spaces Direct (Windows Server 2022 Datacenter)
# Each node contributes local storage to a shared pool
Enable-ClusterStorageSpacesDirect -PoolFriendlyName "S2D Pool" `
-Confirm:$false
# Create a virtual disk
New-Volume -FriendlyName "ClusterVolume1" `
-FileSystem CSVFS_ReFS `
-StoragePoolFriendlyName "S2D Pool" `
-Size 100GB `
-ResiliencySettingName Mirror
Best Practices
- Always run validation tests before creating or modifying a cluster
- Configure a witness: Essential for 2-node clusters to prevent split-brain
- Separate heartbeat network: Use a dedicated network for cluster communication
- Test failover regularly during maintenance windows to ensure it works
- Use Cluster-Aware Updating for rolling patches without downtime
- Monitor cluster health and set up alerts for node failures
- Document your cluster configuration including network, storage, and role assignments