Runbook: Deploy home-dc02 (Windows Server 2025)

Last Updated

2026-02-10

Owner

EvanusModestus

Frequency

One-time


1. Purpose

Deploy home-dc02 as Windows Server 2025 domain controller for AD redundancy.

ISE 3.4 + Windows Server 2025 - CONFIRMED WORKING

Despite Field Notice FN74321 warnings about SAM RPC compatibility, ISE 3.4 Patch 3 successfully joins Windows Server 2025 domains with the following configuration:

  1. Apply registry fixes on WS2025 DC (see WS2025 Registry Fixes below)

  2. Reboot ISE after AD join attempt (critical step)

  3. AD authentication succeeds without TAC hotpatch

Tested: 2026-02-11 - RPC Logon succeeded, groups/attributes retrieved in <50ms total.

This runbook adds a second DC - it does NOT replace home-dc01.

2. Architecture

Component home-dc01 (existing) home-dc02 (new)

OS

Windows Server 2025 Core

Windows Server 2025 Core

IP

10.50.1.50

10.50.1.51

Roles

AD DS, DNS

AD DS, DNS

ISE Compatible

Requires TAC hotpatch (FN74321)

Requires TAC hotpatch (FN74321)

3. Prerequisites

  • Windows Server 2025 ISO downloaded to kvm-01

  • DNS A record for home-dc02.inside.domusdigitalis.dev → 10.50.1.51

  • home-dc01 operational and reachable

  • Domain Administrator credentials available

3.1. Download ISO

Select: 64-bit editionISO

3.2. Transfer ISO to KVM Host

Verify ISO downloaded correctly (~8GB for WS2025 eval):

ls -lh ~/Downloads/26100*SERVER_EVAL*.iso
Expected output
.rw-r--r--  8.2G evanusmodestus  9 Feb 00:42  26100.32230.260111-0550.lt_release_svc_refresh_SERVER_EVAL_x64FRE_en-us.iso

The ~8GB ISO with build 26100 in filename is Windows Server 2025. Smaller ~5GB SERVER_EVAL_x64FRE_en-us.iso is Windows Server 2022.

Transfer to KVM host (rsync to /tmp first, then sudo mv):

rsync -avP ~/Downloads/26100.32230.260111-0550.lt_release_svc_refresh_SERVER_EVAL_x64FRE_en-us.iso kvm-01:/tmp/

Storage Location: The KVM host root disk is small (14GB). Store ISOs and VM disks on /mnt/onboard-ssd (978GB SSD).

Move to onboard SSD:

ssh kvm-01 "sudo mv /tmp/26100.32230.260111-0550.lt_release_svc_refresh_SERVER_EVAL_x64FRE_en-us.iso /mnt/onboard-ssd/windows-server-2025.iso"

Verify on KVM host:

ssh kvm-01 "ls -lh /mnt/onboard-ssd/windows-server-2025.iso"

3.3. Create DNS Records (pfSense)

Load credentials:

dsource d000 dev/network

Verify existing DC DNS entries:

netapi pfsense dns list | grep home-dc

If home-dc01 is missing, add it:

netapi pfsense dns add --host home-dc01 --domain inside.domusdigitalis.dev --ip 10.50.1.50 --descr "Windows Server 2025 DC (Server Core)"

If home-dc01 already exists, you’ll see: Error: [400] Fields [host, domain] together must be unique…​ - this is expected, skip to the next step.

Add home-dc02:

netapi pfsense dns add --host home-dc02 --domain inside.domusdigitalis.dev --ip 10.50.1.51 --descr "Windows Server 2025 DC (Server Core)"

Verify both entries:

netapi pfsense dns list | grep home-dc
Expected output
│ XX │ home-dc01 │ inside.domusdigitalis.dev │ 10.50.1.50 │ Windows Server 2025 DC (Server Core) │
│ XX │ home-dc02 │ inside.domusdigitalis.dev │ 10.50.1.51 │ Windows Server 2025 DC (Server Core) │

Test resolution:

dig home-dc01.inside.domusdigitalis.dev +short
dig home-dc02.inside.domusdigitalis.dev +short

