This post documents the process of setting up a non-domain Windows Server Failover Cluster, officially known as a Workgroup Cluster. The process is similar to Setting Up a Windows Cluster, however there is a slight difference in this scenario which is that the nodes in the cluster are not part of an Active Directory domain. This process can be used to set up a SQL Server Availability Group where the nodes are not in an Active Directory environment.
Installing the Binaries
Firstly, we need to install the binaries for WSFC which, as always, is done through Add Roles and Features in Server Manager or via PowerShell. As per the last post, I’ll install using PowerShell. This is done on each server we want in the cluster, and in my case, that is two SQL Servers – SQL03 and SQL04. Like in the last post, I’ll run these from a remote PowerShell session on a management server. We’ll need to connect to the remote computers using a local account since we’re not on a domain. For ease, I’ll just use the built-in admin account. The script below assumes that the admin password is the same on both machines, which I know is the case in my environment. Unlike my previous post, in this example I’ll loop through an array of the server names so I don’t have to repeat the command:
$servers = @("SQL03","SQL04");
$cred = Get-Credential -UserName Administrator -Message "Enter Password";
$servers | ForEach-Object {
Install-WindowsFeature -Name Failover-Clustering -IncludeManagementTools -ComputerName $_ -Credential $cred
};

All installed OK – fairly straightforward.
Primary DNS Suffix
The next step is specific to a Workgroup Cluster. We need to create a primary DNS suffix on both nodes, SQL03 and SQL04. As the nodes are not on an Active Directory domain, they don’t have a common domain name – adding the DNS suffix on both machines will ensure they both have a common suffix when resolving hostnames.
We can do this via PowerShell with the following command, which I’ll run on both nodes. We need to reboot the servers after the change:
$servers = @("SQL03","SQL04");
$cred = Get-Credential -UserName Administrator -Message "Enter Password";
$servers | ForEach-Object {
Invoke-Command -ComputerName $_ -Credential $cred -ScriptBlock {
Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters" -Name "NV Domain" -Value "ThisIsntAD";
};
Restart-Computer -ComputerName $_ -Credential $cred;
};
Once rebooted, we can verify the change has persisted:
$servers = @("SQL03","SQL04");
$cred = Get-Credential -UserName Administrator -Message "Enter Password";
$servers | ForEach-Object {
Invoke-Command -ComputerName $_ -Credential $cred -ScriptBlock {
[System.Net.Dns]::GetHostEntry($env:COMPUTERNAME).HostName;
};
};

At this stage, both SQL03 and SQL04 now have matching DNS suffixes as they would if they were both in the same domain.
Hosts File Edit
Now we need to ensure each node can resolve the full domain name of the other. To do this, we’ll add records to the hosts file.
The static IP addresses of SQL03 and SQL04 are 192.168.2.100 and 192.168.2.101 respectively, so we’ll run the following PowerShell from our management computer:
$cred = Get-Credential -UserName Administrator -Message "Enter Password";
Invoke-Command -ComputerName SQL04 -Credential $cred -ScriptBlock {
Write-Output "`n192.168.2.100 sql03.ThisIsntAD" | Out-File "C:\Windows\System32\drivers\etc\hosts" -Append -Encoding ASCII
};
Invoke-Command -ComputerName SQL03 -Credential $cred -ScriptBlock {
Write-Output "`n192.168.2.101 sql04.ThisIsntAD" | Out-File "C:\Windows\System32\drivers\etc\hosts" -Append -Encoding ASCII
};
Now let’s verify that the hostname resolves as expected:
$cred = Get-Credential -UserName Administrator -Message "Enter Password";
Invoke-Command -ComputerName SQL04 -Credential $cred -ScriptBlock {
ping SQL03.ThisIsntAD
};
Invoke-Command -ComputerName SQL03 -Credential $cred -ScriptBlock {
ping SQL04.ThisIsntAD
};

Success! Now we’ve done the prerequisites, so we can set up the cluster.
Setting Up the Cluster
Now we have to validate that the nodes are configured correctly for the cluster. Due to all sorts of double-hop authentication problems with the clustering cmdlets, I logged into one of the nodes directly at this point.
Once in the PSSession, we use the same command we used in the last post for the domain cluster:
Test-Cluster -Node @("SQL03","SQL04") -ReportName "C:/temp/ClusterReport"
In the resulting report file in C:\temp, we can see the high-level warnings:

And when drilling down:


These are similar warnings to what we saw in the last post. I’ll ignore the network configurations for the same reasons I mentioned there and bring the Windows updates in line before creating the cluster.
Creating the Cluster
As with the domain cluster, creating the cluster is a one-liner:
New-Cluster -Name NoAdCluster -Node @("SQL03","SQL04") -StaticAddress "192.168.2.251" -AdministrativeAccessPoint DNS
There is an extra parameter here that was not present for the AD cluster, which is the -AdministrativeAccessPoint. As the nodes are not on a domain, there is no AD object created for the cluster, so we need to register the cluster in DNS instead.
This returns the cluster name to us to confirm success:

We can visually confirm the cluster’s creation in Failover Cluster Manager:

Conclusion
We have set up a Windows Failover Cluster where the two nodes are not part of a Windows domain. We compared the process to how we set up a domain cluster in a previous post and contrasted the two. The process was similar, but there were some extra steps we had to take.
References / Further Reading
coeo – Domain-Independent Windows Failover Cluster for SQL Server AlwaysOn Availability Group
Edwin Sarmiento – Deploy Windows Server Failover Cluster without Active Directory Part 1
