a1a17e81a1
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.
304 lines
9.3 KiB
Bash
304 lines
9.3 KiB
Bash
#!/bin/bash
|
|
|
|
##############################################
|
|
#### Create Swap for all Linux Servers ####
|
|
#### ####
|
|
#### Author: Phil Connor ####
|
|
#### Contact: pconnor@ara.com ####
|
|
#### Version 3.51.20250729 ####
|
|
#### ####
|
|
#### Created 06/01/2023 ####
|
|
##############################################
|
|
# v3.51 changes:
|
|
# - Fixed: grep in pipeline crashes under set -euo pipefail when no matches found. Added || true guard
|
|
##############################################
|
|
|
|
# Exit on any error, undefined variables, and pipe failures
|
|
set -euo pipefail
|
|
|
|
# Script configuration constants
|
|
readonly SCRIPT_NAME="$(basename "$0")"
|
|
readonly SWAPFILE_PATH="/.swapfile" # Standard location for swap file
|
|
readonly SWAPPINESS_VALUE=80 # How aggressively to use swap (0-100)
|
|
|
|
# Logging function - outputs to stderr with script name prefix
|
|
log() {
|
|
echo "[$SCRIPT_NAME] $*" >&2
|
|
}
|
|
|
|
# Error function - logs error message and exits with status 1
|
|
error() {
|
|
log "ERROR: $*"
|
|
exit 1
|
|
}
|
|
|
|
# Display usage information
|
|
usage() {
|
|
cat <<EOF
|
|
Usage: $SCRIPT_NAME [-h|--help]
|
|
|
|
Creates and configures a swap file sized 1:1 with system RAM.
|
|
Handles creation, resizing, and removal of existing swap files.
|
|
|
|
Options:
|
|
-h, --help Show this help message and exit
|
|
|
|
Must be run as root.
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
# Clean up partial swap file on unexpected failure
|
|
cleanup_on_error() {
|
|
log "Error detected, cleaning up partial swap file"
|
|
swapoff "$SWAPFILE_PATH" 2>/dev/null || true
|
|
rm -f "$SWAPFILE_PATH"
|
|
}
|
|
|
|
# Detect the operating system distribution (ubuntu, centos, etc.)
|
|
detect_os() {
|
|
if command -v lsb_release >/dev/null 2>&1; then
|
|
# Use lsb_release if available (most reliable)
|
|
lsb_release -i | awk '{print $3}' | tr '[:upper:]' '[:lower:]'
|
|
else
|
|
# Fallback to parsing /etc/os-release
|
|
# shellcheck source=/dev/null
|
|
. /etc/os-release 2>/dev/null && echo "${ID:-unknown}" | tr '[:upper:]' '[:lower:]'
|
|
fi
|
|
}
|
|
|
|
# Get total system memory in GB, rounded to nearest whole number
|
|
get_memory_gb() {
|
|
local mem_kb
|
|
# Extract memory from /proc/meminfo (in KB)
|
|
mem_kb=$({ grep MemTotal /proc/meminfo || true; } | awk '{print $2}')
|
|
|
|
if [[ -z "$mem_kb" || "$mem_kb" -eq 0 ]]; then
|
|
error "Unable to determine system memory"
|
|
fi
|
|
|
|
local mem_gb
|
|
# Convert KB to GB and round to nearest whole number
|
|
mem_gb=$(awk "BEGIN {printf \"%.0f\", ($mem_kb/1024/1024)}")
|
|
# Ensure minimum of 1GB to avoid division by zero issues
|
|
[[ "$mem_gb" -eq 0 ]] && mem_gb=1
|
|
|
|
echo "$mem_gb"
|
|
}
|
|
|
|
# Calculate swap size needed in MB (1:1 ratio with RAM)
|
|
get_swap_needed_mb() {
|
|
local mem_gb="$1"
|
|
echo $((mem_gb * 1024))
|
|
}
|
|
|
|
# Get the current swap file size in MB, or 0 if no swap file exists
|
|
get_current_swap_size() {
|
|
if [[ -f "$SWAPFILE_PATH" ]]; then
|
|
local size_bytes
|
|
size_bytes=$(stat -c%s "$SWAPFILE_PATH" 2>/dev/null || echo 0)
|
|
echo $((size_bytes / 1024 / 1024))
|
|
else
|
|
echo 0
|
|
fi
|
|
}
|
|
|
|
# Check if our swap file is currently active
|
|
is_swap_active() {
|
|
swapon --show=NAME --noheadings 2>/dev/null | grep -q "^${SWAPFILE_PATH}$"
|
|
}
|
|
|
|
# Check if there's enough disk space for the swap file (with 10% buffer)
|
|
check_disk_space() {
|
|
local needed_mb="$1"
|
|
local filesystem="/"
|
|
|
|
log "Checking available disk space for ${needed_mb}MB swap file"
|
|
|
|
local available_kb
|
|
# Get available space in KB from df command
|
|
available_kb=$(df --output=avail "$filesystem" | tail -n 1)
|
|
local available_mb=$((available_kb / 1024))
|
|
|
|
# Add 10% buffer for safety
|
|
local required_mb=$((needed_mb + (needed_mb / 10)))
|
|
|
|
if [[ "$available_mb" -lt "$required_mb" ]]; then
|
|
error "Insufficient disk space. Need ${required_mb}MB (${needed_mb}MB + 10% buffer), but only ${available_mb}MB available on $filesystem"
|
|
fi
|
|
|
|
log "Disk space check passed: ${available_mb}MB available, ${required_mb}MB required"
|
|
}
|
|
|
|
# Verify script is running with root privileges
|
|
check_permissions() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
error "This script must be run as root! Login as root, or use sudo."
|
|
fi
|
|
}
|
|
|
|
# Configure system swappiness (how aggressively to use swap)
|
|
setup_swappiness() {
|
|
local sysconf="/etc/sysctl.conf"
|
|
local procswap="/proc/sys/vm/swappiness"
|
|
|
|
log "Configuring swappiness to $SWAPPINESS_VALUE"
|
|
|
|
# If no swappiness setting exists, add it
|
|
if ! grep -q "vm.swappiness" "$sysconf"; then
|
|
echo "$SWAPPINESS_VALUE" > "$procswap"
|
|
echo "vm.swappiness = $SWAPPINESS_VALUE" >> "$sysconf"
|
|
# If setting exists but with different value, update it
|
|
elif ! grep -q "vm.swappiness = $SWAPPINESS_VALUE" "$sysconf"; then
|
|
sed -i "/vm.swappiness/d" "$sysconf"
|
|
echo "$SWAPPINESS_VALUE" > "$procswap"
|
|
echo "vm.swappiness = $SWAPPINESS_VALUE" >> "$sysconf"
|
|
fi
|
|
}
|
|
|
|
# Set up automated cache clearing cron job (every 5 minutes)
|
|
setup_cache_clearing() {
|
|
local os="$1"
|
|
local ctab
|
|
|
|
# Different crontab locations for different distributions
|
|
if [[ "$os" == "ubuntu" ]]; then
|
|
ctab="/var/spool/cron/crontabs/root"
|
|
else
|
|
ctab="/var/spool/cron/root"
|
|
fi
|
|
|
|
log "Setting up cache clearing cron job"
|
|
|
|
# Remove any existing cache clearing jobs that use 'echo 3' (more aggressive)
|
|
if crontab -l 2>/dev/null | grep -q '/usr/bin/sync; echo 3'; then
|
|
sed -i "/\/usr\/bin\/sync.*echo 3/d" "$ctab" 2>/dev/null || true
|
|
fi
|
|
|
|
# Add cache clearing job if it doesn't exist (echo 1 = page cache only)
|
|
if ! crontab -l 2>/dev/null | grep -q '/usr/bin/sync; echo 1'; then
|
|
(crontab -u root -l 2>/dev/null; echo "*/5 * * * * /usr/bin/sync; echo 1 > /proc/sys/vm/drop_caches") | crontab -u root -
|
|
fi
|
|
}
|
|
|
|
# Remove existing swap file and clean up fstab entries
|
|
remove_swap() {
|
|
local backup_time
|
|
|
|
# Create timestamp for backup file
|
|
backup_time=$(date +%y-%m-%d--%H-%M-%S)
|
|
|
|
log "Removing existing swap file: $SWAPFILE_PATH"
|
|
|
|
# Disable swap file (ignore errors if already disabled)
|
|
swapoff "$SWAPFILE_PATH" 2>/dev/null || true
|
|
|
|
# Backup fstab before modifying
|
|
cp /etc/fstab "/etc/fstab.$backup_time"
|
|
|
|
# Remove swap entries from fstab
|
|
sed -i "\|${SWAPFILE_PATH}|d" /etc/fstab
|
|
|
|
# Delete the swap file
|
|
rm -f "$SWAPFILE_PATH"
|
|
}
|
|
|
|
# Create and configure a new swap file
|
|
create_swap() {
|
|
local swap_mb="$1"
|
|
|
|
if [[ "$swap_mb" -eq 0 ]]; then
|
|
error "Cannot create swap: swap size cannot be 0 MB"
|
|
fi
|
|
|
|
log "Creating swap file of size ${swap_mb}MB at $SWAPFILE_PATH"
|
|
|
|
# Set trap to clean up partial swap file on failure
|
|
trap cleanup_on_error ERR
|
|
|
|
# Create swap file using dd with progress display (oflag=direct avoids polluting page cache)
|
|
dd if=/dev/zero of="$SWAPFILE_PATH" bs=1M count="$swap_mb" oflag=direct status=progress
|
|
|
|
# Set proper permissions (only root can read/write)
|
|
chmod 600 "$SWAPFILE_PATH"
|
|
|
|
# Format the file as swap space
|
|
mkswap "$SWAPFILE_PATH"
|
|
|
|
# Enable the swap file
|
|
swapon "$SWAPFILE_PATH"
|
|
|
|
# Add to fstab for persistent mounting if not already present
|
|
if ! grep -q "$SWAPFILE_PATH" /etc/fstab; then
|
|
echo "$SWAPFILE_PATH swap swap defaults 0 0" >> /etc/fstab
|
|
fi
|
|
|
|
# Clear the error trap now that swap is fully created
|
|
trap - ERR
|
|
|
|
log "Swap file created and enabled successfully"
|
|
}
|
|
|
|
# Main function - orchestrates the entire swap setup process
|
|
main() {
|
|
# Handle --help flag
|
|
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
usage
|
|
fi
|
|
|
|
# Ensure script is run with root privileges
|
|
check_permissions
|
|
|
|
# Detect operating system for distribution-specific configurations
|
|
local os
|
|
os=$(detect_os)
|
|
|
|
# Get system memory information
|
|
local mem_gb
|
|
mem_gb=$(get_memory_gb)
|
|
|
|
# Calculate required swap size
|
|
local needed_mb
|
|
needed_mb=$(get_swap_needed_mb "$mem_gb")
|
|
|
|
# Check current swap configuration
|
|
local current_size
|
|
current_size=$(get_current_swap_size)
|
|
|
|
# Configure system settings
|
|
setup_swappiness
|
|
setup_cache_clearing "$os"
|
|
|
|
# If swap file exists at the correct size and is active, nothing to do
|
|
if [[ "$current_size" -eq "$needed_mb" ]] && is_swap_active; then
|
|
log "Swap size is already correct and active"
|
|
log "Swap setup completed successfully"
|
|
return 0
|
|
fi
|
|
|
|
# If swap file exists but wrong size, remove first so disk space check is accurate
|
|
if [[ "$current_size" -ne 0 && "$needed_mb" -ne "$current_size" ]]; then
|
|
remove_swap
|
|
fi
|
|
|
|
# Verify system has enough disk space (after potential removal)
|
|
if [[ "$needed_mb" -ne "$current_size" ]]; then
|
|
check_disk_space "$needed_mb"
|
|
create_swap "$needed_mb"
|
|
else
|
|
# File is the right size but not active, re-enable it
|
|
log "Swap file exists at correct size but is not active, enabling"
|
|
chmod 600 "$SWAPFILE_PATH"
|
|
mkswap "$SWAPFILE_PATH"
|
|
swapon "$SWAPFILE_PATH"
|
|
if ! grep -q "$SWAPFILE_PATH" /etc/fstab; then
|
|
echo "$SWAPFILE_PATH swap swap defaults 0 0" >> /etc/fstab
|
|
fi
|
|
fi
|
|
|
|
log "Swap setup completed successfully"
|
|
}
|
|
|
|
# Execute main function with all script arguments
|
|
main "$@"
|