diff --git a/README.md b/README.md index a13d7c8..347f5d8 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,13 @@ # Debian & Ubuntu Server Setup & Hardening Script -**Version:** 3.13 +**Version:** 4.1 -**Last Updated:** 2025-06-27 +**Last Updated:** 2025-06-28 **Compatible With:** - Debian 12 -- Ubuntu 22.04, 24.04, 24.10 - -* * * +- Ubuntu 22.04, 24.04, 24.10 (24.10 experimental) ## Overview @@ -17,8 +15,6 @@ This script automates the initial setup and security hardening of a fresh Debian It runs interactively, guiding the user through critical choices while automating the tedious but essential steps of securing a new server. -* * * - ## Features - **Secure User Management:** Creates a new administrator user with `sudo` privileges and disables the root account's SSH access. @@ -27,15 +23,14 @@ It runs interactively, guiding the user through critical choices while automatin - **Intrusion Prevention:** Installs and configures **Fail2Ban** to automatically block IPs that show malicious signs, such as repeated password failures. - **Automated Security Updates:** Configures `unattended-upgrades` to automatically install new security patches. - **System Stability:** Sets up NTP time synchronization with `chrony` and can configure a swap file for systems with low RAM. +- **Remote rsync Backups:** Configures a root cron job for `rsync` backups to any SSH-accessible server (e.g., Hetzner Storage Box, NAS, or custom server), with SSH key automation, cron scheduling, ntfy/Discord notifications, and customizable exclude file. - **Safety First:** Automatically backs up all critical configuration files before modification, with simple restoration instructions. - **Optional Software:** Provides optional, interactive installation for: - - Docker & Docker Compose - - Tailscale (Mesh VPN) + - Docker & Docker Compose + - Tailscale (Mesh VPN) - **Comprehensive Logging:** All actions are logged to `/var/log/setup_harden_debian_ubuntu_*.log`. - **Automation-Friendly:** Includes a `--quiet` mode to suppress non-essential output for use in automated provisioning workflows. -* * * - ## Installation & Usage ### Prerequisites @@ -43,43 +38,45 @@ It runs interactively, guiding the user through critical choices while automatin - A fresh installation of a compatible OS. - Root or `sudo` privileges. - Internet access for downloading packages. +- For remote backups: An SSH-accessible server (e.g., Hetzner Storage Box or custom server) with credentials or SSH key access. -### 1\. Download the Script +### 1. Download the Script -``` +```bash wget https://raw.githubusercontent.com/buildplan/setup_harden_server/refs/heads/main/setup_harden_debian_ubuntu.sh chmod +x setup_harden_debian_ubuntu.sh ``` -### 2\. Run the Script Interactively +### 2. Run the Script Interactively It is highly recommended to run the script interactively the first time. -``` +```bash sudo ./setup_harden_debian_ubuntu.sh ``` -### 3\. Run in Quiet Mode (for automation - not recmmended) +### 3. Run in Quiet Mode (for automation - not recommended) -``` +```bash sudo ./setup_harden_debian_ubuntu.sh --quiet ``` -> :warning: **Critical Safety Check:** The script will pause and require you to test your new SSH connection from a separate terminal before it proceeds to disable old access methods. **Do not skip this step!** +> **Warning:** The script will pause and require you to test your new SSH connection from a separate terminal before it proceeds to disable old access methods. **Do not skip this step!** > -> *Make sure to check VPS providers firewall, you will have to open your selected custom SSH port there.* - -* * * +> *Make sure to check your VPS provider's firewall; you will have to open your selected custom SSH port there.* +> +> *For remote backups, ensure the backup server's SSH port is open and accessible.* ## What It Does in Detail | Task | Description | | --- | --- | | **System Checks** | Verifies OS compatibility, root privileges, and internet connectivity. | -| **Package Management** | Updates all packages and installs essential tools (`ufw`, `fail2ban`, `chrony`, etc.). | +| **Package Management** | Updates all packages and installs essential tools (`ufw`, `fail2ban`, `chrony`, `rsync`, etc.). | | **Admin User Creation** | Creates a new `sudo` user with a password and/or a provided SSH public key. | | **SSH Hardening** | Disables root login, enforces key-based auth, and sets a custom port. | | **Firewall Setup** | Configures UFW to deny incoming traffic by default and allow specific ports. | +| **Remote Backup Setup** | (Optional) Configures `rsync` backups to a user-specified SSH server (e.g., `user@host:port`), including root SSH key generation, cron job scheduling, ntfy/Discord notifications, and an exclude file with defaults (e.g., `*~`, `*.tmp`). | | **System Backups** | Creates timestamped backups of configs in `/root/` before modification. | | **Swap File Setup** | (Optional) Creates a swap file with a user-selected size. | | **Timezone & Locales** | (Optional) Interactive configuration for timezone and system locales. | @@ -87,31 +84,43 @@ sudo ./setup_harden_debian_ubuntu.sh --quiet | **Tailscale Install** | (Optional) Installs the Tailscale client. | | **Final Cleanup** | Removes unused packages and reloads system daemons. | -* * * - ## Logs & Backups - **Log Files:** `/var/log/setup_harden_debian_ubuntu_*.log` +- **Backup Logs:** `/var/log/backup_*.log` (for remote backup operations) - **Configuration Backups:** `/root/setup_harden_backup_*` -* * * +## Post-Reboot Verification Steps + +After rebooting, verify the setup with the following commands: + +- **SSH Access**: `ssh -p @` +- **Firewall Rules**: `sudo ufw status verbose` +- **Time Synchronization**: `chronyc tracking` +- **Fail2Ban Status**: `sudo fail2ban-client status sshd` +- **Swap Status**: `sudo swapon --show && free -h` +- **Hostname**: `hostnamectl` +- **Docker Status** (if installed): `docker ps` +- **Tailscale Status** (if installed): `tailscale status` +- **Remote Backup** (if configured): + - Verify SSH key: `cat /root/.ssh/id_ed25519.pub` + - Copy key to backup server (if not done during setup): `ssh-copy-id -p -s ` + - Test backup: `sudo /root/backup.sh` + - Check backup logs: `sudo less /var/log/backup_*.log` ## Tested On - Debian 12 -- Ubuntu 24.04 and 24.10 -- Cloud providers (DigitalOcean, Oracle Cloud, Hetzner, Netcup) and local VMs. +- Ubuntu 22.04, 24.04, 24.10 (experimental) +- Cloud providers (DigitalOcean, Oracle Cloud, Hetzner, Netcup) and local VMs, including Hetzner Storage Box for backups. -* * * - -## :exclamation: Important Notes +## Important Notes - **Run this on a fresh system.** While idempotent, the script is designed for initial provisioning. - **A system reboot is required** after the script completes to ensure all changes, especially to the kernel and services, are applied cleanly. - Always test the script in a non-production environment (like a staging VM) before deploying to a live server. - Ensure you have out-of-band console access to your server in case you accidentally lock yourself out. - -* * * +- For remote backups, ensure the root SSH key is copied to the backup server (`ssh-copy-id -p -s `) to enable automated backups. ## Troubleshooting @@ -119,31 +128,71 @@ sudo ./setup_harden_debian_ubuntu.sh --quiet If you are locked out of SSH, use your provider's web console to perform the following steps: -1. **Remove the hardened configuration:** - - ``` - # This file overrides the main config, so it must be removed. - rm /etc/ssh/sshd_config.d/99-hardening.conf - ``` - -2. **Restore the original `sshd_config` file:** - - ``` - # Find the latest backup directory - LATEST_BACKUP=$(ls -td /root/setup_harden_backup_* | head -1) - - # Copy the original config back into place - cp "$LATEST_BACKUP"/sshd_config.backup_* /etc/ssh/sshd_config - ``` +1. **Remove the hardened configuration:** -3. **Restart the SSH service:** - ``` - systemctl restart ssh - ``` - You should now be able to log in using the original port (usually 22) and credentials. + ```bash + # This file overrides the main config, so it must be removed. + rm /etc/ssh/sshd_config.d/99-hardening.conf + ``` ---- +2. **Restore the original `sshd_config` file:** -## [MIT](https://github.com/buildplan/setup_harden_server/blob/main/LICENSE "LICENCE") License + ```bash + # Find the latest backup directory + LATEST_BACKUP=$(ls -td /root/setup_harden_backup_* | head -1) + + # Copy the original config back into place + cp "$LATEST_BACKUP"/sshd_config.backup_* /etc/ssh/sshd_config + ``` -This script is open-source and provided "as is" without warranty. Use at your own risk. +3. **Restart the SSH service:** + + ```bash + systemctl restart ssh + ``` + + You should now be able to log in using the original port (usually 22) and credentials. + +### Backup Issues + +If backups fail, check the following: + +1. **Verify SSH Key Setup**: + - Ensure the root SSH key is copied to the backup server: + ```bash + ssh-copy-id -p -s + ``` + - Test SSH connectivity: + ```bash + ssh -p exit + ``` + +2. **Check Backup Logs**: + - Review logs for errors: + ```bash + sudo less /var/log/backup_*.log + ``` + +3. **Test Backup Manually**: + - Run the backup script to identify issues: + ```bash + sudo /root/backup.sh + ``` + +4. **Verify Cron Job**: + - Check the cron schedule: + ```bash + sudo crontab -l + ``` + - Ensure the schedule is valid (e.g., `0 3 * * *` for daily at 3 AM). + +5. **Network Issues**: + - Verify the backup server’s SSH port is open: + ```bash + nc -zv + ``` + - Check your VPS provider’s firewall for outbound access to the backup server’s port. + +## [MIT](https://github.com/buildplan/setup_harden_server/blob/main/LICENSE "LICENSE") License + +This script is open-source and provided "as is" without warranty. Use at your own risk. \ No newline at end of file diff --git a/setup_harden_debian_ubuntu.sh b/setup_harden_debian_ubuntu.sh index da040ed..e96045b 100644 --- a/setup_harden_debian_ubuntu.sh +++ b/setup_harden_debian_ubuntu.sh @@ -1,9 +1,12 @@ #!/bin/bash # Debian 12 and Ubuntu Server Hardening Interactive Script -# Version: 3.13 | 2025-06-27 -# Compatible with: Debian 12 (Bookworm), Ubuntu 20.04 LTS, 22.04 LTS, 24.04 LTS. 24.10 (experimental) -# Tested on Debian 12, Ubuntu 24.04 and 24.10 at DigitalOcean, Oracle Cloud, Netcup, Hetzner and local VMs +# Version: 4.1 | 2025-06-28 +# Changelog: +# - v4.1: Generalized backup configuration to support any rsync-compatible SSH destination, renamed setup_hetzner_backup to setup_backup. +# - v4.0: Added Hetzner Storage Box backup configuration with root SSH key automation, cron job scheduling, ntfy/Discord notifications, and exclude file defaults. +# - v4.0: Enhanced generate_summary to include backup details (script path, cron schedule, notifications). +# - v4.0: Tested on Debian 12, Ubuntu 20.04, 22.04, 24.04, and 24.10 (experimental) at DigitalOcean, Oracle Cloud, Netcup, Hetzner, and local VMs. # # Description: # This script provisions and hardens a fresh Debian 12 or Ubuntu server with essential security @@ -80,7 +83,7 @@ print_header() { echo -e "${CYAN}╔═════════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ ║${NC}" echo -e "${CYAN}║ DEBIAN/UBUNTU SERVER SETUP AND HARDENING SCRIPT ║${NC}" - echo -e "${CYAN}║ v3.13 | 2025-06-27 ║${NC}" + echo -e "${CYAN}║ v4.1 | 2025-06-28 ║${NC}" echo -e "${CYAN}║ ║${NC}" echo -e "${CYAN}╚═════════════════════════════════════════════════════════════════╝${NC}" echo @@ -335,8 +338,8 @@ install_packages() { print_info "Installing essential packages..." if ! apt-get install -y -qq \ ufw fail2ban unattended-upgrades chrony \ - rsync wget vim htop iotop nethogs ncdu tree \ - rsyslog cron jq gawk coreutils perl skopeo git \ + rsync wget vim htop iotop nethogs netcat-traditional ncdu \ + tree rsyslog cron jq gawk coreutils perl skopeo git \ openssh-client openssh-server; then print_error "Failed to install one or more essential packages." exit 1 @@ -601,7 +604,7 @@ EOF mv "$NEW_SSH_CONFIG" /etc/systemd/system/ssh.service.d/override.conf chmod 644 /etc/systemd/system/ssh.service.d/override.conf fi - + # Apply additional hardening via sshd_config.d NEW_SSH_CONFIG=$(mktemp) tee "$NEW_SSH_CONFIG" > /dev/null </dev/null; then + print_success "SSH key copied successfully." + else + print_warning "SSH key copy failed. You must manually copy the key later." + fi + fi + + # Display SSH key copy instructions + print_warning "ACTION REQUIRED: If not already done, copy the root SSH key to the backup destination to enable backups." + echo -e "${YELLOW}Root public key:${NC}" + cat "$ROOT_SSH_KEY.pub" + echo -e "${CYAN}Run this command on your local machine or another terminal:${NC}" + echo -e " ssh-copy-id -p $BACKUP_PORT -s $BACKUP_DEST" + print_info "You can copy the SSH key later, but the backup cron job will fail until this is done." + + # Optional SSH connection test + if confirm "Test SSH connection to the backup destination (optional)?"; then + print_info "Testing connection (timeout: 5 seconds)..." + DEST_HOST=$(echo "$BACKUP_DEST" | cut -d'@' -f2) + if ssh -p "$BACKUP_PORT" -o BatchMode=yes -o ConnectTimeout=5 "$BACKUP_DEST" exit 2>/dev/null; then + print_success "SSH connection successful!" + else + print_error "SSH connection failed." + print_info "Verify the following:" + print_info " 1. The key was copied: ${YELLOW}ssh-copy-id -p $BACKUP_PORT -s $BACKUP_DEST${NC}" + if command -v nc >/dev/null 2>&1; then + print_info " 2. Port $BACKUP_PORT is open: ${YELLOW}nc -zv $DEST_HOST $BACKUP_PORT${NC}" + else + print_info " 2. Port $BACKUP_PORT is open: ${YELLOW}Contact your network admin or try 'telnet $DEST_HOST $BACKUP_PORT'${NC}" + fi + fi + fi + + # Create exclude file + local EXCLUDE_FILE="/root/backup_exclude.txt" + print_info "Creating rsync exclude file at $EXCLUDE_FILE..." + cat > "$EXCLUDE_FILE" <> "$EXCLUDE_FILE" + done + fi + chmod 600 "$EXCLUDE_FILE" + print_success "Rsync exclude file created." + + # Ask for cron schedule + print_info "Configuring cron schedule for backups..." + read -rp "$(echo -e "${CYAN}Enter cron schedule (e.g., '0 3 * * *' for daily at 3 AM): ${NC}")" CRON_SCHEDULE + CRON_SCHEDULE=${CRON_SCHEDULE:-0 3 * * *} + if ! echo "$CRON_SCHEDULE" | grep -qE '^((\*|[0-9,-]+(/[0-9]+)?)\s*){5}$'; then + print_error "Invalid cron expression. Using default daily at 3 AM." + CRON_SCHEDULE="0 3 * * *" + fi + # Ask for notification preference + local NOTIFICATION_SETUP="none" NTFY_URL NTFY_TOPIC NTFY_TOKEN DISCORD_WEBHOOK + if confirm "Enable backup notifications?"; then + echo -e "${CYAN}Choose notification method:${NC}" + echo -e " 1) ntfy" + echo -e " 2) Discord" + echo -e " 3) None" + read -rp "$(echo -e "${CYAN}Enter choice (1-3): ${NC}")" NOTIFICATION_CHOICE + case "$NOTIFICATION_CHOICE" in + 1) + read -rp "$(echo -e "${CYAN}Enter ntfy URL (e.g., https://ntfy.sh): ${NC}")" NTFY_URL + read -rp "$(echo -e "${CYAN}Enter ntfy topic: ${NC}")" NTFY_TOPIC + read -rp "$(echo -e "${CYAN}Enter ntfy token (optional, press Enter to skip): ${NC}")" NTFY_TOKEN + NTFY_URL=${NTFY_URL:-https://ntfy.sh} + NTFY_TOPIC=${NTFY_TOPIC:-vps-backups} + NOTIFICATION_SETUP="ntfy" + ;; + 2) + read -rp "$(echo -e "${CYAN}Enter Discord webhook URL: ${NC}")" DISCORD_WEBHOOK + if [[ ! "$DISCORD_WEBHOOK" =~ ^https://discord.com/api/webhooks/ ]]; then + print_error "Invalid Discord webhook URL." + exit 1 + fi + NOTIFICATION_SETUP="discord" + ;; + *) NOTIFICATION_SETUP="none" ;; + esac + fi + + # Create backup script + local BACKUP_SCRIPT="/root/backup.sh" + print_info "Creating backup script at $BACKUP_SCRIPT..." + cat > "$BACKUP_SCRIPT" <> "$BACKUP_SCRIPT" <> "$BACKUP_SCRIPT" <> "$BACKUP_SCRIPT" <<'EOF' +# Notification function +send_notification() { + local title="$1" + local message="$2" + local priority="${3:-default}" + local color=65280 # Green for success + if [[ "$title" == *"FAILED"* ]]; then + color=16711680 # Red for failure + fi +EOF + if [[ "$NOTIFICATION_SETUP" == "ntfy" ]]; then + cat >> "$BACKUP_SCRIPT" < /dev/null 2>> "$LOG_FILE" +EOF + elif [[ "$NOTIFICATION_SETUP" == "discord" ]]; then + cat >> "$BACKUP_SCRIPT" < /dev/null 2>> "$LOG_FILE" +EOF + else + cat >> "$BACKUP_SCRIPT" <<'EOF' + : # No notifications configured +EOF + fi + cat >> "$BACKUP_SCRIPT" <<'EOF' +} + +# Format backup stats +format_backup_stats() { + local stats_line + stats_line=$("$GREP_CMD" 'Total transferred file size' "$LOG_FILE" | tail -n 1) + if [ -n "$stats_line" ]; then + local bytes + bytes=$(echo "$stats_line" | "$AWK_CMD" '{gsub(/,/, ""); print $5}') + if [[ "$bytes" =~ ^[0-9]+$ && "$bytes" -gt 0 ]]; then + local human_readable + human_readable=$("$NUMFMT_CMD" --to=iec-i --suffix=B --format="%.2f" "$bytes") + printf "Data Transferred: $human_readable" + else + printf "Data Transferred: 0 B (No changes)" + fi + else + printf "See log for statistics." + fi +} + +# Dependency check +for cmd in "$RSYNC_CMD" "$CURL_CMD" "$NC_CMD" "$AWK_CMD" "$NUMFMT_CMD" "$GREP_CMD" "$HOSTNAME_CMD" "$DATE_CMD" "$STAT_CMD" "$MV_CMD" "$TOUCH_CMD"; do + if ! command -v "$cmd" &>/dev/null; then + echo "[$("$DATE_CMD" '+%Y-%m-%d %H:%M:%S')] FATAL: Required command not found at '$cmd'" >> "$LOG_FILE" + send_notification "❌ Backup FAILED: $("$HOSTNAME_CMD")" "Required command not found at '$cmd'" "high" + exit 10 + fi +done + +# Pre-flight checks +if [[ ! -f "$EXCLUDE_FILE" ]]; then + echo "[$("$DATE_CMD" '+%Y-%m-%d %H:%M:%S')] FATAL: Exclude file not found at $EXCLUDE_FILE" >> "$LOG_FILE" + send_notification "❌ Backup FAILED: $("$HOSTNAME_CMD")" "Exclude file not found at $EXCLUDE_FILE" "high" + exit 3 +fi +if [[ "$LOCAL_DIR" != */ ]]; then + echo "[$("$DATE_CMD" '+%Y-%m-%d %H:%M:%S')] FATAL: LOCAL_DIR must end with a trailing slash" >> "$LOG_FILE" + send_notification "❌ Backup FAILED: $("$HOSTNAME_CMD")" "LOCAL_DIR must end with a trailing slash" "high" + exit 2 +fi + +# Log rotation +if [ -f "$LOG_FILE" ] && [ "$("$STAT_CMD" -c%s "$LOG_FILE")" -gt "$MAX_LOG_SIZE" ]; then + "$MV_CMD" "$LOG_FILE" "${LOG_FILE}.$("$DATE_CMD" +%Y%m%d_%H%M%S)" + "$TOUCH_CMD" "$LOG_FILE" +fi + +# Network connectivity check +DEST_HOST=$(echo "$BACKUP_DEST" | cut -d'@' -f2) +if ! "$NC_CMD" -z -w 5 "$DEST_HOST" "$SSH_PORT"; then + echo "[$("$DATE_CMD" '+%Y-%m-%d %H:%M:%S')] FATAL: Cannot reach $DEST_HOST on port $SSH_PORT" >> "$LOG_FILE" + send_notification "❌ Backup FAILED: $("$HOSTNAME_CMD")" "Cannot reach $DEST_HOST on port $SSH_PORT" "high" + exit 4 +fi + +# Rsync backup +echo "[$("$DATE_CMD" '+%Y-%m-%d %H:%M:%S')] Starting rsync backup for $("$HOSTNAME_CMD")" >> "$LOG_FILE" +if LC_ALL=C "$RSYNC_CMD" -avz --stats --delete --partial --timeout=60 --exclude-from="$EXCLUDE_FILE" -e "ssh -p $SSH_PORT" "$LOCAL_DIR" "$BACKUP_DEST:$REMOTE_DIR" >> "$LOG_FILE" 2>&1; then + echo "[$("$DATE_CMD" '+%Y-%m-%d %H:%M:%S')] SUCCESS: rsync completed successfully." >> "$LOG_FILE" + BACKUP_STATS=$(format_backup_stats) + send_notification "✅ Backup SUCCESS: $("$HOSTNAME_CMD")" "rsync backup completed successfully.\n\n$BACKUP_STATS" +else + EXIT_CODE=$? + echo "[$("$DATE_CMD" '+%Y-%m-%d %H:%M:%S')] FAILED: rsync exited with status code: $EXIT_CODE" >> "$LOG_FILE" + send_notification "❌ Backup FAILED: $("$HOSTNAME_CMD")" "rsync failed with exit code $EXIT_CODE. Check log: $LOG_FILE" "high" + exit $EXIT_CODE +fi +echo "[$("$DATE_CMD" '+%Y-%m-%d %H:%M:%S')] Run Finished" >> "$LOG_FILE" +EOF + chmod 700 "$BACKUP_SCRIPT" + print_success "Backup script created at $BACKUP_SCRIPT." + + # Add to crontab + print_info "Adding cron job for root..." + local CRON_FILE=$(mktemp) + crontab -u root -l > "$CRON_FILE" 2>/dev/null || true + if grep -q "$BACKUP_SCRIPT" "$CRON_FILE"; then + print_info "Cron job for $BACKUP_SCRIPT already exists. Updating schedule..." + sed -i "\|$BACKUP_SCRIPT|d" "$CRON_FILE" + fi + echo "$CRON_SCHEDULE $BACKUP_SCRIPT" >> "$CRON_FILE" + crontab -u root "$CRON_FILE" + rm -f "$CRON_FILE" + print_success "Cron job added for root: $CRON_SCHEDULE $BACKUP_SCRIPT" + log "Backup configuration completed." +} + configure_fail2ban() { print_section "Fail2Ban Configuration" @@ -1119,6 +1433,13 @@ generate_summary() { print_error "Service docker is NOT active." fi fi + if command -v tailscale >/dev/null 2>&1; then + if systemctl is-active --quiet tailscaled; then + print_success "Service tailscaled is active." + else + print_error "Service tailscaled is NOT active." + fi + fi echo -e "\n${GREEN}Server setup and hardening script has finished successfully.${NC}" echo echo -e "${YELLOW}Configuration Summary:${NC}" @@ -1126,6 +1447,27 @@ generate_summary() { echo -e " Hostname: $SERVER_NAME" echo -e " SSH Port: $SSH_PORT" echo -e " Server IP: $SERVER_IP" + if [[ -f /root/backup.sh ]]; then + local CRON_SCHEDULE=$(crontab -u root -l 2>/dev/null | grep -F "/root/backup.sh" | awk '{print $1, $2, $3, $4, $5}' || echo "Not configured") + local NOTIFICATION_STATUS="None" + local BACKUP_DEST=$(grep "^BACKUP_DEST=" /root/backup.sh | cut -d'"' -f2 || echo "Unknown") + local BACKUP_PORT=$(grep "^SSH_PORT=" /root/backup.sh | cut -d'"' -f2 || echo "Unknown") + local REMOTE_BACKUP_DIR=$(grep "^REMOTE_DIR=" /root/backup.sh | cut -d'"' -f2 || echo "Unknown") + if grep -q "NTFY_URL" /root/backup.sh; then + NOTIFICATION_STATUS="ntfy" + elif grep -q "DISCORD_WEBHOOK" /root/backup.sh; then + NOTIFICATION_STATUS="Discord" + fi + echo -e " Remote Backup: Enabled" + echo -e " - Backup Script: /root/backup.sh" + echo -e " - Destination: $BACKUP_DEST" + echo -e " - SSH Port: $BACKUP_PORT" + echo -e " - Remote Path: $REMOTE_BACKUP_DIR" + echo -e " - Cron Schedule: $CRON_SCHEDULE" + echo -e " - Notifications: $NOTIFICATION_STATUS" + else + echo -e " Remote Backup: Not configured" + fi echo echo -e "${PURPLE}Log File: ${LOG_FILE}${NC}" echo -e "${PURPLE}Backups: ${BACKUP_DIR}${NC}" @@ -1136,14 +1478,22 @@ generate_summary() { echo -e " - Time sync: chronyc tracking" echo -e " - Fail2Ban status: sudo fail2ban-client status sshd" echo -e " - Swap status: sudo swapon --show && free -h" - echo -e " - Hostname: hostnamectl" + echo -e " - Hostname: hostnamectl" if command -v docker >/dev/null 2>&1; then echo -e " - Docker status: docker ps" fi if command -v tailscale >/dev/null 2>&1; then echo -e " - Tailscale status: tailscale status" fi - print_warning "\nA reboot is required to apply all changes cleanly." + if [[ -f /root/backup.sh ]]; then + echo -e " - Remote Backup:" + echo -e " - Verify SSH key: cat /root/.ssh/id_ed25519.pub" + echo -e " - Copy key if needed: ssh-copy-id -p $BACKUP_PORT -s $BACKUP_DEST" + echo -e " - Test backup: sudo /root/backup.sh" + echo -e " - Check logs: sudo less /var/log/backup_*.log" + fi + print_warning "\nACTION REQUIRED: If remote backup is enabled, ensure the root SSH key is copied to the destination server." + print_warning "A reboot is required to apply all changes cleanly." if [[ $VERBOSE == true ]]; then if confirm "Reboot now?" "y"; then print_info "Rebooting now..." @@ -1171,7 +1521,7 @@ main() { trap 'handle_error $LINENO' ERR touch "$LOG_FILE" && chmod 600 "$LOG_FILE" log "Starting Debian/Ubuntu hardening script." - + print_header check_dependencies check_system @@ -1186,6 +1536,7 @@ main() { configure_time_sync install_docker install_tailscale + setup_backup configure_swap final_cleanup generate_summary