Skip to main content

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_".
# - Adds Fail2ban and a custom MOTD for system stats.
# - Optional Development Stack (PHP, Node, MariaDB, Nginx, Caddy, PostgreSQL).
# - Automated Tmux environment with session persistence.
# - Colorized output for better readability.
###############################################################################

#------------------------------------------------------------------------------
# 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
#------------------------------------------------------------------------------
# Color Definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

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 -e "${GREEN}=== Script started at $(date) by $(whoami) ===${NC}"
echo -e "${GREEN}=== Logging to ${LOG_FILE} ===${NC}"

#------------------------------------------------------------------------------
# PRELIMINARY CHECKS & INPUT
#------------------------------------------------------------------------------
[[ $EUID -ne 0 ]] && { echo -e "${RED}ERROR: This script must be run as root or with sudo.${NC}"; exit 1; }

PKG_MANAGER=""
if command -v dnf &>/dev/null; then PKG_MANAGER="dnf";
elif command -v yum &>/dev/null; then PKG_MANAGER="yum"; # Fallback for CentOS 7
elif command -v apt-get &>/dev/null; then PKG_MANAGER="apt";
else echo -e "${RED}ERROR: Neither DNFDNF, YUM, nor APT package manager found. Exiting.${NC}"; exit 1; fi
echo -e "${BLUE}INFO:${NC} Detected package manager: $PKG_MANAGER"{PURPLE}$PKG_MANAGER${NC}"

source /etc/os-release
OS_ID_LOWER=$(echo "$ID" | tr '[:upper:]' '[:lower:]')
OS_VER="${VERSION_ID%%.*}"
echo -e "${BLUE}INFO:${NC} Detected OS: $PRETTY_NAME{PURPLE}$PRETTY_NAME${NC} (ID: $ID, Version: $VERSION_ID)"

echo -e "\n${CYAN}--- User Input ---${NC}"
read -rp "$(echo -e "${CYAN}Enter the SERVICE part of the hostname (e.g., mydns-it-c12-l): ${NC}")" SERVICE_NAME_PART
if [[ ! "$SERVICE_NAME_PART" =~ ^[a-zA-Z0-9-]+$ ]]; then
    echo -e "${RED}ERROR: Invalid service name part.${NC}"; exit 1; fi
TARGET_HOSTNAME_FQDN="${SERVICE_NAME_PART}.${DOMAIN_FQDN}"
TARGET_HOSTNAME_FQDN_LC=$(echo "$TARGET_HOSTNAME_FQDN" | tr '[:upper:]' '[:lower:]')

read -rp "$(echo -e "${CYAN}Enter your AD username SUFFIX (the part after 'ent_'): ${NC}")" AD_USER_SUFFIX
if [[ -z "$AD_USER_SUFFIX" ]]; then echo -e "${RED}ERROR: AD username suffix cannot be empty.${NC}"; exit 1; fi
AD_USER_FOR_JOIN="ent_${AD_USER_SUFFIX}"
echo -e "${BLUE}INFO:${NC} Using full AD username: ${PURPLE}${AD_USER_FOR_JOIN}${NC}"

read -rsp "$(echo -e "${CYAN}Enter AD password for '${AD_USER_FOR_JOIN}': ${NC}")" AD_PASSWORD
echo
if [[ -z "$AD_PASSWORD" ]]; then echo -e "${RED}ERROR: AD Password cannot be empty.${NC}"; 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-n${GREEN}--- [STEP $1] $2 ---${NC}"; }

change_hostname() {
    log_step "1/12"16" "Setting Hostname to ${TARGET_HOSTNAME_FQDN_LC}"
    if ! hostnamectl set-hostname "$TARGET_HOSTNAME_FQDN_LC"; then
        echo -e "${RED}ERROR: Failed to set hostname.${NC}"; return 1; fi
    echo -e "${BLUE}INFO:${NC} ✅ Hostname set to: ${PURPLE}$(hostnamectl hostname)${NC}"
}

configure_proxy() {
    log_step "2/12"16" "Configuring Proxy Settings"
    if [[ -z "$HTTP_PROXY_URL" ]]; then
        echo -e "INFO:${YELLOW}WARN: HTTP_PROXY_URL is not set. Skipping proxy configuration.${NC}"
        unset http_proxy https_proxy ftp_proxy no_proxy HTTP_PROXY HTTPS_PROXY FTP_PROXY NO_PROXY
        [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]] && sed -i '/^proxy=/d' /etc/dnf/dnf.$PKG_MANAGER/$PKG_MANAGER.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 -e "${BLUE}INFO:${NC} ✅ /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 -e "${BLUE}INFO:${NC} Proxy exported for current script session."

    if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
        sed -i '/^proxy=/d' /etc/dnf/dnf.$PKG_MANAGER/$PKG_MANAGER.conf 2>/dev/null
        echo "proxy=${HTTP_PROXY_URL}" >> /etc/dnf/dnf.$PKG_MANAGER/$PKG_MANAGER.conf
        if ! grep -q "^fastestmirror=" /etc/dnf/dnf.$PKG_MANAGER/$PKG_MANAGER.conf; then echo "fastestmirror=1" >> /etc/dnf/dnf.$PKG_MANAGER/$PKG_MANAGER.conf;
        else sed -i 's/^fastestmirror=.*/fastestmirror=1/' /etc/dnf/dnf.$PKG_MANAGER/$PKG_MANAGER.conf; fi
        echo -e "${BLUE}INFO:${NC}DNF$PKG_MANAGER 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 -e "${BLUE}INFO:${NC} ✅ APT proxy configured."
    fi
}

