754 lines
25 KiB
Bash
Executable File
754 lines
25 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Debian 12 Initial Setup Script
|
|
# Run as root: bash setup.sh
|
|
|
|
set -euo pipefail # Exit on error, undefined vars, pipe failures
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
### === SETTINGS === ###
|
|
SYSADMIN_USER="sysadmin"
|
|
CREATE_ADDITIONAL_USER=""
|
|
ADDITIONAL_USER=""
|
|
USE_UFW=""
|
|
USE_FAIL2BAN=""
|
|
|
|
# Track which users were created during this setup
|
|
SYSADMIN_USER_CREATED=""
|
|
ADDITIONAL_USER_CREATED=""
|
|
|
|
# Track sysadmin password (will be set to generated password)
|
|
SYSADMIN_NEW_PASSWORD=""
|
|
|
|
# Logging functions
|
|
log() {
|
|
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
|
|
}
|
|
|
|
warn() {
|
|
echo -e "${YELLOW}[WARNING] $1${NC}"
|
|
}
|
|
|
|
error() {
|
|
echo -e "${RED}[ERROR] $1${NC}"
|
|
exit 1
|
|
}
|
|
|
|
# Generate a strong random password (32 characters)
|
|
generate_password() {
|
|
# Use openssl to generate a secure 32-character password
|
|
# Base64 encoding of 24 random bytes gives us 32 characters
|
|
openssl rand -base64 24 | tr -d "=+/" | cut -c1-32
|
|
}
|
|
|
|
# Check if running as root
|
|
check_root() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
error "This script must be run as root"
|
|
fi
|
|
}
|
|
|
|
# Check if running on Debian
|
|
check_debian() {
|
|
if ! grep -q "Debian" /etc/os-release; then
|
|
error "This script is designed for Debian systems"
|
|
fi
|
|
}
|
|
|
|
# Check for required commands
|
|
check_commands() {
|
|
for cmd in useradd passwd usermod; do
|
|
if ! command -v $cmd >/dev/null 2>&1; then
|
|
error "$cmd command not found. Please install required packages: apt install -y passwd"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Ask user about creating an additional user
|
|
ask_additional_user() {
|
|
echo ""
|
|
echo -e "${BLUE}=== Additional User Creation ===${NC}"
|
|
echo "This script will create the 'sysadmin' user by default."
|
|
echo "You can also create an additional user account if needed."
|
|
echo ""
|
|
read -p "Would you like to create an additional user account? (y/N): " create_user_choice
|
|
|
|
if [[ "$create_user_choice" =~ ^[Yy]$ ]]; then
|
|
CREATE_ADDITIONAL_USER="yes"
|
|
echo ""
|
|
echo -e "${YELLOW}Enter username for the additional user:${NC}"
|
|
echo "(This user will also have sudo privileges)"
|
|
echo ""
|
|
while true; do
|
|
read -p "Username: " username_input
|
|
|
|
# Validate username
|
|
if [[ -z "$username_input" ]]; then
|
|
echo -e "${RED}Username cannot be empty. Please try again.${NC}"
|
|
continue
|
|
elif [[ ! "$username_input" =~ ^[a-z][a-z0-9_-]*$ ]]; then
|
|
echo -e "${RED}Invalid username. Use lowercase letters, numbers, hyphens, and underscores only.${NC}"
|
|
echo -e "${RED}Username must start with a letter.${NC}"
|
|
continue
|
|
elif [[ "$username_input" == "$SYSADMIN_USER" ]]; then
|
|
echo -e "${RED}Username cannot be the same as sysadmin user. Please choose a different name.${NC}"
|
|
continue
|
|
elif id "$username_input" &>/dev/null; then
|
|
echo -e "${YELLOW}User '$username_input' already exists.${NC}"
|
|
read -p "Continue with existing user '$username_input'? (y/N): " continue_existing
|
|
if [[ "$continue_existing" =~ ^[Yy]$ ]]; then
|
|
ADDITIONAL_USER="$username_input"
|
|
log "Will use existing user: $ADDITIONAL_USER"
|
|
break
|
|
else
|
|
echo "Please choose a different name."
|
|
continue
|
|
fi
|
|
else
|
|
ADDITIONAL_USER="$username_input"
|
|
log "Will create additional user: $ADDITIONAL_USER"
|
|
break
|
|
fi
|
|
done
|
|
else
|
|
CREATE_ADDITIONAL_USER="no"
|
|
log "Skipping additional user creation"
|
|
fi
|
|
}
|
|
|
|
|
|
# Ask user about firewall and security preferences
|
|
ask_firewall_preferences() {
|
|
echo ""
|
|
echo -e "${BLUE}=== Firewall Configuration ===${NC}"
|
|
echo "UFW (Uncomplicated Firewall) provides easy firewall management."
|
|
echo ""
|
|
read -p "Install and configure UFW? (y/N): " ufw_choice
|
|
|
|
if [[ "$ufw_choice" =~ ^[Yy]$ ]]; then
|
|
USE_UFW="yes"
|
|
log "UFW will be installed and configured"
|
|
else
|
|
USE_UFW="no"
|
|
log "UFW will be skipped"
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BLUE}=== Fail2ban Configuration ===${NC}"
|
|
echo "Fail2ban protects against brute-force attacks."
|
|
echo ""
|
|
read -p "Install and configure fail2ban? (Y/n): " fail2ban_choice
|
|
|
|
if [[ "$fail2ban_choice" =~ ^[Nn]$ ]]; then
|
|
USE_FAIL2BAN="no"
|
|
log "Fail2ban will be skipped"
|
|
else
|
|
USE_FAIL2BAN="yes"
|
|
log "Fail2ban will be installed and configured"
|
|
fi
|
|
}
|
|
|
|
# Ask user about SSH key setup for created users
|
|
ask_ssh_key_setup() {
|
|
# Check if any users were created or selected
|
|
local users_for_ssh=()
|
|
|
|
if [[ "$SYSADMIN_USER_CREATED" == "yes" ]]; then
|
|
users_for_ssh+=("$SYSADMIN_USER")
|
|
fi
|
|
|
|
if [[ "$CREATE_ADDITIONAL_USER" == "yes" && -n "$ADDITIONAL_USER" ]]; then
|
|
users_for_ssh+=("$ADDITIONAL_USER")
|
|
fi
|
|
|
|
# Only prompt if users were created or selected
|
|
if [[ ${#users_for_ssh[@]} -eq 0 ]]; then
|
|
return
|
|
fi
|
|
|
|
echo ""
|
|
echo -e "${BLUE}=== SSH Key Setup ===${NC}"
|
|
if [[ "$SYSADMIN_USER_CREATED" == "yes" ]]; then
|
|
echo "Users created during setup: $SYSADMIN_USER"
|
|
fi
|
|
if [[ "$CREATE_ADDITIONAL_USER" == "yes" && -n "$ADDITIONAL_USER" ]]; then
|
|
if [[ "$ADDITIONAL_USER_CREATED" == "yes" ]]; then
|
|
echo "Additional user created: $ADDITIONAL_USER"
|
|
else
|
|
echo "Additional user selected: $ADDITIONAL_USER (existing)"
|
|
fi
|
|
fi
|
|
echo "You can add your SSH public key for easier login."
|
|
echo ""
|
|
read -p "Add your SSH public key to selected users? (Y/n): " add_key_choice
|
|
|
|
if [[ "$add_key_choice" =~ ^[Nn]$ ]]; then
|
|
log "SSH key setup skipped"
|
|
return
|
|
fi
|
|
|
|
local user_public_key=""
|
|
|
|
# Special case for user "sergio" - offer pre-defined keys
|
|
local sergio_keys_added=false
|
|
if [[ " ${users_for_ssh[*]} " =~ " sergio " ]]; then
|
|
echo ""
|
|
echo "Detected user 'sergio' in selected users."
|
|
echo "Use pre-configured SSH keys for sergio? (Y/n)"
|
|
echo "Key 1 (mbpm1): ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINBYyuGSa2wswiiObp2qj30MoiNRyFdBIBciFSbtrkZ8 mbpm1"
|
|
echo "Key 2 (MacMini): ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINhVmvYRywoWQoviB72DGnuv5uEaiumpNAHhDVYFLL+M MacMini"
|
|
echo ""
|
|
read -p "Use these keys? (Y/n): " use_sergio_keys
|
|
|
|
if [[ ! "$use_sergio_keys" =~ ^[Nn]$ ]]; then
|
|
# Add both keys for sergio
|
|
setup_ssh_key_for_user "sergio" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINBYyuGSa2wswiiObp2qj30MoiNRyFdBIBciFSbtrkZ8 mbpm1"
|
|
setup_ssh_key_for_user "sergio" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINhVmvYRywoWQoviB72DGnuv5uEaiumpNAHhDVYFLL+M MacMini"
|
|
log "Using pre-configured keys for sergio"
|
|
sergio_keys_added=true
|
|
fi
|
|
fi
|
|
|
|
# If no pre-defined key was used, prompt for manual entry
|
|
if [[ -z "$user_public_key" ]]; then
|
|
echo ""
|
|
echo "Please paste your SSH public key (starts with ssh-rsa, ssh-ed25519, etc.):"
|
|
echo "You can find it with: cat ~/.ssh/id_ed25519.pub (or id_rsa.pub)"
|
|
echo ""
|
|
|
|
while true; do
|
|
read -r user_public_key
|
|
|
|
if [[ -z "$user_public_key" ]]; then
|
|
echo -e "${RED}Public key cannot be empty. Please try again.${NC}"
|
|
continue
|
|
elif [[ "$user_public_key" =~ ^(ssh-rsa|ssh-dss|ssh-ed25519|ecdsa-sha2-) ]]; then
|
|
break
|
|
else
|
|
echo -e "${RED}Invalid SSH public key format. Please ensure you copied the entire key.${NC}"
|
|
continue
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Add key to all selected users and generate SSH keys for them
|
|
for username in "${users_for_ssh[@]}"; do
|
|
# Skip sergio if we already added their pre-configured keys
|
|
if [[ "$username" == "sergio" && "$sergio_keys_added" == true ]]; then
|
|
continue
|
|
fi
|
|
setup_ssh_key_for_user "$username" "$user_public_key"
|
|
generate_ssh_key_for_user "$username"
|
|
done
|
|
|
|
# Always generate SSH key for sergio if present
|
|
if [[ " ${users_for_ssh[*]} " =~ " sergio " ]]; then
|
|
generate_ssh_key_for_user "sergio"
|
|
fi
|
|
|
|
echo ""
|
|
log "SSH key added to: ${users_for_ssh[*]}"
|
|
log "SSH keys generated for: ${users_for_ssh[*]}"
|
|
}
|
|
|
|
setup_ssh_key_for_user() {
|
|
local username="$1"
|
|
local public_key="$2"
|
|
local user_home="/home/$username"
|
|
local ssh_dir="$user_home/.ssh"
|
|
local authorized_keys="$ssh_dir/authorized_keys"
|
|
|
|
log "Setting up SSH key for user: $username"
|
|
|
|
# Create .ssh directory if it doesn't exist
|
|
if [ ! -d "$ssh_dir" ]; then
|
|
sudo -u "$username" mkdir -p "$ssh_dir"
|
|
sudo -u "$username" chmod 700 "$ssh_dir"
|
|
fi
|
|
|
|
# Check if key already exists
|
|
if [ -f "$authorized_keys" ] && grep -Fxq "$public_key" "$authorized_keys"; then
|
|
warn "SSH key already exists for $username"
|
|
else
|
|
echo "$public_key" | sudo -u "$username" tee -a "$authorized_keys" > /dev/null
|
|
sudo -u "$username" chmod 600 "$authorized_keys"
|
|
log "SSH key added for $username"
|
|
fi
|
|
}
|
|
|
|
generate_ssh_key_for_user() {
|
|
local username="$1"
|
|
local user_home="/home/$username"
|
|
local ssh_dir="$user_home/.ssh"
|
|
local private_key="$ssh_dir/id_ed25519"
|
|
local public_key="$ssh_dir/id_ed25519.pub"
|
|
|
|
# Check if SSH key already exists
|
|
if [[ -f "$private_key" ]]; then
|
|
log "SSH key already exists for $username, skipping generation"
|
|
return
|
|
fi
|
|
|
|
log "Generating SSH key for user: $username"
|
|
|
|
# Create .ssh directory if it doesn't exist
|
|
if [ ! -d "$ssh_dir" ]; then
|
|
sudo -u "$username" mkdir -p "$ssh_dir"
|
|
sudo -u "$username" chmod 700 "$ssh_dir"
|
|
fi
|
|
|
|
# Generate SSH key without passphrase
|
|
sudo -u "$username" ssh-keygen -t ed25519 -f "$private_key" -N "" -C "$username@$(hostname)"
|
|
|
|
# Set proper permissions
|
|
sudo -u "$username" chmod 600 "$private_key"
|
|
sudo -u "$username" chmod 644 "$public_key"
|
|
|
|
log "SSH key pair generated for $username"
|
|
echo " Private key: $private_key"
|
|
echo " Public key: $public_key"
|
|
}
|
|
|
|
### === DEBIAN SYSTEM SETUP === ###
|
|
setup_system() {
|
|
log "Starting Debian 12 initial setup..."
|
|
|
|
# Update system packages
|
|
log "Updating system packages..."
|
|
apt update && apt upgrade -y
|
|
|
|
# Install essential packages
|
|
log "Installing essential packages..."
|
|
|
|
# Build package list based on user preferences
|
|
local packages="sudo curl wget vim htop unzip git openssh-server"
|
|
|
|
if [[ "$USE_UFW" == "yes" ]]; then
|
|
packages="$packages ufw"
|
|
fi
|
|
|
|
if [[ "$USE_FAIL2BAN" == "yes" ]]; then
|
|
packages="$packages fail2ban"
|
|
fi
|
|
|
|
log "Installing packages: $packages"
|
|
apt install -y $packages
|
|
}
|
|
|
|
create_sysadmin_user() {
|
|
log "Creating user: $SYSADMIN_USER"
|
|
log "Checking if user $SYSADMIN_USER already exists..."
|
|
|
|
if id "$SYSADMIN_USER" &>/dev/null; then
|
|
warn "User $SYSADMIN_USER already exists, skipping creation"
|
|
log "User $SYSADMIN_USER found in system, UID: $(id -u $SYSADMIN_USER)"
|
|
SYSADMIN_USER_CREATED="no"
|
|
|
|
# Generate and set a new strong password for existing user
|
|
log "Generating strong password for existing user $SYSADMIN_USER..."
|
|
SYSADMIN_NEW_PASSWORD=$(generate_password)
|
|
echo "$SYSADMIN_USER:$SYSADMIN_NEW_PASSWORD" | chpasswd
|
|
log "Password set for existing user $SYSADMIN_USER"
|
|
else
|
|
# Create user with home directory
|
|
log "Attempting to create user $SYSADMIN_USER with home directory..."
|
|
log "Running command: useradd -m -s /bin/bash $SYSADMIN_USER"
|
|
|
|
if useradd -m -s /bin/bash "$SYSADMIN_USER"; then
|
|
log "User $SYSADMIN_USER created successfully"
|
|
log "User details: $(getent passwd $SYSADMIN_USER)"
|
|
log "Home directory: $(getent passwd $SYSADMIN_USER | cut -d: -f6)"
|
|
SYSADMIN_USER_CREATED="yes"
|
|
else
|
|
error "Failed to create user $SYSADMIN_USER. Exit code: $?"
|
|
fi
|
|
|
|
# Generate and set strong password for new user
|
|
log "Generating strong password for $SYSADMIN_USER..."
|
|
SYSADMIN_NEW_PASSWORD=$(generate_password)
|
|
echo "$SYSADMIN_USER:$SYSADMIN_NEW_PASSWORD" | chpasswd
|
|
log "Password set successfully for $SYSADMIN_USER"
|
|
fi
|
|
|
|
# Add sysadmin to sudo group
|
|
log "Adding $SYSADMIN_USER to sudo group..."
|
|
log "Running command: usermod -aG sudo $SYSADMIN_USER"
|
|
|
|
if usermod -aG sudo "$SYSADMIN_USER"; then
|
|
log "Successfully added $SYSADMIN_USER to sudo group"
|
|
log "User groups: $(groups $SYSADMIN_USER)"
|
|
else
|
|
error "Failed to add $SYSADMIN_USER to sudo group. Exit code: $?"
|
|
fi
|
|
}
|
|
|
|
create_additional_user() {
|
|
if [[ "$CREATE_ADDITIONAL_USER" == "yes" && -n "$ADDITIONAL_USER" ]]; then
|
|
log "Creating additional user: $ADDITIONAL_USER"
|
|
log "Checking if user $ADDITIONAL_USER already exists..."
|
|
|
|
if id "$ADDITIONAL_USER" &>/dev/null; then
|
|
log "Using existing user: $ADDITIONAL_USER"
|
|
log "User $ADDITIONAL_USER found in system, UID: $(id -u $ADDITIONAL_USER)"
|
|
ADDITIONAL_USER_CREATED="no"
|
|
else
|
|
# Create user with home directory
|
|
log "Attempting to create user $ADDITIONAL_USER with home directory..."
|
|
log "Running command: useradd -m -s /bin/bash $ADDITIONAL_USER"
|
|
|
|
if useradd -m -s /bin/bash "$ADDITIONAL_USER"; then
|
|
log "User $ADDITIONAL_USER created successfully"
|
|
log "User details: $(getent passwd $ADDITIONAL_USER)"
|
|
log "Home directory: $(getent passwd $ADDITIONAL_USER | cut -d: -f6)"
|
|
ADDITIONAL_USER_CREATED="yes"
|
|
else
|
|
error "Failed to create user $ADDITIONAL_USER. Exit code: $?"
|
|
fi
|
|
|
|
# Set password for additional user with retry logic
|
|
local max_attempts=3
|
|
local attempt=1
|
|
|
|
while [ $attempt -le $max_attempts ]; do
|
|
echo "Please set a password for user $ADDITIONAL_USER (attempt $attempt of $max_attempts):"
|
|
if passwd "$ADDITIONAL_USER"; then
|
|
log "Password set successfully for $ADDITIONAL_USER"
|
|
break
|
|
else
|
|
warn "Failed to set password for $ADDITIONAL_USER"
|
|
if [ $attempt -eq $max_attempts ]; then
|
|
error "Failed to set password after $max_attempts attempts. Exiting."
|
|
fi
|
|
echo "Please try again..."
|
|
((attempt++))
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Add additional user to sudo group (existing or newly created)
|
|
log "Adding $ADDITIONAL_USER to sudo group..."
|
|
log "Running command: usermod -aG sudo $ADDITIONAL_USER"
|
|
|
|
if usermod -aG sudo "$ADDITIONAL_USER"; then
|
|
log "Successfully added $ADDITIONAL_USER to sudo group"
|
|
log "User groups: $(groups $ADDITIONAL_USER)"
|
|
else
|
|
error "Failed to add $ADDITIONAL_USER to sudo group. Exit code: $?"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
configure_security() {
|
|
# Disable root SSH login
|
|
log "Disabling root SSH login..."
|
|
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
|
|
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
|
|
|
|
# Sysadmin SSH login is ENABLED (no DenyUsers for sysadmin)
|
|
log "Sysadmin SSH login will be enabled..."
|
|
|
|
# Configure SSH settings
|
|
log "Applying SSH security settings..."
|
|
|
|
# Configure basic SSH security - enable password auth by default for safety
|
|
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config
|
|
|
|
# Configure other SSH settings more safely
|
|
sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
|
|
sed -i 's/^#*PermitEmptyPasswords.*/PermitEmptyPasswords no/' /etc/ssh/sshd_config
|
|
sed -i 's/^#*X11Forwarding.*/X11Forwarding no/' /etc/ssh/sshd_config
|
|
sed -i 's/^#*MaxAuthTries.*/MaxAuthTries 3/' /etc/ssh/sshd_config
|
|
|
|
# Add settings that might not exist
|
|
if ! grep -q "^ClientAliveInterval" /etc/ssh/sshd_config; then
|
|
echo "ClientAliveInterval 300" >> /etc/ssh/sshd_config
|
|
else
|
|
sed -i 's/^#*ClientAliveInterval.*/ClientAliveInterval 300/' /etc/ssh/sshd_config
|
|
fi
|
|
|
|
if ! grep -q "^ClientAliveCountMax" /etc/ssh/sshd_config; then
|
|
echo "ClientAliveCountMax 2" >> /etc/ssh/sshd_config
|
|
else
|
|
sed -i 's/^#*ClientAliveCountMax.*/ClientAliveCountMax 2/' /etc/ssh/sshd_config
|
|
fi
|
|
|
|
# Configure AllowUsers (remove old entries first)
|
|
# Sysadmin is always allowed to SSH in
|
|
sed -i '/^AllowUsers/d' /etc/ssh/sshd_config
|
|
if [[ "$CREATE_ADDITIONAL_USER" == "yes" && -n "$ADDITIONAL_USER" ]]; then
|
|
echo "AllowUsers $SYSADMIN_USER $ADDITIONAL_USER" >> /etc/ssh/sshd_config
|
|
log "SSH access enabled for: $SYSADMIN_USER and $ADDITIONAL_USER"
|
|
else
|
|
echo "AllowUsers $SYSADMIN_USER" >> /etc/ssh/sshd_config
|
|
log "SSH access enabled for: $SYSADMIN_USER"
|
|
fi
|
|
|
|
# Test SSH configuration
|
|
log "Testing SSH configuration..."
|
|
sshd -t || error "SSH configuration is invalid!"
|
|
|
|
# Remove/lock root password
|
|
log "Locking root password..."
|
|
passwd -l root
|
|
|
|
# Sysadmin password is NOT locked - it has a strong generated password instead
|
|
log "Sysadmin password remains unlocked with strong generated password"
|
|
|
|
# Configure firewall if requested
|
|
if [[ "$USE_UFW" == "yes" ]]; then
|
|
configure_ufw
|
|
fi
|
|
|
|
# Configure fail2ban if requested
|
|
if [[ "$USE_FAIL2BAN" == "yes" ]]; then
|
|
configure_fail2ban
|
|
fi
|
|
|
|
# Set up automatic security updates
|
|
log "Configuring automatic security updates..."
|
|
apt install -y unattended-upgrades apt-listchanges
|
|
|
|
# Configure unattended upgrades
|
|
cat > /etc/apt/apt.conf.d/50unattended-upgrades << 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
|
|
|
|
# Enable automatic updates
|
|
echo 'APT::Periodic::Update-Package-Lists "1";' > /etc/apt/apt.conf.d/20auto-upgrades
|
|
echo 'APT::Periodic::Unattended-Upgrade "1";' >> /etc/apt/apt.conf.d/20auto-upgrades
|
|
|
|
# Set timezone (optional)
|
|
log "Current timezone: $(timedatectl show --property=Timezone --value)"
|
|
echo "If you want to change timezone, run: timedatectl set-timezone Your/Timezone"
|
|
}
|
|
|
|
configure_ufw() {
|
|
log "Configuring UFW firewall..."
|
|
|
|
# Reset UFW to defaults
|
|
ufw --force reset
|
|
|
|
# Set default policies
|
|
ufw default deny incoming
|
|
ufw default allow outgoing
|
|
|
|
# Allow SSH (port 22)
|
|
ufw allow ssh
|
|
ufw allow 22/tcp
|
|
|
|
# Allow HTTP (port 80)
|
|
ufw allow http
|
|
ufw allow 80/tcp
|
|
|
|
# Allow HTTPS (port 443)
|
|
ufw allow https
|
|
ufw allow 443/tcp
|
|
|
|
# Enable UFW
|
|
ufw --force enable
|
|
|
|
log "UFW status:"
|
|
ufw status verbose
|
|
}
|
|
|
|
|
|
configure_fail2ban() {
|
|
if [[ "$USE_FAIL2BAN" == "yes" ]]; then
|
|
log "Configuring fail2ban..."
|
|
|
|
# Ensure fail2ban directories exist
|
|
mkdir -p /etc/fail2ban/jail.d
|
|
|
|
# Create configuration in jail.d instead of overwriting jail.local
|
|
cat > /etc/fail2ban/jail.d/custom.conf << EOF
|
|
[DEFAULT]
|
|
bantime = 1h
|
|
findtime = 10m
|
|
maxretry = 3
|
|
ignoreip = 127.0.0.1/8 ::1
|
|
|
|
[sshd]
|
|
enabled = true
|
|
port = ssh
|
|
filter = sshd
|
|
logpath = /var/log/auth.log
|
|
maxretry = 3
|
|
bantime = 1h
|
|
EOF
|
|
|
|
# Verify log file exists
|
|
if [[ ! -f /var/log/auth.log ]]; then
|
|
warn "Auth log file doesn't exist yet, creating it..."
|
|
touch /var/log/auth.log
|
|
chmod 640 /var/log/auth.log
|
|
fi
|
|
|
|
# Start and enable fail2ban with error handling
|
|
systemctl enable fail2ban
|
|
|
|
# Give a moment for systemd to process
|
|
sleep 2
|
|
|
|
if systemctl start fail2ban; then
|
|
# Verify it's actually running
|
|
if systemctl is-active --quiet fail2ban; then
|
|
log "Fail2ban configured and started successfully"
|
|
# Show status briefly
|
|
systemctl status fail2ban --no-pager --lines=3
|
|
else
|
|
warn "Fail2ban started but may have issues. Check: systemctl status fail2ban"
|
|
fi
|
|
else
|
|
error "Failed to start fail2ban service"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
|
|
|
|
|
|
### === CLEANUP AND FINALIZATION === ###
|
|
finalize_setup() {
|
|
# Restart SSH service safely
|
|
log "Restarting SSH service..."
|
|
if ! systemctl restart sshd; then
|
|
error "Failed to restart SSH service! Check configuration and try again."
|
|
log "You can restore SSH configuration from backup if needed:"
|
|
log "ls /etc/ssh/sshd_config.backup.*"
|
|
exit 1
|
|
fi
|
|
|
|
# Verify SSH service is running
|
|
if ! systemctl is-active --quiet sshd; then
|
|
error "SSH service is not running after restart!"
|
|
exit 1
|
|
fi
|
|
|
|
log "SSH service restarted successfully"
|
|
|
|
# Copy customization script to sysadmin user home folder (always replace if exists)
|
|
log "Copying customization script..."
|
|
if [[ -f "costumize.sh" ]]; then
|
|
log "Local costumize.sh found, copying to /home/$SYSADMIN_USER/costumize.sh (replacing if exists)"
|
|
cp -f costumize.sh /home/$SYSADMIN_USER/costumize.sh
|
|
chmod +x /home/$SYSADMIN_USER/costumize.sh
|
|
chown $SYSADMIN_USER:$SYSADMIN_USER /home/$SYSADMIN_USER/costumize.sh
|
|
log "Customization script copied to /home/$SYSADMIN_USER/costumize.sh"
|
|
else
|
|
# Fallback to download if local file doesn't exist
|
|
log "Local costumize.sh not found, attempting download..."
|
|
if wget -O /home/$SYSADMIN_USER/costumize.sh "https://git.del-c.net/Del-c.net/debian-first-boot-setup/raw/branch/main/costumize.sh"; then
|
|
chmod +x /home/$SYSADMIN_USER/costumize.sh
|
|
chown $SYSADMIN_USER:$SYSADMIN_USER /home/$SYSADMIN_USER/costumize.sh
|
|
log "Customization script downloaded to /home/$SYSADMIN_USER/costumize.sh"
|
|
else
|
|
warn "Failed to copy or download customization script"
|
|
fi
|
|
fi
|
|
|
|
# Clean up
|
|
log "Cleaning up..."
|
|
apt autoremove -y
|
|
apt autoclean
|
|
|
|
log "Setup completed successfully!"
|
|
echo ""
|
|
echo -e "${BLUE}=== SETUP SUMMARY ===${NC}"
|
|
echo -e "${YELLOW}• Root SSH login: DISABLED${NC}"
|
|
echo -e "${YELLOW}• Root password: LOCKED${NC}"
|
|
echo -e "${GREEN}• Sysadmin SSH login: ENABLED${NC}"
|
|
echo -e "${GREEN}• Sysadmin password: UNLOCKED (strong password set)${NC}"
|
|
echo -e "${YELLOW}• Main user: $SYSADMIN_USER (sudo access)${NC}"
|
|
|
|
# Always display the generated password prominently
|
|
if [[ -n "$SYSADMIN_NEW_PASSWORD" ]]; then
|
|
echo ""
|
|
echo -e "${RED}========================================${NC}"
|
|
echo -e "${RED} IMPORTANT - SAVE THIS PASSWORD!${NC}"
|
|
echo -e "${RED}========================================${NC}"
|
|
echo -e "${RED}Sysadmin user: $SYSADMIN_USER${NC}"
|
|
echo -e "${RED}Password: $SYSADMIN_NEW_PASSWORD${NC}"
|
|
echo -e "${RED}========================================${NC}"
|
|
echo ""
|
|
fi
|
|
|
|
if [[ "$CREATE_ADDITIONAL_USER" == "yes" && -n "$ADDITIONAL_USER" ]]; then
|
|
echo -e "${YELLOW}• Additional user: $ADDITIONAL_USER (sudo access)${NC}"
|
|
fi
|
|
|
|
if [[ "$USE_UFW" == "yes" ]]; then
|
|
echo -e "${YELLOW}• UFW firewall: ENABLED (SSH, HTTP, HTTPS)${NC}"
|
|
fi
|
|
|
|
if [[ "$USE_FAIL2BAN" == "yes" ]]; then
|
|
echo -e "${YELLOW}• Fail2ban: ENABLED (SSH protection)${NC}"
|
|
fi
|
|
|
|
echo -e "${YELLOW}• Automatic security updates: ENABLED${NC}"
|
|
echo ""
|
|
echo -e "${GREEN}Connect with: ssh $SYSADMIN_USER@$(hostname -I | awk '{print $1}')${NC}"
|
|
echo -e "${YELLOW}Reboot recommended${NC}"
|
|
}
|
|
|
|
### === MAIN === ###
|
|
main() {
|
|
# Check prerequisites
|
|
check_root
|
|
check_debian
|
|
check_commands
|
|
|
|
echo -e "${BLUE}=== Debian 12 Initial Setup ===${NC}"
|
|
echo "This script will set up a secure Debian 12 system with:"
|
|
echo "• Sysadmin user with sudo access"
|
|
echo "• Optional additional user"
|
|
echo "• SSH security hardening"
|
|
echo "• Optional UFW firewall and fail2ban"
|
|
echo ""
|
|
read -p "Continue? (y/N): " confirm
|
|
|
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
|
echo "Setup cancelled."
|
|
exit 0
|
|
fi
|
|
|
|
# Ask for user and security preferences
|
|
ask_additional_user
|
|
ask_firewall_preferences
|
|
|
|
# System setup
|
|
setup_system
|
|
create_sysadmin_user
|
|
create_additional_user
|
|
|
|
# SSH key setup for created users
|
|
ask_ssh_key_setup
|
|
|
|
configure_security
|
|
|
|
|
|
# Finalize
|
|
finalize_setup
|
|
|
|
# Self-delete the script after successful completion
|
|
log "Cleaning up setup script..."
|
|
rm -f "$0"
|
|
log "Setup script deleted successfully"
|
|
}
|
|
|
|
main "$@"
|