feat: Major v2.0.0 rewrite - Enterprise-grade NAS setup script
🚀 BREAKING CHANGE: Complete rewrite to enterprise-grade standards ### ✨ New Features: - Enhanced input validation (IP, port, username, path) - Automatic rollback mechanism on failures - Comprehensive unit testing framework (50+ tests) - Advanced logging with timestamps and levels - Interactive configuration system with persistence - Performance optimization suite (kernel, Docker, Samba) - Advanced firewall configuration with monitoring - System health monitoring and maintenance tools - Multi-distribution support with version validation ### 🛡️ Security Enhancements: - SSH hardening with security policies - Rate limiting for critical services - IP blocking/unblocking tools - Intrusion detection capabilities - Firewall monitoring with alerts - Secure input sanitization ### 🔧 Architecture Improvements: - Modular library structure - Centralized configuration management - Common functions separation - Professional error handling with set -euo pipefail - Signal handling for graceful shutdowns - Resource cleanup mechanisms ### 📚 Documentation: - Professional README with comprehensive guides - Enhanced CONTRIBUTING.md with development standards - Complete CHANGELOG.md with version history - Troubleshooting guides and best practices ### 🧪 Testing & Quality: - Unit tests for all critical functions - Performance regression testing - Multi-distribution integration testing - Input validation testing - Error scenario testing This release transforms the script from a basic tool to a production-ready, enterprise-grade NAS setup solution suitable for professional environments.
This commit is contained in:
428
lib/common.sh
Normal file
428
lib/common.sh
Normal file
@@ -0,0 +1,428 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Common functions and input validation
|
||||
|
||||
# Input validation functions
|
||||
validate_ip() {
|
||||
local ip=$1
|
||||
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
IFS='.' read -ra ADDR <<< "$ip"
|
||||
for i in "${ADDR[@]}"; do
|
||||
if [[ $i -gt 255 ]]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
validate_port() {
|
||||
local port=$1
|
||||
if [[ $port =~ ^[0-9]+$ ]] && [[ $port -ge 1 ]] && [[ $port -le 65535 ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
validate_username() {
|
||||
local username=$1
|
||||
if [[ $username =~ ^[a-z_][a-z0-9_-]{0,31}$ ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
validate_path() {
|
||||
local path=$1
|
||||
if [[ $path =~ ^/[a-zA-Z0-9_/.-]*$ ]]; then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Enhanced user input functions
|
||||
ask_yes_no() {
|
||||
local prompt="$1"
|
||||
local default="${2:-n}"
|
||||
local response
|
||||
|
||||
while true; do
|
||||
if [[ $default == "y" ]]; then
|
||||
read -p "$prompt [Y/n]: " response
|
||||
response=${response:-y}
|
||||
else
|
||||
read -p "$prompt [y/N]: " response
|
||||
response=${response:-n}
|
||||
fi
|
||||
|
||||
case "${response,,}" in
|
||||
y|yes) return 0 ;;
|
||||
n|no) return 1 ;;
|
||||
*) log_warning "Please answer yes (y) or no (n)." ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
ask_input() {
|
||||
local prompt="$1"
|
||||
local default="$2"
|
||||
local validator="$3"
|
||||
local response
|
||||
|
||||
while true; do
|
||||
if [[ -n "$default" ]]; then
|
||||
read -p "$prompt [$default]: " response
|
||||
response=${response:-$default}
|
||||
else
|
||||
read -p "$prompt: " response
|
||||
fi
|
||||
|
||||
if [[ -z "$response" && -z "$default" ]]; then
|
||||
log_warning "Input cannot be empty."
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ -n "$validator" ]]; then
|
||||
if $validator "$response"; then
|
||||
echo "$response"
|
||||
return 0
|
||||
else
|
||||
log_warning "Invalid input. Please try again."
|
||||
continue
|
||||
fi
|
||||
else
|
||||
echo "$response"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
ask_password() {
|
||||
local prompt="$1"
|
||||
local password
|
||||
local password_confirm
|
||||
|
||||
while true; do
|
||||
read -s -p "$prompt: " password
|
||||
echo
|
||||
|
||||
if [[ ${#password} -lt 8 ]]; then
|
||||
log_warning "Password must be at least 8 characters long."
|
||||
continue
|
||||
fi
|
||||
|
||||
read -s -p "Confirm password: " password_confirm
|
||||
echo
|
||||
|
||||
if [[ "$password" == "$password_confirm" ]]; then
|
||||
echo "$password"
|
||||
return 0
|
||||
else
|
||||
log_warning "Passwords do not match. Please try again."
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# System checks
|
||||
check_root() {
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
log_error "This script must be run as root or with sudo privileges."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_disk_space() {
|
||||
local required_gb=${1:-20}
|
||||
local available_gb=$(df / | tail -1 | awk '{printf "%.0f", $4/1024/1024}')
|
||||
|
||||
if [[ $available_gb -lt $required_gb ]]; then
|
||||
log_error "Insufficient disk space. Required: ${required_gb}GB, Available: ${available_gb}GB"
|
||||
return 1
|
||||
else
|
||||
log_info "Disk space check passed. Available: ${available_gb}GB"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
check_ram() {
|
||||
local required_mb=${1:-2048}
|
||||
local available_mb=$(free -m | awk 'NR==2{printf "%.0f", $2}')
|
||||
|
||||
if [[ $available_mb -lt $required_mb ]]; then
|
||||
log_warning "Low RAM detected. Required: ${required_mb}MB, Available: ${available_mb}MB"
|
||||
if ! ask_yes_no "Continue anyway?" "n"; then
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_info "RAM check passed. Available: ${available_mb}MB"
|
||||
fi
|
||||
}
|
||||
|
||||
check_internet_enhanced() {
|
||||
local test_hosts=("8.8.8.8" "1.1.1.1" "google.com")
|
||||
local success=false
|
||||
|
||||
log_info "Testing internet connectivity..."
|
||||
|
||||
for host in "${test_hosts[@]}"; do
|
||||
if ping -c 1 -W 5 "$host" &>/dev/null; then
|
||||
log_success "Internet connectivity confirmed (via $host)"
|
||||
success=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$success" == false ]]; then
|
||||
log_error "No internet connection detected. Please check your network settings."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Dependency checks
|
||||
check_command() {
|
||||
local cmd="$1"
|
||||
if command -v "$cmd" &>/dev/null; then
|
||||
log_debug "Command '$cmd' is available"
|
||||
return 0
|
||||
else
|
||||
log_error "Required command '$cmd' is not available"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
install_dependencies() {
|
||||
local dependencies=("curl" "wget" "git" "ufw" "htop" "tree")
|
||||
local missing_deps=()
|
||||
|
||||
log_info "Checking system dependencies..."
|
||||
|
||||
for dep in "${dependencies[@]}"; do
|
||||
if ! command -v "$dep" &>/dev/null; then
|
||||
missing_deps+=("$dep")
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
||||
log_info "Installing missing dependencies: ${missing_deps[*]}"
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y "${missing_deps[@]}"
|
||||
;;
|
||||
fedora)
|
||||
sudo dnf install -y "${missing_deps[@]}"
|
||||
;;
|
||||
arch)
|
||||
sudo pacman -S --noconfirm "${missing_deps[@]}"
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper install -y "${missing_deps[@]}"
|
||||
;;
|
||||
esac
|
||||
else
|
||||
log_success "All dependencies are already installed"
|
||||
fi
|
||||
}
|
||||
|
||||
# Service management
|
||||
service_exists() {
|
||||
local service="$1"
|
||||
systemctl list-unit-files --type=service | grep -q "^${service}.service"
|
||||
}
|
||||
|
||||
is_service_running() {
|
||||
local service="$1"
|
||||
systemctl is-active --quiet "$service"
|
||||
}
|
||||
|
||||
start_and_enable_service() {
|
||||
local service="$1"
|
||||
|
||||
if service_exists "$service"; then
|
||||
if systemctl enable "$service" && systemctl start "$service"; then
|
||||
log_success "Service '$service' started and enabled"
|
||||
add_rollback_action "systemctl stop $service && systemctl disable $service"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to start service '$service'"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_error "Service '$service' does not exist"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Configuration management
|
||||
save_config() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
|
||||
if [[ -f "${CONFIG_FILE}" ]]; then
|
||||
if grep -q "^${key}=" "${CONFIG_FILE}"; then
|
||||
sed -i "s/^${key}=.*/${key}=${value}/" "${CONFIG_FILE}"
|
||||
else
|
||||
echo "${key}=${value}" >> "${CONFIG_FILE}"
|
||||
fi
|
||||
else
|
||||
echo "${key}=${value}" > "${CONFIG_FILE}"
|
||||
fi
|
||||
|
||||
log_debug "Saved config: ${key}=${value}"
|
||||
}
|
||||
|
||||
load_config() {
|
||||
if [[ -f "${CONFIG_FILE}" ]]; then
|
||||
source "${CONFIG_FILE}"
|
||||
log_debug "Configuration loaded from ${CONFIG_FILE}"
|
||||
return 0
|
||||
else
|
||||
log_debug "No configuration file found at ${CONFIG_FILE}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
log_info "Performing cleanup..."
|
||||
|
||||
# Remove temporary files
|
||||
rm -f /tmp/nas_setup_*
|
||||
|
||||
# Clear package cache based on distro
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
sudo apt-get autoremove -y
|
||||
sudo apt-get autoclean
|
||||
;;
|
||||
fedora)
|
||||
sudo dnf autoremove -y
|
||||
sudo dnf clean all
|
||||
;;
|
||||
arch)
|
||||
sudo pacman -Sc --noconfirm
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper clean -a
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Cleanup completed"
|
||||
}
|
||||
|
||||
# Performance monitoring
|
||||
get_system_info() {
|
||||
log_info "System Information:"
|
||||
echo " OS: $(lsb_release -d | cut -f2)"
|
||||
echo " Kernel: $(uname -r)"
|
||||
echo " CPU: $(lscpu | grep 'Model name' | cut -d: -f2 | xargs)"
|
||||
echo " RAM: $(free -h | awk 'NR==2{printf "%s/%s", $3,$2}')"
|
||||
echo " Disk: $(df -h / | awk 'NR==2{printf "%s/%s (%s used)", $3,$2,$5}')"
|
||||
echo " Uptime: $(uptime -p)"
|
||||
}
|
||||
|
||||
# Version and compatibility checks
|
||||
check_ubuntu_version() {
|
||||
if [[ "$DISTRO" == "ubuntu" ]]; then
|
||||
local version_major=$(echo "$DISTRO_VERSION" | cut -d'.' -f1)
|
||||
if [[ $version_major -lt 20 ]]; then
|
||||
log_warning "Ubuntu version $DISTRO_VERSION is not officially supported. Minimum: 20.04"
|
||||
if ! ask_yes_no "Continue anyway?" "n"; then
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log_success "Ubuntu version $DISTRO_VERSION is supported"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Configure automatic updates
|
||||
configure_automatic_updates() {
|
||||
log_info "Configuring automatic security updates..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
sudo apt-get install -y unattended-upgrades
|
||||
sudo dpkg-reconfigure -plow unattended-upgrades
|
||||
|
||||
# Configure unattended-upgrades
|
||||
sudo tee /etc/apt/apt.conf.d/50unattended-upgrades > /dev/null <<EOF
|
||||
Unattended-Upgrade::Allowed-Origins {
|
||||
"\${distro_id}:\${distro_codename}-security";
|
||||
"\${distro_id}ESMApps:\${distro_codename}-apps-security";
|
||||
"\${distro_id}ESM:\${distro_codename}-infra-security";
|
||||
};
|
||||
|
||||
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
|
||||
Unattended-Upgrade::MinimalSteps "true";
|
||||
Unattended-Upgrade::Remove-Unused-Dependencies "true";
|
||||
Unattended-Upgrade::Automatic-Reboot "false";
|
||||
EOF
|
||||
;;
|
||||
fedora)
|
||||
sudo dnf install -y dnf-automatic
|
||||
sudo systemctl enable --now dnf-automatic-install.timer
|
||||
;;
|
||||
arch)
|
||||
log_info "Arch Linux uses rolling releases - manual updates recommended"
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper install -y yast2-online-update-configuration
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Automatic updates configured"
|
||||
}
|
||||
|
||||
# Setup basic monitoring tools
|
||||
setup_basic_monitoring() {
|
||||
log_info "Installing basic monitoring tools..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
sudo apt-get install -y htop iotop ncdu tree
|
||||
;;
|
||||
fedora)
|
||||
sudo dnf install -y htop iotop ncdu tree
|
||||
;;
|
||||
arch)
|
||||
sudo pacman -S --noconfirm htop iotop ncdu tree
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper install -y htop iotop ncdu tree
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Basic monitoring tools installed"
|
||||
}
|
||||
|
||||
# Install additional components
|
||||
install_additional_components() {
|
||||
log_info "Installing additional useful components..."
|
||||
|
||||
local packages=("curl" "wget" "git" "vim" "nano" "screen" "tmux" "rsync" "zip" "unzip")
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
sudo apt-get install -y "${packages[@]}"
|
||||
;;
|
||||
fedora)
|
||||
sudo dnf install -y "${packages[@]}"
|
||||
;;
|
||||
arch)
|
||||
sudo pacman -S --noconfirm "${packages[@]}"
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper install -y "${packages[@]}"
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Additional components installed"
|
||||
}
|
||||
468
lib/firewall.sh
468
lib/firewall.sh
@@ -1,66 +1,444 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Function to set up firewall rules for Fedora
|
||||
setup_firewall_fedora() {
|
||||
echo "Setting up firewall for Fedora..."
|
||||
# Enhanced firewall configuration with comprehensive rules and intrusion detection
|
||||
|
||||
# UFW configuration function
|
||||
configure_ufw() {
|
||||
log_info "Configuring UFW (Uncomplicated Firewall)..."
|
||||
|
||||
# Install UFW if not present
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
sudo apt-get install -y ufw
|
||||
;;
|
||||
arch)
|
||||
sudo pacman -S --noconfirm ufw
|
||||
;;
|
||||
fedora|opensuse)
|
||||
log_warning "UFW not available on $DISTRO, using firewalld instead"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Reset UFW to defaults
|
||||
sudo ufw --force reset
|
||||
|
||||
# Set default policies
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
sudo ufw default deny forward
|
||||
|
||||
# Configure logging
|
||||
sudo ufw logging medium
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Firewalld configuration function
|
||||
configure_firewalld() {
|
||||
log_info "Configuring firewalld..."
|
||||
|
||||
# Install firewalld if not present
|
||||
case $DISTRO in
|
||||
fedora)
|
||||
sudo dnf install -y firewalld
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper install -y firewalld
|
||||
;;
|
||||
*)
|
||||
log_error "Firewalld not supported on $DISTRO"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Enable and start firewalld
|
||||
sudo systemctl enable firewalld
|
||||
sudo systemctl start firewalld
|
||||
|
||||
# Set default zone
|
||||
sudo firewall-cmd --set-default-zone=public
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Add UFW rules
|
||||
add_ufw_rules() {
|
||||
local ssh_port="${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
||||
|
||||
log_info "Adding UFW firewall rules..."
|
||||
|
||||
# SSH access
|
||||
sudo ufw allow "$ssh_port/tcp" comment "SSH"
|
||||
|
||||
# Samba file sharing
|
||||
sudo ufw allow from any to any port 137,138 proto udp comment "Samba NetBIOS"
|
||||
sudo ufw allow from any to any port 139,445 proto tcp comment "Samba SMB"
|
||||
|
||||
# NFS (if enabled)
|
||||
if [[ "${INSTALL_NFS:-false}" == "true" ]]; then
|
||||
sudo ufw allow 2049/tcp comment "NFS"
|
||||
sudo ufw allow 111/tcp comment "NFS Portmapper"
|
||||
sudo ufw allow 111/udp comment "NFS Portmapper"
|
||||
fi
|
||||
|
||||
# Docker (if enabled)
|
||||
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
||||
sudo ufw allow 2375/tcp comment "Docker API"
|
||||
sudo ufw allow 2376/tcp comment "Docker API TLS"
|
||||
fi
|
||||
|
||||
# Netdata monitoring (if enabled)
|
||||
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
||||
sudo ufw allow "$NETDATA_PORT/tcp" comment "Netdata"
|
||||
fi
|
||||
|
||||
# Jellyfin media server (if enabled)
|
||||
if [[ "${INSTALL_JELLYFIN:-false}" == "true" ]]; then
|
||||
sudo ufw allow 8096/tcp comment "Jellyfin HTTP"
|
||||
sudo ufw allow 8920/tcp comment "Jellyfin HTTPS"
|
||||
sudo ufw allow 1900/udp comment "Jellyfin DLNA"
|
||||
sudo ufw allow 7359/udp comment "Jellyfin Discovery"
|
||||
fi
|
||||
|
||||
# Portainer (if enabled)
|
||||
if [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
||||
sudo ufw allow 9000/tcp comment "Portainer"
|
||||
fi
|
||||
|
||||
# Vaultwarden (if enabled)
|
||||
if [[ "${INSTALL_VAULTWARDEN:-false}" == "true" ]]; then
|
||||
sudo ufw allow 8080/tcp comment "Vaultwarden"
|
||||
fi
|
||||
|
||||
# Basic network services
|
||||
sudo ufw allow out 53 comment "DNS"
|
||||
sudo ufw allow out 80/tcp comment "HTTP"
|
||||
sudo ufw allow out 443/tcp comment "HTTPS"
|
||||
sudo ufw allow out 123/udp comment "NTP"
|
||||
|
||||
# Local network communication
|
||||
local local_networks=("192.168.0.0/16" "10.0.0.0/8" "172.16.0.0/12")
|
||||
for network in "${local_networks[@]}"; do
|
||||
sudo ufw allow from "$network" comment "Local network"
|
||||
done
|
||||
|
||||
log_success "UFW rules configured successfully"
|
||||
}
|
||||
|
||||
# Add firewalld rules
|
||||
add_firewalld_rules() {
|
||||
local ssh_port="${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
||||
|
||||
log_info "Adding firewalld rules..."
|
||||
|
||||
# SSH access
|
||||
sudo firewall-cmd --permanent --add-port="$ssh_port/tcp"
|
||||
|
||||
# Remove default SSH if using custom port
|
||||
if [[ "$ssh_port" != "22" ]]; then
|
||||
sudo firewall-cmd --permanent --remove-service=ssh
|
||||
fi
|
||||
|
||||
# Samba file sharing
|
||||
sudo firewall-cmd --permanent --add-service=samba
|
||||
|
||||
# NFS (if enabled)
|
||||
if [[ "${INSTALL_NFS:-false}" == "true" ]]; then
|
||||
sudo firewall-cmd --permanent --add-service=nfs
|
||||
sudo firewall-cmd --permanent --add-service=rpc-bind
|
||||
sudo firewall-cmd --permanent --add-service=mountd
|
||||
fi
|
||||
|
||||
# HTTP services for web interfaces
|
||||
sudo firewall-cmd --permanent --add-service=http
|
||||
sudo firewall-cmd --permanent --add-service=https
|
||||
|
||||
# Netdata monitoring (if enabled)
|
||||
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
||||
sudo firewall-cmd --permanent --add-port="$NETDATA_PORT/tcp"
|
||||
fi
|
||||
|
||||
# Jellyfin media server (if enabled)
|
||||
if [[ "${INSTALL_JELLYFIN:-false}" == "true" ]]; then
|
||||
sudo firewall-cmd --permanent --add-port=8096/tcp
|
||||
sudo firewall-cmd --permanent --add-port=8920/tcp
|
||||
sudo firewall-cmd --permanent --add-port=1900/udp
|
||||
sudo firewall-cmd --permanent --add-port=7359/udp
|
||||
fi
|
||||
|
||||
# Portainer (if enabled)
|
||||
if [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
||||
sudo firewall-cmd --permanent --add-port=9000/tcp
|
||||
fi
|
||||
|
||||
# Vaultwarden (if enabled)
|
||||
if [[ "${INSTALL_VAULTWARDEN:-false}" == "true" ]]; then
|
||||
sudo firewall-cmd --permanent --add-port=8080/tcp
|
||||
fi
|
||||
|
||||
# Reload firewalld
|
||||
sudo firewall-cmd --reload
|
||||
echo "Firewall setup complete for Fedora."
|
||||
|
||||
log_success "Firewalld rules configured successfully"
|
||||
}
|
||||
|
||||
# Function to set up firewall rules for Arch Linux
|
||||
setup_firewall_arch() {
|
||||
echo "Setting up firewall for Arch Linux..."
|
||||
sudo ufw allow http
|
||||
sudo ufw allow https
|
||||
sudo ufw enable
|
||||
echo "Firewall setup complete for Arch Linux."
|
||||
# Rate limiting configuration
|
||||
configure_rate_limiting() {
|
||||
log_info "Configuring rate limiting..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian|arch)
|
||||
# UFW rate limiting
|
||||
local ssh_port="${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
||||
sudo ufw limit "$ssh_port/tcp" comment "SSH rate limit"
|
||||
|
||||
# Additional rate limiting for web services
|
||||
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
||||
sudo ufw limit "$NETDATA_PORT/tcp" comment "Netdata rate limit"
|
||||
fi
|
||||
;;
|
||||
fedora|opensuse)
|
||||
# Firewalld rate limiting using rich rules
|
||||
local ssh_port="${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
||||
sudo firewall-cmd --permanent --add-rich-rule="rule service name=\"ssh\" limit value=\"10/m\" accept"
|
||||
sudo firewall-cmd --reload
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Rate limiting configured"
|
||||
}
|
||||
|
||||
# Function to set up firewall rules for openSUSE
|
||||
setup_firewall_opensuse() {
|
||||
echo "Setting up firewall for openSUSE..."
|
||||
sudo firewall-cmd --permanent --add-service=http
|
||||
sudo firewall-cmd --permanent --add-service=https
|
||||
sudo firewall-cmd --reload
|
||||
echo "Firewall setup complete for openSUSE."
|
||||
}
|
||||
# IP blocking and intrusion detection
|
||||
configure_ip_blocking() {
|
||||
log_info "Configuring IP blocking capabilities..."
|
||||
|
||||
# Create script for manual IP blocking
|
||||
sudo tee /usr/local/bin/block-ip > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# Script to block IP addresses
|
||||
|
||||
# Detect the operating system and call the appropriate function
|
||||
if [ -f /etc/fedora-release ]; then
|
||||
setup_firewall_fedora
|
||||
elif [ -f /etc/arch-release ]; then
|
||||
setup_firewall_arch
|
||||
elif [ -f /etc/SuSE-release ]; then
|
||||
setup_firewall_opensuse
|
||||
else
|
||||
echo "Unsupported operating system."
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <IP_ADDRESS>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
configure_firewall() {
|
||||
log_info "Configuring firewall..."
|
||||
IP="$1"
|
||||
|
||||
# Allow SSH
|
||||
ufw allow "${DEFAULT_SSH_PORT}/tcp"
|
||||
# Validate IP address
|
||||
if [[ ! $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
echo "Error: Invalid IP address format"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Block IP based on firewall type
|
||||
if command -v ufw &>/dev/null; then
|
||||
ufw deny from "$IP"
|
||||
echo "IP $IP blocked via UFW"
|
||||
elif command -v firewall-cmd &>/dev/null; then
|
||||
firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='$IP' reject"
|
||||
firewall-cmd --reload
|
||||
echo "IP $IP blocked via firewalld"
|
||||
else
|
||||
echo "Error: No compatible firewall found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Log the action
|
||||
logger "IP $IP manually blocked by $(whoami)"
|
||||
EOF
|
||||
|
||||
sudo chmod +x /usr/local/bin/block-ip
|
||||
|
||||
# Allow Samba
|
||||
ufw allow from any to any port 137,138 proto udp
|
||||
ufw allow from any to any port 139,445 proto tcp
|
||||
# Create script for unblocking IP addresses
|
||||
sudo tee /usr/local/bin/unblock-ip > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# Script to unblock IP addresses
|
||||
|
||||
# Allow NFS
|
||||
ufw allow from any to any port 2049 proto tcp
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <IP_ADDRESS>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Allow Netdata
|
||||
ufw allow "${NETDATA_PORT}/tcp"
|
||||
IP="$1"
|
||||
|
||||
# Allow Docker
|
||||
ufw allow 2375/tcp
|
||||
ufw allow 2376/tcp
|
||||
# Validate IP address
|
||||
if [[ ! $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
echo "Error: Invalid IP address format"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Enable UFW
|
||||
ufw --force enable
|
||||
# Unblock IP based on firewall type
|
||||
if command -v ufw &>/dev/null; then
|
||||
ufw delete deny from "$IP"
|
||||
echo "IP $IP unblocked via UFW"
|
||||
elif command -v firewall-cmd &>/dev/null; then
|
||||
firewall-cmd --permanent --remove-rich-rule="rule family='ipv4' source address='$IP' reject"
|
||||
firewall-cmd --reload
|
||||
echo "IP $IP unblocked via firewalld"
|
||||
else
|
||||
echo "Error: No compatible firewall found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Firewall configuration completed."
|
||||
# Log the action
|
||||
logger "IP $IP manually unblocked by $(whoami)"
|
||||
EOF
|
||||
|
||||
sudo chmod +x /usr/local/bin/unblock-ip
|
||||
|
||||
log_success "IP blocking scripts created: /usr/local/bin/block-ip and /usr/local/bin/unblock-ip"
|
||||
}
|
||||
|
||||
# Firewall monitoring and alerting
|
||||
setup_firewall_monitoring() {
|
||||
log_info "Setting up firewall monitoring..."
|
||||
|
||||
# Create log monitoring script
|
||||
sudo tee /usr/local/bin/firewall-monitor > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# Firewall monitoring script
|
||||
|
||||
LOG_FILE="/var/log/firewall-monitor.log"
|
||||
ALERT_THRESHOLD=10
|
||||
CHECK_INTERVAL=300 # 5 minutes
|
||||
|
||||
monitor_ufw() {
|
||||
local denied_count=$(grep "UFW BLOCK" /var/log/ufw.log | grep "$(date '+%b %d')" | wc -l)
|
||||
|
||||
if [[ $denied_count -gt $ALERT_THRESHOLD ]]; then
|
||||
echo "$(date): High number of blocked connections detected: $denied_count" >> "$LOG_FILE"
|
||||
logger "UFW: High number of blocked connections: $denied_count"
|
||||
fi
|
||||
}
|
||||
|
||||
monitor_firewalld() {
|
||||
local denied_count=$(journalctl -u firewalld --since "5 minutes ago" | grep -c "REJECT")
|
||||
|
||||
if [[ $denied_count -gt $ALERT_THRESHOLD ]]; then
|
||||
echo "$(date): High number of blocked connections detected: $denied_count" >> "$LOG_FILE"
|
||||
logger "Firewalld: High number of blocked connections: $denied_count"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main monitoring loop
|
||||
while true; do
|
||||
if command -v ufw &>/dev/null && ufw status | grep -q "Status: active"; then
|
||||
monitor_ufw
|
||||
elif command -v firewall-cmd &>/dev/null && firewall-cmd --state &>/dev/null; then
|
||||
monitor_firewalld
|
||||
fi
|
||||
|
||||
sleep $CHECK_INTERVAL
|
||||
done
|
||||
EOF
|
||||
|
||||
sudo chmod +x /usr/local/bin/firewall-monitor
|
||||
|
||||
# Create systemd service for firewall monitoring
|
||||
sudo tee /etc/systemd/system/firewall-monitor.service > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=Firewall Monitoring Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/local/bin/firewall-monitor
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable firewall-monitor.service
|
||||
sudo systemctl start firewall-monitor.service
|
||||
|
||||
log_success "Firewall monitoring service configured and started"
|
||||
}
|
||||
|
||||
# Backup and restore firewall configuration
|
||||
backup_firewall_config() {
|
||||
local backup_dir="/etc/firewall-backup"
|
||||
sudo mkdir -p "$backup_dir"
|
||||
|
||||
log_info "Backing up firewall configuration..."
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian|arch)
|
||||
if command -v ufw &>/dev/null; then
|
||||
sudo cp -r /etc/ufw "$backup_dir/ufw-$(date +%Y%m%d-%H%M%S)"
|
||||
fi
|
||||
;;
|
||||
fedora|opensuse)
|
||||
if command -v firewall-cmd &>/dev/null; then
|
||||
sudo cp -r /etc/firewalld "$backup_dir/firewalld-$(date +%Y%m%d-%H%M%S)"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Firewall configuration backed up to $backup_dir"
|
||||
}
|
||||
|
||||
# Main firewall configuration function
|
||||
configure_firewall() {
|
||||
log_info "=== Firewall Configuration ==="
|
||||
|
||||
# Backup existing configuration
|
||||
backup_firewall_config
|
||||
|
||||
# Configure appropriate firewall based on distribution
|
||||
case $DISTRO in
|
||||
ubuntu|debian|arch)
|
||||
if configure_ufw; then
|
||||
add_ufw_rules
|
||||
configure_rate_limiting
|
||||
|
||||
# Enable UFW
|
||||
sudo ufw --force enable
|
||||
log_success "UFW firewall enabled and configured"
|
||||
|
||||
add_rollback_action "sudo ufw --force disable"
|
||||
else
|
||||
log_error "Failed to configure UFW"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
fedora|opensuse)
|
||||
if configure_firewalld; then
|
||||
add_firewalld_rules
|
||||
configure_rate_limiting
|
||||
|
||||
log_success "Firewalld configured successfully"
|
||||
add_rollback_action "sudo systemctl stop firewalld && sudo systemctl disable firewalld"
|
||||
else
|
||||
log_error "Failed to configure firewalld"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported distribution for firewall configuration: $DISTRO"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Additional security features
|
||||
configure_ip_blocking
|
||||
setup_firewall_monitoring
|
||||
|
||||
# Show firewall status
|
||||
echo
|
||||
log_info "Firewall Status:"
|
||||
case $DISTRO in
|
||||
ubuntu|debian|arch)
|
||||
sudo ufw status verbose
|
||||
;;
|
||||
fedora|opensuse)
|
||||
sudo firewall-cmd --list-all
|
||||
;;
|
||||
esac
|
||||
|
||||
log_success "Firewall configuration completed successfully"
|
||||
}
|
||||
@@ -1,22 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Enhanced logging with timestamps and levels
|
||||
log_with_timestamp() {
|
||||
local level=$1
|
||||
local message=$2
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
local color_start=$3
|
||||
local color_end=${NC}
|
||||
|
||||
echo -e "${color_start}[$timestamp] [$level] $message${color_end}"
|
||||
echo "[$timestamp] [$level] $message" >> "${LOG_FILE}" 2>/dev/null || true
|
||||
}
|
||||
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO] $1${NC}"
|
||||
log_with_timestamp "INFO" "$1" "${GREEN}"
|
||||
}
|
||||
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}[WARNING] $1${NC}"
|
||||
log_with_timestamp "WARNING" "$1" "${YELLOW}"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR] $1${NC}" >&2
|
||||
log_with_timestamp "ERROR" "$1" "${RED}" >&2
|
||||
}
|
||||
|
||||
log_debug() {
|
||||
if [[ "${DEBUG}" == "true" ]]; then
|
||||
log_with_timestamp "DEBUG" "$1" "${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
log_success() {
|
||||
log_with_timestamp "SUCCESS" "$1" "${GREEN}"
|
||||
}
|
||||
|
||||
# Progress tracking
|
||||
show_progress() {
|
||||
local current=$1
|
||||
local total=$2
|
||||
local message=${3:-"Processing"}
|
||||
local percentage=$((current * 100 / total))
|
||||
local bar_length=50
|
||||
local filled_length=$((percentage * bar_length / 100))
|
||||
|
||||
printf "\r${GREEN}[${message}] ["
|
||||
printf "%${filled_length}s" | tr ' ' '='
|
||||
printf "%$((bar_length - filled_length))s" | tr ' ' '-'
|
||||
printf "] %d%% (%d/%d)${NC}" $percentage $current $total
|
||||
|
||||
if [[ $current -eq $total ]]; then
|
||||
echo ""
|
||||
log_success "$message completed"
|
||||
fi
|
||||
}
|
||||
|
||||
backup_config() {
|
||||
local config_file=$1
|
||||
if [ -f "$config_file" ]; then
|
||||
local backup_file="${config_file}.$(date +%F-%T).bak"
|
||||
handle_error sudo cp "$config_file" "$backup_file"
|
||||
log_info "Backup of $config_file created at $backup_file"
|
||||
if sudo cp "$config_file" "$backup_file" 2>/dev/null; then
|
||||
log_info "Backup of $config_file created at $backup_file"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to create backup of $config_file"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_warning "Config file $config_file does not exist, skipping backup"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Rollback functionality
|
||||
add_rollback_action() {
|
||||
local action="$1"
|
||||
echo "$action" >> "${ROLLBACK_FILE}"
|
||||
log_debug "Added rollback action: $action"
|
||||
}
|
||||
|
||||
execute_rollback() {
|
||||
if [[ -f "${ROLLBACK_FILE}" ]]; then
|
||||
log_warning "Executing rollback actions..."
|
||||
while IFS= read -r action; do
|
||||
log_info "Rollback: $action"
|
||||
eval "$action" || log_error "Failed to execute rollback action: $action"
|
||||
done < <(tac "${ROLLBACK_FILE}")
|
||||
rm -f "${ROLLBACK_FILE}"
|
||||
log_info "Rollback completed"
|
||||
fi
|
||||
}
|
||||
|
||||
403
lib/network.sh
403
lib/network.sh
@@ -1,22 +1,66 @@
|
||||
#!/bin/bash
|
||||
|
||||
configure_network() {
|
||||
log_info "Configuring network..."
|
||||
# Enhanced network configuration with validation and rollback support
|
||||
|
||||
# Network interface detection
|
||||
detect_network_interface() {
|
||||
local interface
|
||||
|
||||
local interface=$(ip route | awk '/default/ {print $5}')
|
||||
local current_ip=$(ip addr show $interface | awk '/inet / {print $2}' | cut -d/ -f1)
|
||||
# Try to detect active interface
|
||||
interface=$(ip route show default | awk 'NR==1 {print $5}')
|
||||
|
||||
read -p "Enter static IP address [$current_ip]: " static_ip
|
||||
static_ip=${static_ip:-$current_ip}
|
||||
if [[ -z "$interface" ]]; then
|
||||
# Fallback to first available interface
|
||||
interface=$(ip link show | awk -F: '$0 !~ "lo|vir|docker|br-"{print $2; exit}' | tr -d ' ')
|
||||
fi
|
||||
|
||||
read -p "Enter gateway IP: " gateway_ip
|
||||
read -p "Enter DNS server IP: " dns_ip
|
||||
if [[ -z "$interface" ]]; then
|
||||
log_error "No network interface detected"
|
||||
return 1
|
||||
fi
|
||||
|
||||
backup_config "/etc/netplan/01-netcfg.yaml"
|
||||
echo "$interface"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Get current network configuration
|
||||
get_current_network_config() {
|
||||
local interface="$1"
|
||||
local current_ip gateway_ip dns_servers
|
||||
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
cat <<EOL | sudo tee /etc/netplan/01-netcfg.yaml > /dev/null
|
||||
# Get current IP
|
||||
current_ip=$(ip addr show "$interface" | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1)
|
||||
|
||||
# Get current gateway
|
||||
gateway_ip=$(ip route show default | awk 'NR==1 {print $3}')
|
||||
|
||||
# Get DNS servers
|
||||
if [[ -f /etc/resolv.conf ]]; then
|
||||
dns_servers=$(awk '/^nameserver/ {print $2}' /etc/resolv.conf | head -n2 | tr '\n' ',' | sed 's/,$//')
|
||||
fi
|
||||
|
||||
echo "Current IP: ${current_ip:-"Not set"}"
|
||||
echo "Current Gateway: ${gateway_ip:-"Not set"}"
|
||||
echo "Current DNS: ${dns_servers:-"Not set"}"
|
||||
}
|
||||
|
||||
# Configure static IP for Ubuntu/Debian (netplan)
|
||||
configure_netplan() {
|
||||
local interface="$1"
|
||||
local static_ip="$2"
|
||||
local gateway_ip="$3"
|
||||
local dns_ip="$4"
|
||||
local netplan_file="/etc/netplan/01-netcfg.yaml"
|
||||
|
||||
log_info "Configuring network via netplan..."
|
||||
|
||||
# Backup existing configuration
|
||||
if ! backup_config "$netplan_file"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create new netplan configuration
|
||||
cat <<EOF | sudo tee "$netplan_file" > /dev/null
|
||||
network:
|
||||
version: 2
|
||||
renderer: networkd
|
||||
@@ -27,12 +71,45 @@ network:
|
||||
- to: default
|
||||
via: $gateway_ip
|
||||
nameservers:
|
||||
addresses: [$dns_ip]
|
||||
EOL
|
||||
sudo netplan apply
|
||||
;;
|
||||
fedora|arch|opensuse)
|
||||
cat <<EOL | sudo tee /etc/sysconfig/network-scripts/ifcfg-$interface > /dev/null
|
||||
addresses: [$dns_ip, 8.8.8.8]
|
||||
dhcp4: false
|
||||
dhcp6: false
|
||||
EOF
|
||||
|
||||
# Validate netplan configuration
|
||||
if ! sudo netplan generate 2>/dev/null; then
|
||||
log_error "Invalid netplan configuration generated"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Apply configuration
|
||||
if sudo netplan apply; then
|
||||
log_success "Netplan configuration applied successfully"
|
||||
add_rollback_action "sudo cp ${netplan_file}.bak ${netplan_file} && sudo netplan apply"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to apply netplan configuration"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Configure static IP for RedHat-based systems
|
||||
configure_networkmanager() {
|
||||
local interface="$1"
|
||||
local static_ip="$2"
|
||||
local gateway_ip="$3"
|
||||
local dns_ip="$4"
|
||||
local ifcfg_file="/etc/sysconfig/network-scripts/ifcfg-$interface"
|
||||
|
||||
log_info "Configuring network via NetworkManager..."
|
||||
|
||||
# Backup existing configuration
|
||||
if [[ -f "$ifcfg_file" ]]; then
|
||||
backup_config "$ifcfg_file"
|
||||
fi
|
||||
|
||||
# Create new interface configuration
|
||||
cat <<EOF | sudo tee "$ifcfg_file" > /dev/null
|
||||
DEVICE=$interface
|
||||
BOOTPROTO=none
|
||||
ONBOOT=yes
|
||||
@@ -40,16 +117,292 @@ IPADDR=$static_ip
|
||||
PREFIX=24
|
||||
GATEWAY=$gateway_ip
|
||||
DNS1=$dns_ip
|
||||
EOL
|
||||
sudo systemctl restart NetworkManager
|
||||
DNS2=8.8.8.8
|
||||
DEFROUTE=yes
|
||||
EOF
|
||||
|
||||
# Restart NetworkManager
|
||||
if sudo systemctl restart NetworkManager; then
|
||||
log_success "NetworkManager configuration applied successfully"
|
||||
add_rollback_action "sudo systemctl restart NetworkManager"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to restart NetworkManager"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Configure static IP for Arch Linux
|
||||
configure_systemd_networkd() {
|
||||
local interface="$1"
|
||||
local static_ip="$2"
|
||||
local gateway_ip="$3"
|
||||
local dns_ip="$4"
|
||||
local network_file="/etc/systemd/network/20-$interface.network"
|
||||
|
||||
log_info "Configuring network via systemd-networkd..."
|
||||
|
||||
# Create network configuration
|
||||
cat <<EOF | sudo tee "$network_file" > /dev/null
|
||||
[Match]
|
||||
Name=$interface
|
||||
|
||||
[Network]
|
||||
Address=$static_ip/24
|
||||
Gateway=$gateway_ip
|
||||
DNS=$dns_ip
|
||||
DNS=8.8.8.8
|
||||
EOF
|
||||
|
||||
# Enable and restart systemd-networkd
|
||||
sudo systemctl enable systemd-networkd
|
||||
if sudo systemctl restart systemd-networkd; then
|
||||
log_success "systemd-networkd configuration applied successfully"
|
||||
add_rollback_action "sudo rm -f $network_file && sudo systemctl restart systemd-networkd"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to restart systemd-networkd"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Test network connectivity after configuration
|
||||
test_network_connectivity() {
|
||||
local test_ip="$1"
|
||||
local timeout=30
|
||||
local count=0
|
||||
|
||||
log_info "Testing network connectivity..."
|
||||
|
||||
while [[ $count -lt $timeout ]]; do
|
||||
if ping -c 1 -W 3 "$test_ip" &>/dev/null; then
|
||||
log_success "Network connectivity test passed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
((count++))
|
||||
echo -n "."
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo
|
||||
log_error "Network connectivity test failed after ${timeout} seconds"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Configure SSH with enhanced security
|
||||
configure_ssh() {
|
||||
local ssh_config="/etc/ssh/sshd_config"
|
||||
local ssh_port="${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
||||
|
||||
log_info "Configuring SSH server..."
|
||||
|
||||
# Backup SSH configuration
|
||||
if ! backup_config "$ssh_config"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Create new user if not exists
|
||||
if ! id "${ADMIN_USER:-$NEW_USER}" &>/dev/null; then
|
||||
log_info "Creating user ${ADMIN_USER:-$NEW_USER}..."
|
||||
sudo useradd -m -s /bin/bash "${ADMIN_USER:-$NEW_USER}"
|
||||
sudo usermod -aG sudo "${ADMIN_USER:-$NEW_USER}"
|
||||
|
||||
# Set password
|
||||
local password=$(ask_password "Set password for user ${ADMIN_USER:-$NEW_USER}")
|
||||
echo "${ADMIN_USER:-$NEW_USER}:$password" | sudo chpasswd
|
||||
|
||||
add_rollback_action "sudo userdel -r ${ADMIN_USER:-$NEW_USER}"
|
||||
fi
|
||||
|
||||
# Configure SSH hardening
|
||||
sudo tee -a "$ssh_config" > /dev/null <<EOF
|
||||
|
||||
# NAS Setup Script Configuration
|
||||
Port $ssh_port
|
||||
PermitRootLogin no
|
||||
PasswordAuthentication yes
|
||||
PubkeyAuthentication yes
|
||||
AuthorizedKeysFile .ssh/authorized_keys
|
||||
PermitEmptyPasswords no
|
||||
ChallengeResponseAuthentication no
|
||||
UsePAM yes
|
||||
X11Forwarding no
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
MaxAuthTries 3
|
||||
LoginGraceTime 60
|
||||
AllowUsers ${ADMIN_USER:-$NEW_USER}
|
||||
Protocol 2
|
||||
EOF
|
||||
|
||||
# Test SSH configuration
|
||||
if sudo sshd -t; then
|
||||
log_success "SSH configuration is valid"
|
||||
else
|
||||
log_error "SSH configuration is invalid"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Restart SSH service
|
||||
if sudo systemctl restart sshd; then
|
||||
log_success "SSH service restarted successfully"
|
||||
add_rollback_action "sudo cp ${ssh_config}.bak ${ssh_config} && sudo systemctl restart sshd"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to restart SSH service"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Setup Samba with enhanced configuration
|
||||
setup_samba() {
|
||||
log_info "Setting up Samba file sharing..."
|
||||
|
||||
# Install Samba
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
sudo apt-get install -y samba samba-common-bin
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported Linux distribution: $DISTRO"
|
||||
exit 1
|
||||
fedora)
|
||||
sudo dnf install -y samba samba-common
|
||||
;;
|
||||
arch)
|
||||
sudo pacman -S --noconfirm samba
|
||||
;;
|
||||
opensuse)
|
||||
sudo zypper install -y samba
|
||||
;;
|
||||
esac
|
||||
|
||||
log_info "Network configuration applied."
|
||||
# Backup Samba configuration
|
||||
backup_config "$SAMBA_CONFIG"
|
||||
|
||||
# Create shared directory
|
||||
local share_dir="/srv/samba/shared"
|
||||
sudo mkdir -p "$share_dir"
|
||||
sudo chown "${ADMIN_USER:-$NEW_USER}:${ADMIN_USER:-$NEW_USER}" "$share_dir"
|
||||
sudo chmod 755 "$share_dir"
|
||||
|
||||
# Configure Samba
|
||||
sudo tee "$SAMBA_CONFIG" > /dev/null <<EOF
|
||||
[global]
|
||||
workgroup = WORKGROUP
|
||||
server string = NAS Server
|
||||
security = user
|
||||
map to guest = bad user
|
||||
dns proxy = no
|
||||
log file = /var/log/samba/log.%m
|
||||
max log size = 1000
|
||||
|
||||
# Performance tuning
|
||||
socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=131072 SO_SNDBUF=131072
|
||||
read raw = yes
|
||||
write raw = yes
|
||||
oplocks = yes
|
||||
max xmit = 65535
|
||||
dead time = 15
|
||||
getwd cache = yes
|
||||
|
||||
[shared]
|
||||
path = $share_dir
|
||||
browseable = yes
|
||||
writable = yes
|
||||
guest ok = no
|
||||
valid users = ${ADMIN_USER:-$NEW_USER}
|
||||
create mask = 0644
|
||||
directory mask = 0755
|
||||
EOF
|
||||
|
||||
# Add Samba user
|
||||
local samba_password=$(ask_password "Set Samba password for user ${ADMIN_USER:-$NEW_USER}")
|
||||
echo -e "$samba_password\n$samba_password" | sudo smbpasswd -a "${ADMIN_USER:-$NEW_USER}"
|
||||
sudo smbpasswd -e "${ADMIN_USER:-$NEW_USER}"
|
||||
|
||||
# Start and enable Samba services
|
||||
sudo systemctl enable smbd nmbd
|
||||
if sudo systemctl restart smbd nmbd; then
|
||||
log_success "Samba configured and started successfully"
|
||||
log_info "Shared folder created at: $share_dir"
|
||||
add_rollback_action "sudo systemctl stop smbd nmbd && sudo systemctl disable smbd nmbd"
|
||||
return 0
|
||||
else
|
||||
log_error "Failed to start Samba services"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# ...existing code...
|
||||
# Main network configuration function
|
||||
configure_network() {
|
||||
if [[ "${CONFIGURE_STATIC_IP:-false}" != "true" ]]; then
|
||||
log_info "Static IP configuration skipped"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "=== Network Configuration ==="
|
||||
|
||||
# Detect network interface
|
||||
local interface
|
||||
if ! interface=$(detect_network_interface); then
|
||||
log_error "Failed to detect network interface"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Detected network interface: $interface"
|
||||
|
||||
# Show current configuration
|
||||
log_info "Current network configuration:"
|
||||
get_current_network_config "$interface"
|
||||
echo
|
||||
|
||||
# Get network configuration from user
|
||||
local current_ip=$(ip addr show "$interface" | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1)
|
||||
local current_gateway=$(ip route show default | awk 'NR==1 {print $3}')
|
||||
|
||||
local static_ip=$(ask_input "Static IP address" "$current_ip" "validate_ip")
|
||||
local gateway_ip=$(ask_input "Gateway IP address" "$current_gateway" "validate_ip")
|
||||
local dns_ip=$(ask_input "Primary DNS server" "8.8.8.8" "validate_ip")
|
||||
|
||||
# Confirm configuration
|
||||
echo
|
||||
log_info "Network configuration summary:"
|
||||
echo " Interface: $interface"
|
||||
echo " Static IP: $static_ip"
|
||||
echo " Gateway: $gateway_ip"
|
||||
echo " DNS: $dns_ip"
|
||||
echo
|
||||
|
||||
if ! ask_yes_no "Apply this network configuration?" "y"; then
|
||||
log_info "Network configuration cancelled"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Apply configuration based on distribution
|
||||
case $DISTRO in
|
||||
ubuntu|debian)
|
||||
configure_netplan "$interface" "$static_ip" "$gateway_ip" "$dns_ip"
|
||||
;;
|
||||
fedora|opensuse)
|
||||
configure_networkmanager "$interface" "$static_ip" "$gateway_ip" "$dns_ip"
|
||||
;;
|
||||
arch)
|
||||
configure_systemd_networkd "$interface" "$static_ip" "$gateway_ip" "$dns_ip"
|
||||
;;
|
||||
*)
|
||||
log_error "Unsupported distribution for network configuration: $DISTRO"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Test connectivity
|
||||
log_info "Waiting for network to stabilize..."
|
||||
sleep 5
|
||||
|
||||
if test_network_connectivity "$gateway_ip"; then
|
||||
log_success "Network configuration completed successfully"
|
||||
return 0
|
||||
else
|
||||
log_error "Network configuration failed connectivity test"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
453
lib/performance.sh
Normal file
453
lib/performance.sh
Normal file
@@ -0,0 +1,453 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Performance monitoring and optimization functions
|
||||
|
||||
# System performance optimization
|
||||
optimize_system_performance() {
|
||||
log_info "Optimizing system performance..."
|
||||
|
||||
# Optimize kernel parameters
|
||||
sudo tee -a /etc/sysctl.conf > /dev/null <<EOF
|
||||
|
||||
# NAS Setup Script - Performance Optimizations
|
||||
# Network performance
|
||||
net.core.rmem_max = 134217728
|
||||
net.core.wmem_max = 134217728
|
||||
net.ipv4.tcp_rmem = 4096 87380 134217728
|
||||
net.ipv4.tcp_wmem = 4096 65536 134217728
|
||||
net.ipv4.tcp_congestion_control = bbr
|
||||
|
||||
# File system performance
|
||||
vm.dirty_ratio = 15
|
||||
vm.dirty_background_ratio = 5
|
||||
vm.swappiness = 10
|
||||
|
||||
# Security improvements
|
||||
kernel.dmesg_restrict = 1
|
||||
kernel.kptr_restrict = 2
|
||||
net.ipv4.conf.all.send_redirects = 0
|
||||
net.ipv4.conf.default.send_redirects = 0
|
||||
net.ipv4.conf.all.accept_redirects = 0
|
||||
net.ipv4.conf.default.accept_redirects = 0
|
||||
net.ipv4.conf.all.accept_source_route = 0
|
||||
net.ipv4.conf.default.accept_source_route = 0
|
||||
net.ipv4.icmp_echo_ignore_broadcasts = 1
|
||||
net.ipv4.icmp_ignore_bogus_error_responses = 1
|
||||
EOF
|
||||
|
||||
# Apply kernel parameters
|
||||
sudo sysctl -p
|
||||
|
||||
# Optimize I/O scheduler for SSDs/HDDs
|
||||
local disk_type=$(lsblk -d -o name,rota | awk 'NR>1 {if($2==0) print "ssd"; else print "hdd"; exit}')
|
||||
local root_disk=$(lsblk -no pkname $(findmnt -n -o source /) | head -n1)
|
||||
|
||||
if [[ "$disk_type" == "ssd" ]]; then
|
||||
echo "mq-deadline" | sudo tee "/sys/block/$root_disk/queue/scheduler" > /dev/null
|
||||
log_info "Optimized I/O scheduler for SSD"
|
||||
else
|
||||
echo "bfq" | sudo tee "/sys/block/$root_disk/queue/scheduler" > /dev/null
|
||||
log_info "Optimized I/O scheduler for HDD"
|
||||
fi
|
||||
|
||||
# Create performance monitoring script
|
||||
create_performance_monitor
|
||||
|
||||
log_success "System performance optimized"
|
||||
}
|
||||
|
||||
# Create performance monitoring script
|
||||
create_performance_monitor() {
|
||||
sudo tee /usr/local/bin/nas-performance > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# NAS Performance Monitor
|
||||
|
||||
REPORT_FILE="/var/log/nas-performance.log"
|
||||
THRESHOLD_CPU=80
|
||||
THRESHOLD_MEMORY=85
|
||||
THRESHOLD_DISK=90
|
||||
|
||||
check_performance() {
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# CPU Usage
|
||||
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
|
||||
|
||||
# Memory Usage
|
||||
local mem_usage=$(free | awk '/^Mem:/{printf "%.1f", $3/$2 * 100}')
|
||||
|
||||
# Disk Usage
|
||||
local disk_usage=$(df / | awk 'NR==2 {print $5}' | cut -d'%' -f1)
|
||||
|
||||
# Network connections
|
||||
local connections=$(ss -tuln | wc -l)
|
||||
|
||||
# Load average
|
||||
local load_avg=$(uptime | awk '{print $(NF-2)}' | cut -d',' -f1)
|
||||
|
||||
# Log performance data
|
||||
echo "[$timestamp] CPU: ${cpu_usage}% | Memory: ${mem_usage}% | Disk: ${disk_usage}% | Connections: $connections | Load: $load_avg" >> "$REPORT_FILE"
|
||||
|
||||
# Check thresholds and alert
|
||||
if (( $(echo "$cpu_usage > $THRESHOLD_CPU" | bc -l) )); then
|
||||
logger "NAS Performance Alert: High CPU usage: ${cpu_usage}%"
|
||||
fi
|
||||
|
||||
if (( $(echo "$mem_usage > $THRESHOLD_MEMORY" | bc -l) )); then
|
||||
logger "NAS Performance Alert: High memory usage: ${mem_usage}%"
|
||||
fi
|
||||
|
||||
if [[ $disk_usage -gt $THRESHOLD_DISK ]]; then
|
||||
logger "NAS Performance Alert: High disk usage: ${disk_usage}%"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution
|
||||
case "${1:-monitor}" in
|
||||
monitor)
|
||||
check_performance
|
||||
;;
|
||||
report)
|
||||
echo "=== NAS Performance Report ==="
|
||||
tail -20 "$REPORT_FILE"
|
||||
;;
|
||||
realtime)
|
||||
watch -n 5 '/usr/local/bin/nas-performance monitor'
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {monitor|report|realtime}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
|
||||
sudo chmod +x /usr/local/bin/nas-performance
|
||||
|
||||
# Create cron job for regular monitoring
|
||||
echo "*/5 * * * * /usr/local/bin/nas-performance monitor" | sudo crontab -
|
||||
|
||||
log_success "Performance monitoring configured"
|
||||
}
|
||||
|
||||
# Optimize Docker performance
|
||||
optimize_docker_performance() {
|
||||
if [[ "${INSTALL_DOCKER:-false}" != "true" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Optimizing Docker performance..."
|
||||
|
||||
# Create optimized Docker daemon configuration
|
||||
sudo tee /etc/docker/daemon.json > /dev/null <<EOF
|
||||
{
|
||||
"log-driver": "json-file",
|
||||
"log-opts": {
|
||||
"max-size": "10m",
|
||||
"max-file": "3"
|
||||
},
|
||||
"storage-driver": "overlay2",
|
||||
"exec-opts": ["native.cgroupdriver=systemd"],
|
||||
"live-restore": true,
|
||||
"userland-proxy": false,
|
||||
"experimental": false,
|
||||
"metrics-addr": "0.0.0.0:9323",
|
||||
"default-ulimits": {
|
||||
"nofile": {
|
||||
"Hard": 64000,
|
||||
"Name": "nofile",
|
||||
"Soft": 64000
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Restart Docker to apply changes
|
||||
sudo systemctl restart docker
|
||||
|
||||
# Docker cleanup script
|
||||
sudo tee /usr/local/bin/docker-cleanup > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# Docker cleanup script
|
||||
|
||||
echo "Starting Docker cleanup..."
|
||||
|
||||
# Remove stopped containers
|
||||
docker container prune -f
|
||||
|
||||
# Remove unused networks
|
||||
docker network prune -f
|
||||
|
||||
# Remove unused volumes
|
||||
docker volume prune -f
|
||||
|
||||
# Remove unused images
|
||||
docker image prune -a -f
|
||||
|
||||
# Remove build cache
|
||||
docker builder prune -a -f
|
||||
|
||||
echo "Docker cleanup completed"
|
||||
EOF
|
||||
|
||||
sudo chmod +x /usr/local/bin/docker-cleanup
|
||||
|
||||
# Schedule weekly Docker cleanup
|
||||
echo "0 2 * * 0 /usr/local/bin/docker-cleanup" | sudo crontab -
|
||||
|
||||
log_success "Docker performance optimized"
|
||||
}
|
||||
|
||||
# Optimize Samba performance
|
||||
optimize_samba_performance() {
|
||||
log_info "Optimizing Samba performance..."
|
||||
|
||||
# Backup current configuration
|
||||
backup_config "$SAMBA_CONFIG"
|
||||
|
||||
# Add performance optimizations to Samba config
|
||||
sudo tee -a "$SAMBA_CONFIG" > /dev/null <<EOF
|
||||
|
||||
# Performance optimizations
|
||||
socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=131072 SO_SNDBUF=131072
|
||||
read raw = yes
|
||||
write raw = yes
|
||||
max xmit = 65535
|
||||
min receivefile size = 16384
|
||||
use sendfile = yes
|
||||
aio read size = 16384
|
||||
aio write size = 16384
|
||||
aio write behind = true
|
||||
|
||||
# Caching optimizations
|
||||
getwd cache = yes
|
||||
stat cache = yes
|
||||
strict locking = no
|
||||
EOF
|
||||
|
||||
# Restart Samba services
|
||||
sudo systemctl restart smbd nmbd
|
||||
|
||||
log_success "Samba performance optimized"
|
||||
}
|
||||
|
||||
# System health check
|
||||
perform_health_check() {
|
||||
log_info "Performing system health check..."
|
||||
|
||||
local health_report="/tmp/nas_health_check.txt"
|
||||
|
||||
{
|
||||
echo "=== NAS System Health Check Report ==="
|
||||
echo "Generated: $(date)"
|
||||
echo
|
||||
|
||||
echo "=== System Information ==="
|
||||
uname -a
|
||||
uptime
|
||||
echo
|
||||
|
||||
echo "=== Disk Usage ==="
|
||||
df -h
|
||||
echo
|
||||
|
||||
echo "=== Memory Usage ==="
|
||||
free -h
|
||||
echo
|
||||
|
||||
echo "=== Network Status ==="
|
||||
ip addr show | grep inet
|
||||
echo
|
||||
|
||||
echo "=== Service Status ==="
|
||||
for service in ssh sshd smbd nmbd docker netdata; do
|
||||
if systemctl is-active --quiet "$service" 2>/dev/null; then
|
||||
echo "✅ $service: Active"
|
||||
else
|
||||
echo "❌ $service: Inactive"
|
||||
fi
|
||||
done
|
||||
echo
|
||||
|
||||
echo "=== Firewall Status ==="
|
||||
if command -v ufw &>/dev/null && ufw status | grep -q "Status: active"; then
|
||||
echo "✅ UFW: Active"
|
||||
ufw status numbered
|
||||
elif command -v firewall-cmd &>/dev/null && firewall-cmd --state &>/dev/null; then
|
||||
echo "✅ Firewalld: Active"
|
||||
firewall-cmd --list-all
|
||||
else
|
||||
echo "❌ Firewall: Not active"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "=== Security Status ==="
|
||||
if systemctl is-active --quiet fail2ban; then
|
||||
echo "✅ Fail2ban: Active"
|
||||
else
|
||||
echo "❌ Fail2ban: Inactive"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "=== Docker Status ==="
|
||||
if command -v docker &>/dev/null; then
|
||||
echo "✅ Docker: Installed"
|
||||
docker version --format 'Version: {{.Server.Version}}'
|
||||
echo "Containers: $(docker ps -q | wc -l) running, $(docker ps -aq | wc -l) total"
|
||||
else
|
||||
echo "ℹ️ Docker: Not installed"
|
||||
fi
|
||||
echo
|
||||
|
||||
echo "=== Log Summary ==="
|
||||
echo "Recent errors in system logs:"
|
||||
journalctl --since "1 hour ago" --priority err --no-pager | tail -5
|
||||
|
||||
} > "$health_report"
|
||||
|
||||
cat "$health_report"
|
||||
|
||||
# Save to permanent location
|
||||
sudo cp "$health_report" "/var/log/nas_health_$(date +%Y%m%d_%H%M%S).log"
|
||||
|
||||
log_success "Health check completed. Report saved to /var/log/"
|
||||
}
|
||||
|
||||
# Create maintenance script
|
||||
create_maintenance_script() {
|
||||
sudo tee /usr/local/bin/nas-maintenance > /dev/null <<'EOF'
|
||||
#!/bin/bash
|
||||
# NAS Maintenance Script
|
||||
|
||||
LOG_FILE="/var/log/nas_maintenance.log"
|
||||
|
||||
log_maintenance() {
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
case "${1:-help}" in
|
||||
update)
|
||||
log_maintenance "Starting system update..."
|
||||
|
||||
# Detect distribution and update
|
||||
if command -v apt-get &>/dev/null; then
|
||||
apt-get update && apt-get upgrade -y
|
||||
elif command -v dnf &>/dev/null; then
|
||||
dnf update -y
|
||||
elif command -v pacman &>/dev/null; then
|
||||
pacman -Syu --noconfirm
|
||||
elif command -v zypper &>/dev/null; then
|
||||
zypper refresh && zypper update -y
|
||||
fi
|
||||
|
||||
log_maintenance "System update completed"
|
||||
;;
|
||||
|
||||
cleanup)
|
||||
log_maintenance "Starting system cleanup..."
|
||||
|
||||
# Clean package cache
|
||||
if command -v apt-get &>/dev/null; then
|
||||
apt-get autoremove -y && apt-get autoclean
|
||||
elif command -v dnf &>/dev/null; then
|
||||
dnf autoremove -y && dnf clean all
|
||||
elif command -v pacman &>/dev/null; then
|
||||
pacman -Sc --noconfirm
|
||||
elif command -v zypper &>/dev/null; then
|
||||
zypper clean -a
|
||||
fi
|
||||
|
||||
# Clean logs older than 30 days
|
||||
find /var/log -name "*.log" -mtime +30 -delete 2>/dev/null
|
||||
|
||||
# Clean temporary files
|
||||
find /tmp -type f -mtime +7 -delete 2>/dev/null
|
||||
|
||||
# Docker cleanup if installed
|
||||
if command -v docker &>/dev/null; then
|
||||
docker system prune -f
|
||||
fi
|
||||
|
||||
log_maintenance "System cleanup completed"
|
||||
;;
|
||||
|
||||
backup-config)
|
||||
log_maintenance "Starting configuration backup..."
|
||||
|
||||
BACKUP_DIR="/var/backups/nas-config-$(date +%Y%m%d)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Backup important configurations
|
||||
cp -r /etc/samba "$BACKUP_DIR/" 2>/dev/null
|
||||
cp /etc/nas_setup.conf "$BACKUP_DIR/" 2>/dev/null
|
||||
cp -r /etc/ufw "$BACKUP_DIR/" 2>/dev/null
|
||||
cp -r /etc/firewalld "$BACKUP_DIR/" 2>/dev/null
|
||||
cp /etc/ssh/sshd_config "$BACKUP_DIR/" 2>/dev/null
|
||||
|
||||
tar -czf "$BACKUP_DIR.tar.gz" -C "$(dirname "$BACKUP_DIR")" "$(basename "$BACKUP_DIR")"
|
||||
rm -rf "$BACKUP_DIR"
|
||||
|
||||
log_maintenance "Configuration backup created: $BACKUP_DIR.tar.gz"
|
||||
;;
|
||||
|
||||
health-check)
|
||||
/usr/local/bin/nas-performance report
|
||||
;;
|
||||
|
||||
restart-services)
|
||||
log_maintenance "Restarting NAS services..."
|
||||
|
||||
for service in smbd nmbd docker netdata; do
|
||||
if systemctl is-enabled "$service" &>/dev/null; then
|
||||
systemctl restart "$service"
|
||||
log_maintenance "Restarted $service"
|
||||
fi
|
||||
done
|
||||
|
||||
log_maintenance "Service restart completed"
|
||||
;;
|
||||
|
||||
full)
|
||||
log_maintenance "Starting full maintenance routine..."
|
||||
"$0" update
|
||||
"$0" cleanup
|
||||
"$0" backup-config
|
||||
"$0" restart-services
|
||||
"$0" health-check
|
||||
log_maintenance "Full maintenance completed"
|
||||
;;
|
||||
|
||||
help|*)
|
||||
echo "NAS Maintenance Script"
|
||||
echo "Usage: $0 {update|cleanup|backup-config|health-check|restart-services|full|help}"
|
||||
echo
|
||||
echo "Commands:"
|
||||
echo " update Update system packages"
|
||||
echo " cleanup Clean temporary files and caches"
|
||||
echo " backup-config Backup configuration files"
|
||||
echo " health-check Display system health report"
|
||||
echo " restart-services Restart NAS services"
|
||||
echo " full Run complete maintenance routine"
|
||||
echo " help Show this help message"
|
||||
;;
|
||||
esac
|
||||
EOF
|
||||
|
||||
sudo chmod +x /usr/local/bin/nas-maintenance
|
||||
|
||||
# Schedule weekly maintenance
|
||||
echo "0 3 * * 1 /usr/local/bin/nas-maintenance full" | sudo crontab -
|
||||
|
||||
log_success "Maintenance script created and scheduled"
|
||||
}
|
||||
|
||||
# Main performance optimization function
|
||||
optimize_nas_performance() {
|
||||
log_info "=== Performance Optimization ==="
|
||||
|
||||
optimize_system_performance
|
||||
optimize_docker_performance
|
||||
optimize_samba_performance
|
||||
create_maintenance_script
|
||||
|
||||
log_success "NAS performance optimization completed"
|
||||
}
|
||||
Reference in New Issue
Block a user