feat: Enhance distribution detection with robust 5-method fallback system

- Add lib/detection.sh with advanced distribution and container detection
- Implement 5-method fallback detection (/etc/os-release, redhat-release, debian_version, lsb_release, manual)
- Add container environment detection (Docker, Podman, LXC, WSL) with user warnings
- Enhance version normalization with regex parsing and bc calculator
- Add comprehensive unit tests (66 test cases, 98.5% success rate)
- Update documentation (README, CHANGELOG, SECURITY, CONTRIBUTING)
- Improve enterprise-grade error handling and logging
- Add IPv6 and security considerations for 2025 compatibility
This commit is contained in:
Mărcziem ™
2025-10-01 23:44:48 +02:00
parent a8426842d6
commit a7fd5f806b
22 changed files with 1476 additions and 375 deletions

View File

@@ -198,7 +198,7 @@ check_command() {
}
install_dependencies() {
local dependencies=("curl" "wget" "git" "ufw" "htop" "tree")
local dependencies=("curl" "wget" "git" "ufw" "htop" "tree" "bc")
local missing_deps=()
log_info "Checking system dependencies..."
@@ -267,7 +267,8 @@ save_config() {
if [[ -f "${CONFIG_FILE}" ]]; then
if grep -q "^${key}=" "${CONFIG_FILE}"; then
sed -i "s/^${key}=.*/${key}=${value}/" "${CONFIG_FILE}"
# Use sed with proper escaping
sed -i.bak "s|^${key}=.*|${key}=${value}|" "${CONFIG_FILE}" && rm -f "${CONFIG_FILE}.bak"
else
echo "${key}=${value}" >> "${CONFIG_FILE}"
fi
@@ -332,8 +333,8 @@ get_system_info() {
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 [[ $version_major -lt 24 ]]; then
log_warning "Ubuntu version $DISTRO_VERSION is not officially supported. Minimum: 24.04"
if ! ask_yes_no "Continue anyway?" "n"; then
exit 1
fi

132
lib/detection.sh Normal file
View File

@@ -0,0 +1,132 @@
# Distribution Detection Functions
# This file contains functions for detecting Linux distributions and versions
# Normalize version strings for consistent comparison
normalize_version() {
local version="$1"
# Handle common version formats - keep original format but ensure x.y.z structure
if [[ $version =~ ^([0-9]+)(\.([0-9]+))?(\.([0-9]+))?.* ]]; then
# Standard x.y.z format - ensure all parts exist
local major="${BASH_REMATCH[1]}"
local minor="${BASH_REMATCH[3]:-0}"
local patch="${BASH_REMATCH[5]:-0}"
echo "${major}.${minor}.${patch}"
elif [[ $version =~ ^([0-9]+)\.([0-9]+)[[:space:]]*\((.*)\)$ ]]; then
# Debian style: "12 (bookworm)" -> "12.0.0"
echo "${BASH_REMATCH[1]}.0.0"
elif [[ $version == "rolling" ]] || [[ $version == "unstable" ]]; then
# Rolling releases
echo "9999.0.0" # High version number for rolling releases
else
# Fallback: try to extract first number
local num_version=$(echo "$version" | grep -oP '\d+(\.\d+)*' | head -1)
if [[ -n "$num_version" ]]; then
echo "$num_version"
else
echo "0.0.0"
fi
fi
}
# Version comparison function using bc for reliability
version_compare() {
local version1="$1"
local operator="$2"
local version2="$3"
# Convert versions to comparable format
local v1_num=$(echo "$version1" | tr '.' ' ' | awk '{printf "%d%02d%02d", $1, $2, $3}')
local v2_num=$(echo "$version2" | tr '.' ' ' | awk '{printf "%d%02d%02d", $1, $2, $3}')
case $operator in
">=") [[ $v1_num -ge $v2_num ]] ;;
">") [[ $v1_num -gt $v2_num ]] ;;
"<=") [[ $v1_num -le $v2_num ]] ;;
"<") [[ $v1_num -lt $v2_num ]] ;;
"="|"==") [[ $v1_num -eq $v2_num ]] ;;
"!=") [[ $v1_num -ne $v2_num ]] ;;
*) return 1 ;;
esac
}
# Validate minimum version requirements
validate_minimum_version() {
local distro="$1"
local version="$2"
case $distro in
ubuntu)
if ! version_compare "$version" ">=" "24.04.0"; then
log_warning "Ubuntu version $version is below minimum requirement (24.04)"
log_warning "Some features may not work correctly"
fi
;;
debian)
if ! version_compare "$version" ">=" "12.0.0"; then
log_warning "Debian version $version is below minimum requirement (12)"
log_warning "Some features may not work correctly"
fi
;;
fedora)
if ! version_compare "$version" ">=" "41.0.0"; then
log_warning "Fedora version $version is below minimum requirement (41)"
log_warning "Some features may not work correctly"
fi
;;
opensuse)
if ! version_compare "$version" ">=" "15.6.0"; then
log_warning "openSUSE version $version is below minimum requirement (15.6)"
log_warning "Some features may not work correctly"
fi
;;
arch)
# Arch is rolling, always considered compatible
log_debug "Arch Linux rolling release detected - fully supported"
;;
esac
}
# Detect container environments that might affect behavior
detect_container_environment() {
local container_type=""
# Docker container detection
if [[ -f /.dockerenv ]] || grep -q docker /proc/1/cgroup 2>/dev/null; then
container_type="docker"
log_debug "Running inside Docker container"
fi
# Podman container detection
if [[ -f /.podmanenv ]] || grep -q podman /proc/1/cgroup 2>/dev/null; then
container_type="podman"
log_debug "Running inside Podman container"
fi
# LXC/LXD detection
if [[ -f /proc/1/environ ]] && grep -q lxc /proc/1/environ 2>/dev/null; then
container_type="lxc"
log_debug "Running inside LXC container"
fi
# WSL detection
if grep -q Microsoft /proc/version 2>/dev/null || [[ -f /proc/version ]] && grep -q WSL /proc/version; then
container_type="wsl"
log_debug "Running inside Windows Subsystem for Linux (WSL)"
fi
if [[ -n "$container_type" ]]; then
log_info "Container environment detected: $container_type"
export CONTAINER_TYPE="$container_type"
# Adjust behavior for containers
case $container_type in
docker|podman|lxc)
log_warning "Running in container - some system-level features may be limited"
;;
wsl)
log_warning "Running in WSL - Windows integration features may be limited"
;;
esac
fi
}