DHCP Clients: All clients receiving DNS via DHCP from pfSense (10.50.1.1) will automatically resolve both DCs through these host overrides. No client-side DNS changes required.

DNS Architecture:

  • Client DNS: pfSense (10.50.1.1) - serves host overrides + forwards external queries

  • AD DNS: home-dc01/home-dc02 - AD-integrated zones (SRV records for _ldap._tcp, _kerberos._tcp)

  • pfSense forwards AD queries: Domain override for inside.domusdigitalis.dev → 10.50.1.50

3.4. Verify pfSense Domain Override (AD SRV Records)

Domain-joined clients need SRV records (_ldap._tcp, _kerberos._tcp). pfSense must forward these to a DC.

Check existing domain overrides:

netapi pfsense dns list-overrides

If inside.domusdigitalis.dev is not forwarded to a DC, add it:

Via pfSense GUI

Services → DNS Resolver → Domain Overrides:

Domain

inside.domusdigitalis.dev

IP Address

10.50.1.50

Description

Forward AD DNS queries to home-dc01

Test SRV record resolution:

dig _ldap._tcp.inside.domusdigitalis.dev SRV +short

Expected: Returns SRV record pointing to home-dc01 or home-dc02.

4. Phase 1: Create VM on KVM

4.1. 1.1 VM Specifications

Resource Value

RAM

4 GB

vCPUs

2

Disk

40 GB (on /mnt/onboard-ssd)

Network

virbr0 (default libvirt bridge)

ISO

windows-server-2025.iso (on /mnt/onboard-ssd)

4.2. 1.2 Create VM

ssh kvm-01
sudo virt-install \
    --name home-dc02 \
    --ram 4096 \
    --vcpus 2 \
    --disk path=/mnt/onboard-ssd/home-dc02.qcow2,size=40,bus=virtio \
    --os-variant win2k22 \
    --network bridge=virbr0,model=virtio \
    --graphics vnc,listen=0.0.0.0 \
    --cdrom /mnt/onboard-ssd/windows-server-2025.iso \
    --disk path=/home/evanusmodestus/.cache/yay/virtio-win/virtio-win-0.1.285-1.iso,device=cdrom

os-variant: Use win2k22 as libvirt doesn’t have a win2k25 variant yet. This is compatible with Windows Server 2025.

virtio-win: The VirtIO drivers ISO location may vary. Check with:

find /home -name "virtio-win*.iso" 2>/dev/null

4.3. 1.3 Access VM Console

Option A: Cockpit (Recommended)

Open browser to: kvm-01:9090

  1. Log in with your credentials

  2. Navigate to Virtual Machineshome-dc02

  3. Click Console tab

Option B: VNC

sudo virsh vncdisplay home-dc02

5. Phase 2: Windows Server Installation

5.1. 2.1 Installation Wizard

Select Server Core - NOT Desktop Experience. Server Core uses less resources and has smaller attack surface.

  1. Language/keyboard → Next

  2. Click Install now

  3. Select Windows Server 2025 Standard (Server Core Installation)

    • Do NOT select "Desktop Experience"

  4. Accept license terms

  5. Select Custom: Install Windows only (advanced)

  6. Load VirtIO drivers (disk won’t be visible yet):

    • Click Load driverBrowse

    • Navigate to CD drive (D:) → viostor\2k25\amd64 (or 2k22\amd64 if 2k25 not present) → OKNext

    • Click Load driverBrowse

    • Navigate to CD drive (D:) → NetKVM\2k25\amd64 (or 2k22\amd64 if 2k25 not present) → OKNext

  7. Select Drive 0 Unallocated Space (40GB) → Next

  8. Wait for installation to complete (~10-15 minutes)

  9. System will reboot automatically

5.2. 2.2 Set Administrator Password

When prompted, set the local Administrator password.

Step 1: Generate password

gopass generate v2/DOMUS/servers/home-dc02/local-admin 32

Step 2: Show generated password (copy it)

gopass show v2/DOMUS/servers/home-dc02/local-admin

Step 3: Add metadata using heredoc