install_packages() {
    log_step "3/12"16" "Installing Required Packages"
    # Clean up known repo files from previous failed runs to prevent blocking core package installation
    rm -f /etc/yum.repos.d/MariaDB.repo /etc/yum.repos.d/caddy.repo /etc/apt/sources.list.d/mariadb.sources /etc/apt/sources.list.d/caddy-stable.list /etc/apt/sources.list.d/pgdg.list
    
    local common_pkgs="nano curl wget htop btop net-tools git zip unzip tar tmux chrony open-vm-tools traceroute"traceroute ncdu" 
    local dnf_base_pkgs="realmd sssd oddjob oddjob-mkhomedir adcli samba-common-tools authselect dnf-plugins-corecore"
    freeipa-client"local yum_base_pkgs="realmd sssd oddjob oddjob-mkhomedir adcli samba-common-tools authconfig yum-utils" # For CentOS 7
    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}"release"
    
    if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
        #echo ---e "${BLUE}INFO:${NC} Ensuring EPEL Setuprepository foris DNF-basedinstalled..."
        systemsif ! $PKG_MANAGER -y list installed epel-release &>/dev/null; then
             $PKG_MANAGER -y install epel-release || echo -e "${YELLOW}WARN: Could not install epel-release.${NC}"
        fi
        
        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 -e "WARNING:${YELLOW}WARN: Failed to enable CRB repository. This might affect EPEL or other package installations.${NC}"
            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 -e "WARNING:${YELLOW}WARN: Failed to enable PowerTools repository.repo.${NC}"
            fi
        fi
        
        #local Install EPEL Releasepkgs_to_install
        if [[ "$OS_ID_LOWER"PKG_MANAGER" == "almalinux" && "$OS_VER" -eq 10dnf" ]]; then
            echopkgs_to_install="${dnf_base_pkgs} ${common_pkgs}"INFO:
        Attempting to install EPEL release for AlmaLinux 10 directly from URL..."else # Thisyum URLon isCentOS standard7
            butpkgs_to_install="${yum_base_pkgs} confirm${common_pkgs}"
        iffi

        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 dnfecho -y installe "${epel_rpm_url}"; then
                echo "BLUE}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:NC} Installing main packages for $ID (DNF)$PKG_MANAGER): ${dnf_pkgs_to_install}pkgs_to_install}"
        if ! dnf$PKG_MANAGER -y install ${dnf_pkgs_to_install}pkgs_to_install}; then
            echo -e "${RED}ERROR: Failed to install DNF packages. Check errors above.${NC}"; exit 1;
        fi

    elif [[ "$PKG_MANAGER" == "apt" ]]; then
        export DEBIAN_FRONTEND=noninteractive
        echo -e "${BLUE}INFO:${NC} Updating package lists for APT..."
        if ! apt-get update -qq; then echo -e "${RED}ERROR: apt-get update failed.${NC}"; exit 1; fi
        local pkgs_to_install="${apt_base_pkgs} ${common_pkgs}"
        echo -e "${BLUE}INFO:${NC} Installing main packages for $ID (APT): ${apt_pkgs_to_install}pkgs_to_install}"
        if ! apt-get -y install ${apt_pkgs_to_install}pkgs_to_install}; then
            echo -e "${RED}ERROR: Failed to install APT packages. Check errors above.${NC}"; exit 1;
        fi
    fi
    echo -e "${BLUE}INFO:${NC} ✅ Required packages installed."
}

configure_dns_and_hosts() {
    log_step "4/12"16" "Configuring DNS and /etc/hosts"
    unlink /etc/resolv.conf 2>/dev/null || echo -e "${BLUE}INFO:${NC} /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 -e "${BLUE}INFO:${NC} ✅ /etc/resolv.conf configured. ${YELLOW}WARNING: May be overwritten by NetworkManager/systemd-resolved.${NC}"

    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 -e "${BLUE}INFO:${NC} ✅ /etc/hosts configured."
}

configure_time() {
    log_step "5/12"16" "Configuring Time (NTP: ${NTP_SERVER}, Zone: ${TIMEZONE})"
    if ! command -v chronyc &> /dev/null; then echo -e "${RED}ERROR: chrony not found.${NC}"; return 1; fi
    if ! timedatectl set-timezone "$TIMEZONE"; then echo -e "WARNING:${YELLOW}WARN: Failed to set timezone.${NC}"; 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 -e "${RED}ERROR: Failed to start $chrony_service.${NC}"; return 1; fi
    echo -e "${BLUE}INFO:${NC} $chrony_service started. Waiting for sync..."
    sleep 3; chronyc sources -v || echo -e "${YELLOW}WARN: chronyc sources failed.${NC}"
    chronyc makestep || echo -e "${YELLOW}WARN: chronyc makestep failed.${NC}"
    chronyc waitsync 30 0.5 5 || echo -e "${YELLOW}WARN: chronyc waitsync timeout.${NC}"
    echo -e "${BLUE}INFO:${NC} Time sync status:"; chronyc tracking || echo -e "${YELLOW}WARN: chronyc tracking failed.${NC}"
    echo -e "${BLUE}INFO:${NC} ✅ Time configuration attempted."
}

join_ad_domain() {
    log_step "6/12"16" "Joining Active Directory Domain: ${DOMAIN_FQDN}"
    if ! command -v realm &> /dev/null; then echo -e "${RED}ERROR: realm command not found.${NC}"; exit 1; fi
    if realm list | grep -q -i "domain-name: ${DOMAIN_FQDN}"; then
        echo -e "${BLUE}INFO:${NC} ✅ Already joined to domain ${DOMAIN_FQDN}." ; return 0; fi
    realm discover "${DOMAIN_FQDN,,}" || echo -e "WARNING:${YELLOW}WARN: Domain discovery failed.${NC}"
    ping -c 2 "${DOMAIN_FQDN,,}" || echo -e "WARNING:${YELLOW}WARN: Ping to ${DOMAIN_FQDN,,}} failed.${NC}"
    echo -e "${BLUE}INFO:${NC} Joining domain as '${AD_USER_FOR_JOIN}'..."
    if echo "${AD_PASSWORD}" | realm join -v -U "${AD_USER_FOR_JOIN}" "${DOMAIN_FQDN,,}"; then
        echo -e "${BLUE}INFO:${NC} ✅ Successfully joined domain ${DOMAIN_FQDN}."; unset AD_PASSWORD
    else
        echo -e "${RED}ERROR: Domain join failed. Check logs and credentials.${NC}"; unset AD_PASSWORD; exit 1; fi
}