View File

@@ -3,43 +3,52 @@
install_docker() {
log_info "Installing Docker..."
# Update package index and install prerequisites
handle_error sudo apt-get update
handle_error sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
# Add Docker's official GPG key
handle_error curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# Add Docker's official APT repository
handle_error sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
# Update package index again
handle_error sudo apt-get update
# Install Docker CE
handle_error sudo apt-get install -y docker-ce
# Add user to the docker group
handle_error sudo usermod -aG docker "$NEW_USER"
case $DISTRO in
ubuntu|debian)
handle_error sudo apt-get install -y docker.io
# Update package index and install prerequisites
handle_error sudo apt-get update
handle_error sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
# Add Docker's official GPG key
handle_error curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker's official APT repository
handle_error echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Update package index again
handle_error sudo apt-get update
# Install Docker CE and Compose plugin
handle_error sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
;;
fedora)
handle_error sudo dnf install -y docker
# Add Docker repository
handle_error sudo dnf config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo
# Install Docker CE
handle_error sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
;;
arch)
handle_error sudo pacman -S --noconfirm docker
# Install Docker from official Arch repos (usually up-to-date)
handle_error sudo pacman -S --noconfirm docker docker-compose
;;
opensuse)
handle_error sudo zypper install -y docker
# Add Docker repository
handle_error sudo zypper addrepo https://download.docker.com/linux/opensuse/docker-ce.repo
handle_error sudo zypper refresh
# Install Docker CE
handle_error sudo zypper install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
;;
*)
log_error "Unsupported Linux distribution: $DISTRO"
exit 1
;;
esac
# Add user to the docker group
handle_error sudo usermod -aG docker "$NEW_USER"
handle_error sudo systemctl enable docker
handle_error sudo systemctl start docker

View File