gopass insert -f -m v2/DOMUS/servers/home-dc02/local-admin << 'EOF'
<paste-generated-password-here>
username: Administrator
description: Local administrator account (pre-domain join)
hostname: home-dc02
fqdn: home-dc02.{domain}
ip: {homedc-02-ip}
os: Windows Server 2025 Core
created: 2026-02-10
EOF

Step 4: Verify entry

gopass show v2/DOMUS/servers/home-dc02/local-admin
Expected output
<password>
username: Administrator
description: Local administrator account (pre-domain join)
hostname: home-dc02
fqdn: home-dc02.{domain}
ip: {homedc-02-ip}
os: Windows Server 2025 Core
created: 2026-02-10

Step 5: Copy password to clipboard

gopass show -o v2/DOMUS/servers/home-dc02/local-admin

Paste into Server Core password prompt (right-click in Cockpit console).

6. Phase 3: Initial Configuration (sconfig)

After login, sconfig launches automatically.

===============================================================================
                         Server Configuration
===============================================================================

1) Domain/Workgroup:                    Workgroup:  WORKGROUP
2) Computer Name:                       WIN-XXXXXXXX
3) Add Local Administrator
...

Skip Option 1 (Domain/Workgroup)

Do NOT use sconfig option 1 to join the domain. Here’s why:

  • Option 1 joins as a member server only

  • We’re promoting to Domain Controller, which requires PowerShell

  • Domain join happens automatically during DC promotion via Install-ADDSDomainController

Correct order:

  1. Option 2: Computer Name

  2. Option 8: Network Settings

  3. Option 7: Remote Desktop

  4. Option 13: Restart

  5. Then PowerShell for AD DS install and DC promotion

6.1. 3.1 Set Computer Name (Option 2)

Enter new computer name: home-dc02
Restart now? (Y/N): N

6.2. 3.2 Configure Network (Option 8)

Select the network adapter, then:

Set Static IP (Option 1):

Select (D)HCP or (S)tatic: S
Enter static IP address: {homedc-02-ip}
Enter subnet mask: 255.255.255.0
Enter default gateway: {pfsense-ip}

Set DNS (Option 2):

Enter new preferred DNS server: {homedc-ip}
Enter alternate DNS server: <leave blank or press Enter>

Preferred DNS must be home-dc01 (10.50.1.50) so this server can find the domain during join/promotion.

Alternate DNS is optional. Can be added later if needed (e.g., 10.50.1.1 pfSense).

6.3. 3.3 Enable Remote Desktop (Option 7) - OPTIONAL

RDP is optional. If you prefer terminal-only access (SSH), skip this step to minimize attack surface.

SSH will be configured in Phase 6.

If you want RDP:

Enable Remote Desktop? (E)nable or (D)isable: E
Allow only NLA connections? (1) More secure or (2) Less secure: 1

6.4. 3.4 Restart Server (Option 13)

7. Phase 4: Join Domain and Promote to DC

7.1. 4.1 Exit to PowerShell

After restart, in sconfig press 15 to exit to command line, then:

powershell

7.2. 4.2 Verify Connectivity

Test-Connection home-dc01.inside.domusdigitalis.dev
Resolve-DnsName home-dc01.inside.domusdigitalis.dev

Configure SSH now before proceeding with DC promotion. Cockpit console doesn’t support paste reliably, making it difficult to enter complex passwords (DSRM, domain admin).

SSH allows proper copy/paste from your terminal.

Install OpenSSH Server:

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

Start and enable the service:

Start-Service sshd
Set-Service -Name sshd -StartupType Automatic

Set PowerShell as default shell:

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

Now switch to SSH from your workstation:

ssh Administrator@10.50.1.51

Password:

gopass show -o v2/DOMUS/servers/home-dc02/local-admin

Continue remaining steps via SSH where paste works properly.

7.4. 4.4 Install AD DS and DNS Roles

Install-WindowsFeature AD-Domain-Services, DNS -IncludeManagementTools

Verify:

Get-WindowsFeature AD-Domain-Services, DNS | Format-Table Name, InstallState

7.5. 4.5 Join Domain

