#!/bin/bash # Debian 12 Initial Setup Script with Git Integration # 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 === ### GIT_SERVER="git.del-c.net" USERNAME="" SELECTED_REPO="" SELECTED_DIR="" SYSADMIN_USER="sysadmin" # 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 } # 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 } ### === 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..." apt install -y sudo ufw curl wget vim htop unzip fail2ban git openssh-server } create_sysadmin_user() { log "Creating user: $SYSADMIN_USER" if id "$SYSADMIN_USER" &>/dev/null; then warn "User $SYSADMIN_USER already exists, skipping creation" else # Create user with home directory useradd -m -s /bin/bash "$SYSADMIN_USER" log "User $SYSADMIN_USER created successfully" # Set password for sysadmin user echo "Please set a password for user $SYSADMIN_USER:" passwd "$SYSADMIN_USER" fi # Add sysadmin to sudo group log "Adding $SYSADMIN_USER to sudo group..." usermod -aG sudo "$SYSADMIN_USER" } 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 # Additional SSH hardening log "Applying SSH security settings..." { echo "Protocol 2" echo "PasswordAuthentication no" echo "PubkeyAuthentication yes" echo "PermitEmptyPasswords no" echo "X11Forwarding no" echo "MaxAuthTries 3" echo "ClientAliveInterval 300" echo "ClientAliveCountMax 2" echo "AllowUsers $SYSADMIN_USER" } >> /etc/ssh/sshd_config # Remove/lock root password log "Locking root password..." passwd -l root # Configure UFW (Uncomplicated Firewall) 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 for SSH protection log "Configuring fail2ban..." cat > /etc/fail2ban/jail.local << EOF [DEFAULT] bantime = 1h findtime = 10m maxretry = 3 [sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 1h EOF # Start and enable fail2ban systemctl enable fail2ban systemctl start fail2ban # 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" } ### === GET USERNAME === ### get_username() { echo "[?] Enter your git username:" read -p "Username: " USERNAME if [ -z "$USERNAME" ]; then echo "[!] Username cannot be empty. Please try again." get_username fi echo "[*] Using username: $USERNAME" echo } ### === SSH KEY GENERATION FOR SYSADMIN === ### generate_ssh_key() { local sysadmin_home="/home/$SYSADMIN_USER" local ssh_dir="$sysadmin_home/.ssh" local ssh_key="$ssh_dir/id_ed25519" log "Setting up SSH key for user: $SYSADMIN_USER" # Create .ssh directory for sysadmin user if it doesn't exist if [ ! -d "$ssh_dir" ]; then sudo -u "$SYSADMIN_USER" mkdir -p "$ssh_dir" sudo -u "$SYSADMIN_USER" chmod 700 "$ssh_dir" fi if [ ! -f "$ssh_key.pub" ]; then log "Generating SSH key for $SYSADMIN_USER..." echo "[+] Please enter your email for the SSH key:" read -p "Enter your email: " user_email # Generate SSH key as sysadmin user sudo -u "$SYSADMIN_USER" ssh-keygen -t ed25519 -C "$user_email" -f "$ssh_key" -N "" # Set proper permissions sudo -u "$SYSADMIN_USER" chmod 600 "$ssh_key" sudo -u "$SYSADMIN_USER" chmod 644 "$ssh_key.pub" log "SSH key generated successfully for $SYSADMIN_USER" else warn "SSH key already exists for $SYSADMIN_USER" fi } show_ssh_key() { local sysadmin_home="/home/$SYSADMIN_USER" local ssh_key="$sysadmin_home/.ssh/id_ed25519.pub" echo "" echo -e "${BLUE}=== SSH PUBLIC KEY ===${NC}" echo "Add the following public key to your Git server and any other systems:" echo "----------------------------------------" cat "$ssh_key" echo "----------------------------------------" echo "" echo -e "${YELLOW}Instructions:${NC}" echo "1. Copy the key above" echo "2. Go to your git server ($GIT_SERVER) and add it to your account" echo "3. Add it to any other systems you need SSH access to" echo "" read -p "Press Enter after you've added the key to continue..." } ### === LIST AVAILABLE GIT PROJECTS === ### list_git_projects() { echo "[+] Fetching all accessible git projects..." local repo_count=1 local found_repos=() # Try to use git server API if available (GitLab/Gitea style) if command -v curl &> /dev/null; then echo "[*] Attempting to fetch repositories via API..." # Try GitLab API format local gitlab_repos=$(curl -s -H "Authorization: Bearer $(ssh-add -L 2>/dev/null || echo '')" \ "https://$GIT_SERVER/api/v4/projects?membership=true&per_page=100" 2>/dev/null | \ grep -o '"path_with_namespace":"[^"]*' | cut -d'"' -f4 2>/dev/null || echo "") # Try Gitea API format if [ -z "$gitlab_repos" ]; then local gitea_repos=$(curl -s "https://$GIT_SERVER/api/v1/user/repos" 2>/dev/null | \ grep -o '"full_name":"[^"]*' | cut -d'"' -f4 2>/dev/null || echo "") gitlab_repos="$gitea_repos" fi if [ -n "$gitlab_repos" ]; then echo "[*] Found repositories via API:" while IFS= read -r repo; do if [ -n "$repo" ]; then echo "$repo_count. $repo" found_repos+=("$repo") ((repo_count++)) fi done <<< "$gitlab_repos" fi fi # Fallback: Check common patterns for multiple users and the current user if [ ${#found_repos[@]} -eq 0 ]; then echo "[*] API not available, scanning common repository patterns..." # Check user's own repositories first for repo in "dotfiles" "scripts" "configs" "tools" "projects" "notes" "backup" "workspace"; do local full_repo="$USERNAME/$repo" if git ls-remote "git@$GIT_SERVER:$full_repo.git" &>/dev/null; then echo "$repo_count. $full_repo (owner)" found_repos+=("$full_repo") ((repo_count++)) fi done # Check common shared repositories and other users' public repos local common_users=("admin" "shared" "public" "team" "common" "devops" "infrastructure") local common_repos=("dotfiles" "scripts" "configs" "tools" "projects" "notes" "backup" "workspace" "templates" "shared-configs" "common-tools") for user in "${common_users[@]}"; do for repo in "${common_repos[@]}"; do local full_repo="$user/$repo" if [ "$user" != "$USERNAME" ] && git ls-remote "git@$GIT_SERVER:$full_repo.git" &>/dev/null; then echo "$repo_count. $full_repo (shared)" found_repos+=("$full_repo") ((repo_count++)) fi done done # Try to discover repositories by checking SSH access to common paths echo "[*] Checking for additional accessible repositories..." # This is a more aggressive approach - try common project names local project_names=("website" "api" "frontend" "backend" "database" "monitoring" "deployment" "ci-cd" "documentation") for user in "${common_users[@]}" "$USERNAME"; do for project in "${project_names[@]}"; do local full_repo="$user/$project" if git ls-remote "git@$GIT_SERVER:$full_repo.git" &>/dev/null 2>&1; then # Check if we haven't already added this repo local already_added=false for existing_repo in "${found_repos[@]}"; do if [ "$existing_repo" = "$full_repo" ]; then already_added=true break fi done if [ "$already_added" = false ]; then local access_type="shared" if [ "$user" = "$USERNAME" ]; then access_type="owner" fi echo "$repo_count. $full_repo ($access_type)" found_repos+=("$full_repo") ((repo_count++)) fi fi done done fi if [ ${#found_repos[@]} -eq 0 ]; then echo "[!] No accessible repositories found" echo "[*] You can still enter a custom repository path." else echo echo "[*] Found ${#found_repos[@]} accessible repositories" fi echo } ### === SELECT PROJECT TO DOWNLOAD === ### select_project() { list_git_projects echo "[?] Which project would you like to download?" echo "Enter the number of the repository from the list above, or:" echo "- Press Enter to use $USERNAME/dotfiles (if available)" echo "- Type 'custom' to enter a custom repository path" echo read -p "Enter your choice: " choice if [ -z "$choice" ]; then # Default to dotfiles if it exists if git ls-remote "git@$GIT_SERVER:$USERNAME/dotfiles.git" &>/dev/null; then SELECTED_REPO="git@$GIT_SERVER:$USERNAME/dotfiles.git" SELECTED_DIR="$HOME/.dotfiles" else echo "[!] $USERNAME/dotfiles not found. Please select a repository." select_project return fi elif [ "$choice" = "custom" ]; then read -p "Enter repository path (e.g., $USERNAME/myproject): " custom_repo SELECTED_REPO="git@$GIT_SERVER:$custom_repo.git" SELECTED_DIR="$HOME/$(basename $custom_repo)" elif [[ "$choice" =~ ^[0-9]+$ ]]; then # User selected a number from the list local repo_count=1 local selected_repo="" for repo in "dotfiles" "scripts" "configs" "tools" "projects" "notes" "backup" "workspace"; do local full_repo="$USERNAME/$repo" if git ls-remote "git@$GIT_SERVER:$full_repo.git" &>/dev/null; then if [ "$repo_count" -eq "$choice" ]; then selected_repo="$full_repo" break fi ((repo_count++)) fi done if [ -n "$selected_repo" ]; then SELECTED_REPO="git@$GIT_SERVER:$selected_repo.git" if [ "$(basename $selected_repo)" = "dotfiles" ]; then SELECTED_DIR="$HOME/.dotfiles" else SELECTED_DIR="$HOME/$(basename $selected_repo)" fi else echo "[!] Invalid choice. Please try again." select_project return fi else echo "[!] Invalid choice. Please try again." select_project return fi echo "[*] Selected repository: $SELECTED_REPO" echo "[*] Download directory: $SELECTED_DIR" echo } ### === CLONE SELECTED REPO === ### clone_selected_repo() { local sysadmin_home="/home/$SYSADMIN_USER" # Update selected directory to be relative to sysadmin user's home if [[ "$SELECTED_DIR" == "$HOME/"* ]]; then SELECTED_DIR="${SELECTED_DIR/$HOME/$sysadmin_home}" fi if [ ! -d "$SELECTED_DIR" ]; then log "Cloning selected repository as $SYSADMIN_USER..." sudo -u "$SYSADMIN_USER" git clone "$SELECTED_REPO" "$SELECTED_DIR" else warn "Repository already cloned. Force pulling from remote (overwriting local changes)..." cd "$SELECTED_DIR" sudo -u "$SYSADMIN_USER" git fetch origin sudo -u "$SYSADMIN_USER" git reset --hard origin/$(sudo -u "$SYSADMIN_USER" git symbolic-ref --short HEAD) sudo -u "$SYSADMIN_USER" git clean -fd fi # Only run setup if it's the dotfiles repository if [[ "$SELECTED_REPO" == *"dotfiles.git" && -f "$SELECTED_DIR/setup.sh" ]]; then log "Launching dotfiles setup as $SYSADMIN_USER..." sudo -u "$SYSADMIN_USER" bash "$SELECTED_DIR/setup.sh" else log "Repository cloned successfully to: $SELECTED_DIR" log "Repository is owned by: $SYSADMIN_USER" fi } ### === CLEANUP AND FINALIZATION === ### finalize_setup() { # Restart SSH service log "Restarting SSH service..." systemctl restart sshd # Clean up log "Cleaning up..." apt autoremove -y apt autoclean # Final security check log "Final system status:" echo "================================" echo "UFW Status:" ufw status echo "================================" echo "SSH Configuration:" grep -E "PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|AllowUsers" /etc/ssh/sshd_config echo "================================" echo "Sudo users:" grep -E "sudo|wheel" /etc/group echo "================================" log "Setup completed successfully!" echo "" echo -e "${BLUE}=== IMPORTANT NOTES ===${NC}" echo -e "${YELLOW}1. Root SSH login is now DISABLED${NC}" echo -e "${YELLOW}2. Root password is LOCKED${NC}" echo -e "${YELLOW}3. SSH password authentication is DISABLED${NC}" echo -e "${YELLOW}4. Use '$SYSADMIN_USER' user with SSH key to connect${NC}" echo -e "${YELLOW}5. UFW firewall is active (SSH, HTTP, HTTPS allowed)${NC}" echo -e "${YELLOW}6. Fail2ban is protecting SSH${NC}" echo -e "${YELLOW}7. Automatic security updates are enabled${NC}" echo "" echo -e "${RED}REBOOT RECOMMENDED${NC}" echo "" echo "To connect: ssh $SYSADMIN_USER@$(hostname -I | awk '{print $1}')" } ### === MAIN === ### main() { # Check prerequisites check_root check_debian echo -e "${BLUE}=== Debian 12 Initial Setup with Git Integration ===${NC}" echo "This script will:" echo "1. Set up a secure Debian 12 system" echo "2. Create a sysadmin user with SSH key authentication" echo "3. Optionally clone a git repository" echo "" read -p "Continue? (y/N): " confirm if [[ ! "$confirm" =~ ^[Yy]$ ]]; then echo "Setup cancelled." exit 0 fi # System setup setup_system create_sysadmin_user configure_security # SSH key setup generate_ssh_key show_ssh_key # Optional git repository setup echo "" echo -e "${BLUE}=== Optional Git Repository Setup ===${NC}" read -p "Would you like to clone a git repository? (y/N): " git_setup if [[ "$git_setup" =~ ^[Yy]$ ]]; then get_username select_project clone_selected_repo else log "Skipping git repository setup" fi # Finalize finalize_setup } main "$@"