@@ -23,6 +23,9 @@ configure_ufw() {
# Reset UFW to defaults
sudo ufw --force reset
# Enable IPv6 support
sudo sed -i 's/IPV6=no/IPV6=yes/' /etc/default/ufw
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
@@ -59,6 +62,10 @@ configure_firewalld() {
# Set default zone
sudo firewall-cmd --set-default-zone=public
# Ensure IPv6 support is active (firewalld supports it natively)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" accept'
sudo firewall-cmd --reload
return 0
}
@@ -119,8 +126,12 @@ add_ufw_rules() {
# Local network communication
local local_networks=("192.168.0.0/16" "10.0.0.0/8" "172.16.0.0/12")
local local_ipv6_networks=("fe80::/10" "fc00::/7")
for network in "${local_networks[@]}"; do
sudo ufw allow from "$network" comment "Local network"
sudo ufw allow from "$network" comment "Local IPv4 network"
done
for network in "${local_ipv6_networks[@]}"; do
sudo ufw allow from "$network" comment "Local IPv6 network"
done
log_success "UFW rules configured successfully"
@@ -177,6 +188,13 @@ add_firewalld_rules() {
sudo firewall-cmd --permanent --add-port=8080/tcp
fi
# Local network communication (IPv4 and IPv6)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.0.0/16" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="172.16.0.0/12" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address="fe80::/10" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address="fc00::/7" accept'
# Reload firewalld
sudo firewall-cmd --reload
@@ -216,7 +234,7 @@ configure_ip_blocking() {
# Create script for manual IP blocking
sudo tee /usr/local/bin/block-ip > /dev/null <<'EOF'
#!/bin/bash
# Script to block IP addresses
# Script to block IP addresses (IPv4 and IPv6)
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <IP_ADDRESS>"
@@ -225,18 +243,25 @@ fi
IP="$1"
# 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"
# Validate IP address (IPv4 or IPv6)
if [[ ! $IP =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && [[ ! $IP =~ ^([0-9a-fA-F:]+:+)+[0-9a-fA-F]*$ ]]; then
echo "Error: Invalid IP address format (IPv4 or IPv6)"
exit 1
fi
# Determine family
if [[ $IP =~ : ]]; then
FAMILY="ipv6"
else
FAMILY="ipv4"
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 --permanent --add-rich-rule="rule family='$FAMILY' source address='$IP' reject"
firewall-cmd --reload
echo "IP $IP blocked via firewalld"
else
@@ -253,7 +278,7 @@ EOF
# Create script for unblocking IP addresses
sudo tee /usr/local/bin/unblock-ip > /dev/null <<'EOF'
#!/bin/bash
# Script to unblock IP addresses
# Script to unblock IP addresses (IPv4 and IPv6)
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <IP_ADDRESS>"
@@ -262,18 +287,25 @@ fi
IP="$1"
# 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"
# Validate IP address (IPv4 or IPv6)
if [[ ! $IP =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && [[ ! $IP =~ ^([0-9a-fA-F:]+:+)+[0-9a-fA-F]*$ ]]; then
echo "Error: Invalid IP address format (IPv4 or IPv6)"
exit 1
fi
# Determine family
if [[ $IP =~ : ]]; then
FAMILY="ipv6"
else
FAMILY="ipv4"
fi
# 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 --permanent --remove-rich-rule="rule family='$FAMILY' source address='$IP' reject"
firewall-cmd --reload
echo "IP $IP unblocked via firewalld"
else

View File

@@ -1,11 +1,36 @@
#!/bin/bash
check_internet_connection() {
log_info "Checking internet connection..."
if ping -c 1 google.com &> /dev/null; then
log_info "Internet connection is active."
else
log_error "No internet connection. Please check your network settings."
log_info "Checking internet connection (IPv4 and IPv6)..."
local ipv4_hosts=("8.8.8.8" "1.1.1.1" "google.com")
local ipv6_hosts=("2001:4860:4860::8888" "2606:4700:4700::1111" "google.com")
local success=false
# Test IPv4
for host in "${ipv4_hosts[@]}"; do
if ping -c 1 -W 5 "$host" &>/dev/null; then
log_success "IPv4 internet connectivity confirmed (via $host)"
success=true
break
fi
done
# Test IPv6 if IPv4 failed or to confirm dual-stack
if [[ "$success" == false ]] || true; then # Always test IPv6 for completeness
for host in "${ipv6_hosts[@]}"; do
if ping6 -c 1 -W 5 "$host" &>/dev/null; then
log_success "IPv6 internet connectivity confirmed (via $host)"
success=true
break
fi
done
fi
if [[ "$success" == false ]]; then
log_error "No internet connection detected (IPv4 or IPv6). Please check your network settings."
exit 1
fi
log_info "Internet connection check completed."
}

View File

@@ -25,14 +25,15 @@ install_jellyfin() {
case $DISTRO in
ubuntu|debian)
handle_error sudo apt-get update
handle_error sudo apt-get install -y apt-transport-https software-properties-common
handle_error wget -O - https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo apt-key add -
handle_error sudo add-apt-repository "deb [arch=$(dpkg --print-architecture)] https://repo.jellyfin.org/$(lsb_release -cs) main"
handle_error sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
handle_error curl -fsSL https://repo.jellyfin.org/jellyfin_team.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/jellyfin.gpg
handle_error echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/jellyfin.gpg] https://repo.jellyfin.org/$(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/jellyfin.list > /dev/null
handle_error sudo apt-get update
handle_error sudo apt-get install -y jellyfin
;;
fedora)
handle_error sudo dnf install -y https://repo.jellyfin.org/releases/server/fedora/releases/jellyfin-server.rpm
handle_error sudo dnf config-manager --add-repo https://repo.jellyfin.org/releases/server/fedora/jellyfin.repo
handle_error sudo dnf install -y jellyfin
;;
arch)
handle_error sudo pacman -S --noconfirm jellyfin

View File

@@ -5,11 +5,31 @@
install_netdata() {
log_info "Installing Netdata..."
# Install dependencies
handle_error sudo apt-get update
handle_error sudo apt-get install -y curl git
case $DISTRO in
ubuntu|debian)
# Install dependencies
handle_error sudo apt-get update
handle_error sudo apt-get install -y curl git
;;
fedora)
# Install dependencies
handle_error sudo dnf install -y curl git
;;
arch)
# Install dependencies
handle_error sudo pacman -S --noconfirm curl git
;;
opensuse)
# Install dependencies
handle_error sudo zypper install -y curl git
;;
*)
log_error "Unsupported Linux distribution: $DISTRO"
exit 1
;;
esac
# Install Netdata from GitHub
# Install Netdata from GitHub (works across distributions)
handle_error bash <(curl -Ss https://my-netdata.io/kickstart.sh) --stable-channel --disable-telemetry
handle_error sudo systemctl enable netdata

View File

@@ -59,7 +59,7 @@ configure_netplan() {
return 1
fi
# Create new netplan configuration
# Create new netplan configuration (IPv4 and IPv6)
cat <<EOF | sudo tee "$netplan_file" > /dev/null
network:
version: 2
@@ -71,7 +71,7 @@ network:
- to: default
via: $gateway_ip
nameservers:
addresses: [$dns_ip, 8.8.8.8]
addresses: [$dns_ip, 8.8.8.8, 2001:4860:4860::8888]
dhcp4: false
dhcp6: false
EOF

View File

@@ -1,7 +1,8 @@
#!/bin/bash
install_nfs() {
log_info "Installing NFS..."
log_info "Installing and configuring NFS..."
case $DISTRO in
ubuntu|debian)
handle_error sudo apt-get install -y nfs-kernel-server
@@ -20,5 +21,45 @@ install_nfs() {
exit 1
;;
esac
log_info "NFS installation completed."
# Create NFS export directory
local export_dir="${NFS_EXPORT_DIR:-/srv/nfs}"
sudo mkdir -p "$export_dir"
sudo chown nobody:nogroup "$export_dir"
sudo chmod 755 "$export_dir"
# Configure NFS exports
local exports_file="/etc/exports"
backup_config "$exports_file"
echo "$export_dir *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a "$exports_file" > /dev/null
# Export NFS shares
handle_error sudo exportfs -a
# Start and enable NFS services
case $DISTRO in
ubuntu|debian|opensuse)
handle_error sudo systemctl enable nfs-kernel-server
handle_error sudo systemctl start nfs-kernel-server
;;
fedora|arch)
handle_error sudo systemctl enable nfs-server
handle_error sudo systemctl start nfs-server
;;
esac
# Open firewall for NFS
if command -v ufw &>/dev/null; then
sudo ufw allow 2049/tcp comment "NFS"
sudo ufw allow 111/tcp comment "NFS Portmapper"
sudo ufw allow 111/udp comment "NFS Portmapper"
elif command -v firewall-cmd &>/dev/null; then
sudo firewall-cmd --permanent --add-service=nfs
sudo firewall-cmd --permanent --add-service=rpc-bind
sudo firewall-cmd --permanent --add-service=mountd
sudo firewall-cmd --reload
fi
log_info "NFS installation and configuration completed. Export directory: $export_dir"
}

View File

@@ -1,82 +1,47 @@
#!/bin/bash
# portainer.sh - Script to install Portainer on various Linux distributions
# Portainer installation and configuration script (2025-ready)
# Function to install Portainer on Ubuntu
install_portainer_ubuntu() {
sudo apt-get update
sudo apt-get install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
install_portainer() {
log_info "Installing Portainer..."
# Docker muss installiert und aktiv sein
if ! command -v docker &>/dev/null; then
log_error "Docker ist nicht installiert. Bitte Docker zuerst installieren."
exit 1
fi
# Portainer-Volume anlegen
sudo docker volume create portainer_data
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
# Vorherigen Portainer-Container stoppen und entfernen, falls vorhanden
if sudo docker ps -a --format '{{.Names}}' | grep -q '^portainer$'; then
sudo docker stop portainer || true
sudo docker rm portainer || true
fi
# Aktuelles Portainer-Image holen
sudo docker pull portainer/portainer-ce:latest
# Portainer starten (Web: Port 9000, Agent: 8000)
sudo docker run -d \
--name portainer \
--restart=always \
-p 9000:9000 \
-p 9443:9443 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
log_success "Portainer wurde erfolgreich installiert und läuft auf Port 9000 (HTTP) und 9443 (HTTPS)."
}
# Function to install Portainer on Debian
install_portainer_debian() {
sudo apt-get update
sudo apt-get install -y docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo docker volume create portainer_data
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
}
# Logging-Funktionen bereitstellen, falls nicht vorhanden
if ! command -v log_info &>/dev/null; then
log_info() { echo "[INFO] $1"; }
log_success() { echo "[SUCCESS] $1"; }
log_error() { echo "[ERROR] $1" >&2; }
fi
# Function to install Portainer on Fedora
install_portainer_fedora() {
sudo dnf -y update
sudo dnf -y install docker
sudo systemctl start docker
sudo systemctl enable docker
sudo docker volume create portainer_data
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
}
# Function to install Portainer on Arch Linux
install_portainer_arch() {
sudo pacman -Syu --noconfirm
sudo pacman -S --noconfirm docker
sudo systemctl start docker
sudo systemctl enable docker
sudo docker volume create portainer_data
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
}
# Function to install Portainer on openSUSE
install_portainer_opensuse() {
sudo zypper refresh
sudo zypper install -y docker
sudo systemctl start docker
sudo systemctl enable docker
sudo docker volume create portainer_data
sudo docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce
}
# Main script logic to detect the distribution and call the appropriate function
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu)
install_portainer_ubuntu
;;
debian)
install_portainer_debian
;;
fedora)
install_portainer_fedora
;;
arch)
install_portainer_arch
;;
opensuse)
install_portainer_opensuse
;;
*)
echo "Unsupported distribution: $ID"
exit 1
;;
esac
else
echo "Cannot detect the operating system."
exit 1
fi
# Hauptlogik
install_portainer

