- Change --quiet to -q for zypper refresh and update commands - zypper uses short options for quiet mode
764 lines
27 KiB
Bash
764 lines
27 KiB
Bash
#!/bin/bash
|
|
|
|
# NAS Setup Script - Version 2.1.1
|
|
#
|
|
# This script automates the setup of a NAS system with various services.
|
|
# It is designed to run on multiple Linux distributions, including:
|
|
# - Ubuntu 24.04+
|
|
# - Debian 12+
|
|
# - Fedora 41+
|
|
# - Arch Linux
|
|
# - openSUSE Leap 15.6+
|
|
#
|
|
# Disclaimer:
|
|
# This script is provided "as is", without warranty of any kind, express or implied,
|
|
# including but not limited to the warranties of merchantability, fitness for a particular purpose,
|
|
# and noninfringement. In no event shall the authors or copyright holders be liable for any claim,
|
|
# damages, or other liability, whether in an action of contract, tort, or otherwise, arising from,
|
|
# out of, or in connection with the software or the use or other dealings in the software.
|
|
#
|
|
# Usage:
|
|
# Run this script with root privileges on a fresh installation of a supported Linux distribution.
|
|
# Ensure you have an active internet connection before starting the setup.
|
|
#
|
|
# Author: Sebastian Palencsár
|
|
# License: MIT License
|
|
# (c) 2025 Sebastian Palencsár
|
|
|
|
set -euo pipefail # Strict error handling
|
|
|
|
# Script directory and imports
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# Import configuration and functions
|
|
source "${SCRIPT_DIR}/config/defaults.sh"
|
|
source "${SCRIPT_DIR}/lib/logging.sh"
|
|
source "${SCRIPT_DIR}/lib/common.sh"
|
|
source "${SCRIPT_DIR}/lib/detection.sh"
|
|
source "${SCRIPT_DIR}/lib/network.sh"
|
|
source "${SCRIPT_DIR}/lib/docker.sh"
|
|
source "${SCRIPT_DIR}/lib/security.sh"
|
|
source "${SCRIPT_DIR}/lib/internet.sh"
|
|
source "${SCRIPT_DIR}/lib/nfs.sh"
|
|
source "${SCRIPT_DIR}/lib/netdata.sh"
|
|
source "${SCRIPT_DIR}/lib/firewall.sh"
|
|
source "${SCRIPT_DIR}/lib/unattended-upgrades.sh"
|
|
source "${SCRIPT_DIR}/lib/vaultwarden.sh"
|
|
source "${SCRIPT_DIR}/lib/jellyfin.sh"
|
|
source "${SCRIPT_DIR}/lib/portainer.sh"
|
|
source "${SCRIPT_DIR}/lib/webmin.sh"
|
|
source "${SCRIPT_DIR}/lib/performance.sh"
|
|
|
|
# Initialize logging
|
|
mkdir -p "$(dirname "${LOG_FILE}")"
|
|
mkdir -p "${TEMP_DIR}"
|
|
|
|
# Setup logging with rotation
|
|
exec > >(tee -a "${LOG_FILE}") 2>&1
|
|
|
|
# Enhanced error handling with rollback
|
|
handle_error() {
|
|
# Dual-mode: if called with a non-numeric first argument, treat as wrapper
|
|
# e.g. handle_error sudo cp ... -> execute the command and handle failures
|
|
if [[ $# -ge 1 && ! "$1" =~ ^[0-9]+$ ]]; then
|
|
"$@"
|
|
local _rc=$?
|
|
if [[ $_rc -ne 0 ]]; then
|
|
local _line_number=${BASH_LINENO[0]:-0}
|
|
local _command="$*"
|
|
log_error "Script failed at line ${_line_number}: ${_command} (exit code: ${_rc})"
|
|
if ask_yes_no "An error occurred. Would you like to rollback changes?" "y"; then
|
|
execute_rollback
|
|
fi
|
|
cleanup
|
|
exit $_rc
|
|
fi
|
|
return 0
|
|
fi
|
|
|
|
# Trap handler mode: handle_error <line> "<command>"
|
|
local exit_code=$?
|
|
local line_number=$1
|
|
local command="$2"
|
|
|
|
log_error "Script failed at line ${line_number}: ${command} (exit code: ${exit_code})"
|
|
|
|
if ask_yes_no "An error occurred. Would you like to rollback changes?" "y"; then
|
|
execute_rollback
|
|
fi
|
|
|
|
cleanup
|
|
exit $exit_code
|
|
}
|
|
|
|
# Set error trap
|
|
trap 'handle_error ${LINENO} "$BASH_COMMAND"' ERR
|
|
|
|
# Signal handlers
|
|
cleanup_on_exit() {
|
|
log_info "Script interrupted. Performing cleanup..."
|
|
cleanup
|
|
exit 130
|
|
}
|
|
|
|
trap cleanup_on_exit SIGINT SIGTERM
|
|
|
|
# Detect Linux distribution with comprehensive fallback methods
|
|
detect_distro() {
|
|
local detected_distro=""
|
|
local detected_version=""
|
|
local detected_codename=""
|
|
local detection_method=""
|
|
|
|
log_debug "Starting distribution detection..."
|
|
|
|
# Method 1: /etc/os-release (primary method for modern systems)
|
|
if [[ -f /etc/os-release ]]; then
|
|
source /etc/os-release 2>/dev/null || true
|
|
detected_distro=${ID,,} # Convert to lowercase
|
|
detected_version=$VERSION_ID
|
|
detected_codename=${VERSION_CODENAME:-${UBUNTU_CODENAME:-""}}
|
|
detected_pretty_name=$PRETTY_NAME
|
|
detection_method="/etc/os-release"
|
|
log_debug "Detected via /etc/os-release: $PRETTY_NAME"
|
|
fi
|
|
|
|
# Method 2: /etc/redhat-release (fallback for RHEL/CentOS/Fedora)
|
|
if [[ -z "$detected_distro" ]] && [[ -f /etc/redhat-release ]]; then
|
|
local redhat_info=$(cat /etc/redhat-release)
|
|
if [[ $redhat_info =~ ^(CentOS|Red Hat Enterprise|Fedora) ]]; then
|
|
detected_distro="fedora"
|
|
detected_version=$(echo "$redhat_info" | grep -oP '\d+\.\d+' | head -1)
|
|
detection_method="/etc/redhat-release"
|
|
log_debug "Detected via /etc/redhat-release: $redhat_info"
|
|
fi
|
|
fi
|
|
|
|
# Method 3: /etc/debian_version (fallback for Debian/Ubuntu)
|
|
if [[ -z "$detected_distro" ]] && [[ -f /etc/debian_version ]]; then
|
|
local debian_version=$(cat /etc/debian_version)
|
|
if [[ -f /etc/lsb-release ]]; then
|
|
source /etc/lsb-release 2>/dev/null || true
|
|
detected_distro=${DISTRIB_ID,,}
|
|
detected_version=$DISTRIB_RELEASE
|
|
detected_codename=${DISTRIB_CODENAME:-""}
|
|
detection_method="/etc/lsb-release"
|
|
else
|
|
# Pure Debian system
|
|
detected_distro="debian"
|
|
detected_version=$debian_version
|
|
detection_method="/etc/debian_version"
|
|
fi
|
|
log_debug "Detected via Debian method: $detected_distro $detected_version"
|
|
fi
|
|
|
|
# Method 4: lsb_release command (fallback)
|
|
if [[ -z "$detected_distro" ]] && command -v lsb_release >/dev/null 2>&1; then
|
|
detected_distro=$(lsb_release -si 2>/dev/null | tr '[:upper:]' '[:lower:]')
|
|
detected_version=$(lsb_release -sr 2>/dev/null)
|
|
detected_codename=$(lsb_release -sc 2>/dev/null)
|
|
detection_method="lsb_release command"
|
|
log_debug "Detected via lsb_release command: $detected_distro $detected_version"
|
|
fi
|
|
|
|
# Method 5: uname and manual detection (last resort)
|
|
if [[ -z "$detected_distro" ]]; then
|
|
if [[ -f /etc/arch-release ]]; then
|
|
detected_distro="arch"
|
|
detected_version="rolling"
|
|
detection_method="/etc/arch-release"
|
|
elif [[ -f /etc/gentoo-release ]]; then
|
|
detected_distro="gentoo"
|
|
detected_version=$(cat /etc/gentoo-release | grep -oP '\d+\.\d+' | head -1)
|
|
detection_method="/etc/gentoo-release"
|
|
elif uname -a | grep -qi "opensuse"; then
|
|
detected_distro="opensuse"
|
|
detected_version="unknown"
|
|
detection_method="uname opensuse"
|
|
fi
|
|
log_debug "Detected via fallback method: $detected_distro"
|
|
fi
|
|
|
|
# Validate detection
|
|
if [[ -z "$detected_distro" ]]; then
|
|
log_error "Failed to detect Linux distribution using all available methods"
|
|
log_error "Please check your system and ensure it's a supported Linux distribution"
|
|
log_error "Supported: ${SUPPORTED_DISTROS[*]}"
|
|
exit 1
|
|
fi
|
|
|
|
# Normalize distribution names
|
|
case $detected_distro in
|
|
ubuntu|debian|fedora|arch|opensuse|opensuse-leap)
|
|
if [[ "$detected_distro" == "opensuse-leap" ]]; then
|
|
DISTRO="opensuse"
|
|
else
|
|
DISTRO=$detected_distro
|
|
fi
|
|
;;
|
|
"red hat enterprise linux server"|"rhel")
|
|
DISTRO="fedora" # Treat RHEL as Fedora for package management
|
|
;;
|
|
"centos linux"|"centos")
|
|
DISTRO="fedora" # CentOS uses same package manager as Fedora
|
|
;;
|
|
*)
|
|
# Check if it's a known variant
|
|
if [[ " ${SUPPORTED_DISTROS[*]} " =~ " ${detected_distro} " ]]; then
|
|
DISTRO=$detected_distro
|
|
else
|
|
log_error "Detected distribution '$detected_distro' is not in supported list"
|
|
log_error "Supported distributions: ${SUPPORTED_DISTROS[*]}"
|
|
log_error "Detection method: $detection_method"
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# Parse and normalize version
|
|
DISTRO_VERSION=$(normalize_version "$detected_version")
|
|
DISTRO_CODENAME=$detected_codename
|
|
DISTRO_NAME=${detected_pretty_name:-$DISTRO}
|
|
|
|
log_info "Distribution detected: $DISTRO $DISTRO_VERSION ($detection_method)"
|
|
if [[ -n "$DISTRO_CODENAME" ]]; then
|
|
log_debug "Codename: $DISTRO_CODENAME"
|
|
fi
|
|
|
|
# Validate supported distribution
|
|
if [[ ! " ${SUPPORTED_DISTROS[*]} " =~ " ${DISTRO} " ]]; then
|
|
log_error "Unsupported Linux distribution: $DISTRO"
|
|
log_info "Supported distributions: ${SUPPORTED_DISTROS[*]}"
|
|
log_info "Detection method: $detection_method"
|
|
exit 1
|
|
fi
|
|
|
|
# Check minimum versions with improved parsing
|
|
validate_minimum_version "$DISTRO" "$DISTRO_VERSION"
|
|
|
|
# Check for container environments
|
|
detect_container_environment
|
|
|
|
# Cache the results for performance
|
|
export DISTRO DETECTED_DISTRO=$DISTRO
|
|
export DISTRO_VERSION DETECTED_VERSION=$DISTRO_VERSION
|
|
export DISTRO_CODENAME DETECTED_CODENAME=$DISTRO_CODENAME
|
|
export DISTRO_NAME
|
|
}
|
|
|
|
# System requirements check
|
|
check_system_requirements() {
|
|
log_info "Checking system requirements..."
|
|
|
|
local requirements_met=true
|
|
|
|
# Check disk space
|
|
if ! check_disk_space $MIN_DISK_SPACE_GB; then
|
|
requirements_met=false
|
|
fi
|
|
|
|
# Check RAM
|
|
check_ram $MIN_RAM_MB
|
|
|
|
# Check if running as root
|
|
check_root
|
|
|
|
# Check internet connectivity
|
|
if ! check_internet_enhanced; then
|
|
requirements_met=false
|
|
fi
|
|
|
|
# Check architecture
|
|
local arch=$(uname -m)
|
|
case $arch in
|
|
x86_64|amd64)
|
|
log_info "Architecture check passed: $arch"
|
|
;;
|
|
aarch64|arm64)
|
|
log_warning "ARM64 architecture detected. Some packages may not be available."
|
|
;;
|
|
*)
|
|
log_error "Unsupported architecture: $arch"
|
|
requirements_met=false
|
|
;;
|
|
esac
|
|
|
|
if [[ "$requirements_met" == false ]]; then
|
|
log_error "System requirements not met. Exiting."
|
|
exit 1
|
|
fi
|
|
|
|
log_success "All system requirements met"
|
|
}
|
|
|
|
# Configuration management
|
|
load_or_create_config() {
|
|
log_info "Loading configuration..."
|
|
|
|
if load_config; then
|
|
log_info "Configuration loaded from ${CONFIG_FILE}"
|
|
if ! validate_config; then
|
|
log_warning "Configuration validation failed - creating new configuration"
|
|
create_interactive_config
|
|
load_config # Reload the new configuration
|
|
fi
|
|
else
|
|
log_info "Creating new configuration..."
|
|
create_interactive_config
|
|
load_config # Load the new configuration
|
|
fi
|
|
|
|
# Export configuration variables for use in subshells
|
|
export ADMIN_USER SSH_PORT CONFIGURE_STATIC_IP INSTALL_DOCKER INSTALL_NFS INSTALL_NETDATA INSTALL_VAULTWARDEN INSTALL_JELLYFIN INSTALL_PORTAINER INSTALL_WEBMIN ENABLE_AUTO_UPDATES
|
|
}
|
|
|
|
create_interactive_config() {
|
|
log_info "Interactive configuration setup"
|
|
echo
|
|
|
|
# SSH configuration
|
|
local ssh_port=$(ask_input "SSH port" "$DEFAULT_SSH_PORT" "validate_port")
|
|
save_config "SSH_PORT" "$ssh_port"
|
|
|
|
# User configuration
|
|
local current_user
|
|
if [[ -n "${SUDO_USER:-}" ]]; then
|
|
current_user="$SUDO_USER"
|
|
log_info "Using current sudo user: $current_user"
|
|
else
|
|
current_user="$USER"
|
|
log_info "Using current user: $current_user"
|
|
fi
|
|
|
|
# Pre-fill with current user, but allow override
|
|
local username=$(ask_input "Admin username" "$current_user" "validate_username")
|
|
save_config "ADMIN_USER" "$username"
|
|
# Ensure the configured admin user exists (offer interactive creation)
|
|
ensure_user_exists_interactive "$username" || log_warning "Admin user '$username' not created; some features may require it."
|
|
|
|
# Network configuration
|
|
if ask_yes_no "Configure static IP?" "n"; then
|
|
save_config "CONFIGURE_STATIC_IP" "true"
|
|
else
|
|
save_config "CONFIGURE_STATIC_IP" "false"
|
|
fi
|
|
|
|
# Service selection
|
|
local install_docker=$(ask_yes_no "Install Docker?" "y" && echo "true" || echo "false")
|
|
save_config "INSTALL_DOCKER" "$install_docker"
|
|
save_config "INSTALL_NFS" "$(ask_yes_no "Install NFS?" "n" && echo "true" || echo "false")"
|
|
save_config "INSTALL_NETDATA" "$(ask_yes_no "Install Netdata monitoring?" "y" && echo "true" || echo "false")"
|
|
|
|
# Docker-dependent services
|
|
if [[ "$install_docker" == "true" ]]; then
|
|
save_config "INSTALL_VAULTWARDEN" "$(ask_yes_no "Install Vaultwarden password manager?" "n" && echo "true" || echo "false")"
|
|
save_config "INSTALL_JELLYFIN" "$(ask_yes_no "Install Jellyfin media server?" "n" && echo "true" || echo "false")"
|
|
save_config "INSTALL_PORTAINER" "$(ask_yes_no "Install Portainer Docker management?" "n" && echo "true" || echo "false")"
|
|
else
|
|
log_warning "Docker not selected - skipping Docker-dependent services (Vaultwarden, Jellyfin, Portainer)"
|
|
save_config "INSTALL_VAULTWARDEN" "false"
|
|
save_config "INSTALL_JELLYFIN" "false"
|
|
save_config "INSTALL_PORTAINER" "false"
|
|
fi
|
|
|
|
# Automatic updates (optional)
|
|
save_config "ENABLE_AUTO_UPDATES" "$(ask_yes_no "Enable automatic security updates (unattended-upgrades)?" "n" && echo "true" || echo "false")"
|
|
|
|
save_config "INSTALL_WEBMIN" "$(ask_yes_no "Install Webmin web interface?" "n" && echo "true" || echo "false")"
|
|
|
|
log_success "Configuration created and saved to ${CONFIG_FILE}"
|
|
}
|
|
|
|
# System update with progress
|
|
update_system() {
|
|
log_info "Updating system packages..."
|
|
show_progress 1 10 "System Update"
|
|
|
|
case $DISTRO in
|
|
ubuntu|debian)
|
|
sudo apt-get update -qq
|
|
show_progress 5 10 "System Update"
|
|
sudo apt-get upgrade -y -qq
|
|
;;
|
|
fedora)
|
|
sudo dnf update -y -q
|
|
;;
|
|
arch)
|
|
sudo pacman -Syu --noconfirm --quiet
|
|
;;
|
|
opensuse)
|
|
sudo zypper refresh -q
|
|
show_progress 5 10 "System Update"
|
|
sudo zypper update -y -q
|
|
;;
|
|
esac
|
|
|
|
show_progress 10 10 "System Update"
|
|
add_rollback_action "# System packages updated - no rollback needed"
|
|
}
|
|
|
|
# Main installation orchestrator
|
|
run_installation() {
|
|
local total_steps=13
|
|
local current_step=0
|
|
|
|
log_info "Starting NAS installation process..."
|
|
|
|
# Core system setup
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to install dependencies (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing dependencies"
|
|
install_dependencies
|
|
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to configure network (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Configuring network"
|
|
if [[ "${CONFIGURE_STATIC_IP:-false}" == "true" ]]; then
|
|
configure_network
|
|
fi
|
|
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to configure SSH (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Configuring SSH"
|
|
configure_ssh
|
|
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to setup Samba (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Setting up Samba"
|
|
setup_samba
|
|
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to configure firewall (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Configuring firewall"
|
|
configure_firewall
|
|
|
|
# Security setup
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to implement security measures (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Implementing security measures"
|
|
secure_shared_memory
|
|
install_fail2ban
|
|
# Configure automatic updates only if user opted in
|
|
if [[ "${ENABLE_AUTO_UPDATES:-false}" == "true" ]]; then
|
|
configure_automatic_updates
|
|
else
|
|
log_info "Automatic security updates are disabled by configuration"
|
|
fi
|
|
|
|
# Optional services
|
|
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to install Docker (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Docker"
|
|
install_docker
|
|
else
|
|
current_step=$((current_step + 1))
|
|
fi
|
|
|
|
if [[ "${INSTALL_NFS:-false}" == "true" ]]; then
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to install NFS (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing NFS"
|
|
install_nfs
|
|
else
|
|
current_step=$((current_step + 1))
|
|
fi
|
|
|
|
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to install Netdata (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Netdata"
|
|
install_netdata
|
|
else
|
|
current_step=$((current_step + 1))
|
|
fi
|
|
|
|
if [[ "${INSTALL_VAULTWARDEN:-false}" == "true" ]]; then
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to install Vaultwarden (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Vaultwarden"
|
|
install_vaultwarden
|
|
else
|
|
current_step=$((current_step + 1))
|
|
fi
|
|
|
|
if [[ "${INSTALL_JELLYFIN:-false}" == "true" ]]; then
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to install Jellyfin (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Jellyfin"
|
|
install_jellyfin
|
|
else
|
|
current_step=$((current_step + 1))
|
|
fi
|
|
|
|
if [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to install Portainer (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Portainer"
|
|
install_portainer
|
|
else
|
|
current_step=$((current_step + 1))
|
|
fi
|
|
|
|
if [[ "${INSTALL_WEBMIN:-false}" == "true" ]]; then
|
|
current_step=$((current_step + 1)); log_debug "run_installation: about to install Webmin (step $current_step/$total_steps)"; show_progress $current_step $total_steps "Installing Webmin"
|
|
install_webmin
|
|
configure_webmin
|
|
else
|
|
current_step=$((current_step + 1))
|
|
fi
|
|
}
|
|
|
|
# Installation summary
|
|
show_installation_summary() {
|
|
local ip_address
|
|
ip_address=$(hostname -I | awk '{print $1}')
|
|
local user_home
|
|
if [[ -n "${SUDO_USER:-}" ]]; then
|
|
user_home=$(eval echo "~${SUDO_USER}")
|
|
else
|
|
user_home="$HOME"
|
|
fi
|
|
local summary_file="${user_home}/nas_services.txt"
|
|
|
|
echo
|
|
log_success "=== NAS Setup Completed Successfully ==="
|
|
echo
|
|
log_info "Installation Summary:"
|
|
echo " ✓ System updated and secured"
|
|
echo " ✓ User '${ADMIN_USER:-$USER}' created with sudo access"
|
|
echo " ✓ SSH configured on port ${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
|
echo " ✓ Samba file sharing configured"
|
|
echo " ✓ Firewall configured and enabled"
|
|
echo " ✓ Fail2ban installed and configured"
|
|
if [[ "${ENABLE_AUTO_UPDATES:-false}" == "true" ]]; then
|
|
echo " ✓ Automatic updates enabled"
|
|
else
|
|
echo " - Automatic updates not enabled (optional)"
|
|
fi
|
|
|
|
# Service summary
|
|
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
|
echo " ✓ Docker installed and configured"
|
|
fi
|
|
if [[ "${INSTALL_NFS:-false}" == "true" ]]; then
|
|
echo " ✓ NFS server installed"
|
|
fi
|
|
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
|
echo " ✓ Netdata monitoring: http://${ip_address}:${NETDATA_PORT}"
|
|
fi
|
|
if [[ "${INSTALL_JELLYFIN:-false}" == "true" ]]; then
|
|
echo " ✓ Jellyfin media server: http://${ip_address}:8096"
|
|
fi
|
|
if [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
|
echo " ✓ Portainer Docker management: http://${ip_address}:9000"
|
|
fi
|
|
if [[ "${INSTALL_WEBMIN:-false}" == "true" ]]; then
|
|
echo " ✓ Webmin web interface: https://${ip_address}:10000"
|
|
fi
|
|
|
|
# Create services summary file
|
|
log_info "Creating services summary file: ${summary_file}"
|
|
cat > "${summary_file}" << EOF
|
|
============================================================
|
|
NAS Services - Installation Summary
|
|
============================================================
|
|
|
|
Installation Date: $(date)
|
|
System IP Address: ${ip_address}
|
|
Admin User: ${ADMIN_USER:-$USER}
|
|
SSH Port: ${SSH_PORT:-$DEFAULT_SSH_PORT}
|
|
|
|
------------------------------------------------------------
|
|
Installed Services and Access Information:
|
|
------------------------------------------------------------
|
|
|
|
SSH Access:
|
|
- Host: ${ip_address}
|
|
- Port: ${SSH_PORT:-$DEFAULT_SSH_PORT}
|
|
- User: ${ADMIN_USER:-$USER}
|
|
- Command: ssh -p ${SSH_PORT:-$DEFAULT_SSH_PORT} ${ADMIN_USER:-$USER}@${ip_address}
|
|
|
|
EOF
|
|
|
|
# Add service information to file
|
|
if [[ "${INSTALL_NETDATA:-false}" == "true" ]]; then
|
|
cat >> "${summary_file}" << EOF
|
|
Netdata Monitoring:
|
|
- URL: http://${ip_address}:${NETDATA_PORT}
|
|
- Description: Real-time system monitoring and metrics
|
|
|
|
EOF
|
|
fi
|
|
|
|
if [[ "${INSTALL_JELLYFIN:-false}" == "true" ]]; then
|
|
cat >> "${summary_file}" << EOF
|
|
Jellyfin Media Server:
|
|
- Web Interface: http://${ip_address}:8096
|
|
- HTTPS Interface: http://${ip_address}:8920
|
|
- DLNA Port: ${ip_address}:1900 (UDP)
|
|
- Description: Media streaming and management server
|
|
|
|
EOF
|
|
fi
|
|
|
|
if [[ "${INSTALL_PORTAINER:-false}" == "true" ]]; then
|
|
cat >> "${summary_file}" << EOF
|
|
Portainer Docker Management:
|
|
- HTTP Interface: http://${ip_address}:9000
|
|
- HTTPS Interface: https://${ip_address}:9443
|
|
- Description: Web-based Docker container management
|
|
- Note: Use HTTPS (9443) for secure access
|
|
|
|
EOF
|
|
fi
|
|
|
|
if [[ "${INSTALL_VAULTWARDEN:-false}" == "true" ]]; then
|
|
cat >> "${summary_file}" << EOF
|
|
Vaultwarden Password Manager:
|
|
- URL: http://${ip_address}:8080
|
|
- Description: Bitwarden-compatible password manager
|
|
|
|
EOF
|
|
fi
|
|
|
|
if [[ "${INSTALL_WEBMIN:-false}" == "true" ]]; then
|
|
cat >> "${summary_file}" << EOF
|
|
Webmin System Administration:
|
|
- URL: https://${ip_address}:10000
|
|
- Description: Web-based system administration interface
|
|
|
|
EOF
|
|
fi
|
|
|
|
if [[ "${INSTALL_NFS:-false}" == "true" ]]; then
|
|
cat >> "${summary_file}" << EOF
|
|
NFS Server:
|
|
- Port: ${ip_address}:2049
|
|
- Description: Network File System for Unix/Linux clients
|
|
- Mount example: mount -t nfs ${ip_address}:/srv/nfs /mnt/nfs
|
|
|
|
EOF
|
|
fi
|
|
|
|
# Samba information
|
|
cat >> "${summary_file}" << EOF
|
|
Samba File Sharing:
|
|
- Ports: ${ip_address}:139 (TCP), ${ip_address}:445 (TCP), ${ip_address}:137-138 (UDP)
|
|
- Description: Windows file sharing (SMB/CIFS)
|
|
- Access: \\\\${ip_address} or smb://${ip_address}
|
|
|
|
EOF
|
|
|
|
# Docker information if installed
|
|
if [[ "${INSTALL_DOCKER:-false}" == "true" ]]; then
|
|
cat >> "${summary_file}" << EOF
|
|
Docker:
|
|
- Status: Installed and running
|
|
- Socket: /var/run/docker.sock
|
|
- Description: Container runtime for additional services
|
|
|
|
EOF
|
|
fi
|
|
|
|
cat >> "${summary_file}" << EOF
|
|
------------------------------------------------------------
|
|
System Information:
|
|
------------------------------------------------------------
|
|
- Configuration file: ${CONFIG_FILE}
|
|
- Installation log: ${LOG_FILE}
|
|
- System distribution: ${DISTRO_NAME} ${DISTRO_VERSION}
|
|
- Kernel: $(uname -r)
|
|
|
|
------------------------------------------------------------
|
|
Security Notes:
|
|
------------------------------------------------------------
|
|
- Firewall is active and configured
|
|
- Fail2ban is monitoring for suspicious activity
|
|
- SSH uses Ed25519 keys for enhanced security
|
|
- Root login via SSH is disabled
|
|
EOF
|
|
|
|
if [[ "${ENABLE_AUTO_UPDATES:-false}" == "true" ]]; then
|
|
echo "- Automatic security updates are enabled" >> "${summary_file}"
|
|
else
|
|
echo "- Automatic updates are disabled (manual updates recommended)" >> "${summary_file}"
|
|
fi
|
|
|
|
cat >> "${summary_file}" << EOF
|
|
|
|
------------------------------------------------------------
|
|
Next Steps:
|
|
------------------------------------------------------------
|
|
1. Reboot the system to ensure all changes take effect
|
|
2. Review the services above and access them using the provided URLs
|
|
3. Configure user accounts and permissions for file sharing
|
|
4. Set up backups for your important data
|
|
5. Regularly check system logs and monitoring
|
|
|
|
============================================================
|
|
EOF
|
|
|
|
log_success "Services summary saved to: ${summary_file}"
|
|
log_info "You can view this file with: cat ${summary_file}"
|
|
|
|
echo
|
|
log_info "Next steps:"
|
|
echo " 1. Reboot the system to ensure all changes take effect"
|
|
echo " 2. Access your NAS via SSH on port ${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
|
echo " 3. Configure file shares through Samba"
|
|
echo " 4. Review firewall rules with: sudo ufw status"
|
|
echo " 5. Check the services summary file: cat ${summary_file}"
|
|
echo
|
|
log_warning "Important: Please save the following information:"
|
|
echo " - SSH Port: ${SSH_PORT:-$DEFAULT_SSH_PORT}"
|
|
echo " - Admin User: ${ADMIN_USER:-$USER}"
|
|
echo " - Configuration saved in: ${CONFIG_FILE}"
|
|
echo " - Installation log: ${LOG_FILE}"
|
|
echo " - Services summary: ${summary_file}"
|
|
}
|
|
|
|
# Main script execution
|
|
main() {
|
|
clear
|
|
echo -e "${CYAN}${BOLD}"
|
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
echo "║ ║"
|
|
echo "║ ${SCRIPT_NAME} v${SCRIPT_VERSION} ║"
|
|
echo "║ ║"
|
|
echo "║ Automated NAS Setup for Multiple Linux Distros ║"
|
|
echo "║ ║"
|
|
echo "║ by ${SCRIPT_AUTHOR} ║"
|
|
echo "║ ║"
|
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
echo -e "${NC}"
|
|
echo
|
|
|
|
log_info "${SCRIPT_NAME} v${SCRIPT_VERSION} started"
|
|
log_info "Running on: $(uname -a)"
|
|
|
|
# Pre-flight checks
|
|
detect_distro
|
|
check_system_requirements
|
|
get_system_info
|
|
|
|
# Unset any existing config variables to ensure clean state
|
|
unset INSTALL_DOCKER INSTALL_NFS INSTALL_NETDATA INSTALL_VAULTWARDEN INSTALL_JELLYFIN INSTALL_PORTAINER INSTALL_WEBMIN CONFIGURE_STATIC_IP SSH_PORT ADMIN_USER
|
|
|
|
# Configuration
|
|
load_or_create_config
|
|
|
|
# Confirmation
|
|
echo
|
|
if ! ask_yes_no "Ready to start installation?" "y"; then
|
|
log_info "Installation cancelled by user"
|
|
exit 0
|
|
fi
|
|
|
|
# Main installation
|
|
log_info "Starting installation process..."
|
|
|
|
# Run apt cleanup only for apt-based distributions
|
|
if [[ "$DISTRO" == "ubuntu" || "$DISTRO" == "debian" ]]; then
|
|
preflight_apt_cleanup
|
|
fi
|
|
|
|
update_system
|
|
run_installation
|
|
|
|
# Cleanup and summary
|
|
cleanup
|
|
optimize_nas_performance
|
|
perform_health_check
|
|
show_installation_summary
|
|
|
|
# Reboot prompt
|
|
echo
|
|
if ask_yes_no "Reboot system now to complete setup?" "y"; then
|
|
log_info "System will reboot in 5 seconds..."
|
|
sleep 5
|
|
sudo reboot
|
|
else
|
|
log_warning "Please reboot the system manually to complete the setup"
|
|
fi
|
|
}
|
|
|
|
# Run main function
|
|
main "$@"
|