SambaDC/scripts/add-replica.sh
2026-09-24 11:29:54 -05:00

51 lines
2.6 KiB
Bash
Executable file

#!/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=<this machine's LAN 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=\"<ip> ${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"