#!/usr/bin/env bash # ===================================================================================== # Add a second domain controller (replica) for availability. # # This runs the `replica` compose profile, which needs its own hostname/IP and the join # credentials of an existing DC. Because the profile uses host networking it is meant to # run on a SECOND MACHINE that has this repo synced to it (otherwise two containers fight # over UDP/TCP 53, 88, 445...). For one machine, use macvlan instead. # # Required in .env on the replica machine: # AD_DNS_DOMAIN / AD_REALM = the existing domain # AD_HOSTNAME2=dc2 # AD_IP= # AD_JOIN_SERVER=dc1.ad.example.com # AD_JOIN_USER=administrator # AD_JOIN_PASSWORD (or secrets/join.password) # ===================================================================================== set -euo pipefail cd "$(dirname "$0")/.." . "$(dirname "$0")/envfile.sh"; ad_env_load .env # parsed, never executed (see envfile.sh) [ -n "${AD_DNS_DOMAIN:-}" ] || { echo "set AD_DNS_DOMAIN to the existing domain in .env" >&2; exit 2; } [ -n "${AD_HOSTNAME2:-}" ] || { echo "set AD_HOSTNAME2 (e.g. dc2) in .env" >&2; exit 2; } [ -n "${AD_IP:-}" ] || { echo "set AD_IP to the reachable LAN address of this machine" >&2; exit 2; } [ -n "${AD_JOIN_SERVER:-}" ] || { echo "set AD_JOIN_SERVER (existing DC FQDN) in .env" >&2; exit 2; } echo ">> replica: ${AD_HOSTNAME2}.${AD_DNS_DOMAIN} joining via ${AD_JOIN_SERVER}" # the joining DC must be able to resolve the existing DC before its own DNS is trustworthy if ! getent hosts "$AD_JOIN_SERVER" >/dev/null 2>&1; then echo "!! ${AD_JOIN_SERVER} does not resolve from this host." echo " add AD_EXTRA_HOSTS=\" ${AD_JOIN_SERVER} ${AD_JOIN_SERVER%%.*}\" to .env" exit 1 fi # sanity: realm must be reachable over Kerberos before we attempt the join if command -v kinit >/dev/null 2>&1; then echo " (tip: pre-auth once with 'kinit administrator@${AD_REALM:-}' to catch realm/ clock problems early)" fi docker compose --profile replica up -d ad-dc2 sleep 20 AD_CONTAINER="${AD_CONTAINER2:-ad-dc2}" ./scripts/verify.sh || true echo echo "Post-join checklist" echo " 1. DNS: point clients at BOTH DCs (DHCP option 006 = dc1,dc2)" echo " 2. docker exec ${AD_CONTAINER2:-ad-dc2} samba-tool drs showrepl -> no failing inbound/outbound" echo " 3. docker exec ${AD_CONTAINER2:-ad-dc2} samba-tool ntacl sysvolcheck" echo " 4. from a joined Windows host: nltest /dsgetdc:${AD_DNS_DOMAIN^^} (should list both DCs)" echo " 5. time sources: both DCs must be NTP-synced from outside; clients follow the PDC emulator"