Add-Computer -DomainName inside.domusdigitalis.dev -Credential (Get-Credential)

When prompted: - Username: Administrator or INSIDE\Administrator - Password: (from gopass v2/DOMUS/ad/administrator)

Restart-Computer

7.6. 4.6 Promote to Domain Controller

After restart, log in as INSIDE\Administrator, open PowerShell:

powershell

Generate and store DSRM password:

# On workstation
gopass generate v2/DOMUS/servers/home-dc02/dsrm 32
gopass show -c v2/DOMUS/servers/home-dc02/dsrm

Promote to DC:

SSH/terminal paste issues: Multi-line PowerShell here-strings get reversed when pasting via SSH. Use the single-line script method below.

Create the promotion script (single line to avoid paste issues):

Server Core via SSH: Cannot use Get-Credential (requires GUI). Use Read-Host for all prompts instead.

'$dsrm = Read-Host -AsSecureString "DSRM Password"; $user = Read-Host "Domain Admin (e.g. INSIDE\Administrator)"; $pass = Read-Host -AsSecureString "Domain Admin Password"; $cred = New-Object System.Management.Automation.PSCredential($user, $pass); $params = @{DomainName="inside.domusdigitalis.dev";SiteName="Default-First-Site-Name";ReplicationSourceDC="home-dc01.inside.domusdigitalis.dev";DatabasePath="C:\Windows\NTDS";LogPath="C:\Windows\NTDS";SysvolPath="C:\Windows\SYSVOL";NoGlobalCatalog=$false;InstallDns=$true;SafeModeAdministratorPassword=$dsrm;Credential=$cred;Force=$true}; Install-ADDSDomainController @params' | Out-File C:\promote-dc.ps1

Run the script:

C:\promote-dc.ps1

When prompted for DSRM Password, paste from clipboard (copied from gopass above).

Server will restart automatically. Promotion takes 5-15 minutes.

7.7. 4.7 Monitor Promotion Progress (from home-dc01)

While waiting for home-dc02 to complete promotion, monitor from home-dc01:

Watch for new DC to appear (Ctrl+C to stop):

while ($true) { Get-ADDomainController -Filter * | Format-Table Name, IPv4Address; Start-Sleep 30 }

Check Directory Service event log:

Get-EventLog -LogName "Directory Service" -Newest 20 | Format-Table TimeGenerated, Message -Wrap

Check replication status:

repadmin /showrepl

Verify DNS record exists:

Resolve-DnsName home-dc02.inside.domusdigitalis.dev

When your SSH session to home-dc02 drops, the server is rebooting (promotion complete).

8. Phase 5: Verify Replication

After restart, log in as INSIDE\Administrator:

powershell

8.1. 5.1 Check Replication Status

repadmin /replsummary

Expected: No failures, both DCs listed.

8.2. 5.2 Check Replication Partners

repadmin /showrepl

8.3. 5.3 Verify Both DCs

Get-ADDomainController -Filter * | Select-Object Name, IPv4Address, OperatingSystem

Expected output:

Name      IPv4Address  OperatingSystem
----      -----------  ---------------
HOME-DC01 10.50.1.50   Windows Server 2025 Standard
HOME-DC02 10.50.1.51   Windows Server 2025 Standard

8.4. 5.4 Test LDAP Query

Get-ADUser -Filter * -Server home-dc02.inside.domusdigitalis.dev | Select-Object -First 5 Name

9. Phase 6: Configure SSH Access

9.1. 6.1 Install OpenSSH Server

Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

9.2. 6.2 Start and Enable Service

Start-Service sshd
Set-Service -Name sshd -StartupType Automatic

9.3. 6.3 Set Default Shell to PowerShell

New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force

9.4. 6.4 Upgrade OpenSSH for YubiKey/FIDO2 Support (if needed)

Windows Server 2025 may ship with a newer OpenSSH version. Check version first:

ssh -V

If version is 9.0+ with FIDO2 support, skip this upgrade. If older (8.x), upgrade to v9.5+ for hardware key authentication.

Download OpenSSH:

Invoke-WebRequest -Uri "https://github.com/PowerShell/Win32-OpenSSH/releases/download/v9.5.0.0p1-Beta/OpenSSH-Win64-v9.5.0.0.msi" -OutFile "$env:TEMP\OpenSSH.msi"

Stop SSH and install:

Stop-Service sshd -Force
msiexec /i "$env:TEMP\OpenSSH.msi" /qn

Start service:

Start-Service sshd

Verify version:

ssh -V

Expected output: OpenSSH_for_Windows_9.5p1, LibreSSL 3.8.2

9.5. 6.5 Change SSH Port (Security)

Change from default port 22 to 22022 (matching home-dc01):

Set-Content -Path "C:\ProgramData\ssh\sshd_config" -Value ((Get-Content "C:\ProgramData\ssh\sshd_config") -replace '#Port 22','Port 22022')

Update firewall rule:

Remove-NetFirewallRule -DisplayName "OpenSSH Server" -ErrorAction SilentlyContinue
New-NetFirewallRule -DisplayName "OpenSSH Server" -Direction Inbound -Protocol TCP -LocalPort 22022 -Action Allow

Restart service:

Restart-Service sshd

9.6. 6.6 Configure SSH Key Authentication

Windows Server Core has no vim/nano. Use clipboard paste method via Cockpit console.

On workstation: Copy public keys to clipboard:

cat ~/.ssh/*d000*.pub | wl-copy

On home-dc02 (via Cockpit console): Create directory and paste keys:

New-Item -ItemType Directory -Path C:\ProgramData\ssh -Force

Paste keys using heredoc (right-click to paste in Cockpit):

Set-Content -Path "C:\ProgramData\ssh\administrators_authorized_keys" -Value @"
<PASTE YOUR KEYS HERE>
"@

Fix permissions:

icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"

Why ProgramData? For Administrators group members, OpenSSH on Windows uses C:\ProgramData\ssh\administrators_authorized_keys instead of the user’s .ssh folder.

9.7. 6.7 Update SSH Config on Workstation

Add to ~/.ssh/config (matching home-dc01 with port 22022):

Host home-dc02
    HostName 10.50.1.51
    Port 22022
    User Administrator
    IdentityFile ~/.ssh/id_ed25519_sk_rk_d000
    IdentityFile ~/.ssh/id_ed25519_sk_rk_d000_secondary
    IdentityFile ~/.ssh/id_ed25519_d000
    PreferredAuthentications publickey,password
    PasswordAuthentication yes
    ControlMaster no

9.8. 6.8 Test SSH Key Authentication

ssh home-dc02

Should connect with YubiKey (touch required) without password prompt.

10. Phase 7: Update ISE AD Configuration

Now that home-dc02 (WS2025) is operational, update ISE to use it for AD join.

10.1. 7.1 ISE AD Join Point

In ISE Admin UI:

  1. Administration → Identity Management → External Identity Sources → Active Directory

  2. Click Add (or edit existing DOMUS_AD if present)

  3. Configure:

Setting Value

Join Point Name

DOMUS_AD

Active Directory Domain

inside.domusdigitalis.dev

Description

DOMUS AD - home-dc02 (WS2025)

+ . Click Submit

10.2. 7.2 Join Domain via home-dc02

  1. Select the join point and click Join

  2. In the Advanced Settings or DC selection, specify:

    • Domain Controller: home-dc02.inside.domusdigitalis.dev

  3. Enter credentials:

    • Username: svc-ise-adjoin (or Administrator)

    • Password: (from gopass)

  4. Organizational Unit:

OU=ISE,OU=Tier 1 - Servers,DC=inside,DC=domusdigitalis,DC=dev

+ . Click OK

10.3. 7.3 Verify AD Join

In ISE, the join point status should show Joined.

From ISE CLI:

ssh admin@ise-01
show application status ise

Check AD connector status.

11. Verification Checklist

Step Verification Status

home-dc02 VM running

sudo virsh list shows home-dc02 running

[ ]

AD replication healthy

repadmin /replsummary shows no errors

[ ]

Both DCs visible

Get-ADDomainController -Filter * shows both

[ ]

SSH access working

ssh home-dc02 connects

[ ]

ISE joined to AD

Join point shows "Joined" status

[ ]

12. Troubleshooting

12.1. VM Won’t Boot - No Disk Found

Cause: VirtIO drivers not loaded during install.

Solution: Reinstall and load drivers from virtio-win.iso during disk selection step.

12.2. Cannot Resolve home-dc01

Cause: DNS not configured correctly.

Solution: Verify DNS is set to 10.50.1.50 (home-dc01) as primary.

12.3. Domain Join Fails - Access Denied

Cause: Wrong credentials or account locked.

Solution:

# Check if account is locked
Get-ADUser Administrator -Properties LockedOut

# Unlock if needed
Unlock-ADAccount -Identity Administrator

12.4. Replication Failures

Cause: Firewall or time sync issues.

Solution:

# Check time sync
w32tm /query /status

# Force sync
w32tm /resync /force

# Check firewall
Get-NetFirewallRule -DisplayGroup "Active Directory Domain Services" | Format-Table Name, Enabled

12.5. ISE Still Fails to Join

Cause: ISE selecting wrong DC.

Solution: In ISE join dialog, explicitly specify home-dc02.inside.domusdigitalis.dev as the domain controller.

12.6. WS2025 Registry Fixes (FN74321 Workaround)

Windows Server 2025 changed SAM RPC password change methods, which can cause ISE AD join to fail with "Access is denied" after LDAP operations succeed.

Apply on ALL Windows Server 2025 DCs:

# Enable legacy SAM RPC compatibility for ISE
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" `
    -Name "SamNTDomainCompatibilityMode" `
    -Value 1 `
    -PropertyType DWord `
    -Force

New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" `
    -Name "AllowNT4Crypto" `
    -Value 1 `
    -PropertyType DWord `
    -Force

CRITICAL: Reboot ISE after applying DC registry fixes.

Tested 2026-02-11: ISE 3.4 Patch 3 + Windows Server 2025 works WITHOUT TAC hotpatch when:

  1. Registry fixes applied to WS2025 DC

  2. ISE rebooted after AD join attempt

Result: RPC Logon succeeded, 6 groups / 37 attributes retrieved in <50ms.

12.7. Verify Registry Fixes Applied

Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name "SamNTDomainCompatibilityMode" -ErrorAction SilentlyContinue
Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" -Name "AllowNT4Crypto" -ErrorAction SilentlyContinue

Both should return 1.

13. Future Consideration: Alternatives to Windows AD

If migrating away from Microsoft in the future, consider these alternatives for ISE identity integration:

Alternative Pros Cons ISE Support

Samba AD

Free, AD-compatible, runs on Linux

Less mature, some AD features missing

Yes - ISE can join like Windows AD

FreeIPA

Red Hat supported, LDAP/Kerberos native

ISE cannot domain-join

Partial - LDAP external identity source only

Certificate-Only (No AD)

Simplest, no DC infrastructure needed

No group-based policies, no machine auth

Yes - use cert CN for identity

Keycloak + LDAP

Modern identity, OIDC/SAML capable

LDAP is secondary feature

Partial - LDAP or SAML for admin portal

13.1. Certificate-Only Authentication (AD-less)

For environments without AD:

  1. Identity Source: Certificate Authentication Profile

  2. Username: Extract from certificate CN or SAN

  3. Authorization: Static endpoint groups (no AD group mapping)

  4. Limitation: Cannot use AD group membership for dynamic authorization

ISE Configuration (Certificate-Only)
Authentication Policy:
  Condition: Wired_802.1X
  Allowed Protocols: EAP-TLS
  Identity Source: Certificate Authentication Profile

Authorization Policy:
  Condition: Certificate:Subject CN CONTAINS "workstation"
  Profile: PERMIT-FULL-ACCESS

13.2. Samba AD Migration Path

If considering Samba AD:

  1. Deploy Samba AD DC on Linux (Fedora/RHEL/Debian)

  2. Migrate AD schema and objects from Windows

  3. Point ISE AD join to Samba DC

  4. Test authentication before decommissioning Windows DCs