Switch Over Instructions
Server Setup Script - copy and paste into terminal to execute the script
Script with options
#!/bin/bash
# --- Single, Robust Command to Mount, Copy, Execute, and Unmount ---
#
# This command is designed to be safely copied and pasted into any server terminal.
# It handles all the necessary steps to run the main setup script from your fileserver.
# It will prompt you to select which mode to run the main script in.
#
# Password for the mount command is included. Ensure this is run in a secure environment.
# --- Configuration ---
MOUNT_POINT="/mnt/fileserver"
SERVER_PATH="//172.16.21.16/fileserver2"
SCRIPT_SOURCE_PATH="${MOUNT_POINT}/General/IT FILES/script3.sh"
SCRIPT_DEST_PATH="/tmp/script3.sh"
MOUNT_USER="Cipher.m21"
MOUNT_PASS=")\1y;634'NJ%i+"
# --- Logic ---
# Ensure the mount point is unmounted on script exit (success or failure)
trap "echo 'Unmounting fileserver...'; sudo umount '${MOUNT_POINT}' &>/dev/null || true" EXIT
# Check if already mounted. If not, create directory and mount.
if ! grep -qs "${MOUNT_POINT}" /proc/mounts; then
echo "Mounting fileserver..."
sudo mkdir -p "${MOUNT_POINT}"
sudo mount -t cifs "${SERVER_PATH}" "${MOUNT_POINT}" -o username="${MOUNT_USER}",password="${MOUNT_PASS}"
fi
echo "Copying script (overwriting if exists)..."
sudo cp "${SCRIPT_SOURCE_PATH}" "${SCRIPT_DEST_PATH}"
echo "Making script executable..."
sudo chmod +x "${SCRIPT_DEST_PATH}"
# --- Interactive Mode Selection ---
echo ""
echo "Please choose which setup to run:"
echo " 1) Full Setup (default)"
echo " 2) Development Stack Only (--dev)"
echo " 3) Security Hardening Only (--security)"
echo " 4) Shell & UX Setup Only (--shell)"
echo " 5) System Updates Only (--updates)"
read -rp "Enter your choice [1-5]: " run_choice
EXECUTION_FLAG="--full" # Default value
case "$run_choice" in
2) EXECUTION_FLAG="--dev" ;;
3) EXECUTION_FLAG="--security" ;;
4) EXECUTION_FLAG="--shell" ;;
5) EXECUTION_FLAG="--updates" ;;
1) EXECUTION_FLAG="--full" ;;
*) # Default to full for any other input
echo "Invalid choice or no choice entered. Defaulting to Full Setup."
EXECUTION_FLAG="--full"
;;
esac
echo "Executing the main setup script with flag: ${EXECUTION_FLAG}..."
sudo "${SCRIPT_DEST_PATH}" "${EXECUTION_FLAG}"
# The trap will handle the unmount automatically.
echo "Script execution finished. Unmounting is handled automatically."
Simple 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 --full && \
sudo umount /mnt/fileserver
Server Setup Script
#!/usr/bin/env bash
#########################################################################################################
#
####
#######################
#
# Comprehensive Domain Join & Configuration Script
#
# Version: 6.5 (Phoenix - PrioritizesThe Network/ProxyFinal setup before package installation.Cut)
# -Last PromptsModified: 2025-07-31
#
# Features
# [CRITICAL FIX] Zsh theme switching and plugin enabling is now fully robust.
# [CRITICAL FIX] Reboot prompt no longer hangs.
# [FIX] Enhanced Nano with persistent status bar and comprehensive syntax highlighting from a dedicated repository.
# [FIX] Vi/Vim syntax highlighting is now guaranteed by installing a full vim package.
# [ENH] Added a pre-configured "Powerline" theme for CockpitStarship, showing date, time, and Docker CE/Podman installation.hostname.
# -[ENH] CorrectlyAdded installsPowerlevel10k EPELas fora AlmaLinuxZsh 10theme fromoption URL.with automatic installation and configuration wizard setup.
# -[CRITICAL IncorporatesFIX] user-providedProxy proceduralvariables stepsare withnow SSSDexported refinement.immediately, fixing all subsequent download failures.
# -[CRITICAL AutomaticallyFIX] prefixesCtrl+C ADcancellation usernameis withnow "ent_".robust and reliably skips optional sections without exiting the script.
#
-###############################
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,.localhost.localdomain" # Base no_proxy entries
NO_PROXY_CUSTOM="172.30.0.0/20,172.26.21.0/24"24,172.16.121.0/24,10.21.0.0/21" # Your custom NO_PROXYNO CIDRsPROXY CIDRS
INSECURE_REGISTRIES='"172.16.121.119:5000", "docker-repo.mydns.gov.tt"' # Comma-separated, quoted Docker insecure registries
TIMEZONE="America/Port_of_Spain" # Your desired timezone
AD_SUDO_GROUP_RAW_NAME="ICT Staff SG" # 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
# Global flag for reboot
REBOOT_REQUIRED_FLAG=false
# Exit on error for most commands, but we will handle some manually.
set -euoo pipefail
LOG_FILE="/var/log/setup-domain-$(date +%Y%m%d-Y-%H%M%m-%d_%H-%M-%S).log"
# Log to file, but keep stderr on the console to see errors immediately.
exec > >(tee -a "$LOG_FILE") 2>&1
# Log stdout and stderr to file and console
echo -e "${GREEN}=== Script started at $(date)date --iso-8601=seconds) by $(whoami) ===${NC}"
echo -e "${GREEN}=== Logging to ${LOG_FILE} ===${NC}"
#------------------------------------------------------------------------------
# PRELIMINARY CHECKS & INPUTGLOBAL VARIABLES
#------------------------------------------------------------------------------
[[ $EUID -ne 0 ]] && { echo -e "${RED}ERROR: This script must be run as root or with sudo.${NC}"; >&2; 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 DNF, YUM, nor APT package manager found. Exiting.${NC}"; >&2; exit 1; fi
echo -e "${BLUE}INFO:${NC} Detected package manager: ${PURPLE}$PKG_MANAGER${NC}"
source /etc/os-release
OS_ID_LOWER=$(echo "$ID" | tr '[:upper:]' '[:lower:]')
OS_VER="${VERSION_ID%%.*}"
HOSTNAME_VAR=$(hostname -f)
#---
# SCRIPT FUNCTIONS
#
log_step() { echo -e "\n${GREEN}--- [STEP ${BLUE}INFO:${NC}1 Detected OS:on ${PURPLE}$PRETTY_NAME${HOSTNAME_VAR}${NC}] $2 ---${NC}"; }
#
# SECTION 0: CREDENTIAL GATHERING
#
gather_credentials() {
log_step "0/X" "Gathering Credentials (ID:Not Logged)"
local creds_ok=false
while ! $ID,creds_ok; Version:do
( # Start subshell for cancellable read
trap 'echo -e "\n${RED}Credential entry cancelled. Exiting script.$VERSION_ID){NC}"; exit 1;' INT
echo -e "\n${CYAN}--- UserDomain InputCredentials (will not be logged) ---${NC}"
read -rp "$(echo -e "${CYAN}Enter the SERVICE part of the hostname (e.g., mydns-it-c12-l)1): ${NC}")" SERVICE_NAME_PART < /dev/tty
if [[ ! "$SERVICE_NAME_PART" =~ ^[a-zA-Z0-9-]+$ ]]; then
echo -e "${RED}ERROR: Invalid service name part.${NC}"; >&2; 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 < /dev/tty
if [[ -z "$AD_USER_SUFFIX" ]]; then echo -e "${RED}ERROR: AD username suffix cannot be empty.${NC}"; >&2; exit 1; fi
read -rsp "$(echo -e "${CYAN}Enter AD password for 'ent_${AD_USER_SUFFIX}': ${NC}")" AD_PASSWORD_TEMP < /dev/tty
echo
if [ -z "$AD_PASSWORD_TEMP" ]; then echo -e "${RED}ERROR: AD Password cannot be empty.${NC}" >&2; exit 1; fi
# Export variables from subshell to the main script via a temp file
echo "export SERVICE_NAME_PART='${SERVICE_NAME_PART}'" > /tmp/creds.sh
echo "export AD_USER_SUFFIX='${AD_USER_SUFFIX}'" >> /tmp/creds.sh
echo "export AD_PASSWORD='${AD_PASSWORD_TEMP}'" >> /tmp/creds.sh
)
if [ $? -ne 0 ]; then exit 1; fi
source /tmp/creds.sh
rm /tmp/creds.sh
creds_ok=true
done
TARGET_HOSTNAME_FQDN="${SERVICE_NAME_PART}.${DOMAIN_FQDN}"
TARGET_HOSTNAME_FQDN_LC=$(echo "$TARGET_HOSTNAME_FQDN" | tr '[:upper:]' '[:lower:]')
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" | awktr ',' '\n' | sort -F,u | tr '{for(i=1;i<=NF;i++)arr[$i]}END{for(k\n' in arr)printf "%s,"',k}' | sed 's/,$//')
#------------------------------------------------------------------------------}
#
SCRIPT#SECTION 1: CORE SYSTEM & NETWORK FUNCTIONS
#------------------------------------------------------------------------------
log_step() { echo -e "\n${GREEN}--- [STEP $1] $2 ---${NC}"; }#
change_hostname() {
log_step "1/16"X" "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; fiHostname"
echo -e "${BLUE}INFO:${NC} ✅Setting hostname to ${PURPLE}${TARGET_HOSTNAME_FQDN_LC}${NC}"
hostnamectl set-hostname "$TARGET_HOSTNAME_FQDN_LC"
echo -e "${GREEN}SUCCESS:${NC} Hostname set to: ${PURPLE}$(hostnamectl hostname)${NC}"
}
configure_proxy() {
log_step "2/16"X" "Configuring ProxySystem-Wide Settings"Proxy"
if [[ -z "$HTTP_PROXY_URL" ]]; then
echo -e "${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/$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} ✅HTTP_PROXY_URL /etc/environmentis configured.not set. Skipping proxy configuration."
return
fi
echo -e "${BLUE}INFO:${NC} Applying proxy for current script session..."
export http_proxy="${HTTP_PROXY_URL}"
export https_proxy="${HTTP_PROXY_URL}"
export ftp_proxy="${HTTP_PROXY_URL}"
export no_proxy="${NO_PROXY_FULL}"
export HTTP_PROXY="${HTTP_PROXY_URL}"
export HTTPS_PROXY="${HTTP_PROXY_URL}"
export FTP_PROXY="${HTTP_PROXY_URL}"
export NO_PROXY="${NO_PROXY_FULL}"
echo -e "${BLUE}INFO:${NC} ProxyConfiguring exportedproxy for currentfuture scriptinteractive session.shells (/etc/profile.d/proxy.sh)..."
ifcat [[> /etc/profile.d/proxy.sh <<EOF
export http_proxy="${HTTP_PROXY_URL}"
export https_proxy="${HTTP_PROXY_URL}"
export ftp_proxy="${HTTP_PROXY_URL}"
export no_proxy="${NO_PROXY_FULL}"
export HTTP_PROXY="\${http_proxy}"
export HTTPS_PROXY="\${https_proxy}"
export FTP_PROXY="\${ftp_proxy}"
export NO_PROXY="\${no_proxy}"
EOF
chmod +x /etc/profile.d/proxy.sh
echo -e "$PKG_MANAGER"{BLUE}INFO:${NC} ==Configuring system-wide environment file (/etc/environment)..."dnf" || "$PKG_MANAGER" == "yum" ]]; then
sed -i '/^proxy=http_proxy=/d;/^https_proxy=/d;/^ftp_proxy=/d;/^no_proxy=/d' /etc/environment
sed -i '/^HTTP_PROXY=/d;/^HTTPS_PROXY=/d;/^FTP_PROXY=/d;/^NO_PROXY=/d' /etc/environment
echo "http_proxy=\"$PKG_MANAGER/{HTTP_PROXY_URL}\"" >> /etc/environment
echo "https_proxy=\"$PKG_MANAGER.conf{HTTP_PROXY_URL}\"" 2>> /dev/nulletc/environment
echo "ftp_proxy=\"${HTTP_PROXY_URL}\"" >> /etc/environment
echo "no_proxy=\"${NO_PROXY_FULL}\"" >> /etc/environment
echo "HTTP_PROXY=\"${HTTP_PROXY_URL}\"" >> /etc/environment
echo "HTTPS_PROXY=\"${HTTP_PROXY_URL}\"" >> /etc/environment
echo "FTP_PROXY=\"${HTTP_PROXY_URL}\"" >> /etc/environment
echo "NO_PROXY=\"${NO_PROXY_FULL}\"" >> /etc/environment
echo -e "${BLUE}INFO:${NC} Configuring package manager proxy..."
case "$PKG_MANAGER" in
dnf|yum)
if ! grep -q "proxy=" /etc/dnf/dnf.conf; then
echo "proxy=${HTTP_PROXY_URL}" >> /etc/$PKG_MANAGER/$PKG_MANAGER.dnf/dnf.conf
iffi
!;;
grepapt)
-qcat "^fastestmirror="> /etc/apt/apt.conf.d/80proxy <<EOF
Acquire::http::proxy "$PKG_MANAGER/{HTTP_PROXY_URL}";
Acquire::https::proxy "$PKG_MANAGER.conf;{HTTP_PROXY_URL}";
thenAcquire::ftp::proxy "${HTTP_PROXY_URL}";
EOF
;;
esac
echo -e "fastestmirror=1"${GREEN}SUCCESS:${NC} System-wide proxy configured."
}
configure_dns_and_hosts() {
log_step "3/X" "Configuring DNS and NetworkManager"
echo -e "${BLUE}INFO:${NC} Configuring /etc/hosts file..."
sed -i "/${DOMAIN_FQDN}/d" /etc/hosts
cat >> /etc/hosts <<EOF
# AD Domain Configuration
$PKG_MANAGER/{DC_DNS_IP} $PKG_MANAGER.conf;{DOMAIN_FQDN}
else${FILE_SERVER_IP} sed${FILE_SERVER_FQDN} ${FILE_SERVER_HOSTNAME}
EOF
echo -ie 's/^fastestmirror="${BLUE}INFO:${NC} Configuring DNS via NetworkManager..*/fastestmirror=1/."
local conn
conn=$(nmcli -t -f NAME,DEVICE connection show --active | grep -v "lo$" | head -n1 | cut -d':' /etc/-f1)
if [ -z "$PKG_MANAGER/conn" ]; then
echo -e "$PKG_MANAGER.conf;{RED}ERROR:${NC} Could not find an active network connection to configure." >&2
return 1
fi
echo -e "${BLUE}INFO:${NC} ✅Modifying connection: $PKG_MANAGER proxy and fastestmirror configured.{PURPLE}${conn}${NC}"
elifnmcli [[connection modify "$PKG_MANAGER"conn" ==ipv4.dns "apt"$DC_DNS_IP"
]];nmcli thenconnection catmodify >"$conn" /etc/apt/apt.conf.d/80scriptproxyipv4.ignore-auto-dns <<EOFyes
Acquire::http::Proxynmcli connection up "$conn"
echo -e "${HTTP_PROXY_URL}GREEN}SUCCESS:${NC} DNS configured to ${DC_DNS_IP} and /etc/hosts updated.";
Acquire::https::Proxy}
check_connectivity() {
log_step "${HTTP_PROXY_URL}";
Acquire::ftp::Proxy4/X" "${HTTP_PROXY_URL}";Checking EOFNetwork Connectivity"
local has_error=0
echo -e "${BLUE}INFO:${NC} ✅Pinging APTDomain proxyController configured.(${DC_DNS_IP})..."
if ! ping -c 3 "$DC_DNS_IP"; then
echo -e "${RED}ERROR:${NC} Domain Controller is not reachable." >&2; has_error=1
fi
echo -e "${BLUE}INFO:${NC} Checking DNS resolution for ${DOMAIN_FQDN}..."
if ! getent hosts "$DOMAIN_FQDN"; then
echo -e "${RED}ERROR:${NC} Could not resolve domain FQDN." >&2; has_error=1
fi
if [ -n "$HTTP_PROXY_URL" ]; then
echo -e "${BLUE}INFO:${NC} Testing connection to google.com via proxy..."
if ! curl -s --head --connect-timeout 5 http://www.google.com | head -n 1 | grep "200 OK" > /dev/null; then
echo -e "${YELLOW}WARNING:${NC} Could not connect to the internet via proxy. External repos may fail."
fi
fi
if [ $has_error -eq 0 ]; then
echo -e "${GREEN}SUCCESS:${NC} All connectivity checks passed."
else
echo -e "${RED}ERROR:${NC} One or more connectivity checks failed. Please review the logs." >&2; exit 1
fi
}
install_packages() {
log_step "3/16"5/X" "Installing RequiredCore & Utility 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 ncdu policycoreutils-python-utils"utils logrotate tree bash-completion bat jq fontconfig util-linux-user"
local pkgs_to_install
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
common_pkgs+=" bind-utils dnf-utils vim-enhanced"
echo -e "${BLUE}INFO:${NC} Ensuring core DNF plugins are installed..."
$PKG_MANAGER -y install dnf-plugins-core
echo -e "${BLUE}INFO:${NC} Enabling CRB/PowerTools repository..."
if [[ "$OS_VER" -ge 9 ]]; then
dnf config-manager --set-enabled crb -y
else
dnf config-manager --set-enabled powertools -y || dnf config-manager --set-enabled PowerTools -y
fi
echo -e "${BLUE}INFO:${NC} Installing EPEL repository..."
if ! $PKG_MANAGER -y install epel-release; then
echo -e "${RED}ERROR: Failed to install EPEL repository. Cannot continue.${NC}" >&2; exit 1;
fi
local dnf_base_pkgs="realmd sssd oddjob oddjob-mkhomedir adcli samba-common-tools authselectauthselect"
dnf-plugins-core"pkgs_to_install="${dnf_base_pkgs} local${common_pkgs}"
yum_base_pkgs=elif [[ "realmd$PKG_MANAGER" sssd== oddjob"apt" oddjob-mkhomedir]]; adclithen
samba-common-toolscommon_pkgs+=" authconfigdnsutils yum-utils"debian-goodies #vim"
For[[ CentOS"$OS_ID_LOWER" 7== "ubuntu" ]] && common_pkgs=${common_pkgs/bat/batcat}
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"
if [[ pkgs_to_install="$PKG_MANAGER"{apt_base_pkgs} == ${common_pkgs}"dnf" || "$PKG_MANAGER" == "yum" ]]; then
echo -e "${BLUE}INFO:${NC} EnsuringUpdating EPELpackage repositorylists isfor installed.APT..."
#apt-get 1. Enable CRB/PowerTools repo first, as EPEL often depends on it.
if [[ "$OS_ID_LOWER" =~ ^(almalinux|rhel|centos|rocky)$ ]]; then
if [[ "$OS_VER"update -ge 9 ]]; then
dnf config-manager --set-enabled crb || echo -e "${YELLOW}WARN: Failed to enable CRB repository.${NC}"
elif [[ "$OS_VER" -eq 8 ]]; then
dnf config-manager --set-enabled powertools || dnf config-manager --set-enabled PowerTools || echo -e "${YELLOW}WARN: Failed to enable PowerTools repo.${NC}"qq
fi
fi
# 2. Install EPEL Release package.
if ! $PKG_MANAGER -y list installed epel-release &>/dev/null; then
# For AlmaLinux 10, try direct URL first.
if [[ "$OS_ID_LOWER" == "almalinux" && "$OS_VER" -eq 10 ]]; then
echo -e "${BLUE}INFO:${NC} Attempting to install EPEL for AlmaLinux 10 directly from URL..."
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 -e "${YELLOW}WARN: Failed to install EPEL from URL. Some packages may not be available.${NC}"
else
echo -e "${BLUE}INFO:${NC} ✅ EPEL release installed for AlmaLinux 10 from URL."
fi
else # For other DNF/YUM-based systems
if ! $PKG_MANAGER -y install epel-release; then
echo -e "${YELLOW}WARN: Could not install 'epel-release' package. Some packages may be unavailable.${NC}"
else
echo -e "${BLUE}INFO:${NC} ✅ 'epel-release' package installed."
fi
fi
else
echo -e "${BLUE}INFO:${NC} EPEL repository is already installed."
fi
# --- End EPEL Setup ---
local pkgs_to_install
if [[ "$PKG_MANAGER" == "dnf" ]]; then pkgs_to_install="${dnf_base_pkgs} ${common_pkgs}";
else pkgs_to_install="${yum_base_pkgs} ${common_pkgs}"; fi # yum
echo -e "${BLUE}INFO:${NC} Installing main packages for $ID ($PKG_MANAGER).packages..."
if ! $PKG_MANAGER -y install ${pkgs_to_install}; then
echo -e "${RED}ERROR: FailedPackage installation failed. This is often due to installnetwork, packages.proxy, Checkor errorsrepository above.issues.${NC}"; >&2; exit 1;
fi
elifif [[command "$PKG_MANAGER"-v ==batcat "apt"&>/dev/null ]];&& ! command -v bat &>/dev/null; then
exportln DEBIAN_FRONTEND=noninteractive-sf /usr/bin/batcat /usr/local/bin/bat
fi
echo -e "${BLUE}INFO:GREEN}SUCCESS:${NC} UpdatingCore packagepackages lists for APT...installed."
if}
!configure_time() apt-get{
update -qq; then echo -elog_step "${RED}ERROR:6/X" apt-get"Configuring updateSystem failed.${NC}";Time exit(NTP 1;& fi
local pkgs_to_install="${apt_base_pkgs} ${common_pkgs}Timezone)"
echo -e "${BLUE}INFO:${NC} InstallingSetting maintimezone packagesto ${TIMEZONE}..."
timedatectl set-timezone "$TIMEZONE"
echo -e "${BLUE}INFO:${NC} Configuring chrony to use NTP server ${NTP_SERVER}..."
sed -i '/^pool/d' /etc/chrony.conf
sed -i '/^server/d' /etc/chrony.conf
echo "server ${NTP_SERVER} iburst" >> /etc/chrony.conf
echo -e "${BLUE}INFO:${NC} Restarting and enabling chronyd service..."
systemctl restart chronyd
systemctl enable chronyd
timedatectl set-ntp true
echo -e "${GREEN}SUCCESS:${NC} System time configured."
}
#
#SECTION 2: DOMAIN & AUTHENTICATION FUNCTIONS
#
join_ad_domain() {
log_step "7/X" "Joining Active Directory Domain"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Domain Join...$ID{NC}"; exit 0;' INT
if realm list | grep -q "$DOMAIN_FQDN"; then
read -rp "$(echo -e "${YELLOW}WARNING:${NC} Server is already joined to ${DOMAIN_FQDN}. Action? (APT).[S]kip, [R]e-join): ${NC}")" choice < /dev/tty
case "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" in
r|re-join)
echo -e "${BLUE}INFO:${NC} Leaving the domain first..."
if ! apt-getrealm -y install ${pkgs_to_install};leave; then
echo -e "${RED}ERROR:${NC} Failed to installleave APTthe packages.domain. CheckPlease errorscheck above.logs. Aborting re-join." >&2
exit 1
fi
echo -e "${GREEN}SUCCESS:${NC} Left the domain."
;;
*)
echo -e "${BLUE}INFO:${NC} Skipping domain join step."
exit 1;0
fi;;
esac
fi
echo -e "${BLUE}INFO:${NC} ✅Attempting Requiredto packagesjoin installed."
}
configure_dns_and_hosts() {
log_step "4/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
searchdomain ${DOMAIN_FQDN,,}DOMAIN_FQDN} nameserveras user ${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//AD_USER_FOR_JOIN}./\\.}(\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/16" "Configuring Time (NTP: ${NTP_SERVER}, Zone: ${TIMEZONE})"
if ! command -v chronyc &> /dev/null; then echo -en "${RED}ERROR:AD_PASSWORD" chrony| notrealm found.join --user="${NC}"; return 1; fi
if ! timedatectl set-timezoneAD_USER_FOR_JOIN" "$TIMEZONE"; then echo -e "${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"DOMAIN_FQDN"; then
echo -e "${RED}ERROR:${NC} Failed to startjoin the Active Directory domain." >&2
echo -e "$chrony_service.{YELLOW}Check username, password, and connectivity to the DC.${NC}" >&2
exit 1
fi
echo -e "${GREEN}SUCCESS:${NC} Successfully joined the domain."
)
}
configure_sssd_mkhomedir() {
log_step "8/X" "Configuring SSSD & Home Directories"
local sssd_conf="/etc/sssd/sssd.conf"
if [ ! -f "$sssd_conf" ]; then
echo -e "${RED}ERROR:${NC} SSSD configuration file not found at ${sssd_conf}" >&2; return 1;
fi
echo -e "${BLUE}INFO:${NC} Modifying $chrony_service started. Waiting for sync.{sssd_conf}..."
sleep 3; chronyc sourcessed -vi || echo -e'/^use_fully_qualified_names/d' "${YELLOW}WARN:sssd_conf"
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/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 -qsed -i "domain-name: ${DOMAIN_FQDN}"; then
echo -e "${BLUE}INFO:${NC} ✅ Already joined to domain ${DOMAIN_FQDN}." ; return 0; fi
realm discover "/\[domain\/${DOMAIN_FQDN,,}"\]/a || echo -e "${YELLOW}WARN: Domain discovery failed.${NC}"
ping -c 2 "${DOMAIN_FQDN,,}" || echo -e "${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/16" "Configuring SSSD and Automatic Home Directory Creation"
local sssd_conf="/etc/sssd/sssd.conf"
if [[ ! -f "$sssd_conf" ]]; then
echo -e "${YELLOW}WARN: ${sssd_conf} not found. Domain join might have failed. Skipping SSSD config.${NC}"
return 1
fi
echo -e "${BLUE}INFO:${NC} Optimizing SSSD configuration process..."
# The new section to be added or to replace the old one
local new_domain_section
new_domain_section=$(printf '%s\n' \
"[domain/${DOMAIN_FQDN,,}]" \
"id_provider = ad" \
"access_provider = ad" \
"ad_domain = ${DOMAIN_FQDN,,}" \
"krb5_realm = ${DOMAIN_FQDN^^}" \
"realmd_tags = manages-system joined-with-adcli" \
"cache_credentials = True" \
"krb5_store_password_if_offline = True" \
"ldap_id_mapping = True" \
"use_fully_qualified_names = False" \"$sssd_conf"
sed -i '/^fallback_homedir/d' "$sssd_conf"
sed -i "/\[domain\/${DOMAIN_FQDN,,}\]/a fallback_homedir = /home/%u" \
"default_shell = /bin/bash" \
"override_homedir = /home/%u" \
"create_homedir = true" \
"ad_gpo_access_control = permissive"
)
cp "$sssd_conf" "${sssd_conf}.bak-$(date +%s)"
local temp_conf; temp_conf=$(mktemp)
# Remove the old domain section entirely
awk -v domain_name="${DOMAIN_FQDN,,}" '
BEGIN { in_section_to_remove = 0 }
$0 ~ "^\\[domain\\/" domain_name "\\]" { in_section_to_remove = 1; next }
in_section_to_remove && /^\s*\[/ { in_section_to_remove = 0 }
!in_section_to_remove { print }
' "$sssd_conf" > "$temp_conf"
# Append the new, complete domain section
echo -e "\n${new_domain_section}" >> "$temp_conf"
if [[ -s "$temp_conf" ]]; then
mv "$temp_conf" "$sssd_conf"
chmod 0600 "$sssd_conf"
echo -e "${BLUE}INFO:${NC} sssd.conf updated. Restarting service..."
systemctl restart sssd || echo -e "${YELLOW}WARN: Failed to restart SSSD after config change.${NC}"
else
echo -e "${RED}ERROR: Generated temporary sssd.conf was empty. No changes made.${NC}"
rm -f "$temp_conf"; return 1; fi
echo -e "${BLUE}INFO:${NC} Enabling automatic home directory creation..."
if [[ "$PKG_MANAGER" == "dnf" ]]; then
if command -v authselect &>/dev/null;enable-feature thenwith-mkhomedir
ifsystemctl authselectrestart checksssd &&oddjobd
authselectsystemctl currentenable | grep -q "with-mkhomedir"; thenoddjobd
echo -e "${BLUE}INFO:GREEN}SUCCESS:${NC} authselect already has mkhomedir enabled."
else
authselect select sssd with-mkhomedir --force || echo -e "${YELLOW}WARN: authselect command failed.${NC}"
echo -e "${BLUE}INFO:${NC} ✅ authselect configured for SSSD with mkhomedir."
fi
else echo -e "${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 mkhomedirhome ondirectory CentOScreation 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 "${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 "${YELLOW}WARN: pam-auth-update command not found.${NC}"; fi
fi
echo -e "${BLUE}INFO:${NC} ✅ SSSD configuration and mkhomedir setup attempted.configured."
}
configure_sudoers() {
log_step "8/16"9/X" "Configuring Sudoers for AD Group: ${AD_SUDO_GROUP_RAW_NAME}"
if [[ -z "$AD_SUDO_GROUP_RAW_NAME" ]]; then
echo -e "${YELLOW}WARN: AD_SUDO_GROUP_RAW_NAME empty. Skipping sudoers.${NC}"; return; fiGroup"
local sudoers_file="/etc/sudoers.d/90-domain-${DOMAIN_NETBIOS,,}-admins"escaped_group_name
local group_name_escaped=escaped_group_name=$(echo "$AD_SUDO_GROUP_RAW_NAME" | sed 's/ /\\ /g')
local sudo_entry_line=sudoer_file="%${DOMAIN_NETBIOS}\\\\${group_name_escaped} ALL=(ALL:ALL) ALL"/etc/sudoers.d/90-ad-admins"
echo -e "${BLUE}INFO:${NC} CreatingGranting sudoerssudo entry:rights to AD group '${sudo_entry_line}AD_SUDO_GROUP_RAW_NAME}'..."
echo "\"%${sudo_entry_line}escaped_group_name}\" ALL=(ALL) ALL" > "${sudoers_file}" &&sudoer_file"
chmod 0440440 "$sudoer_file"
echo -e "${sudoers_file}GREEN}SUCCESS:${NC} Sudoers configured. Rule added to ${sudoer_file}."
if}
visudo#
-cf#SECTION 3: SECURITY HARDENING FUNCTIONS
#
optimize_sshd() {
log_step "${sudoers_file}10/X" ";Optimizing thenSSH Daemon for Faster Logins"
local sshd_config="/etc/ssh/sshd_config"
echo -e "${BLUE}INFO:${NC} ✅Setting Sudoers'UseDNS fileno' in ${sudoers_file}sshd_config}..."
validated.if grep -q "^#\?UseDNS" "$sshd_config"; then
sed -i 's/^#\?UseDNS.*/UseDNS no/' "$sshd_config"
else
echo "UseDNS no" >> "$sshd_config"
fi
systemctl restart sshd
echo -e "${RED}ERROR:GREEN}SUCCESS:${NC} SudoersSSHD fileoptimized syntaxfor error!faster logins."
}
install_fail2ban() {
log_step "11/X" "Installing Fail2ban (Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Fail2ban...${NC}"; rmexit 0;' INT
if [ -f "${sudoers_file}"/etc/fail2ban/jail.local ]; return 1; fi
}
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/16" "Installing Development Stack (Optional)"then
read -rp "$(echo -e "${CYAN}InstallYELLOW}WARNING:${NC} DevelopmentFail2ban Stackconfiguration already exists. Action? (Webservers, Databases, etc)?[S]kip, [y/N]O]verwrite): ${NC}")" install_choicechoice install_choice=< /dev/tty
if [[ "$(echo "$install_choice"choice" | tr '[:upper:]' '[:lower:]')
if [[ "$install_choice" != "y"o" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping DevelopmentFail2ban 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 PHP ${php_choice}..."
local php_modules="php php-cli php-fpm php-mysqlnd php-gd php-xml php-mbstring php-intl php-zip php-curl php-opcache php-pgsql"
local php_install_success=false
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
$PKG_MANAGER -y install https://rpms.remirepo.net/enterprise/remi-release-$(rpm -E %rhel).rpm
if [[ "$PKG_MANAGER" == "dnf" ]]; then dnf module reset php -y && dnf module enable php:remi-${php_choice} -y;
else yum-config-manager --enable remi-php${php_choice//.}; fi
if $PKG_MANAGER -y install ${php_modules}; then
php_install_success=true
else
echo -e "${YELLOW}WARN: Failed to install PHP ${php_choice} from Remi repository. Trying system default.${NC}"
if [[ "$PKG_MANAGER" == "dnf" ]]; then dnf module reset php -y; fi
if $PKG_MANAGER -y install php php-cli php-fpm php-mysqlnd; then php_install_success=true;
else echo -e "${RED}ERROR: Fallback installation of system PHP also failed.${NC}setup."; fiexit fi
elif [[ "$PKG_MANAGER" == "apt" ]]; then
add-apt-repository ppa:ondrej/php -y && apt-get update -qq
local apt_php_modules="php${php_choice} php${php_choice}-cli php${php_choice}-fpm php${php_choice}-mysql php${php_choice}-gd 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 "${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. Skipping Composer.${NC}";0;
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..."
if curl -fsSL https://rpm.nodesource.com/setup_${node_choice}.x | bash - || curl -fsSL https://deb.nodesource.com/setup_${node_choice}.x | bash - ; 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.${NC}"; fi
else echo -e "${RED}ERROR: Failed to setup NodeSource repository.${NC}"; fi
else echo -e "${YELLOW}WARN: Invalid Node.js version. Skipping.${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
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
dnf -y install 'dnf-command(copr)' && dnf copr enable @caddy/caddy -y
elif [[ "$PKG_MANAGER" == "apt" ]]; then
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
fi
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
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..."
curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash -s -- --mariadb-server-version="mariadb-10.11"
if $PKG_MANAGER -y install MariaDB-server MariaDB-client && systemctl enable --now mariadb; then
echo -e "${BLUE}INFO:${NC} ✅ MariaDB 10.11 installed. Configuring..."
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED VIA unix_socket;" || echo -e "${YELLOW}WARN: Could not set passwordless root login for MariaDB.${NC}"
echo -e "${YELLOW}IMPORTANT: Run 'sudo mariadb-secure-installation' to secure your database.${NC}"
else echo -e "${RED}ERROR: MariaDB installation failed.${NC}"; fi
elif [[ "$(echo "$mariadb_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]]; then echo -e "${YELLOW}WARN: MySQL client detected. Skipping MariaDB install.${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}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}..."
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
$PKG_MANAGER -y install "https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %rhel)-x86_64/pgdg-redhat-repo-latest.noarch.rpm"
$PKG_MANAGER -y install postgresql${pg_ver_choice}-server
/usr/pgsql-${pg_ver_choice}/bin/postgresql-${pg_ver_choice}-setup initdb
systemctl enable --now postgresql-${pg_ver_choice}
elif [[ "$PKG_MANAGER" == "apt" ]]; then
echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list
curl -s https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/postgresql.gpg
apt-get update -qq && apt-get -y install postgresql-${pg_ver_choice}
fi
echo -e "${BLUE}INFO:${NC} ✅ PostgreSQL ${pg_ver_choice} installed."
else echo -e "${YELLOW}WARN: Invalid PostgreSQL version. Skipping.${NC}"; fi
elif [[ "$(echo "$pg_choice" | tr '[:upper:]' '[:lower:]')" == "y" ]]; then echo -e "${YELLOW}WARN: PostgreSQL client detected. Skipping install.${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."; set -e; return; fi
echo -e "${BLUE}INFO:${NC} Installing Cockpit..."
local pkgs="cockpit cockpit-podman pcp python3-pcp"; if [[ "$PKG_MANAGER" == "apt" ]]; then pkgs="cockpit cockpit-podman"; fi
if ! $PKG_MANAGER -y install $pkgs; then echo -e "${RED}ERROR: Failed to install Cockpit packages.${NC}"; set -e; return; 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
mkdir -p /etc/systemd/system/cockpit.service.d
echo -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
systemctl daemon-reload
echo -e "${BLUE}INFO:${NC} ✅ Cockpit proxy configured."
fi
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)."
elif 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: Firewall not active/managed. Manual config for port 9090 needed.${NC}"; fi
local cockpit_service="cockpit.socket"; [[ "$PKG_MANAGER" == "apt" ]] && cockpit_service="cockpit"
if ! systemctl enable --now "$cockpit_service"; then echo -e "${RED}ERROR: Failed to start/enable ${cockpit_service}.${NC}"; set -e; return; fi
echo -e "${BLUE}INFO:${NC} ✅ Cockpit installation complete."
echo -e "${CYAN}Access Cockpit at:${NC}"
hostname -I 2>/dev/null | xargs -n1 | grep -v '^127' | while read -r ip; do echo -e " ${GREEN}https://${ip}:9090${NC}"; done
set -e
}
install_container_runtime() {
log_step "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:]')
[[ "$install_choice" != "y" ]] && echo -e "${BLUE}INFO:${NC} Skipping container runtime." && return
local runtime_selection
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; fi
if [[ "$runtime_selection" == "podman" ]]; then
echo -e "${BLUE}INFO:${NC} Installing Podman..."
if $PKG_MANAGER -y install podman podman-docker; then
if [[ -n "$HTTP_PROXY_URL" ]]; then
mkdir -p /etc/containers/containers.conf.d; cat > /etc/containers/containers.conf.d/01-proxy.conf <<EOF
[engine]
env = [ "HTTP_PROXY=${HTTP_PROXY_URL}", "HTTPS_PROXY=${HTTP_PROXY_URL}", "NO_PROXY=${NO_PROXY_FULL}" ]
EOF
fi
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 CE..."
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
if [[ "$OS_ID_LOWER" == "almalinux" && "$OS_VER" -eq 10 ]]; then
echo -e "${YELLOW}WARN: Docker CE on AlmaLinux $OS_VER might conflict or need '--allowerasing'.${NC}"
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
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 -e "${RED}ERR: Docker CE install failed. Try with --allowerasing.${NC}"; return 1; fi
elif [[ "$PKG_MANAGER" == "apt" ]]; then
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 -e "${RED}ERR: Docker CE install failed.${NC}"; return 1; fi
fi
# Common Docker post-install steps
if [[ -n "$HTTP_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=${HTTP_PROXY_URL}" "HTTPS_PROXY=${HTTP_PROXY_URL}" "NO_PROXY=${NO_PROXY_FULL}"
EOF
mkdir -p /etc/docker; cat >/etc/docker/daemon.json <<EOF
{ "proxies": { "http-proxy": "${HTTP_PROXY_URL}", "https-proxy": "${HTTP_PROXY_URL}", "no-proxy": "${NO_PROXY_FULL}" } }
EOF
fi
systemctl daemon-reload && systemctl enable --now docker || { echo -e "${RED}ERR: Docker service failed.${NC}"; 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 -e "${BLUE}INFO:${NC} Added $SUDO_USER to docker group."; fi
echo -e "${BLUE}INFO:${NC} ✅ Docker CE installed."
fi
}
install_fail2ban() {
set +e
log_step "12/16" "Installing Fail2ban (Optional)"
read -rp "$(echo -e "${CYAN}Install and configure Fail2ban for SSH?SSH protection? [y/N]: ${NC}")" install_choicechoice install_choice=< /dev/tty
if [[ "$(echo "$install_choice"choice" | tr '[:upper:]' '[:lower:]')
if [[ "$install_choice" != "y" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping Fail2ban installation."; setexit -e;0;
return;fi
fi
echo -e "${BLUE}INFO:${NC} Installing Fail2ban..."
if ! $PKG_MANAGER -y install fail2ban; then echo -e "${RED}ERROR: Fail2ban install failed.${NC}"; set -e; return; fifail2ban
echo -e "${BLUE}INFO:${NC} ConfiguringCreating SSHlocal jail configuration for Fail2ban.SSHD..."
cat > /etc/fail2ban/jail.local <<EOF
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
EOF
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
sed -i 's|/var/log/auth.log|/var/log/secure|' /etc/fail2ban/jail.local
fi
if ! systemctl enable --now fail2ban; thenfail2ban
echo -e "${RED}ERROR:GREEN}SUCCESS:${NC} FailedFail2ban toinstalled start/enableand Fail2ban.enabled for SSHD."
)
}
#
#SECTION 4: SHELL & USER EXPERIENCE FUNCTIONS
#
install_nano_syntax() {
(
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping extra Nano syntax...${NC}"; setexit -e;0;' return; fiINT
echo -e "${BLUE}INFO:${NC} ✅Installing Fail2banenhanced installedsyntax andhighlighting SSHfor jail configured.Nano..."
sleeplocal 2nano_syntax_dir="/tmp/nanorc"
fail2ban-clientif statusgit sshdclone ||https://github.com/scopatz/nanorc.git "$nano_syntax_dir"; then
sudo cp -r ${nano_syntax_dir}/*.nanorc /usr/share/nano/
rm -rf "$nano_syntax_dir"
echo -e "${YELLOW}WARN: Could not get fail2ban status.GREEN}SUCCESS:${NC} Enhanced Nano syntax installed."
setelse
echo -e "${RED}ERROR:${NC} Failed to download enhanced Nano syntax files."
fi
)
}
setup_tmux(configure_nano() {
log_step "12/X" "Configuring Nano Editor"
echo -e "${BLUE}INFO:${NC} Applying system-wide Nano configuration..."
cat > /etc/nanorc <<EOF
## Nano Editor Default Configuration
set +linenumbers
set softwrap
set tabsize 4
set casesensitive
set constantshow # Always show line/col info
## Include all standard syntax definitions
include "/usr/share/nano/*.nanorc"
EOF
install_nano_syntax
echo -e "${GREEN}SUCCESS:${NC} Nano configured with defaults and syntax highlighting."
}
configure_vim() {
log_step "12.1/X" "Configuring Vim/Vi"
echo -e "${BLUE}INFO:${NC} Applying system-wide Vim configuration..."
cat > /etc/vimrc <<EOF
" System-wide .vimrc file
syntax on
set background=dark
set number
set ruler
set showcmd
set incsearch
set wildmenu
EOF
echo -e "${GREEN}SUCCESS:${NC} Vim configured with syntax highlighting."
}
enhance_bash() {
log_step "13/16"X" "SettingEnhancing upBash Automated Tmux EnvironmentExperience (Optional)Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Bash enhancements...${NC}"; exit 0;' INT
read -rp "$(echo -e "${CYAN}SetupEnhance persistentthe TmuxBash environment?shell with a better prompt and aliases? [y/N]: ${NC}")" tmux_choicechoice < /dev/tty
if [[ "$(echo "$tmux_choice"choice" | tr '[:upper:]' '[:lower:]')" != "y" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping Bash enhancements."; exit 0;
fi
echo -e "${BLUE}INFO:${NC} Creating /etc/profile.d/enhanced_bash.sh..."
cat > /etc/profile.d/enhanced_bash.sh <<'EOF'
# Custom Bash prompt
PS1='\[\e[32m\]\u@\h \[\e[33m\]\w\[\e[0m\]\n\$ '
# Useful Aliases
alias ls='ls --color=auto'
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias grep='grep --color=auto'
alias ..='cd ..'
EOF
echo -e "${GREEN}SUCCESS:${NC} Bash enhancements will be applied on next login."
)
}
setup_tmux() {
log_step "14/X" "Setting up Automated Tmux Environment (Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Tmux setup...${NC}"; exit 0;' INT
read -rp "$(echo -e "${CYAN}Set up a default Tmux configuration? [y/N]: ${NC}")" choice < /dev/tty
if [[ "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" != "y" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping Tmux setup."; setexit -e; return;0;
fi
echo -e "${BLUE}INFO:${NC} InstallingCreating Tmux Plugin Manager (TPM)..."
git clone https://github.com/tmux-plugins/tpmsystem-wide /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.tmux.conf..."
cat > /etc/tmux.conf <<'EOF'
# ListSet ofprefix pluginsto Ctrl-a
set -g @pluginprefix 'tmux-plugins/tpm'C-a
unbind C-b
bind C-a send-prefix
# Enable mouse mode
set -g @pluginmouse 'tmux-plugins/tmux-sensible'on
# Improve status bar
set -g @pluginstatus-bg 'tmux-plugins/tmux-resurrect'black
set -g @pluginstatus-fg 'tmux-plugins/tmux-continuum'
# Restore session on tmux startwhite
set -g @continuum-restorestatus-left 'on'#[fg=green]#H'
set -g status-right '#[fg=yellow]%Y-%m-%d %H:%M'
EOF
echo -e "${GREEN}SUCCESS:${NC} Default Tmux configuration created."
)
}
setup_motd() {
log_step "15/X" "Setting Up Dynamic MOTD (Optional, Ctrl+C to skip)"
( # InitializeStart TMUXsubshell pluginfor managercancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping MOTD setup...${NC}"; exit 0;' INT
if [ -f /etc/profile.d/99-custom-motd.sh ]; then
read -rp "$(echo -e "${YELLOW}WARNING:${NC} Custom MOTD script already exists. Action? (keep[S]kip, this[O]verwrite): line${NC}")" atchoice the< very/dev/tty
bottomif of[[ tmux.conf)"$(echo run"$choice" | tr '/etc/tmux/plugins/tpm/tpm'[:upper:]' EOF'[:lower:]')" != "o" ]]; then
echo -e "${BLUE}INFO:${NC} CreatingSkipping tmuxMOTD auto-startsetup."; script...exit 0;
fi
else
read -rp "$(echo -e "${CYAN}Setup a dynamic MOTD (Message of the Day)? [y/N]: ${NC}")" catchoice >< /etc/profile.d/98-tmux-autostart.sh <<'EOF'
#!/bin/bashdev/tty
if [[ "$-(echo ="$choice" | tr '[:upper:]' '[:lower:]')" != *i*"y" ]] && [[ -z "$TMUX" ]] && command -v tmux &>/dev/null;; then
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 DynamicSkipping MOTD (Messagesetup."; ofexit the0;
Day)"fi
fi
echo -e "${BLUE}INFO:${NC} Creating a dynamic message of the day..."
# Disable default MOTD generation if they exist
chmod -x /etc/update-motd.d/* &>/dev/null || true
# Disable printing MOTD via pam_motd.so which can interfere
sed -i '/^session\s\+optional\s\+pam_motd.so/s/^/#/' /etc/pam.d/sshd 2>/dev/null || true
cat > /etc/profile.d/99-custom-motd.sh <<'EOF'
#!/bin/bash
# OnlyThis runscript runs for interactive shells onto login,display nota insidedynamic tmuxMOTD.
if [[ $- !== *i* ]] ||&& [[ -n "$TMUX"{SHLVL:-1}" -le 1 ]]; then
return
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 -e ""\nWelcome #to Display Hostname and OS
HOSTNAME=${GREEN}$(hostname -f)${NC}"
echo -e "System time is: ${CYAN}$(date --iso-8601=seconds)${NC}\n"
# Display OS Info
if [ -f /etc/os-release ]; then
OS_INFO=$(grep PRETTY_NAME /etc/os-release | cut -d'"' -f2)
echo -e "Hostname: ${GREEN}$HOSTNAME$PURPLE}System Information${NC}"
echo -e " OS: ${YELLOW}$OS_INFO${OS_INFO}${NC}"
echo -e "" Uptime: $(uptime -p | sed 's/up //')\n"
fi
# Display Network Information
echo -e "${BLUE}PURPLE}Network Information:$Information${NC}"
ip -4 addr | grep -oP '(?<=inet\s)\d+(\.\d+){3}/\d+\s.*\s\K\w+$' | while read -r dev;
do
ip_addr=$(ip -4 addr show dev "$dev" | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
if [[ -n "$ip_addr" ]]; then echo -e " - Interface ${GREEN}$dev${NC}: ${CYAN}$ip_addr${NC}"; fi
done || echo -e " ${RED}No active IPv4 interfaces found.${NC}"
echo
""
# Display System Usage
echo -e "${BLUE}PURPLE}System Usage:$Usage${NC}"
df -h / | awk '$NR==2 {print " Disk (/): " $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 }2}' | sed 's/ //g')"\n"
# Display Installed Software Versions
echo -e "${PURPLE}Installed Software${NC}"
declare -A progs=(
["Docker"]="docker --version" ["Podman"]="podman --version"
["Nginx"]="nginx -v" ["Apache"]="httpd -v" ["PHP"]="php -v"
["Node"]="node -v" ["NPM"]="npm -v" ["Go"]="go version"
["Java"]="java -version" ["MySQL"]="mysql --version" ["PostgreSQL"]="psql --version"
)
output=""
for name in "${!progs[@]}"; do
if command -v ${progs[$name]%% *} &>/dev/null; then
version=$(${progs[$name]} 2>&1 | grep -oP '(\d+\.){1,}\d+' | head -n1)
[[ -n "$version" ]] && output+=" ${GREEN}${name}${NC}:${CYAN}${version}${NC}"
fi
done
echo -e "${output:- None detected}\n"
fi
EOF
chmod +x /etc/profile.d/99-custom-motd.sh
echo -e "${BLUE}INFO:GREEN}SUCCESS:${NC} ✅ Dynamic MOTD script created."
It)
will}
beinstall_nerd_fonts() displayed{
onlog_step next"16.1/X" SSH"Installing login.Nerd Fonts (Sub-step)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Nerd Fonts...${NC}"; exit 124;' INT
echo -e "${BLUE}INFO:${NC} Checking for Nerd Fonts..."
local font_dir="/usr/local/share/fonts/FiraCodeNerdFont"
if [ -d "$font_dir" ]; then
echo -e "${BLUE}INFO:${NC} Nerd Font directory already exists. Skipping download."
exit 0
fi
read -rp "$(echo -e "${CYAN}Install FiraCode Nerd Font for Zsh themes? [y/N]: ${NC}")" choice < /dev/tty
if [[ "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" != "y" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping Nerd Font installation."; exit 0;
fi
mkdir -p "$font_dir"
local tmp_zip="/tmp/FiraCode.zip"
local retries=3; local count=0; local success=false
until [ $count -ge $retries ]
do
echo -e "${BLUE}INFO:${NC} Attempting to download FiraCode Nerd Font (attempt $((count+1))/${retries})..."
ping -c 1 google.com &>/dev/null || true
sleep 1
curl --connect-timeout 20 -L "https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/FiraCode.zip" -o "$tmp_zip"
if [ $? -eq 0 ]; then success=true; break; fi
count=$((count+1))
echo -e "${YELLOW}WARNING:${NC} Download failed. Retrying in 5 seconds..."
sleep 5
done
if ! $success; then
echo -e "${RED}ERROR:${NC} Failed to download Nerd Fonts after $retries attempts." >&2; rm -f "$tmp_zip"; exit 1;
fi
unzip -o "$tmp_zip" -d "$font_dir"; rm -f "$tmp_zip"
echo -e "${BLUE}INFO:${NC} Rebuilding font cache..."; fc-cache -fv &>/dev/null
echo -e "${GREEN}SUCCESS:${NC} Nerd Fonts installed."
)
return $?
}
configure_starship() {
local user=$1
local home_dir
home_dir=$(eval echo ~$user)
local config_dir="${home_dir}/.config"
local starship_config="${config_dir}/starship.toml"
echo -e "${BLUE}INFO:${NC} Creating Starship 'Powerline' config for ${user}..."
sudo -u "$user" mkdir -p "$config_dir"
sudo -u "$user" tee "$starship_config" > /dev/null <<'EOF'
# Starship "Powerline" configuration
# Shows: [USER@HOST] [DATE TIME] [DIRECTORY] [GIT] [CMD_DURATION]
# >>>
# A minimal left prompt
format = """$username$hostname$time$directory$git_branch$cmd_duration$character"""
# Move the directory to the second line
# format = """$username$hostname$time$directory$git_branch$cmd_duration$fill$character"""
[username]
style_user = "yellow bold"
style_root = "red bold"
format = "[$user]($style_user)@"
show_always = true
[hostname]
style = "green bold"
format = "[$hostname]($style) "
ssh_only = false
disabled = false
[time]
disabled = false
format = '[\[$time\]]($style) '
style = "blue bold"
time_format = "%Y-%m-%d %H:%M:%S"
[directory]
style = "cyan bold"
format = "[$path]($style) "
truncation_length = 4
[git_branch]
style = "bold purple"
format = "[$branch]($style) "
[cmd_duration]
min_time = 500
style = "bold italic yellow"
format = "[$duration]($style) "
[character]
success_symbol = "[>](bold green)"
error_symbol = "[x](bold red)"
EOF
}
install_zsh_omz() {
log_step "16/X" "Installing Zsh & Oh My Zsh (Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Zsh setup...${NC}"; exit 124;' INT
local choice
if command -v zsh &>/dev/null; then
read -rp "$(echo -e "${CYAN}Zsh is already installed. Action? ([S]kip, [R]econfigure): ${NC}")" choice < /dev/tty
if [[ "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" == "s" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping Zsh setup."; exit 0;
fi
else
read -rp "$(echo -e "${CYAN}Install Zsh and Oh My Zsh? [y/N]: ${NC}")" choice < /dev/tty
if [[ "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" != "y" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping Zsh installation."; exit 0;
fi
fi
$PKG_MANAGER -y install zsh git
install_nerd_fonts
if [ $? -ne 0 ]; then
echo -e "${YELLOW}WARNING:${NC} Nerd font installation failed or was skipped. Zsh themes may not render correctly."
fi
local users_to_configure=()
users_to_configure+=("root")
if [[ -n "${SUDO_USER:-}" ]] && [[ "$SUDO_USER" != "root" ]]; then
users_to_configure+=("$SUDO_USER")
fi
local prompt_choice
read -rp "$(echo -e "${CYAN}Which Zsh prompt? ([1] Oh My Zsh (rkj-repos), [2] Starship, [3] Powerlevel10k): ${NC}")" prompt_choice < /dev/tty
for user in "${users_to_configure[@]}"; do
echo -e "${BLUE}INFO:${NC} Configuring Zsh for user ${PURPLE}${user}${NC}..."
local home_dir; home_dir=$(eval echo ~$user)
local zsh_dir="${home_dir}/.oh-my-zsh"
if [ ! -d "$zsh_dir" ]; then
local installer_sh="/tmp/omz_install.sh"
local retries=3; local count=0; local success=false
echo -e "${BLUE}INFO:${NC} Downloading Oh My Zsh installer..."
until [ $count -ge $retries ]; do
curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -o "$installer_sh"
if [ $? -eq 0 ]; then success=true; break; fi
count=$((count+1)); echo -e "${YELLOW}WARNING:${NC} Download failed. Retrying..."; sleep 3
done
if $success; then
echo -e "${BLUE}INFO:${NC} Running Oh My Zsh installer for ${user}..."
sudo -u "$user" sh "$installer_sh" --unattended
rm "$installer_sh"
else
echo -e "${RED}ERROR:${NC} Failed to download Oh My Zsh installer for ${user}." >&2; continue
fi
fi
local custom_plugins_dir="${zsh_dir}/custom/plugins"
if [ ! -d "${custom_plugins_dir}/zsh-autosuggestions" ]; then
sudo -u "$user" git clone https://github.com/zsh-users/zsh-autosuggestions "$custom_plugins_dir/zsh-autosuggestions"
fi
if [ ! -d "${custom_plugins_dir}/zsh-syntax-highlighting" ]; then
sudo -u "$user" git clone https://github.com/zsh-users/zsh-syntax-highlighting.git "$custom_plugins_dir/zsh-syntax-highlighting"
fi
local zshrc_file="${home_dir}/.zshrc"
# FIX: Robustly set plugins
sed -i 's/^plugins=(.*)$/plugins=(git docker npm nvm zsh-autosuggestions zsh-syntax-highlighting)/' "$zshrc_file"
# FIX: Clean up old theme settings before applying a new one
sed -i '/^# Init Starship Prompt/d' "$zshrc_file"
sed -i '/eval "$(starship init zsh)"/d' "$zshrc_file"
case "$prompt_choice" in
2) # Starship
if ! command -v starship &>/dev/null; then
local installer_sh="/tmp/starship_install.sh"
echo -e "${BLUE}INFO:${NC} Downloading Starship installer..."
if curl -sS https://starship.rs/install.sh -o "$installer_sh"; then
sh "$installer_sh" -y
rm "$installer_sh"
else
echo -e "${RED}ERROR:${NC} Failed to download starship installer." >&2
fi
fi
echo -e '\n# Init Starship Prompt\neval "$(starship init zsh)"' >> "$zshrc_file"
configure_starship "$user"
;;
3) # Powerlevel10k
local p10k_dir="${zsh_dir}/custom/themes/powerlevel10k"
if [ ! -d "$p10k_dir" ]; then
echo -e "${BLUE}INFO:${NC} Cloning Powerlevel10k theme..."
sudo -u "$user" git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "$p10k_dir"
fi
echo -e "${BLUE}INFO:${NC} Setting Powerlevel10k theme in .zshrc..."
sed -i 's|^ZSH_THEME=.*|ZSH_THEME="powerlevel10k/powerlevel10k"|' "$zshrc_file"
if ! grep -q 'POWERLEVEL9K_DISABLE_CONFIGURATION_WIZARD=true' "$zshrc_file"; then
echo -e '\n# To customize prompt, run `p10k configure` or edit ~/.p10k.zsh.\n[[ ! -f ~/.p10k.zsh ]] && p10k configure' >> "$zshrc_file"
fi
;;
*) # Default to rkj-repos
echo -e "${BLUE}INFO:${NC} Setting ZSH_THEME to rkj-repos..."
sed -i 's|^ZSH_THEME=.*|ZSH_THEME="rkj-repos"|' "$zshrc_file"
;;
esac
if ! grep -q 'setopt EXTENDED_HISTORY' "$zshrc_file"; then
echo -e '\n# Custom settings by setup script\nsetopt EXTENDED_HISTORY\nHIST_STAMPS="yyyy-mm-dd"\n' >> "$zshrc_file"
fi
if ! grep -q "alias ls='ls --color=auto'" "$zshrc_file"; then
echo -e '\n# Color Aliases\nalias ls="ls --color=auto"\nalias grep="grep --color=auto"' >> "$zshrc_file"
fi
local current_shell; current_shell=$(getent passwd "$user" | cut -d: -f7)
if [[ "$current_shell" != "$(which zsh)" ]]; then
echo -e "${BLUE}INFO:${NC} Changing shell for user ${user} to Zsh..."
chsh -s "$(which zsh)" "$user"
echo -e "${GREEN}SUCCESS:${NC} Shell changed."
else
echo -e "${BLUE}INFO:${NC} Shell for user ${user} is already zsh."
fi
done
)
}
#
#SECTION 5: APPLICATION STACK FUNCTIONS
#
install_dev_stack() {
log_step "18/X" "Installing Development Stack (Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Dev Stack...${NC}"; exit 0;' INT
read -rp "$(echo -e "${CYAN}Install a development stack (Nginx, PHP, Node.js)? [y/N]: ${NC}")" choice < /dev/tty
if [[ "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" != "y" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping dev stack installation."; exit 0;
fi
echo -e "${BLUE}INFO:${NC} Installing Nginx..."
$PKG_MANAGER -y install nginx
systemctl enable nginx; systemctl start nginx
echo -e "${BLUE}INFO:${NC} Installing Node.js (LTS)..."
curl -fsSL https://rpm.nodesource.com/setup_lts.x | bash -
$PKG_MANAGER -y install nodejs
echo -e "${BLUE}INFO:${NC} Installing PHP..."
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
$PKG_MANAGER -y install http://rpms.remirepo.net/enterprise/remi-release-8.rpm
$PKG_MANAGER -y module reset php; $PKG_MANAGER -y module install php:remi-8.1
$PKG_MANAGER -y install php-cli php-fpm php-mysqlnd php-json php-gd php-mbstring
else # APT
add-apt-repository ppa:ondrej/php -y; $PKG_MANAGER update
$PKG_MANAGER -y install php8.1-cli php8.1-fpm php8.1-mysql php8.1-json php8.1-gd php8.1-mbstring
fi
echo -e "${GREEN}SUCCESS:${NC} Development stack installed."
)
}
install_cockpit() {
log_step "19/X" "Installing Cockpit Web Console (Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Cockpit...${NC}"; exit 0;' INT
read -rp "$(echo -e "${CYAN}Install the Cockpit web administration console? [y/N]: ${NC}")" choice < /dev/tty
if [[ "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" != "y" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping Cockpit installation."; exit 0;
fi
echo -e "${BLUE}INFO:${NC} Installing Cockpit..."
$PKG_MANAGER -y install cockpit cockpit-storaged cockpit-networkmanager
echo -e "${BLUE}INFO:${NC} Starting and enabling Cockpit socket..."
systemctl enable --now cockpit.socket
echo -e "${GREEN}SUCCESS:${NC} Cockpit is installed. Access it at https://$(hostname -f):9090"
)
}
install_container_runtime() {
log_step "20/X" "Installing Container Runtime (Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Container Runtime...${NC}"; exit 0;' INT
read -rp "$(echo -e "${CYAN}Install a container runtime? ([D]ocker, [P]odman, [N]one): ${NC}")" choice < /dev/tty
case "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" in
d|docker)
echo -e "${BLUE}INFO:${NC} Installing Docker..."
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
$PKG_MANAGER config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
$PKG_MANAGER -y install docker-ce docker-ce-cli containerd.io
else # APT
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
$PKG_MANAGER update
$PKG_MANAGER -y install docker-ce docker-ce-cli containerd.io
fi
systemctl enable --now docker
if [[ -n "${SUDO_USER:-}" ]]; then
echo -e "${BLUE}INFO:${NC} Adding user ${SUDO_USER} to the docker group..."
usermod -aG docker "$SUDO_USER"
fi
echo -e "${GREEN}SUCCESS:${NC} Docker installed."
;;
p|podman)
echo -e "${BLUE}INFO:${NC} Installing Podman..."
$PKG_MANAGER -y install podman
echo -e "${GREEN}SUCCESS:${NC} Podman installed."
;;
*)
echo -e "${BLUE}INFO:${NC} Skipping container runtime installation.";;
esac
)
}
#
#SECTION 6: UTILITY & FINALIZATION FUNCTIONS
#
setup_logrotate() {
log_step "21/X" "Setting up Logrotate (Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping Logrotate setup...${NC}"; exit 0;' INT
read -rp "$(echo -e "${CYAN}Configure log rotation for this script's log files? [y/N]: ${NC}")" choice < /dev/tty
if [[ "$(echo "$choice" | tr '[:upper:]' '[:lower:]')" != "y" ]]; then
echo -e "${BLUE}INFO:${NC} Skipping logrotate setup."; exit 0;
fi
echo -e "${BLUE}INFO:${NC} Creating /etc/logrotate.d/setup-domain..."
cat > /etc/logrotate.d/setup-domain <<EOF
/var/log/setup-domain-*.log {
monthly
rotate 4
compress
delaycompress
missingok
notifempty
create 640 root root
}
EOF
echo -e "${GREEN}SUCCESS:${NC} Logrotate configured."
)
}
final_summary() {
log_step "15/16"22/X" "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: ${PURPLE}$LOG_FILE${NC}"
echo -e "${YELLOW}GREEN}================================================== SUMMARY ==================${NC}"
echo -e " Hostname: ${PURPLE}$(hostname -f)${NC}"
echo -e " IP Address: ${CYAN}$(hostname -I | awk '{print $1}')${NC}"
echo -e " Timezone: ${CYAN}${TIMEZONE}${NC}"
echo -e " Domain Membership: ${PURPLE}${DOMAIN_FQDN}${NC}"
realm list | grep "configured: yes" &>/dev/null
if [ $? -eq 0 ]; then
echo -e " Domain Join Status: ${GREEN}Success${NC}"
echo -e " Login with AD users as: ${CYAN}username${NC}"
echo -e " Sudo enabled for group: ${PURPLE}${AD_SUDO_GROUP_RAW_NAME}${NC}"
else
echo -e " Domain Join Status: ${RED}Failed or Not Performed${NC}"
fi
echo -e " Log File: ${YELLOW}IMPORTANT: Review log for errors. Reboot may be required.${LOG_FILE}${NC}"
echo -e "${YELLOW}=======================GREEN}=============================================${NC}"
}
system_updates_interactive() {
log_step "16/16"23/X" "System Updates (Optional)Optional, Ctrl+C to skip)"
( # Start subshell for cancellation
trap 'echo -e "\n${YELLOW}Operation cancelled. Skipping System Updates...${NC}"; exit 0;' INT
read -rp "$(echo -e "${CYAN}PerformCheck fullfor and apply all available system updates now?updates? [y/N]: ${NC}")" update_choicechoice update_choice=< /dev/tty
if [[ "$(echo "$update_choice"choice" | tr '[:upper:]' '[:lower:]')" if [[ "$update_choice" =!= "y" ]]; then
echo -e "${BLUE}INFO:${NC} StartingSkipping system update..."
if ! $PKG_MANAGER -y upgrade; then echo -e "${RED}ERROR: System upgrade failed.${NC}updates."; elseexit 0;
fi
echo -e "${BLUE}INFO:${NC} ✅Checking for updates..."
$PKG_MANAGER -y update
echo -e "${GREEN}SUCCESS:${NC} System is up-to-date."
echo -e "${BLUE}INFO:${NC} Checking if a reboot is required..."
if [[ "$PKG_MANAGER" == "dnf" || "$PKG_MANAGER" == "yum" ]]; then
if needs-restarting -r &>/dev/null; then
# Using an external file to communicate back to the main script
echo "true" > /tmp/reboot_required.flag
fi
elif [[ "$PKG_MANAGER" == "apt" ]]; then
if [ -f /var/run/reboot-required ]; then
echo "true" > /tmp/reboot_required.flag
fi
fi
if [ -f /tmp/reboot_required.flag ]; then
echo -e "\n${YELLOW}####################################################################"
echo -e "# WARNING: System updates installed.have been installed that require a reboot."
echo -e "####################################################################${NC}"
else
echo -e "${GREEN}INFO:${NC} No reboot is required at this time."
fi
)
}
cleanup() {
unset AD_PASSWORD
rm -f /tmp/reboot_required.flag
echo -e "${BLUE}INFO:${NC} Sensitive variables cleared from memory."
}
usage() {
echo -e "${CYAN}Usage: $0 [OPTION]${NC}"
echo " --full Run the complete end-to-end installation and configuration."
echo " --dev Install the development stack (PHP, Node, Nginx, etc.)."
echo " --security Apply security hardening (Fail2ban, SSH optimization)."
echo " --shell Configure user experience (Bash, Zsh, Tmux, MOTD)."
echo " --updates Check for and apply system updates."
echo " --help Display this help message."
echo
echo -e "${YELLOW}If no option is provided, the script will run the full installation interactively.${NC}"
}
#---
# MODULAR EXECUTION RUNNERS
#
run_full_install() {
echo -e "${PURPLE}Starting Full System Setup...${NC}"
gather_credentials
# Core System & Network (Not cancellable - these are critical)
change_hostname
configure_proxy
configure_dns_and_hosts
check_connectivity
install_packages
configure_time
# Domain & Auth (Not cancellable - these are critical)
join_ad_domain
configure_sssd_mkhomedir
configure_sudoers
# Security (Optional sections are now cancellable)
optimize_sshd
install_fail2ban
#Shell & UX
configure_nano
configure_vim
enhance_bash
setup_tmux
setup_motd
install_zsh_omz
# App Stacks
install_dev_stack
install_cockpit
install_container_runtime
# Utilities & Finalization
setup_logrotate
system_updates_interactive
final_summary
}
run_dev_stack() {
echo -e "${PURPLE}Starting Development Stack Setup...${NC}"
install_packages
install_dev_stack
final_summary
}
run_security_hardening() {
echo -e "${PURPLE}Starting Security Hardening...${NC}"
install_packages
optimize_sshd
install_fail2ban
final_summary
}
run_shell_ux() {
echo -e "${PURPLE}Starting Shell & UX Setup...${NC}"
install_packages
configure_nano
configure_vim
enhance_bash
setup_tmux
setup_motd
install_zsh_omz
final_summary
}
#---
# MAIN EXECUTION FLOW
#---
main() {
trap cleanup EXIT
if [ $# -eq 0 ]; then
run_full_install
else
case "$1" in
--full) run_full_install ;;
--dev) run_dev_stack ;;
--security) run_security_hardening ;;
--shell) run_shell_ux ;;
--updates) system_updates_interactive ;;
--help) usage ;;
*)
echo -e "${RED}Error: Invalid option '$1'${NC}" >&2
usage
exit 1
;;
esac
fi
echo -e "\n${GREEN}========= Script finished at $(date --iso-8601=seconds) =========${NC}"
if [ -f /tmp/reboot_required.flag ]; then
REBOOT_REQUIRED_FLAG=true
fi
if $REBOOT_REQUIRED_FLAG; then
read -rp "$(echo -e "${CYAN}YELLOW}A reboot is required to apply updates. Reboot now? [y/N]: ${NC}")" r;choice r=< /dev/tty
if [[ "$(echo "$r"choice" | tr '[:upper:]' '[:lower:]')
if [[ "$r" == "y" ]]; then
echo -e "Rebooting.${RED}Rebooting now...${NC}";
sleepreboot
5;else
reboot;echo fi-e "${YELLOW}Please reboot the server manually to apply all changes.${NC}"
fi
else
echo -e "${BLUE}INFO:GREEN}Script complete. No reboot required.${NC} Skipping updates.";
fi
}
#------------------------------------------------------------------------------
# MAINOnly EXECUTIONrun FLOWmain #------------------------------------------------------------------------------
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
# Run optional steps in a way that doesn't haltif the script onis failureexecuted (install_dev_stack)directly
||if echo -e[[ "${RED}ERROR during Development Stack installation. Check log. Continuing script...${NC}BASH_SOURCE[0]}" (install_cockpit) || echo -e== "${RED}ERROR during Cockpit installation. Check log. Continuing script...${NC}0}" (install_container_runtime)]]; ||then
echo -emain "${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
fi
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*******************************
