Sync all scripts from website downloads — 352 scripts total
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
This commit is contained in:
@@ -0,0 +1,934 @@
|
||||
#!/usr/bin/env bash
|
||||
# ============================================================================
|
||||
# install-pxe-server.sh
|
||||
# Automated PXE boot server setup — installs dnsmasq, TFTP, and nginx,
|
||||
# configures PXE boot menus, generates Kickstart and Preseed templates
|
||||
#
|
||||
# Author: Phil Connor
|
||||
# Contact: contact@mylinux.work
|
||||
# License: MIT
|
||||
# Version: 1.0.0
|
||||
# ============================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# ============================================================================
|
||||
# Defaults
|
||||
# ============================================================================
|
||||
INTERFACE=""
|
||||
DHCP_RANGE="10.0.0.100,10.0.0.200"
|
||||
TFTP_ROOT="/srv/tftp"
|
||||
HTTP_ROOT="/var/www/pxe"
|
||||
DISTROS="rocky9"
|
||||
SERVER_IP=""
|
||||
OS_FAMILY=""
|
||||
OS_ID=""
|
||||
OS_VERSION=""
|
||||
|
||||
# ============================================================================
|
||||
# Colour output
|
||||
# ============================================================================
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() { echo -e "${CYAN}[INFO]${NC} $*"; }
|
||||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
||||
log_success() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||||
|
||||
# ============================================================================
|
||||
# Usage
|
||||
# ============================================================================
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [OPTIONS]
|
||||
|
||||
Automated PXE boot server setup. Installs and configures dnsmasq (DHCP + TFTP),
|
||||
nginx (HTTP), generates PXE boot menus, Kickstart and Preseed templates.
|
||||
|
||||
Options:
|
||||
--interface <iface> Network interface for DHCP/TFTP binding
|
||||
(default: auto-detected from default route)
|
||||
--dhcp-range <start,end> DHCP range as start,end
|
||||
(default: 10.0.0.100,10.0.0.200)
|
||||
--tftp-root <path> TFTP root directory
|
||||
(default: /srv/tftp)
|
||||
--http-root <path> HTTP document root for install media
|
||||
(default: /var/www/pxe)
|
||||
--distros <list> Comma-separated list of distros to configure
|
||||
(default: rocky9)
|
||||
--help Print this help and exit
|
||||
|
||||
Supported distros:
|
||||
rocky9, rocky8, rhel9, rhel8, alma9,
|
||||
ubuntu2404, ubuntu2204, debian12, debian11
|
||||
|
||||
Examples:
|
||||
sudo $(basename "$0")
|
||||
sudo $(basename "$0") --interface eth0 --dhcp-range 10.0.0.100,10.0.0.200
|
||||
sudo $(basename "$0") --distros rocky9,ubuntu2404,debian12
|
||||
sudo $(basename "$0") --interface ens192 --tftp-root /data/tftp --distros rocky9
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Parse arguments
|
||||
# ============================================================================
|
||||
parse_args() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--interface)
|
||||
INTERFACE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--dhcp-range)
|
||||
DHCP_RANGE="$2"
|
||||
shift 2
|
||||
;;
|
||||
--tftp-root)
|
||||
TFTP_ROOT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--http-root)
|
||||
HTTP_ROOT="$2"
|
||||
shift 2
|
||||
;;
|
||||
--distros)
|
||||
DISTROS="$2"
|
||||
shift 2
|
||||
;;
|
||||
--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
log_error "Unknown option: $1"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Detect OS
|
||||
# ============================================================================
|
||||
detect_os() {
|
||||
log_info "Detecting operating system..."
|
||||
|
||||
if [[ ! -f /etc/os-release ]]; then
|
||||
log_error "Cannot detect OS — /etc/os-release not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1091
|
||||
source /etc/os-release
|
||||
|
||||
OS_ID="${ID}"
|
||||
OS_VERSION="${VERSION_ID}"
|
||||
|
||||
case "${OS_ID}" in
|
||||
debian|ubuntu)
|
||||
OS_FAMILY="debian"
|
||||
;;
|
||||
rocky|rhel|almalinux|centos)
|
||||
OS_FAMILY="rhel"
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported OS: ${OS_ID} ${OS_VERSION}"
|
||||
log_error "Supported: Debian 11+, Ubuntu 22.04+, RHEL/Rocky/Alma 8+"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Detected ${OS_ID} ${OS_VERSION} (${OS_FAMILY} family)"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Detect network interface
|
||||
# ============================================================================
|
||||
detect_interface() {
|
||||
if [[ -n "${INTERFACE}" ]]; then
|
||||
if ! ip link show "${INTERFACE}" &>/dev/null; then
|
||||
log_error "Interface ${INTERFACE} does not exist"
|
||||
echo "Available interfaces:"
|
||||
ip -o link show | awk -F': ' '{print " " $2}'
|
||||
exit 1
|
||||
fi
|
||||
log_info "Using specified interface: ${INTERFACE}"
|
||||
else
|
||||
log_info "Auto-detecting network interface..."
|
||||
INTERFACE=$(ip route show default 2>/dev/null | awk '{print $5; exit}')
|
||||
|
||||
if [[ -z "${INTERFACE}" ]]; then
|
||||
log_error "Cannot detect default network interface"
|
||||
log_error "Specify one with --interface"
|
||||
exit 1
|
||||
fi
|
||||
log_success "Detected interface: ${INTERFACE}"
|
||||
fi
|
||||
|
||||
SERVER_IP=$(ip -4 addr show "${INTERFACE}" | awk '/inet / {split($2,a,"/"); print a[1]; exit}')
|
||||
|
||||
if [[ -z "${SERVER_IP}" ]]; then
|
||||
log_error "Cannot determine IP address for interface ${INTERFACE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Server IP: ${SERVER_IP}"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Validate distro list
|
||||
# ============================================================================
|
||||
validate_distros() {
|
||||
local valid_distros="rocky9 rocky8 rhel9 rhel8 alma9 ubuntu2404 ubuntu2204 debian12 debian11"
|
||||
|
||||
IFS=',' read -ra DISTRO_LIST <<< "${DISTROS}"
|
||||
|
||||
for distro in "${DISTRO_LIST[@]}"; do
|
||||
local found=false
|
||||
for valid in ${valid_distros}; do
|
||||
if [[ "${distro}" == "${valid}" ]]; then
|
||||
found=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "${found}" == "false" ]]; then
|
||||
log_error "Invalid distro: ${distro}"
|
||||
log_error "Valid options: ${valid_distros}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
log_success "Distros to configure: ${DISTROS}"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Install packages
|
||||
# ============================================================================
|
||||
install_packages() {
|
||||
log_info "Installing packages..."
|
||||
|
||||
if [[ "${OS_FAMILY}" == "debian" ]]; then
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq \
|
||||
dnsmasq \
|
||||
tftpd-hpa \
|
||||
syslinux-common \
|
||||
pxelinux \
|
||||
nginx \
|
||||
wget \
|
||||
curl \
|
||||
>/dev/null 2>&1
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log_error "Package installation failed"
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "${OS_FAMILY}" == "rhel" ]]; then
|
||||
dnf install -y -q \
|
||||
dnsmasq \
|
||||
tftp-server \
|
||||
syslinux \
|
||||
nginx \
|
||||
wget \
|
||||
curl \
|
||||
>/dev/null 2>&1
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log_error "Package installation failed"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_success "Packages installed"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Configure dnsmasq
|
||||
# ============================================================================
|
||||
configure_dnsmasq() {
|
||||
log_info "Configuring dnsmasq..."
|
||||
|
||||
local dhcp_start dhcp_end
|
||||
dhcp_start=$(echo "${DHCP_RANGE}" | cut -d',' -f1)
|
||||
dhcp_end=$(echo "${DHCP_RANGE}" | cut -d',' -f2)
|
||||
|
||||
# Disable default dnsmasq DNS to avoid conflicts
|
||||
if [[ -f /etc/dnsmasq.conf ]]; then
|
||||
cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
|
||||
fi
|
||||
|
||||
mkdir -p /etc/dnsmasq.d
|
||||
|
||||
cat > /etc/dnsmasq.d/pxe.conf <<EOF
|
||||
# PXE Boot Server Configuration
|
||||
# Generated by install-pxe-server.sh
|
||||
|
||||
# Interface binding
|
||||
interface=${INTERFACE}
|
||||
bind-interfaces
|
||||
|
||||
# Disable DNS (use dnsmasq only for DHCP + TFTP)
|
||||
port=0
|
||||
|
||||
# DHCP range — 1 hour lease
|
||||
dhcp-range=${dhcp_start},${dhcp_end},255.255.255.0,1h
|
||||
|
||||
# PXE boot options — BIOS
|
||||
dhcp-boot=pxelinux.0,,${SERVER_IP}
|
||||
|
||||
# UEFI detection — serve GRUB for UEFI clients
|
||||
dhcp-match=set:efi-x86_64,option:client-arch,7
|
||||
dhcp-match=set:efi-x86_64,option:client-arch,9
|
||||
dhcp-boot=tag:efi-x86_64,grubx64.efi,,${SERVER_IP}
|
||||
|
||||
# TFTP server
|
||||
enable-tftp
|
||||
tftp-root=${TFTP_ROOT}
|
||||
|
||||
# Set next-server for PXE
|
||||
dhcp-option=66,${SERVER_IP}
|
||||
|
||||
# Logging
|
||||
log-dhcp
|
||||
log-queries
|
||||
log-facility=/var/log/dnsmasq-pxe.log
|
||||
EOF
|
||||
|
||||
# Ensure main config includes the .d directory
|
||||
if [[ -f /etc/dnsmasq.conf ]]; then
|
||||
if ! grep -q "^conf-dir=/etc/dnsmasq.d" /etc/dnsmasq.conf; then
|
||||
echo "conf-dir=/etc/dnsmasq.d/,*.conf" >> /etc/dnsmasq.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
log_success "dnsmasq configured at /etc/dnsmasq.d/pxe.conf"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Setup TFTP directory
|
||||
# ============================================================================
|
||||
setup_tftp() {
|
||||
log_info "Setting up TFTP directory..."
|
||||
|
||||
mkdir -p "${TFTP_ROOT}/pxelinux.cfg"
|
||||
mkdir -p "${TFTP_ROOT}/grub"
|
||||
|
||||
# Copy syslinux/pxelinux files
|
||||
if [[ "${OS_FAMILY}" == "debian" ]]; then
|
||||
local pxe_src="/usr/lib/PXELINUX"
|
||||
local sys_src="/usr/lib/syslinux/modules/bios"
|
||||
|
||||
if [[ -f "${pxe_src}/pxelinux.0" ]]; then
|
||||
cp "${pxe_src}/pxelinux.0" "${TFTP_ROOT}/"
|
||||
else
|
||||
log_warn "pxelinux.0 not found at ${pxe_src}/pxelinux.0"
|
||||
fi
|
||||
|
||||
for file in ldlinux.c32 menu.c32 libmenu.c32 libutil.c32; do
|
||||
if [[ -f "${sys_src}/${file}" ]]; then
|
||||
cp "${sys_src}/${file}" "${TFTP_ROOT}/"
|
||||
else
|
||||
log_warn "${file} not found at ${sys_src}/${file}"
|
||||
fi
|
||||
done
|
||||
|
||||
elif [[ "${OS_FAMILY}" == "rhel" ]]; then
|
||||
local sys_src="/usr/share/syslinux"
|
||||
|
||||
for file in pxelinux.0 ldlinux.c32 menu.c32 libmenu.c32 libutil.c32; do
|
||||
if [[ -f "${sys_src}/${file}" ]]; then
|
||||
cp "${sys_src}/${file}" "${TFTP_ROOT}/"
|
||||
else
|
||||
log_warn "${file} not found at ${sys_src}/${file}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Create distro directories in TFTP root
|
||||
IFS=',' read -ra DISTRO_LIST <<< "${DISTROS}"
|
||||
for distro in "${DISTRO_LIST[@]}"; do
|
||||
mkdir -p "${TFTP_ROOT}/${distro}"
|
||||
done
|
||||
|
||||
# Set permissions
|
||||
chmod -R 755 "${TFTP_ROOT}"
|
||||
|
||||
if [[ "${OS_FAMILY}" == "debian" ]]; then
|
||||
chown -R tftp:tftp "${TFTP_ROOT}"
|
||||
|
||||
# Configure tftpd-hpa
|
||||
cat > /etc/default/tftpd-hpa <<EOF
|
||||
TFTP_USERNAME="tftp"
|
||||
TFTP_DIRECTORY="${TFTP_ROOT}"
|
||||
TFTP_ADDRESS=":69"
|
||||
TFTP_OPTIONS="--secure --verbose"
|
||||
EOF
|
||||
elif [[ "${OS_FAMILY}" == "rhel" ]]; then
|
||||
chown -R nobody:nobody "${TFTP_ROOT}"
|
||||
fi
|
||||
|
||||
log_success "TFTP directory structure created at ${TFTP_ROOT}"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Create PXE boot menu
|
||||
# ============================================================================
|
||||
create_pxe_menu() {
|
||||
log_info "Generating PXE boot menu..."
|
||||
|
||||
local menu_file="${TFTP_ROOT}/pxelinux.cfg/default"
|
||||
|
||||
cat > "${menu_file}" <<'MENU_HEADER'
|
||||
DEFAULT menu.c32
|
||||
PROMPT 0
|
||||
TIMEOUT 300
|
||||
ONTIMEOUT local
|
||||
|
||||
MENU TITLE ===== PXE Boot Server =====
|
||||
MENU COLOR border 30;44 #40ffffff #a0000000 std
|
||||
MENU COLOR title 1;36;44 #9033cccc #a0000000 std
|
||||
MENU COLOR sel 7;37;40 #e0ffffff #20ffffff all
|
||||
MENU COLOR unsel 37;44 #50ffffff #a0000000 std
|
||||
MENU COLOR help 37;40 #c0ffffff #a0000000 std
|
||||
MENU COLOR timeout_msg 37;40 #80ffffff #00000000 std
|
||||
MENU COLOR timeout 1;37;40 #c0ffffff #00000000 std
|
||||
|
||||
LABEL local
|
||||
MENU LABEL Boot from local disk
|
||||
MENU DEFAULT
|
||||
LOCALBOOT 0
|
||||
|
||||
MENU_HEADER
|
||||
|
||||
IFS=',' read -ra DISTRO_LIST <<< "${DISTROS}"
|
||||
for distro in "${DISTRO_LIST[@]}"; do
|
||||
case "${distro}" in
|
||||
rocky9)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL rocky9
|
||||
MENU LABEL Install Rocky Linux 9
|
||||
KERNEL rocky9/vmlinuz
|
||||
APPEND initrd=rocky9/initrd.img inst.ks=http://${SERVER_IP}/ks/ks-rocky9.cfg ip=dhcp
|
||||
EOF
|
||||
;;
|
||||
rocky8)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL rocky8
|
||||
MENU LABEL Install Rocky Linux 8
|
||||
KERNEL rocky8/vmlinuz
|
||||
APPEND initrd=rocky8/initrd.img inst.ks=http://${SERVER_IP}/ks/ks-rocky8.cfg ip=dhcp
|
||||
EOF
|
||||
;;
|
||||
rhel9)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL rhel9
|
||||
MENU LABEL Install RHEL 9
|
||||
KERNEL rhel9/vmlinuz
|
||||
APPEND initrd=rhel9/initrd.img inst.ks=http://${SERVER_IP}/ks/ks-rhel9.cfg ip=dhcp
|
||||
EOF
|
||||
;;
|
||||
rhel8)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL rhel8
|
||||
MENU LABEL Install RHEL 8
|
||||
KERNEL rhel8/vmlinuz
|
||||
APPEND initrd=rhel8/initrd.img inst.ks=http://${SERVER_IP}/ks/ks-rhel8.cfg ip=dhcp
|
||||
EOF
|
||||
;;
|
||||
alma9)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL alma9
|
||||
MENU LABEL Install AlmaLinux 9
|
||||
KERNEL alma9/vmlinuz
|
||||
APPEND initrd=alma9/initrd.img inst.ks=http://${SERVER_IP}/ks/ks-alma9.cfg ip=dhcp
|
||||
EOF
|
||||
;;
|
||||
ubuntu2404)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL ubuntu2404
|
||||
MENU LABEL Install Ubuntu 24.04 LTS
|
||||
KERNEL ubuntu2404/linux
|
||||
APPEND initrd=ubuntu2404/initrd.gz auto=true priority=critical url=http://${SERVER_IP}/preseed/preseed-ubuntu2404.cfg interface=auto
|
||||
EOF
|
||||
;;
|
||||
ubuntu2204)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL ubuntu2204
|
||||
MENU LABEL Install Ubuntu 22.04 LTS
|
||||
KERNEL ubuntu2204/linux
|
||||
APPEND initrd=ubuntu2204/initrd.gz auto=true priority=critical url=http://${SERVER_IP}/preseed/preseed-ubuntu2204.cfg interface=auto
|
||||
EOF
|
||||
;;
|
||||
debian12)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL debian12
|
||||
MENU LABEL Install Debian 12 (Bookworm)
|
||||
KERNEL debian12/linux
|
||||
APPEND initrd=debian12/initrd.gz auto=true priority=critical url=http://${SERVER_IP}/preseed/preseed-debian12.cfg interface=auto
|
||||
EOF
|
||||
;;
|
||||
debian11)
|
||||
cat >> "${menu_file}" <<EOF
|
||||
|
||||
LABEL debian11
|
||||
MENU LABEL Install Debian 11 (Bullseye)
|
||||
KERNEL debian11/linux
|
||||
APPEND initrd=debian11/initrd.gz auto=true priority=critical url=http://${SERVER_IP}/preseed/preseed-debian11.cfg interface=auto
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log_success "PXE boot menu created at ${menu_file}"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Generate Kickstart template
|
||||
# ============================================================================
|
||||
generate_kickstart() {
|
||||
local distro="$1"
|
||||
local ks_dir="${HTTP_ROOT}/ks"
|
||||
local ks_file="${ks_dir}/ks-${distro}.cfg"
|
||||
|
||||
mkdir -p "${ks_dir}"
|
||||
|
||||
log_info "Generating Kickstart template: ${ks_file}"
|
||||
|
||||
cat > "${ks_file}" <<EOF
|
||||
# Kickstart configuration for ${distro}
|
||||
# Generated by install-pxe-server.sh
|
||||
# Edit this file to match your environment
|
||||
|
||||
# Install method — update URL to match your repo path
|
||||
url --url="http://${SERVER_IP}/${distro}/"
|
||||
text
|
||||
reboot
|
||||
|
||||
# Locale
|
||||
lang en_US.UTF-8
|
||||
keyboard us
|
||||
timezone UTC --utc
|
||||
|
||||
# Network
|
||||
network --bootproto=dhcp --device=link --activate --onboot=yes
|
||||
network --hostname=${distro}-host
|
||||
|
||||
# Authentication
|
||||
# Generate hash: python3 -c "import crypt; print(crypt.crypt('password', crypt.mksalt(crypt.METHOD_SHA512)))"
|
||||
rootpw --iscrypted \$6\$rounds=4096\$CHANGEME\$CHANGEME_HASH_HERE
|
||||
|
||||
# Create admin user
|
||||
user --name=admin --groups=wheel --iscrypted --password=\$6\$rounds=4096\$CHANGEME\$CHANGEME_HASH_HERE
|
||||
|
||||
# Security
|
||||
selinux --enforcing
|
||||
firewall --enabled --service=ssh
|
||||
|
||||
# Disk partitioning — auto with LVM
|
||||
ignoredisk --only-use=sda
|
||||
clearpart --all --initlabel --drives=sda
|
||||
autopart --type=lvm --fstype=xfs
|
||||
|
||||
# Bootloader
|
||||
bootloader --append="crashkernel=auto" --location=mbr --boot-drive=sda
|
||||
|
||||
# Package selection
|
||||
%packages
|
||||
@^minimal-environment
|
||||
@standard
|
||||
bash-completion
|
||||
vim-enhanced
|
||||
tmux
|
||||
curl
|
||||
wget
|
||||
net-tools
|
||||
bind-utils
|
||||
chrony
|
||||
rsync
|
||||
%end
|
||||
|
||||
# Post-install script
|
||||
%post --log=/root/ks-post.log
|
||||
#!/bin/bash
|
||||
|
||||
# Enable SSH
|
||||
systemctl enable --now sshd
|
||||
|
||||
# Update packages
|
||||
dnf update -y
|
||||
|
||||
# Configure chrony
|
||||
systemctl enable --now chronyd
|
||||
|
||||
# Set up automatic security updates
|
||||
dnf install -y dnf-automatic
|
||||
sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf
|
||||
systemctl enable --now dnf-automatic-install.timer
|
||||
|
||||
# Disable root SSH login
|
||||
sed -i 's/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
|
||||
|
||||
echo "Post-install completed: \$(date)" >> /root/ks-post.log
|
||||
%end
|
||||
EOF
|
||||
|
||||
log_success "Kickstart template created: ${ks_file}"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Generate Preseed template
|
||||
# ============================================================================
|
||||
generate_preseed() {
|
||||
local distro="$1"
|
||||
local preseed_dir="${HTTP_ROOT}/preseed"
|
||||
local preseed_file="${preseed_dir}/preseed-${distro}.cfg"
|
||||
|
||||
mkdir -p "${preseed_dir}"
|
||||
|
||||
log_info "Generating Preseed template: ${preseed_file}"
|
||||
|
||||
local mirror_host="deb.debian.org"
|
||||
local mirror_dir="/debian"
|
||||
if [[ "${distro}" == ubuntu* ]]; then
|
||||
mirror_host="archive.ubuntu.com"
|
||||
mirror_dir="/ubuntu"
|
||||
fi
|
||||
|
||||
cat > "${preseed_file}" <<EOF
|
||||
# Preseed configuration for ${distro}
|
||||
# Generated by install-pxe-server.sh
|
||||
# Edit this file to match your environment
|
||||
|
||||
### Locale and keyboard
|
||||
d-i debian-installer/locale string en_US.UTF-8
|
||||
d-i keyboard-configuration/xkb-keymap select us
|
||||
d-i console-setup/ask_detect boolean false
|
||||
|
||||
### Network
|
||||
d-i netcfg/choose_interface select auto
|
||||
d-i netcfg/get_hostname string ${distro}-host
|
||||
d-i netcfg/get_domain string lab.local
|
||||
d-i netcfg/hostname string ${distro}-host
|
||||
|
||||
### Mirror
|
||||
d-i mirror/country string manual
|
||||
d-i mirror/http/hostname string ${mirror_host}
|
||||
d-i mirror/http/directory string ${mirror_dir}
|
||||
d-i mirror/http/proxy string
|
||||
|
||||
### Clock and timezone
|
||||
d-i clock-setup/utc boolean true
|
||||
d-i time/zone string UTC
|
||||
d-i clock-setup/ntp boolean true
|
||||
|
||||
### Partitioning — guided LVM entire disk
|
||||
d-i partman-auto/method string lvm
|
||||
d-i partman-auto-lvm/guided_size string max
|
||||
d-i partman-lvm/device_remove_lvm boolean true
|
||||
d-i partman-md/device_remove_md boolean true
|
||||
d-i partman-lvm/confirm boolean true
|
||||
d-i partman-lvm/confirm_nooverwrite boolean true
|
||||
d-i partman-auto/choose_recipe select atomic
|
||||
d-i partman-partitioning/confirm_write_new_label boolean true
|
||||
d-i partman/choose_partition select finish
|
||||
d-i partman/confirm boolean true
|
||||
d-i partman/confirm_nooverwrite boolean true
|
||||
|
||||
### User account
|
||||
# Generate hash: mkpasswd -m sha-512 'password'
|
||||
d-i passwd/root-login boolean false
|
||||
d-i passwd/user-fullname string Admin User
|
||||
d-i passwd/username string admin
|
||||
d-i passwd/user-password-crypted password \$6\$rounds=4096\$CHANGEME\$CHANGEME_HASH_HERE
|
||||
|
||||
### Package selection
|
||||
tasksel tasksel/first multiselect standard, ssh-server
|
||||
d-i pkgsel/include string bash-completion vim tmux curl wget net-tools rsync
|
||||
d-i pkgsel/upgrade select full-upgrade
|
||||
popularity-contest popularity-contest/participate boolean false
|
||||
|
||||
### GRUB bootloader
|
||||
d-i grub-installer/only_debian boolean true
|
||||
d-i grub-installer/bootdev string default
|
||||
|
||||
### Post-install commands
|
||||
d-i preseed/late_command string \\
|
||||
in-target systemctl enable ssh ; \\
|
||||
echo "Post-install completed: \$(date)" >> /target/root/preseed-post.log
|
||||
|
||||
### Reboot after install
|
||||
d-i finish-install/reboot_in_progress note
|
||||
d-i debian-installer/exit/poweroff boolean false
|
||||
EOF
|
||||
|
||||
log_success "Preseed template created: ${preseed_file}"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Configure nginx
|
||||
# ============================================================================
|
||||
configure_nginx() {
|
||||
log_info "Configuring nginx..."
|
||||
|
||||
mkdir -p "${HTTP_ROOT}"/{ks,preseed}
|
||||
|
||||
# Create distro directories in HTTP root
|
||||
IFS=',' read -ra DISTRO_LIST <<< "${DISTROS}"
|
||||
for distro in "${DISTRO_LIST[@]}"; do
|
||||
mkdir -p "${HTTP_ROOT}/${distro}"
|
||||
done
|
||||
|
||||
# Remove default site if present
|
||||
rm -f /etc/nginx/sites-enabled/default 2>/dev/null
|
||||
rm -f /etc/nginx/conf.d/default.conf 2>/dev/null
|
||||
|
||||
cat > /etc/nginx/conf.d/pxe.conf <<EOF
|
||||
# PXE Boot HTTP Server
|
||||
# Generated by install-pxe-server.sh
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root ${HTTP_ROOT};
|
||||
|
||||
location / {
|
||||
autoindex on;
|
||||
autoindex_exact_size off;
|
||||
autoindex_localtime on;
|
||||
}
|
||||
|
||||
location /ks/ {
|
||||
alias ${HTTP_ROOT}/ks/;
|
||||
autoindex on;
|
||||
}
|
||||
|
||||
location /preseed/ {
|
||||
alias ${HTTP_ROOT}/preseed/;
|
||||
autoindex on;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Test nginx config
|
||||
if nginx -t &>/dev/null; then
|
||||
log_success "nginx configured at /etc/nginx/conf.d/pxe.conf"
|
||||
else
|
||||
log_error "nginx configuration test failed"
|
||||
nginx -t
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Configure firewall
|
||||
# ============================================================================
|
||||
configure_firewall() {
|
||||
log_info "Configuring firewall..."
|
||||
|
||||
if command -v firewall-cmd &>/dev/null && systemctl is-active --quiet firewalld; then
|
||||
log_info "Detected firewalld"
|
||||
firewall-cmd --permanent --add-port=67/udp # DHCP
|
||||
firewall-cmd --permanent --add-port=68/udp # DHCP client
|
||||
firewall-cmd --permanent --add-port=69/udp # TFTP
|
||||
firewall-cmd --permanent --add-port=80/tcp # HTTP
|
||||
firewall-cmd --permanent --add-port=4011/udp # ProxyDHCP
|
||||
firewall-cmd --reload
|
||||
log_success "Firewall ports opened (firewalld)"
|
||||
|
||||
elif command -v ufw &>/dev/null && ufw status | grep -q "Status: active"; then
|
||||
log_info "Detected ufw"
|
||||
ufw allow 67/udp comment "DHCP server"
|
||||
ufw allow 68/udp comment "DHCP client"
|
||||
ufw allow 69/udp comment "TFTP"
|
||||
ufw allow 80/tcp comment "HTTP"
|
||||
ufw allow 4011/udp comment "ProxyDHCP"
|
||||
log_success "Firewall ports opened (ufw)"
|
||||
|
||||
else
|
||||
log_warn "No active firewall detected — skipping firewall configuration"
|
||||
log_warn "Manually open ports: 67/udp, 68/udp, 69/udp, 80/tcp, 4011/udp"
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Enable services
|
||||
# ============================================================================
|
||||
enable_services() {
|
||||
log_info "Enabling and starting services..."
|
||||
|
||||
# dnsmasq
|
||||
systemctl enable dnsmasq
|
||||
systemctl restart dnsmasq
|
||||
if systemctl is-active --quiet dnsmasq; then
|
||||
log_success "dnsmasq is running"
|
||||
else
|
||||
log_error "dnsmasq failed to start"
|
||||
journalctl -u dnsmasq --no-pager -n 10
|
||||
fi
|
||||
|
||||
# TFTP
|
||||
if [[ "${OS_FAMILY}" == "debian" ]]; then
|
||||
systemctl enable tftpd-hpa
|
||||
systemctl restart tftpd-hpa
|
||||
if systemctl is-active --quiet tftpd-hpa; then
|
||||
log_success "tftpd-hpa is running"
|
||||
else
|
||||
log_error "tftpd-hpa failed to start"
|
||||
journalctl -u tftpd-hpa --no-pager -n 10
|
||||
fi
|
||||
elif [[ "${OS_FAMILY}" == "rhel" ]]; then
|
||||
systemctl enable tftp.socket
|
||||
systemctl restart tftp.socket
|
||||
if systemctl is-active --quiet tftp.socket; then
|
||||
log_success "tftp.socket is running"
|
||||
else
|
||||
log_error "tftp.socket failed to start"
|
||||
journalctl -u tftp.socket --no-pager -n 10
|
||||
fi
|
||||
fi
|
||||
|
||||
# nginx
|
||||
systemctl enable nginx
|
||||
systemctl restart nginx
|
||||
if systemctl is-active --quiet nginx; then
|
||||
log_success "nginx is running"
|
||||
else
|
||||
log_error "nginx failed to start"
|
||||
journalctl -u nginx --no-pager -n 10
|
||||
fi
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Print summary
|
||||
# ============================================================================
|
||||
print_summary() {
|
||||
local dhcp_start dhcp_end
|
||||
dhcp_start=$(echo "${DHCP_RANGE}" | cut -d',' -f1)
|
||||
dhcp_end=$(echo "${DHCP_RANGE}" | cut -d',' -f2)
|
||||
|
||||
echo ""
|
||||
echo "╔══════════════════════════════════════════════════════════════╗"
|
||||
echo "║ PXE Boot Server — Setup Complete ║"
|
||||
echo "╠══════════════════════════════════════════════════════════════╣"
|
||||
echo "║ ║"
|
||||
printf "║ Server IP: %-41s║\n" "${SERVER_IP}"
|
||||
printf "║ Interface: %-41s║\n" "${INTERFACE}"
|
||||
printf "║ DHCP Range: %-41s║\n" "${dhcp_start} — ${dhcp_end}"
|
||||
printf "║ TFTP Root: %-41s║\n" "${TFTP_ROOT}"
|
||||
printf "║ HTTP Root: %-41s║\n" "${HTTP_ROOT}"
|
||||
printf "║ Distros: %-41s║\n" "${DISTROS}"
|
||||
echo "║ ║"
|
||||
echo "╠══════════════════════════════════════════════════════════════╣"
|
||||
echo "║ Configuration Files ║"
|
||||
echo "╠══════════════════════════════════════════════════════════════╣"
|
||||
printf "║ dnsmasq: %-41s║\n" "/etc/dnsmasq.d/pxe.conf"
|
||||
printf "║ PXE menu: %-41s║\n" "${TFTP_ROOT}/pxelinux.cfg/default"
|
||||
printf "║ nginx: %-41s║\n" "/etc/nginx/conf.d/pxe.conf"
|
||||
echo "║ ║"
|
||||
|
||||
IFS=',' read -ra DISTRO_LIST <<< "${DISTROS}"
|
||||
for distro in "${DISTRO_LIST[@]}"; do
|
||||
case "${distro}" in
|
||||
rocky*|rhel*|alma*)
|
||||
printf "║ Kickstart: %-41s║\n" "http://${SERVER_IP}/ks/ks-${distro}.cfg"
|
||||
;;
|
||||
ubuntu*|debian*)
|
||||
printf "║ Preseed: %-41s║\n" "http://${SERVER_IP}/preseed/preseed-${distro}.cfg"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "║ ║"
|
||||
echo "╠══════════════════════════════════════════════════════════════╣"
|
||||
echo "║ Next Steps ║"
|
||||
echo "╠══════════════════════════════════════════════════════════════╣"
|
||||
echo "║ ║"
|
||||
echo "║ 1. Mount or extract distro ISOs into the HTTP root: ║"
|
||||
|
||||
for distro in "${DISTRO_LIST[@]}"; do
|
||||
printf "║ mount -o loop,ro <iso> %-33s║\n" "${HTTP_ROOT}/${distro}/"
|
||||
done
|
||||
|
||||
echo "║ ║"
|
||||
echo "║ 2. Copy kernel + initrd to TFTP root: ║"
|
||||
|
||||
for distro in "${DISTRO_LIST[@]}"; do
|
||||
printf "║ %s -> %-43s║\n" "vmlinuz/initrd" "${TFTP_ROOT}/${distro}/"
|
||||
done
|
||||
|
||||
echo "║ ║"
|
||||
echo "║ 3. Edit Kickstart/Preseed templates: ║"
|
||||
echo "║ - Set root/user password hashes ║"
|
||||
echo "║ - Adjust partitioning layout ║"
|
||||
echo "║ - Add site-specific packages ║"
|
||||
echo "║ ║"
|
||||
echo "║ 4. PXE boot a target machine and select a distro ║"
|
||||
echo "║ ║"
|
||||
echo "╚══════════════════════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Main
|
||||
# ============================================================================
|
||||
main() {
|
||||
echo ""
|
||||
echo "================================================"
|
||||
echo " PXE Boot Server — Automated Setup"
|
||||
echo " Version 1.0.0"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
|
||||
# Check root
|
||||
if [[ "${EUID}" -ne 0 ]]; then
|
||||
log_error "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
parse_args "$@"
|
||||
detect_os
|
||||
detect_interface
|
||||
validate_distros
|
||||
install_packages
|
||||
configure_dnsmasq
|
||||
setup_tftp
|
||||
create_pxe_menu
|
||||
|
||||
# Generate answer file templates based on selected distros
|
||||
IFS=',' read -ra DISTRO_LIST <<< "${DISTROS}"
|
||||
for distro in "${DISTRO_LIST[@]}"; do
|
||||
case "${distro}" in
|
||||
rocky*|rhel*|alma*)
|
||||
generate_kickstart "${distro}"
|
||||
;;
|
||||
ubuntu*|debian*)
|
||||
generate_preseed "${distro}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
configure_nginx
|
||||
configure_firewall
|
||||
enable_services
|
||||
print_summary
|
||||
|
||||
log_success "PXE boot server setup complete"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user