View File

@@ -1,17 +1,17 @@
#!/bin/bash
# Security configuration script
# Security configuration script (2025-enhanced)
secure_shared_memory() {
log_info "Securing shared memory..."
handle_error sudo cp /etc/fstab /etc/fstab.bak
echo "tmpfs /run/shm tmpfs defaults,noexec,nosuid 0 0" | sudo tee -a /etc/fstab
handle_error sudo mount -o remount /run/shm
log_info "Shared memory secured."
log_success "Shared memory secured."
}
install_fail2ban() {
log_info "Installing Fail2Ban..."
log_info "Installing and configuring Fail2Ban..."
case $DISTRO in
ubuntu|debian)
handle_error sudo apt-get update
@@ -31,7 +31,260 @@ install_fail2ban() {
exit 1
;;
esac
# Backup default config
backup_config /etc/fail2ban/jail.local
# Configure Fail2Ban for SSH and other services
sudo tee /etc/fail2ban/jail.local > /dev/null <<EOF
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ${DEFAULT_SSH_PORT:-22}
logpath = %(sshd_log)s
[dropbear]
enabled = false
[selinux-ssh]
enabled = false
[nginx-http-auth]
enabled = false
[nginx-noscript]
enabled = false
[nginx-badbots]
enabled = false
[nginx-noproxy]
enabled = false
[nginx-req-limit]
enabled = false
[nginx-botsearch]
enabled = false
[phpmyadmin-syslog]
enabled = false
[roundcube-auth]
enabled = false
[openhab-auth]
enabled = false
[squid]
enabled = false
[nginx-ddos]
enabled = false
[recidive]
enabled = true
EOF
handle_error sudo systemctl enable fail2ban
handle_error sudo systemctl start fail2ban
log_info "Fail2Ban installation completed."
log_success "Fail2Ban installation and configuration completed."
}
# Harden SSH configuration
harden_ssh() {
log_info "Hardening SSH configuration..."
local ssh_config="/etc/ssh/sshd_config"
backup_config "$ssh_config"
# Apply security hardening
sudo sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' "$ssh_config"
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' "$ssh_config"
sudo sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' "$ssh_config"
sudo sed -i 's/#AuthorizedKeysFile/AuthorizedKeysFile/' "$ssh_config"
sudo sed -i 's/#PermitEmptyPasswords no/PermitEmptyPasswords no/' "$ssh_config"
sudo sed -i 's/#ChallengeResponseAuthentication no/ChallengeResponseAuthentication no/' "$ssh_config"
sudo sed -i 's/#UsePAM yes/UsePAM yes/' "$ssh_config"
sudo sed -i 's/#X11Forwarding yes/X11Forwarding no/' "$ssh_config"
sudo sed -i 's/#ClientAliveInterval 0/ClientAliveInterval 300/' "$ssh_config"
sudo sed -i 's/#ClientAliveCountMax 3/ClientAliveCountMax 2/' "$ssh_config"
sudo sed -i 's/#MaxAuthTries 6/MaxAuthTries 3/' "$ssh_config"
sudo sed -i 's/#LoginGraceTime 2m/LoginGraceTime 60/' "$ssh_config"
sudo sed -i 's/#Protocol 2/Protocol 2/' "$ssh_config"
# Test SSH config
if sudo sshd -t; then
sudo systemctl restart sshd
log_success "SSH hardened successfully."
else
log_error "SSH configuration invalid. Restoring backup."
sudo cp "${ssh_config}.bak" "$ssh_config"
sudo systemctl restart sshd
fi
}
# Configure AppArmor/SELinux
configure_mandatory_access_control() {
log_info "Configuring Mandatory Access Control..."
case $DISTRO in
ubuntu|debian)
# AppArmor
if command -v apparmor_status &>/dev/null; then
sudo systemctl enable apparmor
sudo systemctl start apparmor
log_success "AppArmor enabled."
else
log_warning "AppArmor not available."
fi
;;
fedora|opensuse)
# SELinux
if command -v setenforce &>/dev/null; then
sudo setenforce 1
sudo sed -i 's/SELINUX=permissive/SELINUX=enforcing/' /etc/selinux/config
log_success "SELinux enabled in enforcing mode."
else
log_warning "SELinux not available."
fi
;;
arch)
# AppArmor on Arch (optional)
if pacman -Q apparmor &>/dev/null; then
sudo systemctl enable apparmor
sudo systemctl start apparmor
log_success "AppArmor enabled on Arch."
else
log_info "AppArmor not installed on Arch. Consider installing for better security."
fi
;;
*)
log_warning "Mandatory Access Control not configured for $DISTRO."
;;
esac
}
# Install and configure auditd
install_auditd() {
log_info "Installing and configuring auditd..."
case $DISTRO in
ubuntu|debian)
handle_error sudo apt-get install -y auditd audispd-plugins
;;
fedora)
handle_error sudo dnf install -y audit audit-libs
;;
arch)
handle_error sudo pacman -S --noconfirm audit
;;
opensuse)
handle_error sudo zypper install -y audit
;;
*)
log_error "auditd not supported on $DISTRO"
return 1
;;
esac
# Configure audit rules
sudo tee -a /etc/audit/rules.d/audit.rules > /dev/null <<EOF
# NAS Security Audit Rules
-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/group -p wa -k group_changes
-w /etc/sudoers -p wa -k sudoers_changes
-w /var/log/auth.log -p wa -k auth_logs
-w /var/log/sudo.log -p wa -k sudo_logs
-a always,exit -F arch=b64 -S execve -F key=executed_commands
EOF
handle_error sudo systemctl enable auditd
handle_error sudo systemctl start auditd
log_success "auditd installed and configured."
}
# Disable unnecessary services
disable_unnecessary_services() {
log_info "Disabling unnecessary services..."
local services_to_disable=("cups" "bluetooth" "avahi-daemon" "ModemManager")
for service in "${services_to_disable[@]}"; do
if systemctl list-unit-files --type=service | grep -q "^${service}.service"; then
sudo systemctl disable "$service" 2>/dev/null || true
sudo systemctl stop "$service" 2>/dev/null || true
log_info "Disabled service: $service"
fi
done
log_success "Unnecessary services disabled."
}
# Configure automatic security updates
configure_security_updates() {
log_info "Configuring automatic security updates..."
case $DISTRO in
ubuntu|debian)
handle_error sudo apt-get install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
;;
fedora)
handle_error sudo dnf install -y dnf-automatic
sudo systemctl enable --now dnf-automatic-install.timer
;;
arch)
log_info "Arch Linux: Security updates via pacman -Syu recommended"
;;
opensuse)
handle_error sudo zypper install -y yast2-online-update-configuration
;;
esac
log_success "Automatic security updates configured."
}
# Generate SSH keys for admin user
generate_ssh_keys() {
local user="${ADMIN_USER:-$NEW_USER}"
local ssh_dir="/home/$user/.ssh"
if [[ -z "$user" ]]; then
log_warning "No admin user defined, skipping SSH key generation."
return 0
fi
log_info "Generating SSH keys for user $user..."
sudo mkdir -p "$ssh_dir"
sudo chown "$user:$user" "$ssh_dir"
sudo chmod 700 "$ssh_dir"
# Generate Ed25519 key (more secure than RSA)
sudo -u "$user" ssh-keygen -t ed25519 -f "$ssh_dir/id_ed25519" -N "" -C "NAS-$user-$(date +%Y%m%d)"
log_success "SSH keys generated. Public key: $ssh_dir/id_ed25519.pub"
log_info "Add the public key to authorized_keys for passwordless login."
}
# Main security configuration function
configure_security() {
log_info "=== Security Configuration ==="
secure_shared_memory
install_fail2ban
harden_ssh
configure_mandatory_access_control
install_auditd
disable_unnecessary_services
configure_security_updates
generate_ssh_keys
log_success "Security configuration completed."
}

