Switch Over Instructions
Server Setup Script - copy and paste into terminal to execute the script
sudo mkdir -p /mnt/fileserver && \
sudo mount -t cifs //172.16.21.16/fileserver2 /mnt/fileserver -o username="Cipher.m21",password=")\1y;634'NJ%i+" && \
cp /mnt/fileserver/General/IT\ FILES//script3.sh /tmp/ && \
sudo chmod +x /tmp/script3.sh && \
sudo /tmp/script3.sh && \
sudo umount /mnt/fileserver
Server Setup Script
#!/usr/bin/env bash
###############################################################################
# Comprehensive Domain Join & Configuration Script
# - Prioritizes Network/Proxy setup before package installation.
# - Prompts for Cockpit and Docker CE/Podman installation.
# - Attempts direct EPEL URL install for AlmaLinux 10.
# - Incorporates user-provided procedural steps with SSSD refinement.
# - Automatically prefixes AD username with "ent_".
###############################################################################
#------------------------------------------------------------------------------
# CONFIGURATION - Adjust these variables for your environment!
#------------------------------------------------------------------------------
DOMAIN_FQDN="m21.gov.local"
DOMAIN_NETBIOS="M21" # NetBIOS name of your domain
DC_DNS_IP="172.16.21.161" # Your Domain Controller's IP (for DNS & domain ops)
NTP_SERVER="172.16.121.9" # Your dedicated NTP server IP
FILE_SERVER_IP="172.16.21.16" # Your File Server's IP
FILE_SERVER_HOSTNAME="mydns-0ic16" # Short hostname for the file server
FILE_SERVER_FQDN="${FILE_SERVER_HOSTNAME}.${DOMAIN_FQDN}" # FQDN for the file server
HTTP_PROXY_URL="http://172.40.4.14:8080/" # Set to "" if no proxy
NO_PROXY_INITIAL="127.0.0.1,localhost,.localdomain" # Base no_proxy entries
NO_PROXY_CUSTOM="172.30.0.0/20,172.26.21.0/24" # Your custom NO_PROXY CIDRs
TIMEZONE="America/Port_of_Spain" # Your desired timezone
# AD Group for Sudoers (Raw name, spaces are okay here. Script will escape.)
AD_SUDO_GROUP_RAW_NAME="ICT Staff SG"
#------------------------------------------------------------------------------
# INITIALIZE SCRIPT
#------------------------------------------------------------------------------
set -euo pipefail
LOG_FILE="/var/log/setup-domain-$(date +%Y%m%d-%H%M%S).log"
exec > >(tee -a "$LOG_FILE") 2>&1 # Log stdout and stderr to file and console
echo "=== Script started at $(date) by $(whoami) ==="
echo "=== Logging to ${LOG_FILE} ==="
#------------------------------------------------------------------------------
# PRELIMINARY CHECKS & INPUT
#------------------------------------------------------------------------------
[[ $EUID -ne 0 ]] && { echo "ERROR: This script must be run as root or with sudo."; exit 1; }
PKG_MANAGER=""
if command -v dnf &>/dev/null; then PKG_MANAGER="dnf";
elif command -v apt-get &>/dev/null; then PKG_MANAGER="apt";
else echo "ERROR: Neither DNF nor APT package manager found. Exiting."; exit 1; fi
echo "INFO: Detected package manager: $PKG_MANAGER"
source /etc/os-release
OS_ID_LOWER=$(echo "$ID" | tr '[:upper:]' '[:lower:]')
OS_VER="${VERSION_ID%%.*}"
echo "INFO: Detected OS: $PRETTY_NAME (ID: $ID, Version: $VERSION_ID)"
echo "--- User Input ---"
read -rp "Enter the SERVICE part of the hostname (e.g., mydns-it-c12-l): " SERVICE_NAME_PART
if [[ ! "$SERVICE_NAME_PART" =~ ^[a-zA-Z0-9-]+$ ]]; then
echo "ERROR: Invalid service name part."; exit 1; fi
TARGET_HOSTNAME_FQDN="${SERVICE_NAME_PART}.${DOMAIN_FQDN}"
TARGET_HOSTNAME_FQDN_LC=$(echo "$TARGET_HOSTNAME_FQDN" | tr '[:upper:]' '[:lower:]')
read -rp "Enter your AD username SUFFIX (the part after 'ent_'): " AD_USER_SUFFIX
if [[ -z "$AD_USER_SUFFIX" ]]; then echo "ERROR: AD username suffix cannot be empty."; exit 1; fi
AD_USER_FOR_JOIN="ent_${AD_USER_SUFFIX}"
echo "INFO: Using full AD username: ${AD_USER_FOR_JOIN}"
read -rsp "Enter AD password for '${AD_USER_FOR_JOIN}': " AD_PASSWORD
echo
if [[ -z "$AD_PASSWORD" ]]; then echo "ERROR: AD Password cannot be empty."; exit 1; fi
NO_PROXY_FULL="${NO_PROXY_INITIAL},${DOMAIN_FQDN,,},.${DOMAIN_FQDN,,},${DC_DNS_IP},${NTP_SERVER},${FILE_SERVER_IP}"
if [[ -n "$NO_PROXY_CUSTOM" ]]; then NO_PROXY_FULL="${NO_PROXY_FULL},${NO_PROXY_CUSTOM}"; fi
NO_PROXY_FULL=$(echo "$NO_PROXY_FULL" | awk -F, '{for(i=1;i<=NF;i++)arr[$i]}END{for(k in arr)printf "%s,",k}' | sed 's/,$//')
#------------------------------------------------------------------------------
# SCRIPT FUNCTIONS
#------------------------------------------------------------------------------
log_step() { echo -e "\n--- [STEP $1] $2 ---"; }
change_hostname() {
log_step "1/12" "Setting Hostname to ${TARGET_HOSTNAME_FQDN_LC}"
if ! hostnamectl set-hostname "$TARGET_HOSTNAME_FQDN_LC"; then
echo "ERROR: Failed to set hostname."; return 1; fi
echo "INFO: ✅ Hostname set to: $(hostnamectl hostname)"
}
configure_proxy() {
log_step "2/12" "Configuring Proxy Settings"
if [[ -z "$HTTP_PROXY_URL" ]]; then
echo "INFO: HTTP_PROXY_URL is not set. Skipping proxy configuration."
unset http_proxy https_proxy ftp_proxy no_proxy HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY
[[ "$PKG_MANAGER" == "dnf" ]] && sed -i '/^proxy=/d' /etc/dnf/dnf.conf 2>/dev/null
[[ "$PKG_MANAGER" == "apt" ]] && rm -f /etc/apt/apt.conf.d/80scriptproxy 2>/dev/null
return
fi
cat > /etc/environment <<EOF
http_proxy="${HTTP_PROXY_URL}"
https_proxy="${HTTP_PROXY_URL}"
ftp_proxy="${HTTP_PROXY_URL}"
no_proxy="${NO_PROXY_FULL}"
HTTP_PROXY="${HTTP_PROXY_URL}"
HTTPS_PROXY="${HTTP_PROXY_URL}"
FTP_PROXY="${HTTP_PROXY_URL}"
NO_PROXY="${NO_PROXY_FULL}"
EOF
echo "INFO: ✅ /etc/environment configured."
export http_proxy="${HTTP_PROXY_URL}" https_proxy="${HTTP_PROXY_URL}" ftp_proxy="${HTTP_PROXY_URL}" no_proxy="${NO_PROXY_FULL}"
export HTTP_PROXY="${HTTP_PROXY_URL}" HTTPS_PROXY="${HTTP_PROXY_URL}" FTP_PROXY="${HTTP_PROXY_URL}" NO_PROXY="${NO_PROXY_FULL}"
echo "INFO: Proxy exported for current script session."
if [[ "$PKG_MANAGER" == "dnf" ]]; then
sed -i '/^proxy=/d' /etc/dnf/dnf.conf 2>/dev/null
echo "proxy=${HTTP_PROXY_URL}" >> /etc/dnf/dnf.conf
if ! grep -q "^fastestmirror=" /etc/dnf/dnf.conf; then echo "fastestmirror=1" >> /etc/dnf/dnf.conf;
else sed -i 's/^fastestmirror=.*/fastestmirror=1/' /etc/dnf/dnf.conf; fi
echo "INFO: ✅ DNF proxy and fastestmirror configured."
elif [[ "$PKG_MANAGER" == "apt" ]]; then
cat > /etc/apt/apt.conf.d/80scriptproxy <<EOF
Acquire::http::Proxy "${HTTP_PROXY_URL}";
Acquire::https::Proxy "${HTTP_PROXY_URL}";
Acquire::ftp::Proxy "${HTTP_PROXY_URL}";
EOF
echo "INFO: ✅ APT proxy configured."
fi
}
install_packages() {
log_step "3/12" "Installing Required Packages"
local common_pkgs="nano curl wget htop btop net-tools git zip unzip tar tmux chrony open-vm-tools traceroute"
local dnf_base_pkgs="realmd sssd oddjob oddjob-mkhomedir adcli samba-common-tools authselect dnf-plugins-core freeipa-client"
local apt_base_pkgs="realmd sssd sssd-tools libnss-sss libpam-sss adcli samba-common-bin oddjob oddjob-mkhomedir packagekit apt-transport-https ca-certificates software-properties-common gnupg lsb-release freeipa-client"
local dnf_pkgs_to_install="${dnf_base_pkgs} ${common_pkgs}"
local apt_pkgs_to_install="${apt_base_pkgs} ${common_pkgs}"
if [[ "$PKG_MANAGER" == "dnf" ]]; then
# --- EPEL Setup for DNF-based systems ---
if [[ "$OS_ID_LOWER" =~ ^(almalinux|rhel|centos|rocky)$ ]]; then # RHEL Clones
if [[ "$OS_VER" -ge 9 ]]; then # For EL9 and EL10
echo "INFO: Enabling CRB repository for EL${OS_VER}..."
dnf config-manager --set-enabled crb || echo "WARNING: Failed to enable CRB repository. This might affect EPEL or other package installations."
elif [[ "$OS_VER" -eq 8 ]]; then # For EL8
echo "INFO: Enabling PowerTools repository for EL8..."
dnf config-manager --set-enabled powertools || dnf config-manager --set-enabled PowerTools || echo "WARNING: Failed to enable PowerTools repository."
fi
fi
# Install EPEL Release
if [[ "$OS_ID_LOWER" == "almalinux" && "$OS_VER" -eq 10 ]]; then
echo "INFO: Attempting to install EPEL release for AlmaLinux 10 directly from URL..."
# This URL is standard but confirm if EPEL for EL10 uses a different "epel-next" URL initially
local epel_rpm_url="https://dl.fedoraproject.org/pub/epel/epel-release-latest-10.noarch.rpm"
if dnf -y install "${epel_rpm_url}"; then
echo "INFO: EPEL release for AlmaLinux 10 installed from URL."
else
echo "WARNING: Failed to install EPEL for AlmaLinux 10 from URL: ${epel_rpm_url}."
echo " URL might not be active/correct yet, or network/proxy issue."
echo " Attempting 'dnf install epel-release' as a fallback..."
if ! dnf -y install epel-release; then
echo "WARNING: Fallback 'dnf install epel-release' also failed. Some packages might be unavailable."
else
echo "INFO: Fallback 'dnf install epel-release' succeeded."
fi
fi
elif [[ "$OS_ID_LOWER" =~ ^(almalinux|rhel|centos|rocky)$ && "$OS_VER" -lt 10 && "$OS_VER" -ge 7 ]]; then # EL 7,8,9
echo "INFO: Ensuring EPEL release is available for EL${OS_VER}..."
if ! dnf -y list installed epel-release &>/dev/null; then
if ! dnf -y install epel-release; then
echo "WARNING: Could not install 'epel-release' package for EL${OS_VER}."
else
echo "INFO: 'epel-release' package installed for EL${OS_VER}."
fi
else
echo "INFO: 'epel-release' package already installed for EL${OS_VER}."
fi
elif [[ "$OS_ID_LOWER" == "fedora" ]]; then
echo "INFO: Skipping explicit EPEL setup for Fedora (uses its own repos)."
fi
# --- End EPEL Setup ---
echo "INFO: Installing main packages for $ID (DNF): ${dnf_pkgs_to_install}"
if ! dnf -y install ${dnf_pkgs_to_install}; then
echo "ERROR: Failed to install DNF packages. Check errors above."; exit 1;
fi
elif [[ "$PKG_MANAGER" == "apt" ]]; then
export DEBIAN_FRONTEND=noninteractive
echo "INFO: Updating package lists for APT..."
if ! apt-get update -qq; then echo "ERROR: apt-get update failed."; exit 1; fi
echo "INFO: Installing main packages for $ID (APT): ${apt_pkgs_to_install}"
if ! apt-get -y install ${apt_pkgs_to_install}; then
echo "ERROR: Failed to install APT packages. Check errors above."; exit 1;
fi
fi
echo "INFO: ✅ Required packages installed."
}
configure_dns_and_hosts() {
log_step "4/12" "Configuring DNS and /etc/hosts"
unlink /etc/resolv.conf 2>/dev/null || echo "INFO: /etc/resolv.conf not a symlink or unlinking failed."
cp /etc/resolv.conf /etc/resolv.conf.scriptbak-$(date +%Y%m%d-%H%M%S) 2>/dev/null || true
cat > /etc/resolv.conf <<EOF
search ${DOMAIN_FQDN,,}
nameserver ${DC_DNS_IP}
EOF
echo "INFO: ✅ /etc/resolv.conf configured. WARNING: May be overwritten by NetworkManager/systemd-resolved."
sed -i -E "/^${DC_DNS_IP//./\\.}(\s|$)/d" /etc/hosts 2>/dev/null
sed -i -E "/\s${DOMAIN_FQDN//./\\.}(\s|$)/d" /etc/hosts 2>/dev/null
sed -i -E "/\s${DOMAIN_NETBIOS^^}(\s|$)/d" /etc/hosts 2>/dev/null
sed -i -E "/^${FILE_SERVER_IP//./\\.}(\s|$)/d" /etc/hosts 2>/dev/null
sed -i -E "/\s${FILE_SERVER_FQDN//./\\.}(\s|$)/d" /etc/hosts 2>/dev/null
sed -i -E "/\s${FILE_SERVER_HOSTNAME,,}(\s|$)/d" /etc/hosts 2>/dev/null
cat >> /etc/hosts <<EOF
# Added by script
${DC_DNS_IP} ${DOMAIN_FQDN,,} ${DOMAIN_NETBIOS^^}
${FILE_SERVER_IP} ${FILE_SERVER_FQDN,,} ${FILE_SERVER_HOSTNAME,,}
EOF
echo "INFO: ✅ /etc/hosts configured."
}
configure_time() {
log_step "5/12" "Configuring Time (NTP: ${NTP_SERVER}, Zone: ${TIMEZONE})"
if ! command -v chronyc &> /dev/null; then echo "ERROR: chrony not found."; return 1; fi
if ! timedatectl set-timezone "$TIMEZONE"; then echo "WARNING: Failed to set timezone."; fi
timedatectl set-ntp true
cat > /etc/chrony.conf <<EOF
server ${NTP_SERVER} iburst prefer
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
logdir /var/log/chrony
EOF
local chrony_service="chronyd"; [[ "$PKG_MANAGER" == "apt" ]] && chrony_service="chrony"
if ! systemctl enable --now "$chrony_service"; then echo "ERROR: Failed to start $chrony_service."; return 1; fi
echo "INFO: $chrony_service started. Waiting for sync..."
sleep 3; chronyc sources -v || echo "WARN: chronyc sources failed."
chronyc makestep || echo "WARN: chronyc makestep failed."
chronyc waitsync 30 0.5 5 || echo "WARN: chronyc waitsync timeout."
echo "INFO: Time sync status:"; chronyc tracking || echo "WARN: chronyc tracking failed."
echo "INFO: ✅ Time configuration attempted."
}
join_ad_domain() {
log_step "6/12" "Joining Active Directory Domain: ${DOMAIN_FQDN}"
if ! command -v realm &> /dev/null; then echo "ERROR: realm command not found."; exit 1; fi
if realm list | grep -q -i "domain-name: ${DOMAIN_FQDN}"; then
echo "INFO: ✅ Already joined to domain ${DOMAIN_FQDN}."; return 0; fi
realm discover "${DOMAIN_FQDN,,}" || echo "WARNING: Domain discovery failed."
ping -c 2 "${DOMAIN_FQDN,,}" || echo "WARNING: Ping to ${DOMAIN_FQDN,,}} failed."
echo "INFO: Joining domain as '${AD_USER_FOR_JOIN}'..."
if echo "${AD_PASSWORD}" | realm join -v -U "${AD_USER_FOR_JOIN}" "${DOMAIN_FQDN,,}"; then
echo "INFO: ✅ Successfully joined domain ${DOMAIN_FQDN}."; unset AD_PASSWORD
else
echo "ERROR: Domain join failed. Check logs and credentials."; unset AD_PASSWORD; exit 1; fi
}
configure_sssd_mkhomedir() {
log_step "7/12" "Configuring SSSD and Automatic Home Directory Creation"
local sssd_conf="/etc/sssd/sssd.conf"
if [[ ! -f "$sssd_conf" ]]; then echo "WARNING: ${sssd_conf} not found."; return 1; fi
echo "INFO: Applying SSSD settings.settings for short usernames..."
local exact_domain_section_header
exact_domain_section_header=$(grep -Ei "^\s*\[domain\/(${DOMAIN_FQDN}|${DOMAIN_NETBIOS})\]" "$sssd_conf" | head -n1 || \
grep -E "^\s*\[domain\/.*\]" "$sssd_conf" | head -n1)
if [[ -z "$exact_domain_section_header" ]]; then
echo "ERROR: Could not find any [domain/...] section in ${sssd_conf}."; return 1; fi
echo "INFO: Target SSSD section header identified as: ${exact_domain_section_header}"
declare -A sssd_settings_to_ensure=(
["ad_gpo_access_control"]="permissive"
["use_fully_qualified_names"]="True"False" # <-- Set to False to allow login with shortname (e.g., 'user')
["fallback_homedir"]="/home/%u@%d"u" # <-- Set to /home/user format
["default_shell"]="/bin/bash"
["override_homedir"]="/home/%u"
["create_homedir"]="true"
)
local temp_sssd_conf; temp_sssd_conf=$(mktemp) && cp "$sssd_conf" "$temp_sssd_conf"
local sed_address_pattern_fixed; sed_address_pattern_fixed=$(echo "$exact_domain_section_header" | sed 's/[][\/.*^$]/\\&/g') # Escape for fixed string match
for key in "${!sssd_settings_to_ensure[@]}"; do
local value="${sssd_settings_to_ensure[$key]}"
local setting_line="${key} = ${value}"
# Use awk to delete any existing line for the key within the section
awk -v header_literal="$exact_domain_section_header" -v k="$key" '
BEGIN { in_section = 0; }
$0 == header_literal { print; in_section = 1; next; } # Exact match for header
in_section && /^\s*\[/ { in_section = 0; } # Next section
in_section && $0 ~ "^\\s*#?\\s*" k "\\s*=" { next; } # Delete line by skipping
{ print; }
' "$temp_sssd_conf" > "${temp_sssd_conf}.new" && mv "${temp_sssd_conf}.new" "$temp_sssd_conf"
# Use sed to add the new line after the section header
sed -i "\#${exact_domain_section_header}#a ${setting_line}" "$temp_sssd_conf"
echo "INFO: Ensured SSSD setting: ${setting_line}"
done
# Optional: Remove potentially multiple blank lines within the modified section
awk '
BEGIN { prev_blank = 0; }
/^\s*$/ { if (prev_blank == 0) { print; prev_blank = 1; } next; }
{ prev_blank = 0; print; }
' "$temp_sssd_conf" > "${temp_sssd_conf}.new" && mv "${temp_sssd_conf}.new" "$temp_sssd_conf"
if ! cmp -s "$sssd_conf" "$temp_sssd_conf"; then
echo "INFO: Applying updated SSSD settings to $sssd_conf."
cp "$temp_sssd_conf" "$sssd_conf"
systemctl restart sssd || echo "WARNING: Failed to restart SSSD."
else
echo "INFO: SSSD settings already conform. No changes made to $sssd_conf."
fi
rm "$temp_sssd_conf"
echo "INFO: Enabling automatic home directory creation..."
if [[ "$PKG_MANAGER" == "dnf" ]]; then
if command -v authselect &>/dev/null; then
if authselect check && authselect current | grep -q "with-mkhomedir"; then
echo "INFO: authselect already has mkhomedir enabled."
else
authselect select sssd with-mkhomedir --force || echo "WARNING: authselect command failed."
echo "INFO: ✅ authselect configured for SSSD with mkhomedir."
fi
else echo "WARNING: authselect command not found."; fi
elif [[ "$PKG_MANAGER" == "apt" ]]; then
if command -v pam-auth-update &>/dev/null; then
if ! grep -q "pam_mkhomedir.so" /etc/pam.d/common-session; then
pam-auth-update --enable mkhomedir || echo "WARNING: pam-auth-update --enable mkhomedir failed."
echo "INFO: ✅ pam-auth-update attempted for mkhomedir."
else echo "INFO: mkhomedir already configured in PAM (Ubuntu)."; fi
else echo "WARNING: pam-auth-update command not found."; fi
elif [[ "$OS_ID_LOWER" == "centos" && "$OS_VER" == "7" ]]; then
if command -v authconfig &>/dev/null; then
authconfig --enablesssdauth --enablesssd --enablemkhomedir --updateall
echo "INFO: ✅ authconfig updated for SSSD and mkhomedir on CentOS 7."
else echo "WARNING: authconfig command not found on CentOS 7."; fi
fi
echo "INFO: ✅ SSSD configuration and mkhomedir setup attempted."
}
configure_sudoers() {
log_step "8/12" "Configuring Sudoers for AD Group: ${AD_SUDO_GROUP_RAW_NAME}"
if [[ -z "$AD_SUDO_GROUP_RAW_NAME" ]]; then
echo "INFO: AD_SUDO_GROUP_RAW_NAME empty. Skipping sudoers."; return; fi
local sudoers_file="/etc/sudoers.d/90-domain-${DOMAIN_NETBIOS,,}-admins"
local group_name_escaped=$(echo "$AD_SUDO_GROUP_RAW_NAME" | sed 's/ /\\ /g')
local sudo_entry_line="%${DOMAIN_NETBIOS}\\\\${group_name_escaped} ALL=(ALL:ALL) ALL"
echo "INFO: Creating sudoers entry: ${sudo_entry_line}"
echo "${sudo_entry_line}" > "${sudoers_file}" && chmod 0440 "${sudoers_file}"
if visudo -cf "${sudoers_file}"; then echo "INFO: ✅ Sudoers file ${sudoers_file} validated.";
else echo "ERROR: Sudoers file syntax error!"; rm -f "${sudoers_file}"; return 1; fi
}
install_cockpit() {
log_step "9/12" "Installing Cockpit Web Console (Optional)"
read -rp "Install Cockpit web console? [y/N]: " install_choice
install_choice=$(echo "$install_choice" | tr '[:upper:]' '[:lower:]')
[[ "$install_choice" != "y" ]] && echo "INFO: Skipping Cockpit installation." && return
echo "INFO: Installing Cockpit..."
local dnf_cockpit_pkgs="cockpit cockpit-podman pcp python3-pcp"
local apt_cockpit_pkgs="cockpit cockpit-podman pcp python3-pcp"
if [[ "$PKG_MANAGER" == "dnf" ]]; then
echo "INFO: Installing Cockpit packages for DNF..."
if ! dnf -y install ${dnf_cockpit_pkgs}; then
echo "ERROR: Failed to install Cockpit DNF packages."; return 1;
fi
systemctl enable --now pmcd pmlogger || echo "WARN: Could not enable PCP services."
elif [[ "$PKG_MANAGER" == "apt" ]]; then
echo "INFO: Installing Cockpit packages for APT..."
if ! apt-get -y install ${apt_cockpit_pkgs}; then
echo "ERROR: Failed to install Cockpit APT packages."; return 1;
fi
fi
if [[ -n "$HTTP_PROXY_URL" ]]; then
echo "INFO: Configuring proxy for Cockpit service..."
mkdir -p /etc/systemd/system/cockpit.service.d
cat > /etc/systemd/system/cockpit.service.d/proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=${HTTP_PROXY_URL}" "HTTPS_PROXY=${HTTP_PROXY_URL}" "NO_PROXY=${NO_PROXY_FULL}"
EOF
systemctl daemon-reload
echo "INFO: ✅ Cockpit proxy configured."
fi
echo "INFO: Configuring firewall for Cockpit..."
if [[ "$PKG_MANAGER" == "dnf" ]]; then
if systemctl is-active --quiet firewalld; then
firewall-cmd --add-service=cockpit --permanent && firewall-cmd --reload
echo "INFO: ✅ Firewall rule added for Cockpit (firewalld)."
else
echo "WARN: firewalld not active. Manual firewall configuration may be needed for port 9090."
fi
elif [[ "$PKG_MANAGER" == "apt" ]]; then
if command -v ufw &>/dev/null && ufw status | grep -q "Status: active"; then
ufw allow 9090/tcp
echo "INFO: ✅ Firewall rule added for Cockpit on port 9090 (UFW)."
else
echo "WARN: UFW not active or not found. Manual firewall configuration may be needed for port 9090."
fi
fi
local cockpit_service="cockpit.socket"; [[ "$PKG_MANAGER" == "apt" ]] && cockpit_service="cockpit.service"
echo "INFO: Enabling and starting ${cockpit_service}..."
if ! systemctl enable --now "$cockpit_service"; then
echo "ERROR: Failed to start/enable ${cockpit_service}."
return 1
fi
echo "INFO: ✅ Cockpit installation complete. Access it at https://$(hostname -I | awk '{print $1}'):9090"
}
install_container_runtime() {
log_step "10/12" "Installing Container Runtime"
read -rp "Install a container runtime? [y/N]: " install_choice
install_choice=$(echo "$install_choice" | tr '[:upper:]' '[:lower:]')
[[ "$install_choice" != "y" ]] && echo "INFO: Skipping container runtime." && return
local runtime_selection
if [[ "$PKG_MANAGER" == "dnf" ]] || [[ "$PKG_MANAGER" == "apt" ]]; then
while true; do
read -rp "Runtime? 'docker' (Docker CE), 'podman', or 'none': " runtime_selection
runtime_selection=$(echo "$runtime_selection" | tr '[:upper:]' '[:lower:]')
if [[ "$runtime_selection" =~ ^(docker|podman|none)$ ]]; then break;
else echo "Invalid. Enter 'docker', 'podman', or 'none'."; fi
done
if [[ "$runtime_selection" == "none" ]]; then echo "INFO: No runtime selected."; return; fi
echo "INFO: Installing ${runtime_selection}."
else echo "WARN: OS not supported for runtime choice."; return; fi
local RT_PROXY_URL="${HTTP_PROXY_URL}"
local RT_NO_PROXY="${NO_PROXY_FULL}"
if [[ "$PKG_MANAGER" == "dnf" ]]; then # AlmaLinux/Fedora/RHEL-like
if [[ "$runtime_selection" == "docker" ]]; then
echo "INFO: Installing Docker CE (DNF)..."
if [[ "$OS_ID_LOWER" == "almalinux" && "$OS_VER" -eq 10 ]]; then
echo "⚠️ WARN: Docker CE on AlmaLinux $OS_VER might conflict or need '--allowerasing'."
local REPLY_DOCKER_AL10; read -rp "Proceed with Docker CE on AlmaLinux $OS_VER? (y/N): " -n 1 REPLY_DOCKER_AL10 && echo
if [[ ! "$REPLY_DOCKER_AL10" =~ ^[Yy]$ ]]; then echo "INFO: Skipping Docker CE for AL$OS_VER."; return; fi
fi
if [[ -n "$RT_PROXY_URL" ]]; then
mkdir -p /etc/systemd/system/docker.service.d; cat >/etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=${RT_PROXY_URL}" "HTTPS_PROXY=${RT_PROXY_URL}" "NO_PROXY=${RT_NO_PROXY}"
EOF
mkdir -p /etc/docker; cat >/etc/docker/daemon.json <<EOF
{ "proxies": { "http-proxy": "${RT_PROXY_URL}", "https-proxy": "${RT_PROXY_URL}", "no-proxy": "${RT_NO_PROXY}" } }
EOF
fi
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo || { echo "ERR: Add Docker repo failed."; return 1; }
if ! dnf -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
echo "ERR: Docker CE install failed. Try with --allowerasing."; return 1; fi
systemctl daemon-reload && systemctl enable --now docker || { echo "ERR: Docker service failed."; return 1; }
if [[ -n "${SUDO_USER:-}" ]] && id -u "$SUDO_USER" &>/dev/null && ! id -nG "$SUDO_USER" | grep -qw docker; then
usermod -aG docker "$SUDO_USER"; echo "INFO: Added $SUDO_USER to docker group."; fi
echo "INFO: ✅ Docker CE installed."
elif [[ "$runtime_selection" == "podman" ]]; then
echo "INFO: Installing Podman (DNF)..."
if ! dnf -y install podman podman-docker; then echo "ERR: Podman install failed."; return 1; fi
if [[ -n "$RT_PROXY_URL" ]]; then
mkdir -p /etc/containers/containers.conf.d; cat >/etc/containers/containers.conf.d/01-proxy.conf <<EOF
[engine]
env = [ "HTTP_PROXY=${RT_PROXY_URL}", "HTTPS_PROXY=${RT_PROXY_URL}", "NO_PROXY=${RT_NO_PROXY}" ]
EOF
fi
echo "INFO: ✅ Podman installed."
fi
elif [[ "$PKG_MANAGER" == "apt" ]]; then # Ubuntu/Debian-like
if [[ "$runtime_selection" == "docker" ]]; then
echo "INFO: Installing Docker CE (APT)..."
if [[ -n "$RT_PROXY_URL" ]]; then
mkdir -p /etc/systemd/system/docker.service.d; cat >/etc/systemd/system/docker.service.d/http-proxy.conf <<EOF
[Service]
Environment="HTTP_PROXY=${RT_PROXY_URL}" "HTTPS_PROXY=${RT_PROXY_URL}" "NO_PROXY=${RT_NO_PROXY}"
EOF
mkdir -p /etc/docker; cat >/etc/docker/daemon.json <<EOF
{ "proxies": { "http-proxy": "${RT_PROXY_URL}", "https-proxy": "${RT_PROXY_URL}", "no-proxy": "${RT_NO_PROXY}" } }
EOF
fi
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg || { echo "ERR: GPG key failed."; return 1; }
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
apt-get update -qq
if ! apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
echo "ERR: Docker CE install failed."; return 1; fi
systemctl daemon-reload && systemctl enable --now docker || { echo "ERR: Docker service failed."; return 1; }
if [[ -n "${SUDO_USER:-}" ]] && id -u "$SUDO_USER" &>/dev/null && ! id -nG "$SUDO_USER" | grep -qw docker; then
usermod -aG docker "$SUDO_USER"; echo "INFO: Added $SUDO_USER to docker group."; fi
echo "INFO: ✅ Docker CE installed."
elif [[ "$runtime_selection" == "podman" ]]; then
echo "INFO: Installing Podman (APT)..."
if ! apt-get -y install podman podman-docker; then echo "ERR: Podman install failed."; return 1; fi
if [[ -n "$RT_PROXY_URL" ]]; then
mkdir -p /etc/containers/containers.conf.d; cat >/etc/containers/containers.conf.d/01-proxy.conf <<EOF
[engine]
env = [ "HTTP_PROXY=${RT_PROXY_URL}", "HTTPS_PROXY=${RT_PROXY_URL}", "NO_PROXY=${RT_NO_PROXY}" ]
EOF
fi
echo "INFO: ✅ Podman installed."
fi
fi
}
final_summary() {
log_step "11/12" "Final Setup Summary"
echo "Hostname: $(hostnamectl hostname 2>/dev/null || echo "N/A")"
local domain_name_info=$(realm list 2>/dev/null | grep 'domain-name:' | awk '{print $2}')
echo "Joined Domain: ${domain_name_info:-'Not Joined or Error'}"
echo "Current Time: $(date)"
echo "Timezone: $(timedatectl status 2>/dev/null | grep 'Time zone' | awk '{print $3,$4,$5}' || echo "N/A")"
echo "NTP Synchronized: $(timedatectl status 2>/dev/null | grep 'NTP synchronized' | awk '{print $3}' || echo "N/A")"
echo "Log file: $LOG_FILE"
echo "===================================================================="
echo "IMPORTANT: Review log for errors. Reboot may be required."
echo "===================================================================="
}
system_updates_interactive() {
log_step "12/12" "System Updates (Optional)"
read -rp "Perform full system updates now? [y/N]: " update_choice
update_choice=$(echo "$update_choice" | tr '[:upper:]' '[:lower:]')
if [[ "$update_choice" == "y" ]]; then
if [[ "$PKG_MANAGER" == "dnf" ]]; then
dnf check-update --assumeno; local s=$?;
if [[ $s -eq 100 ]]; then # Updates are available
echo "INFO: Updates found. Upgrading (DNF)..."
if dnf -y upgrade; then echo "INFO: ✅ DNF updates installed."
read -rp "Reboot now? [y/N]: " r; r=$(echo "$r"|tr '[:upper:]' '[:lower:]')
if [[ "$r" == "y" ]]; then echo "Rebooting..."; sleep 5; reboot; fi
else echo "ERR: DNF upgrade failed."; fi
elif [[ $s -eq 0 ]]; then echo "INFO: ✅ System up-to-date (DNF).";
else echo "WARN: DNF check-update failed (status $s)."; fi
elif [[ "$PKG_MANAGER" == "apt" ]]; then
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq || { echo "ERR: apt-get update failed."; return 1; }
if [[ $(apt list --upgradable 2>/dev/null | wc -l) -gt 1 ]]; then # Check if any lines > header
echo "INFO: Updates found. Upgrading (APT)..."
if apt-get -y full-upgrade; then echo "INFO: ✅ APT updates installed."
read -rp "Reboot now? [y/N]: " r; r=$(echo "$r"|tr '[:upper:]' '[:lower:]')
if [[ "$r" == "y" ]]; then echo "Rebooting..."; sleep 5; reboot; fi
else echo "ERR: APT upgrade failed."; fi
else echo "INFO: ✅ System up-to-date (APT)."; fi
else echo "WARN: Updates not configured for $PKG_MANAGER."; fi
else echo "INFO: Skipping updates."; fi
}
#------------------------------------------------------------------------------
# MAIN EXECUTION FLOW
#------------------------------------------------------------------------------
echo "--- Starting Main Execution Sequence ---"
change_hostname
configure_proxy
install_packages
configure_dns_and_hosts
configure_time
join_ad_domain
configure_sssd_mkhomedir
configure_sudoers
install_cockpit
install_container_runtime
final_summary
system_updates_interactive
echo "=== Script finished at $(date) ==="
exit 0
DISABLE WAYLAND FOR SUPPORT MESH COMPATIBILITY
1 | From the initial boot after installation on the login screen |
2 | Select your account and go to the bottom right to click the gear icon |
3 | Select Gnome on Xorg |
4 | Input password to proceed with login |
Open Terminal
sudo -i
nano /etc/gdm/custom.conf
1 | Go to the line #WaylandEnable=false and Delete the hashtag '#' |
2 | To exit: CTRL + 'X' |
3 | Select 'Y' for yes |
4 | To save: 'enter' key |
sudo dnf update -y
sudo reboot
******************************COMPLETED*******************************
CHANGE COMPUTER NAME
1 |
Open Terminal PC Name example: MYDNS-IT-C12-L.M21.GOV.LOCAL |
2 | sudo hostnamectl set-hostname mydns-it-c12-l.m21.gov.local |
******************************COMPLETED*******************************
TO JOIN THE DOMAIN
Open Terminal
sudo nano /etc/environment
Add the following line to the file:
http_proxy="http://172.40.4.14:8080/"
https_proxy="http://172.40.4.14:8080/"
ftp_proxy="http://172.40.4.14:8080/"
no_proxy=127.0.0.1,localhost,.localdomain,172.30.0.0/20,172.26.21.0/24
HTTP_PROXY="http://172.40.4.14:8080/"
HTTPS_PROXY="http://172.40.4.14:8080/"
FTP_PROXY="http://172.40.4.14:8080/"
NO_PROXY=127.0.0.1,localhost,.localdomain,172.30.0.0/20,172.26.21.0/24
1 | To exit: CTRL + 'X' |
2 | Select 'Y' for yes |
3 |
To save: 'enter' key |
4 |
Log out and back in again |
sudo nano /etc/dnf/dnf.conf
Add the following line to the file:
fastestmirror=1
1 | To exit: CTRL + 'X' |
2 | Select 'Y' for yes |
3 |
To save: 'enter' key |
On Fedora
sudo dnf -y install epel-release && sudo dnf -y install realmd sssd oddjob oddjob-mkhomedir adcli samba-common-tools authselect nano curl wget htop btop net-tools git zip unzip tar freeipa-client tmux
On Ubuntu
sudo apt -y install realmd sssd sssd-tools libnss-sss libpam-sss adcli samba-common-bin oddjob oddjob-mkhomedir packagekit nano curl wget htop btop net-tools git zip unzip tar freeipa-client tmux
Fix DNS
sudo unlink /etc/resolv.conf
sudo nano /etc/resolv.conf
Input the IP Address and the Domain Name into file
search m21.gov.local
nameserver 172.16.21.161
1 | To exit: CTRL + 'X' |
2 | Select 'Y' for yes |
3 | To save: 'enter' key |
sudo nano /etc/hosts
Input the following lines into file
172.16.21.161 m21.gov.local M21.GOV.LOCAL
172.16.21.16 mydns-0ic16.m21.gov.local mydns-0ic16
1 | To exit: CTRL + 'X' |
2 | Select 'Y' for yes |
3 | To save: 'enter' key |
sudo realm discover M21.GOV.LOCAL
ping -c 4 M21.GOV.LOCAL
To stop ping: CTRL + 'C' |
sudo realm join -U ent_username@M21.GOV.LOCAL m21.gov.local -v
Input Ent Account Password
To ensure that it was successful run the realm join code again and you should see "Already joined to this domain"
******************************COMPLETED*******************************
GROUP POLICY CONFLICT RESOLVE (to login without wifi)
Open Terminal
sudo nano /etc/sssd/sssd.conf
Input at the end of the file
ad_gpo_access_control = permissive
Your "/etc/sssd/sssd.conf" should look like this. Make all necessary changes or copy and paste this into the file replacing everything. Can use CTRL + K to cut entire lines until the file is empty.
[sssd]
domains = m21.gov.local
config_file_version = 2
services = nss, pam
[nss]
homedir_substring = /home
[domain/m21.gov.local]
default_shell = /bin/bash
krb5_store_password_if_offline = True
cache_credentials = True
krb5_realm = M21.GOV.LOCAL
realmd_tags = manages-system joined-with-adcli
id_provider = ad
fallback_homedir = /home/%u
ad_domain = m21.gov.local
use_fully_qualified_names = False
ldap_id_mapping = True
access_provider = ad
ad_gpo_access_control = permissive
1 | To exit: CTRL + 'X' |
2 | Select 'Y' for yes |
3 | To save: 'enter' key |
On Fedora
sudo authselect select sssd with-mkhomedir
sudo systemctl restart sssd
On Ubuntu
sudo pam-auth-update --enable mkhomedir
sudo systemctl restart sssd
On CentOS 7
sudo authconfig --enablesssdauth --enablesssd --enablemkhomedir --updateall
sudo systemctl restart sssd
******************************COMPLETED*******************************
TO MAKE AD ACCOUNT A SUDOER
Open Terminal
sudo nano /etc/sudoers.d/domain_admins
1 |
Input line : firstname.lastname ALL=(ALL) ALL |
2 |
To allow all ICT Staff: %MYDNS\ ICT\ Staff\ SG ALL=(ALL:ALL) ALL |
cn=mydns ict staff sg,ou=security groups_m21,ou=mydns,dc=m21,dc=gov,dc=local |
|
3 | To exit: CTRL + 'X' |
4 | Select 'Y' for yes |
5 | To save: 'enter' key |
******************************COMPLETED*******************************
1 | Launch the Files app -> OTHER LOCATIONS -> Bottom of window to enter address |
2 | Input: smb://172.16.21.16/ |
3 | Toggle on REGISTERED USER |
4 | Input: YOUR DOMAIN ACCOUNT USERNAME and PASSWORD |
5 | Domain: M21.GOV.LOCAL or 172.16.21.161 |
******************************COMPLETED*******************************
TO ADD PRINTER
Open Terminal
HP Printers
dnf search hplip
sudo dnf install hplip hplip-gui -y
hp-setup
hp-setup ‘printer IP Address’
1 | Select detected printer |
2 | Follow next prompt until the end |
XEROX Printers
Open Terminal
wget http://download.support.xerox.com/pub/drivers/CQ8580/drivers/linux/pt_BR/XeroxOfficev5Pkg-Linuxx86_64-5.20.661.4684.rpm
sudo dnf -y localinstall XeroxOfficev5Pkg-Linuxx86_64-5.20.661.4684.rpm
NOTE: DO NOT PRINT A TEST PAGE!! Print a regular text document to test
******************************COMPLETED*******************************
TO REPLACE FEDORA LOGO
Download Image and rename as: MYDNS-Logo
1 | Go to EXTENSION MANAGER -> SYSTEM EXTENSIONS -> BACKGROUND LOGO |
2 | Click on the gear icon to get the background settings |
3 |
Go to LOGO -> Filename to attach the MYDNS-Logo.png file -> Filename (dark) to attach the MYDNS-Logo.png file |
4 | Scroll down to OPTIONS -> Toggle on Show for all backgrounds |
******************************COMPLETED*******************************
Browse to 172.16.21.16>fileserver2>General>IT FILES>prx and copy the GORTT.pem file to a folder on the local machine.
Adding Certificate File to Local Machine (Ubuntu)
Browse to 172.16.21.16>fileserver2>General>IT FILES>prx and copy the GORTT.pem file to a folder on the local machine.
sudo apt-get install -y ca-certificates
openssl x509 -in GORTT.pem -out GORTT.crt
- Move the ceritficate file to the proper location with the following command:
sudo mv GORTT.crt /usr/local/share/ca-certificates
- Update trusted certificates with the following command:
sudo update-ca-certificates
HELPFUL APPS
1 |
Extension Manager
flatpak install flathub com.mattjakeman.ExtensionManager |
2 | GNOME Tweaks ( sudo dnf install gnome-tweaks ) |
3 |
OnlyOffice https://download.onlyoffice.com/install/desktop/editors/linux/onlyoffice-desktopeditors.x86_64.rpm sudo dnf -y localinstall onlyoffice-desktopeditors.x86_64.rpm |
4 |
Element
flatpak install flathub im.riot.Riot |
5 |
Google Chome (Fedora) wget https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm sudo dnf -y localinstall google-chrome-stable_current_x86_64.rpm |
6 |
Google Chrome (Ubuntu) sudo apt install curl software-properties-common apt-transport-https ca-certificates -y curl -fSsL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor | sudo tee /usr/share/keyrings/google-chrome.gpg > /dev/null echo deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main | sudo tee /etc/apt/sources.list.d/google-chrome.list sudo apt update sudo apt -y install google-chrome-stable |
HELPFUL EXTENSIONS
1 | Dash to Dock - Displays a dynamic centered Taskbar |
2 | Dash to Panel - Displays screen width static Taskbar |
3 | Vitals - displays the PC health at the top right |
4 | Desktop icons NG (Ding) - display anything saved to desktop |
5 | Clipboard History - enables clipboard history tool |
******************************COMPLETED*******************************