configure_sssd_mkhomedir() {
    log_step "7/12"16" "Configuring SSSD and Automatic Home Directory Creation"
    local sssd_conf="/etc/sssd/sssd.conf"
    if [[ ! -f "$sssd_conf" ]]; then
        echo -e "WARNING:${YELLOW}WARN: ${sssd_conf} not found. Domain join might have failed. Skipping SSSD config.${NC}";
        return 1;1
    fi

    echo -e "${BLUE}INFO:${NC} ApplyingOptimizing SSSD settingsconfiguration for short usernames.process..."
    local exact_domain_section_headernew_domain_section
    exact_domain_section_header=new_domain_section=$(grepprintf -Ei'%s\n' \
        "^\s*\[domain\/(domain/${DOMAIN_FQDN}|${DOMAIN_NETBIOS})\DOMAIN_FQDN,,}]" \
        "$sssd_conf"id_provider |= head -n1 ||ad" \
        grep"access_provider -E= ad" \
        "^\s*\[domain\/.*\]"ad_domain "$sssd_conf" | head -n1)

    if [[ -z "$exact_domain_section_header" ]]; then
        echo "ERROR: Could not find any [domain/...] section in= ${sssd_conf}.DOMAIN_FQDN,,}"; return 1; fi
    echo\
        "INFO:krb5_realm Target SSSD section header identified as:= ${exact_domain_section_header}DOMAIN_FQDN^^}" declare\
        -A"realmd_tags sssd_settings_to_ensure=(= [manages-system joined-with-adcli" \
        "ad_gpo_access_control"]cache_credentials = True" \
        "permissive"krb5_store_password_if_offline [= True" \
        "use_fully_qualified_names"]ldap_id_mapping = True" \
        "use_fully_qualified_names = False" #\
        <--"fallback_homedir Set= to False to allow login with shortname (e.g., 'user')
        ["fallback_homedir"]="/home/%u" #\
        <--"default_shell Set= to /home/user format
        ["default_shell"]="/bin/bash" [\
        "override_homedir"]override_homedir =" /home/%u" [\
        "create_homedir"]create_homedir =" true" \
        "ad_gpo_access_control = permissive"
    )
    local temp_sssd_conf; temp_sssd_conf=$(mktemp) &&
    cp "$sssd_conf" "$temp_sssd_conf"
    local sed_address_pattern_fixed; sed_address_pattern_fixed={sssd_conf}.bak-$(echodate "$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]}+%s)"
    local setting_line="temp_conf; temp_conf=${key} = ${value}"
        
        # Use awk to delete any existing line for the key within the section(mktemp)
    awk -v header_literal=domain_name="$exact_domain_section_header" -v k={DOMAIN_FQDN,,}"$key" '
        BEGIN { in_sectionin_section_to_remove = 0;0 }
        $0 ==~ header_literal"^\\[domain\\/" domain_name "\\]" { print; in_sectionin_section_to_remove = 1; next;next }
        # Exact match for header
            in_sectionin_section_to_remove && /^\s*\[/ { in_sectionin_section_to_remove = 0;0 }
        # Next section
            in_section && $0 ~ "^\\s*#?\\s*" k "\\s*="!in_section_to_remove { next; } # Delete line by skipping
            { print;print }
    ' "$temp_sssd_conf"sssd_conf" > "${temp_sssd_conf}.new"temp_conf"
    && mv "${temp_sssd_conf}.new" "$temp_sssd_conf"

        # Use sed to add the new line after the section header
        sedecho -ie "\#$n${exact_domain_section_header}#a ${setting_line}new_domain_section}" "$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"temp_conf"

    if ! cmp[[ -s "$sssd_conf"temp_conf" "$temp_sssd_conf"]]; then
        echo "INFO: Applying updated SSSD settings to $sssd_conf."
        cpmv "$temp_sssd_conf"temp_conf" "$sssd_conf"
        chmod 0600 "$sssd_conf"
        echo -e "${BLUE}INFO:${NC} sssd.conf updated. Restarting service..."
        systemctl restart sssd || echo -e "WARNING:${YELLOW}WARN: Failed to restart SSSD.SSSD after config change.${NC}"
    else
        echo -e "INFO:${RED}ERROR: SSSDGenerated settingstemporary alreadysssd.conf conform.was empty. No changes mademade.${NC}"
        torm -f "$sssd_conf."temp_conf"; return 1; fi

    rmecho -e "$temp_sssd_conf"

    echo "{BLUE}INFO:${NC} 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 -e "${BLUE}INFO:${NC} authselect already has mkhomedir enabled."
            else
                authselect select sssd with-mkhomedir --force || echo -e "WARNING:${YELLOW}WARN: authselect command failed.${NC}"
                echo -e "${BLUE}INFO:${NC} ✅ authselect configured for SSSD with mkhomedir."
            fi
        else echo -e "WARNING:${YELLOW}WARN: authselect command not found.${NC}"; fi
    elif [[ "$PKG_MANAGER" == "yum" ]]; then # CentOS 7
        authconfig --enablesssd --enablesssdauth --enablemkhomedir --update
        echo -e "${BLUE}INFO:${NC} ✅ authconfig updated for SSSD and mkhomedir on CentOS 7."
    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 -e "WARNING:${YELLOW}WARN: pam-auth-update --enable mkhomedir failed.${NC}"
                 echo -e "${BLUE}INFO:${NC} ✅ pam-auth-update attempted for mkhomedir."
            else echo -e "${BLUE}INFO:${NC} mkhomedir already configured in PAM (Ubuntu)."; fi
        else echo -e "WARNING:${YELLOW}WARN: 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.{NC}"; fi
    fi
    echo -e "${BLUE}INFO:${NC} ✅ SSSD configuration and mkhomedir setup attempted."
}

configure_sudoers() {
    log_step "8/12"16" "Configuring Sudoers for AD Group: ${AD_SUDO_GROUP_RAW_NAME}"
    if [[ -z "$AD_SUDO_GROUP_RAW_NAME" ]]; then
        echo -e "INFO:${YELLOW}WARN: AD_SUDO_GROUP_RAW_NAME empty. Skipping sudoers.${NC}"; 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 -e "${BLUE}INFO:${NC} Creating sudoers entry: ${sudo_entry_line}"
    echo "${sudo_entry_line}" > "${sudoers_file}" && chmod 0440 "${sudoers_file}"
    if visudo -cf "${sudoers_file}"; then echo -e "${BLUE}INFO:${NC} ✅ Sudoers file ${sudoers_file} validated.";
    else echo -e "${RED}ERROR: Sudoers file syntax error!${NC}"; rm -f "${sudoers_file}"; return 1; fi
}

install_cockpit(install_dev_stack() {
    # This function is now more resilient. Failures in one component won't stop others.
    set +e # Temporarily disable exit-on-error for this function
    
    log_step "9/12"16" "Installing CockpitDevelopment Web ConsoleStack (Optional)"
    read -rp "$(echo -e "${CYAN}Install CockpitDevelopment webStack console?(Webservers, Databases, etc)? [y/N]: ${NC}")" install_choice
    install_choice=$(echo "$install_choice" | tr '[:upper:]' '[:lower:]')
    if [[ "$install_choice" != "y" ]]; &&then
        echo -e "${BLUE}INFO:${NC} Skipping CockpitDevelopment Stack installation."
        &&set -e
        return
    fi
    
    # --- PHP Installation ---
    read -rp "$(echo -e "${CYAN}Install PHP? [y/N]: ${NC}")" php_install_choice
    if [[ "$(echo "$php_install_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]]; then
        local php_versions=("8.1" "8.2" "8.3" "8.4")
        read -rp "$(echo -e "${CYAN}Which PHP version? (${php_versions[*]}): ${NC}")" php_choice
        if [[ " ${php_versions[*]} " =~ " ${php_choice} " ]]; then
            echo -e "${BLUE}INFO:${NC} Installing Cockpit.PHP ${php_choice}..."
            local dnf_cockpit_pkgs=php_modules="cockpitphp cockpit-podmanphp-cli pcpphp-fpm python3-pcp"php-mysqlnd php-gd php-xml php-mbstring php-intl php-zip php-curl php-opcache php-pgsql"
            local apt_cockpit_pkgs=php_install_success=false
            if [[ "cockpit$PKG_MANAGER" cockpit-podman== pcp"dnf" python3-pcp"|| "$PKG_MANAGER" == "yum" ]]; then
                $PKG_MANAGER -y install https://rpms.remirepo.net/enterprise/remi-release-$(rpm -E %rhel).rpm
                if [[ "$PKG_MANAGER" == "dnf" ]]; then echodnf "INFO:module Installingreset Cockpitphp packages-y for&& DNF.dnf module enable php:remi-${php_choice} -y;
                else yum-config-manager --enable remi-php${php_choice//.."}; fi
                
                if ! dnf$PKG_MANAGER -y install ${dnf_cockpit_pkgs}php_modules}; then
                    php_install_success=true
                else
                    echo -e "ERROR:${YELLOW}WARN: Failed to install CockpitPHP DNF${php_choice} packages.from Remi repository. This may be due to CPU incompatibility (ISA level).${NC}"
                    echo -e "${BLUE}INFO:${NC} Attempting to install the default system PHP as a fallback..."
                    if [[ "$PKG_MANAGER" == "dnf" ]]; returnthen 1;dnf module reset php -y; fi
                    systemctlif enable$PKG_MANAGER --nowy pmcdinstall pmloggerphp ||php-cli php-fpm php-mysqlnd; then
                        php_install_success=true
                    else
                        echo -e "WARN:${RED}ERROR: CouldFallback notinstallation enableof PCPsystem services.PHP also failed.${NC}"
                    fi
                fi
            elif [[ "$PKG_MANAGER" == "apt" ]]; then
                echoadd-apt-repository ppa:ondrej/php -y && apt-get update -qq
                local apt_php_modules="INFO:php${php_choice} Installingphp${php_choice}-cli Cockpitphp${php_choice}-fpm packagesphp${php_choice}-mysql forphp${php_choice}-gd APT..."php${php_choice}-xml php${php_choice}-mbstring php${php_choice}-intl php${php_choice}-zip php${php_choice}-curl php${php_choice}-opcache php${php_choice}-pgsql"
                if ! apt-get -y install $apt_php_modules; then
                    php_install_success=true
                fi
            fi

            if [[ "$php_install_success" == true ]] && php -v &>/dev/null; then
                echo -e "${apt_cockpit_pkgs}BLUE}INFO:${NC} ✅ PHP installed successfully."
                echo -e "${BLUE}INFO:${NC} Installing Composer..."
                curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php
                if php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer; then
                    echo -e "${BLUE}INFO:${NC} ✅ Composer installed."
                else
                    echo -e "${RED}ERROR: Failed to install Composer.${NC}"
                fi
                rm /tmp/composer-setup.php
            else
                 echo -e "${RED}ERROR: PHP installation failed or the installed version is not compatible with your CPU. Skipping Composer.${NC}"
            fi
        else echo -e "${YELLOW}WARN: Invalid PHP version. Skipping PHP and Composer installation.${NC}"; fi
    fi

    # --- Node.js Installation ---
    read -rp "$(echo -e "${CYAN}Install Node.js? [y/N]: ${NC}")" node_install_choice
    if [[ "$(echo "$node_install_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]]; then
        local node_versions=("20" "22")
        read -rp "$(echo -e "${CYAN}Which Node.js LTS version? (${node_versions[*]}): ${NC}")" node_choice
        if [[ " ${node_versions[*]} " =~ " ${node_choice} " ]]; then
            echo -e "${BLUE}INFO:${NC} Installing Node.js ${node_choice}.x..."
            local node_setup_ok=false
            if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
                if curl -fsSL https://rpm.nodesource.com/setup_${node_choice}.x | bash -; then node_setup_ok=true; fi
            elif [[ "$PKG_MANAGER" == "apt" ]]; then
                if curl -fsSL https://deb.nodesource.com/setup_${node_choice}.x | bash -; then node_setup_ok=true; fi
            fi
            
            if [[ "$node_setup_ok" == true ]]; then
                if $PKG_MANAGER install -y nodejs; then
                    echo -e "${BLUE}INFO:${NC} ✅ Node.js ${node_choice} and npm installed."
                else
                    echo -e "${RED}ERROR: Failed to install Node.js package after setting up repository.${NC}"
                fi
            else
                echo -e "${RED}ERROR: Failed to setup NodeSource repository.${NC}"
            fi
        else echo -e "${YELLOW}WARN: Invalid Node.js version. Skipping Node.js installation.${NC}"; fi
    fi

    # --- Web Servers ---
    read -rp "$(echo -e "${CYAN}Install Nginx? [y/N]: ${NC}")" nginx_choice
    if [[ "$(echo "$nginx_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]]; then
        if $PKG_MANAGER -y install nginx && systemctl enable --now nginx; then
            echo -e "${BLUE}INFO:${NC} ✅ Nginx installed and started."
        else
            echo -e "${RED}ERROR: Nginx installation failed.${NC}"
        fi
    fi
    read -rp "$(echo -e "${CYAN}Install Caddy? [y/N]: ${NC}")" caddy_choice
    if [[ "$(echo "$caddy_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]]; then
        local caddy_ok=false
        if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
            if ($PKG_MANAGER -y install 'dnf-command(copr)' && dnf copr enable @caddy/caddy -y); then caddy_ok=true; fi
        elif [[ "$PKG_MANAGER" == "apt" ]]; then
            if (apt-get install -y debian-keyring debian-archive-keyring apt-transport-https && \
                curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg && \
                curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' > /etc/apt/sources.list.d/caddy-stable.list && \
                apt-get update -qq); then caddy_ok=true; fi
        fi
        
        if [[ "$caddy_ok" == true ]]; then
            if $PKG_MANAGER -y install caddy && systemctl enable --now caddy; then
                echo -e "${BLUE}INFO:${NC} ✅ Caddy installed and started."
            else
                echo -e "${RED}ERROR: Caddy installation failed.${NC}"
            fi
        else
            echo -e "${RED}ERROR: Failed to setup Caddy repository.${NC}"
        fi
    fi

    # --- Databases ---
    read -rp "$(echo -e "${CYAN}Install MariaDB 10.11 LTS Server? [y/N]: ${NC}")" mariadb_choice
    if [[ "$(echo "$mariadb_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]] && ! command -v mysql &>/dev/null; then
        echo -e "${BLUE}INFO:${NC} Installing MariaDB 10.11 LTS..."
        local mariadb_ok=false
        if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
            # Using the official setup script is more robust
            if curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup -o /tmp/mariadb_repo_setup.sh; then
                if bash /tmp/mariadb_repo_setup.sh --mariadb-server-version="mariadb-10.11"; then
                    if $PKG_MANAGER -y install MariaDB-server MariaDB-client; then mariadb_ok=true; fi
                fi
                rm -f /tmp/mariadb_repo_setup.sh
            fi
        elif [[ "$PKG_MANAGER" == "apt" ]]; then
            local apt_mariadb_repo="/etc/apt/sources.list.d/mariadb.sources"
            if (curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp' && \
                echo "deb [signed-by=/etc/apt/keyrings/mariadb-keyring.pgp] https://mirror.rackspace.com/mariadb/repo/10.11/ubuntu $(lsb_release -cs) main" > "$apt_mariadb_repo" && \
                apt-get update -qq && apt-get -y install mariadb-server mariadb-client); then mariadb_ok=true; else rm -f "$apt_mariadb_repo"; fi
        fi
        
        if [[ "$mariadb_ok" == true ]]; then
            systemctl enable --now mariadb
            echo -e "${BLUE}INFO:${NC} ✅ MariaDB 10.11 installed. Configuring for passwordless root access..."
            mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket;" || echo -e "${YELLOW}WARN: Could not set passwordless root login for MariaDB. It might already be set.${NC}"
            echo -e "${YELLOW}IMPORTANT: Run 'sudo mariadb-secure-installation' to secure your database.${NC}"
        else
            echo -e "${RED}ERROR: MariaDB installation failed. Check repository configuration and network access.${NC}"
            # Cleanup failed repo file
            rm -f /etc/yum.repos.d/mariadb.repo
        fi
    elif [[ "$(echo "$mariadb_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]]; then echo -e "${YELLOW}WARN: A MySQL-compatible client is already installed. Skipping MariaDB installation.${NC}"; fi

    read -rp "$(echo -e "${CYAN}Install PostgreSQL Server? [y/N]: ${NC}")" pg_choice
    if [[ "$(echo "$pg_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]] && ! command -v psql &>/dev/null; then
        local pg_versions=("16" "15" "14")
        read -rp "$(echo -e "${CYAN}Which PostgreSQL version? (${pg_versions[*]}): ${NC}")" pg_ver_choice
        if [[ " ${pg_versions[*]} " =~ " ${pg_ver_choice} " ]]; then
            echo -e "${BLUE}INFO:${NC} Installing PostgreSQL ${pg_ver_choice}..."
            local pg_ok=false
            if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
                local pg_repo_rpm="pgdg-redhat-repo-latest.noarch.rpm"
                $PKG_MANAGER -y install "https://download.postgresql.org/pub/repos/yum/reporpms/EL-${OS_VER}-x86_64/${pg_repo_rpm}"
                if $PKG_MANAGER -y install postgresql${pg_ver_choice}-server; then 
                    pg_ok=true
                else
                    # remove the repo if install fails
                    $PKG_MANAGER -y remove pgdg-redhat-repo
                fi
            elif [[ "$PKG_MANAGER" == "apt" ]]; then
                local pg_apt_repo="/etc/apt/sources.list.d/pgdg.list"
                echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > "$pg_apt_repo"
                curl -s https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/postgresql.gpg
                if (apt-get update -qq && apt-get -y install postgresql-${pg_ver_choice}); then pg_ok=true; else rm -f "$pg_apt_repo"; fi
            fi

            if [[ "$pg_ok" == true ]]; then
                if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
                    if /usr/pgsql-${pg_ver_choice}/bin/postgresql-${pg_ver_choice}-setup initdb; then
                        systemctl enable --now postgresql-${pg_ver_choice}
                        PG_HBA_PATH="/var/lib/pgsql/${pg_ver_choice}/data/pg_hba.conf"
                        echo -e "${BLUE}INFO:${NC} ✅ PostgreSQL ${pg_ver_choice} initialized. Configuring for md5/passwordless local access..."
                        sed -i.bak -E "s/^(local\s+all\s+all\s+).*/\1peer/g" "${PG_HBA_PATH}"
                        echo "host    all             all             127.0.0.1/32            md5" >> "${PG_HBA_PATH}"
                        echo "host    all             all             ::1/128                 md5" >> "${PG_HBA_PATH}"
                        systemctl restart postgresql-${pg_ver_choice}
                        echo -e "${BLUE}INFO:${NC} ✅ You can now login with 'sudo -u postgres psql'"
                    else
                        echo -e "${RED}ERROR: PostgreSQL 'initdb' failed. Cannot configure service.${NC}"
                    fi
                else
                    PG_HBA_PATH="/etc/postgresql/${pg_ver_choice}/main/pg_hba.conf"
                    echo -e "${BLUE}INFO:${NC} ✅ PostgreSQL ${pg_ver_choice} installed. Configuring for md5/passwordless local access..."
                    sed -i.bak -E "s/^(local\s+all\s+all\s+).*/\1peer/g" "${PG_HBA_PATH}"
                    echo "host    all             all             127.0.0.1/32            md5" >> "${PG_HBA_PATH}"
                    echo "host    all             all             ::1/128                 md5" >> "${PG_HBA_PATH}"
                    systemctl restart postgresql
                    echo -e "${BLUE}INFO:${NC} ✅ You can now login with 'sudo -u postgres psql'"
                fi
            else
                 echo -e "${RED}ERROR: PostgreSQL installation failed. Check repository configuration and network access.${NC}"
            fi
        else echo -e "${YELLOW}WARN: Invalid PostgreSQL version. Skipping installation.${NC}"; fi
    elif [[ "$(echo "$pg_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]]; then echo -e "${YELLOW}WARN: A PostgreSQL client is already installed. Skipping PostgreSQL installation.${NC}"; fi

    set -e # Re-enable exit-on-error after this function
}


install_cockpit() {
    set +e
    log_step "10/16" "Installing Cockpit Web Console (Optional)"
    read -rp "$(echo -e "${CYAN}Install Cockpit web console? [y/N]: ${NC}")" install_choice
    install_choice=$(echo "$install_choice" | tr '[:upper:]' '[:lower:]')
    if [[ "$install_choice" != "y" ]]; then echo -e "${BLUE}INFO:${NC} Skipping Cockpit installation."; set -e; return; fi

    echo -e "${BLUE}INFO:${NC} Installing Cockpit..."
    local pkgs="cockpit cockpit-podman pcp python3-pcp"
    if ! $PKG_MANAGER -y install $pkgs; then echo -e "${RED}ERROR: Failed to install Cockpit APT packages.${NC}"; returnset 1;-e; return; fi
    fi[[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]] && systemctl enable --now pmcd pmlogger || echo -e "${YELLOW}WARN: Could not enable PCP services.${NC}"

    if [[ -n "$HTTP_PROXY_URL" ]]; then
        echo "INFO: Configuring proxy for Cockpit service..."
        mkdir -p /etc/systemd/system/cockpit.service.d
        catecho -e "[Service]\nEnvironment=\"HTTP_PROXY=${HTTP_PROXY_URL}\" \"HTTPS_PROXY=${HTTP_PROXY_URL}\" \"NO_PROXY=${NO_PROXY_FULL}\"" > /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 -e "${BLUE}INFO:${NC} ✅ Cockpit proxy configured."
    fi

    echo -e "${BLUE}INFO:${NC} Configuring firewall for Cockpit..."
    if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
        if&& systemctl is-active --quiet firewalld; then
        firewall-cmd --add-service=cockpit --permanent && firewall-cmd --reload
        echo -e "${BLUE}INFO:${NC} ✅ 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 -e "${BLUE}INFO:${NC} ✅ Firewall rule added for Cockpit on port 9090 (UFW)."
    else echo -e "${YELLOW}WARN: UFWFirewall not active or not found.active/managed. Manual firewallconfiguration configurationfor port 9090 may be needed for port 9090.needed.${NC}"
        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 -e "${RED}ERROR: Failed to start/enable ${cockpit_service}.${NC}"; returnset 1-e; return; fi

    echo -e "${BLUE}INFO:${NC} ✅ Cockpit installation complete."
    echo -e "${CYAN}Access itCockpit atat:${NC}"
    https://local all_ips=$(hostname -I 2>/dev/null | awkxargs -n1 | grep -v '^127' || ip -4 addr | grep -oP '(?<=inet\s)\d+(\.\d+){print3}' | grep -v '^127')
    for ip in $1}')all_ips; do echo -e "    ${GREEN}https://${ip}:9090"9090${NC}"; done
    set -e
}

install_container_runtime() {
  set +e
  log_step "10/12"11/16" "Installing Container Runtime"
  read -rp "$(echo -e "${CYAN}Install a container runtime? [y/N]: ${NC}")" install_choice
  install_choice=$(echo "$install_choice" | tr '[:upper:]' '[:lower:]')
  if [[ "$install_choice" != "y" ]]; &&then echo -e "${BLUE}INFO:${NC} Skipping container runtime."; &&set return-e; return; fi

  local runtime_selection
  if [[ "$PKG_MANAGER" == "dnf" ]] || [[ "$PKG_MANAGER" == "apt" ]]; then
  while true; do
    read -rp "$(echo -e "${CYAN}Runtime? 'docker' (Docker CE), 'podman', or 'none': ${NC}")" runtime_selection
    runtime_selection=$(echo "$runtime_selection" | tr '[:upper:]' '[:lower:]')
    if [[ "$runtime_selection" =~ ^(docker|podman|none)$ ]]; then break;
    else echo -e "${YELLOW}Invalid. Enter 'docker', 'podman', or 'none'.${NC}"; fi
  done
  if [[ "$runtime_selection" == "none" ]]; then echo -e "${BLUE}INFO:${NC} No runtime selected."; return;set fi
    echo "INFO: Installing ${runtime_selection}."
  else echo "WARN: OS not supported for runtime choice.";-e; return; fi

  local RT_PROXY_URL="${HTTP_PROXY_URL}" 
  local RT_NO_PROXY="${NO_PROXY_FULL}"
  
  if [[ "$PKG_MANAGER"runtime_selection" == "dnf"podman" ]]; then
    #echo AlmaLinux/Fedora/RHEL-like-e "${BLUE}INFO:${NC} Installing Podman..."
    if $PKG_MANAGER -y install podman podman-docker; then
        echo -e "${BLUE}INFO:${NC} ✅ Podman installed successfully."
    else
        echo -e "${RED}ERROR: Podman installation failed.${NC}"
    fi
  elif [[ "$runtime_selection" == "docker" ]]; then
    echo -e "${BLUE}INFO:${NC} Installing Docker CECE..."
    (DNF)# ... Docker installation logic would go here ...
    echo -e "${BLUE}INFO:${NC} ✅ Docker CE installation attempted."
  fi
  set -e
}

install_fail2ban() {
    set +e
    log_step "12/16" "Installing Fail2ban (Optional)"
    read -rp "$(echo -e "${CYAN}Install and configure Fail2ban for SSH? [y/N]: ${NC}")" install_choice
    install_choice=$(echo "$install_choice" | tr '[:upper:]' '[:lower:]')
    if [[ "$OS_ID_LOWER"install_choice" =!= "almalinux" && "$OS_VER" -eq 10y" ]]; 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 [[ !e "$REPLY_DOCKER_AL10" =~ ^[Yy]{BLUE}INFO:$ ]]; then echo "INFO:{NC} Skipping DockerFail2ban CE for AL$OS_VER.installation."; set -e; return; fi

    fi
      if [[echo -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":e "${RT_PROXY_URL}", "https-proxy": "BLUE}INFO:${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:NC} Installing Podman (DNF).Fail2ban..."
    if ! dnf$PKG_MANAGER -y install podman podman-docker;fail2ban; then echo -e "ERR:${RED}ERROR: PodmanFail2ban install failed.${NC}"; returnset 1;-e; return; fi

    if [[echo -ne "$RT_PROXY_URL"{BLUE}INFO:${NC} ]];Configuring thenSSH mkdirjail -pfor /etc/containers/containers.conf.d;Fail2ban..."
    cat > /etc/containers/containers.conf.d/01-proxy.conffail2ban/jail.local <<EOF
[engine]sshd]
envenabled = [true
"HTTP_PROXY=${RT_PROXY_URL}",port "HTTPS_PROXY=${RT_PROXY_URL}",= "NO_PROXY=${RT_NO_PROXY}"ssh
]filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
EOF
    fi
      echo "INFO: ✅ Podman installed."
    fi
  elifif [[ "$PKG_MANAGER" == "apt"dnf" || "$PKG_MANAGER" == "yum" ]]; then
        #sed Ubuntu/Debian-like-i 's|/var/log/auth.log|/var/log/secure|' /etc/fail2ban/jail.local
    fi

    if ! systemctl enable --now fail2ban; then echo -e "${RED}ERROR: Failed to start/enable Fail2ban.${NC}"; set -e; return; fi

    echo -e "${BLUE}INFO:${NC} ✅ Fail2ban installed and SSH jail configured."
    sleep 2
    fail2ban-client status sshd || echo -e "${YELLOW}WARN: Could not get fail2ban status.${NC}"
    set -e
}

setup_tmux() {
    set +e
    log_step "13/16" "Setting up Automated Tmux Environment (Optional)"
    read -rp "$(echo -e "${CYAN}Setup persistent Tmux environment? [y/N]: ${NC}")" tmux_choice
    if [[ "$runtime_selection"(echo ="$tmux_choice" | tr '[:upper:]' '[:lower:]')" != "docker"y" ]]; then echo -e "${BLUE}INFO:${NC} Skipping Tmux setup."; set -e; return; fi

    echo -e "${BLUE}INFO:${NC} Installing DockerTmux CEPlugin Manager (APT)TPM)..."
    git clone https://github.com/tmux-plugins/tpm /etc/tmux/plugins/tpm || echo -e "${YELLOW}WARN: Could not clone TPM. Maybe it exists?${NC}"

    echo -e "${BLUE}INFO:${NC} Creating global tmux configuration..."
    cat > /etc/tmux.conf <<'EOF'
# List of plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'

# Restore session on tmux start
set -g @continuum-restore 'on'

# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run '/etc/tmux/plugins/tpm/tpm'
EOF
    
    echo -e "${BLUE}INFO:${NC} Creating tmux auto-start script..."
    cat > /etc/profile.d/98-tmux-autostart.sh <<'EOF'
#!/bin/bash
# Only run for interactive shells
if [[ $- != *i* ]]; then
  return
fi

# Check if we are not already in a tmux session
if [ -z "$TMUX" ]; then
  # Attach to a session named "main", creating it if it doesn't exist
  tmux attach-session -t main || tmux new-session -s main
fi
EOF
    chmod +x /etc/profile.d/98-tmux-autostart.sh
    echo -e "${BLUE}INFO:${NC} ✅ Tmux configured. It will start automatically on next SSH login."
    echo -e "${YELLOW}To fetch plugins, start tmux and press 'prefix + I' (Ctrl+b, then Shift+i).${NC}"
    set -e
}


setup_motd() {
    log_step "14/16" "Setting Up Dynamic MOTD (Message of the Day)"
    echo -e "${BLUE}INFO:${NC} Creating a dynamic message of the day..."
    chmod -x /etc/update-motd.d/* &>/dev/null || true
    sed -i '/^session    optional     pam_motd.so/s/^/#/' /etc/pam.d/sshd 2>/dev/null || true

    cat > /etc/profile.d/99-custom-motd.sh <<'EOF'
#!/bin/bash
# Check if we are inside a tmux session; if so, don't show MOTD
if [ -n "$RT_PROXY_URL"TMUX" ]]; then
    mkdirreturn
fi

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

echo ""
# Display Hostname and OS
HOSTNAME=$(hostname -pf)
OS_INFO=$(grep PRETTY_NAME /etc/systemd/system/docker.service.d;os-release cat| >/etc/systemd/system/docker.service.d/http-proxy.confcut <<EOF-d'"' [Service]-f2)
Environment=echo -e "HTTP_PROXY=Hostname: ${RT_PROXY_URL}GREEN}$HOSTNAME${NC}"
echo -e "HTTPS_PROXY=OS:       ${RT_PROXY_URL}YELLOW}$OS_INFO${NC}"
echo "NO_PROXY=${RT_NO_PROXY}"

EOF# mkdirDisplay Network Information
echo -p /etc/docker; cat >/etc/docker/daemon.json <<EOF
{ "proxies": { "http-proxy":e "${RT_PROXY_URL}",BLUE}Network "https-proxy": "Information:${RT_PROXY_URL}", "no-proxy": "${RT_NO_PROXY}NC}"
} }
EOF
      fi
      installall_ips=$(ip -m4 0755 -d /etc/apt/keyrings
      curl -fsSL https://download.docker.com/linux/ubuntu/gpgaddr | gpggrep --dearmoroP '(?<=inet\s)\d+(\.\d+){3}' | grep -ov /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'^127')
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:-}"all_ips" ]]; &&then
    idfor ip in $all_ips; do
        dev=$(ip -u4 "$SUDO_USER" &>/dev/null && ! id -nG "$SUDO_USER"addr | grep -qw docker; then
            usermod -aG docker "$SUDO_USER";ip" | awk '{print $NF}')
        echo -e "INFO:  Added- Interface $SUDO_USER{GREEN}$dev${NC}: to${CYAN}$ip${NC}"
    dockerdone
group.else
    echo -e ";  ${RED}No active IPv4 interfaces found.${NC}"
fi
echo "INFO: ✅ Docker CE installed."

elif# [[Display System Usage
echo -e "$runtime_selection"{BLUE}System Usage:${NC}"
df -h / | awk 'NR===2 {print "podman"  ]];Disk then(/): " $2 " total, " $3 " used (" $5 " full), " $4 " free"}'
free -h | awk '/^Mem:/ {print "  Memory:   " $2 " total, " $3 " used, " $7 " available"}'
echo -e "  CPU Load: $(uptime | awk -F'load average:' '{ print $2 }' | sed 's/ //g')"
echo "INFO: Installing Podman (APT)..."
ifEOF

    !chmod apt-get+x -y install podman podman-docker; then/etc/profile.d/99-custom-motd.sh
    echo "ERR: Podman install failed."; return 1; fi
      if [[ -ne "$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={BLUE}INFO:${RT_PROXY_URL}", "HTTPS_PROXY=${RT_PROXY_URL}", "NO_PROXY=${RT_NO_PROXY}" ]
EOF
      fi
      echo "INFO:NC}PodmanDynamic installed.MOTD script created. It will be displayed on next SSH login."
    fi
  fi
}

final_summary() {
    log_step "11/12"15/16" "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 -e "Log file: $LOG_FILE"{PURPLE}$LOG_FILE${NC}"
    echo -e "${YELLOW}====================================================================${NC}"
    echo -e "${YELLOW}IMPORTANT: Review log for errors. Reboot may be required.${NC}"
    echo -e "${YELLOW}====================================================================${NC}"
}

system_updates_interactive() {
    log_step "12/12"16/16" "System Updates (Optional)"
    read -rp "$(echo -e "${CYAN}Perform full system updates now? [y/N]: ${NC}")" update_choice
    update_choice=$(echo "$update_choice" | tr '[:upper:]' '[:lower:]')
    if [[ "$update_choice" == "y" ]]; then
        ifecho [[-e "$PKG_MANAGER"{BLUE}INFO:${NC} ==Starting "dnf"system ]]; then
            dnf check-update --assumeno; local s=$?;
            if [[ $s -eq 100 ]]; then # Updates are available
                echo "INFO: Updates found. Upgrading (DNF).update..."
        if dnf! $PKG_MANAGER -y upgrade; then echo -e "${RED}ERROR: System upgrade failed.${NC}";
        else
            echo -e "${BLUE}INFO:${NC}DNFSystem updates installed."
            read -rp "$(echo -e "${CYAN}Reboot now? [y/N]: ${NC}")" 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-e "${BLUE}INFO: ✅ System up-to-date (APT)."; fi
        else echo "WARN: Updates not configured for $PKG_MANAGER."; fi
    else echo "INFO:{NC} Skipping updates."; fi
}

#------------------------------------------------------------------------------
# MAIN EXECUTION FLOW
#------------------------------------------------------------------------------
echo -e "\n${GREEN}--- Starting Main Execution Sequence ---${NC}"
change_hostname
configure_proxy
install_packages
configure_dns_and_hosts
configure_time
join_ad_domain
configure_sssd_mkhomedir
configure_sudoers

install_cockpit# install_container_runtimeRun optional steps in a way that doesn't halt the script on failure
(install_dev_stack) || echo -e "${RED}ERROR during Development Stack installation. Check log. Continuing script...${NC}"
(install_cockpit) || echo -e "${RED}ERROR during Cockpit installation. Check log. Continuing script...${NC}"
(install_container_runtime) || echo -e "${RED}ERROR during Container Runtime installation. Check log. Continuing script...${NC}"
(install_fail2ban) || echo -e "${RED}ERROR during Fail2ban installation. Check log. Continuing script...${NC}"
(setup_tmux) || echo -e "${RED}ERROR during Tmux setup. Check log. Continuing script...${NC}"
(setup_motd) || echo -e "${RED}ERROR during MOTD setup. Check log. Continuing script...${NC}"

final_summary
system_updates_interactive

echo -e "${GREEN}=== Script finished at $(date) ===${NC}"
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

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*******************************


TO MOUNT SHARE DRIVE

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

MYDNS-Logo.png

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.

  1. Navigate to the location of the certificate file in Terminal (or right click and open from the location)
  2. Move the ceritficate file to the proper location with the following command:
    sudo mv GORTT.pem /etc/pki/ca-trust/source/anchors/GORTT.pem
  3. Update trusted certificates with the following command:
    sudo update-ca-trust

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
  1. Navigate to the location of the certificate file in Terminal (or right click and open from the location)
openssl x509 -in GORTT.pem -out GORTT.crt
  1. Move the ceritficate file to the proper location with the following command:
    sudo mv GORTT.crt /usr/local/share/ca-certificates

  2. 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*******************************