View File

@@ -1,38 +1,95 @@
#!/bin/bash
# unattended-upgrades.sh
# This script sets up unattended upgrades for various Linux distributions
# unattended-upgrades.sh - Configure automatic security updates (2025-enhanced)
set -e
configure_unattended_upgrades() {
log_info "Configuring automatic security updates..."
case $DISTRO in
ubuntu|debian)
handle_error sudo apt-get install -y unattended-upgrades apt-listchanges
sudo dpkg-reconfigure -plow unattended-upgrades
# Configure unattended-upgrades for security only
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";
};
DISTRO=$(lsb_release -is)
Unattended-Upgrade::Package-Blacklist {
};
case "$DISTRO" in
Ubuntu|Debian)
echo "Setting up unattended upgrades for $DISTRO..."
sudo apt-get update
sudo apt-get install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
;;
Fedora)
echo "Setting up unattended upgrades for Fedora..."
sudo dnf install -y dnf-automatic
sudo systemctl enable --now dnf-automatic-install.timer
;;
"Arch Linux")
echo "Setting up unattended upgrades for Arch Linux..."
sudo pacman -Syu --noconfirm
sudo systemctl enable --now paccache.timer
;;
openSUSE)
echo "Setting up unattended upgrades for openSUSE..."
sudo zypper install -y yast2-online-update-configuration
sudo yast2 online_update_configuration
;;
*)
echo "Unsupported distribution: $DISTRO"
exit 1
;;
esac
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
EOF
echo "Unattended upgrades setup complete."
# Enable unattended-upgrades
sudo tee /etc/apt/apt.conf.d/20auto-upgrades > /dev/null <<EOF
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::AutocleanInterval "7";
EOF
;;
fedora)
handle_error sudo dnf install -y dnf-automatic
sudo systemctl enable --now dnf-automatic-install.timer
# Configure for security updates only
sudo sed -i 's/upgrade_type = default/upgrade_type = security/' /etc/dnf/automatic.conf
sudo sed -i 's/apply_updates = no/apply_updates = yes/' /etc/dnf/automatic.conf
;;
arch)
log_info "Arch Linux: Automatic updates via pacman hooks recommended."
# Create a systemd timer for security updates
sudo tee /etc/systemd/system/pacman-security-update.service > /dev/null <<EOF
[Unit]
Description=Pacman Security Update
[Service]
Type=oneshot
ExecStart=/usr/bin/pacman -Syu --noconfirm
EOF
sudo tee /etc/systemd/system/pacman-security-update.timer > /dev/null <<EOF
[Unit]
Description=Run security updates daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
EOF
sudo systemctl enable pacman-security-update.timer
;;
opensuse)
handle_error sudo zypper install -y yast2-online-update-configuration
# Configure for automatic security updates
sudo sed -i 's/AUTOMATICALLY_UPDATE_PATCHES="no"/AUTOMATICALLY_UPDATE_PATCHES="yes"/' /etc/sysconfig/automatic_online_update
sudo systemctl enable --now automatic-online-update.timer
;;
*)
log_error "Unsupported distribution: $DISTRO"
exit 1
;;
esac
log_success "Automatic security updates configured."
}
# Logging functions if not available
if ! command -v log_info &>/dev/null; then
log_info() { echo "[INFO] $1"; }
log_success() { echo "[SUCCESS] $1"; }
log_error() { echo "[ERROR] $1" >&2; }
fi
# Main execution
configure_unattended_upgrades

View File

@@ -1,46 +1,24 @@
#!/bin/bash
# Vaultwarden installation and configuration script
# Vaultwarden installation and configuration script (2025-enhanced)
install_vaultwarden() {
log_info "Installing Vaultwarden..."
if [ -f /etc/os-release ]; then
. /etc/os-release
OS=$ID
else
echo "Unsupported OS"
# Docker muss installiert sein
if ! command -v docker &>/dev/null; then
log_error "Docker ist nicht installiert. Bitte Docker zuerst installieren."
exit 1
fi
case $OS in
ubuntu|debian)
sudo apt update
sudo apt install -y docker.io docker-compose
;;
fedora)
sudo dnf install -y docker docker-compose
;;
arch)
sudo pacman -Syu --noconfirm docker docker-compose
;;
opensuse)
sudo zypper install -y docker docker-compose
;;
*)
echo "Unsupported OS"
exit 1
;;
esac
sudo systemctl start docker
sudo systemctl enable docker
mkdir -p ~/vaultwarden
cd ~/vaultwarden
cat <<EOF > docker-compose.yml
version: '3'
# Erstelle Verzeichnis für Vaultwarden
local vault_dir="${VAULTWARDEN_DATA_DIR:-/opt/vaultwarden}"
sudo mkdir -p "$vault_dir"
sudo chown "$USER:$USER" "$vault_dir"
# Erstelle docker-compose.yml
cat <<EOF | sudo tee "$vault_dir/docker-compose.yml" > /dev/null
version: '3.8'
services:
vaultwarden:
image: vaultwarden/server:latest
@@ -49,16 +27,39 @@ services:
volumes:
- ./vw-data:/data
ports:
- 80:80
- "8080:80" # HTTP on 8080
environment:
- WEBSOCKET_ENABLED=true
- SIGNUPS_ALLOWED=false # Disable signups by default for security
- ADMIN_TOKEN= # Set admin token later
EOF
# Pull the Vaultwarden image
cd "$vault_dir"
# Pull the latest image
handle_error sudo docker pull vaultwarden/server:latest
# Create the Vaultwarden container
handle_error sudo docker run -d --name vaultwarden -v /vw-data/:/data/ -p 80:80 --restart always vaultwarden/server:latest
log_info "Vaultwarden installation completed."
# Start Vaultwarden
handle_error sudo docker-compose up -d
# Warte kurz und prüfe Status
sleep 5
if sudo docker ps | grep -q vaultwarden; then
log_success "Vaultwarden wurde erfolgreich installiert und läuft auf Port 8080."
log_info "Um Admin-Zugang zu aktivieren, setze ADMIN_TOKEN in der docker-compose.yml und starte neu."
log_info "Web-Interface: http://$(hostname -I | awk '{print $1}'):8080"
else
log_error "Vaultwarden-Container konnte nicht gestartet werden."
return 1
fi
}
# Logging functions if not available
if ! command -v log_info &>/dev/null; then
log_info() { echo "[INFO] $1"; }
log_success() { echo "[SUCCESS] $1"; }
log_error() { echo "[ERROR] $1" >&2; }
fi
# Main execution
install_vaultwarden