mirror of
https://github.com/buildplan/du_setup.git
synced 2025-12-17 17:55:35 +00:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f1b2563df | ||
|
|
b6a392dbfb | ||
|
|
5857a1a45e | ||
|
|
be54f03de3 | ||
|
|
c7e66378ee | ||
|
|
df67befa0c | ||
|
|
428f6fa9d5 | ||
|
|
e9161387c7 | ||
|
|
ff72d42b14 | ||
|
|
d3bb2dca38 | ||
|
|
1f0a20d998 | ||
|
|
c5a1621ae6 | ||
|
|
dfae3a2fb9 | ||
|
|
37655c0736 | ||
|
|
b7fdd5b456 | ||
|
|
d86e9b1eb8 | ||
|
|
87c241c208 | ||
|
|
0733e58651 | ||
|
|
e7dbe538dc | ||
|
|
30a77d43be | ||
|
|
9f9b158c12 | ||
|
|
38690ea41f | ||
|
|
e59a56581f | ||
|
|
ca160b3a4a | ||
|
|
ffa1245386 | ||
|
|
80d6b140d5 | ||
|
|
4a35b98ebc | ||
|
|
11bbc21057 | ||
|
|
2b78321971 | ||
|
|
a284a908d1 | ||
|
|
d24ec53084 | ||
|
|
bb252fdc1b | ||
|
|
54c5eb3d0f | ||
|
|
91c9057203 | ||
|
|
b40b1793e4 | ||
|
|
5a917cb9e9 | ||
|
|
8f12b2f21a | ||
|
|
4ef957bd85 | ||
|
|
8b555fe771 | ||
|
|
b75c9b77ff | ||
|
|
fe0af92e91 | ||
|
|
21e95b0b6f | ||
|
|
c9eea30d97 | ||
|
|
b6b04f96d2 | ||
|
|
cdff42881a | ||
|
|
83e4420ee6 | ||
|
|
a306b9b675 | ||
|
|
0f00ade070 | ||
|
|
b31e0311b0 | ||
|
|
ee9fc1b017 | ||
|
|
aa452e5008 | ||
|
|
b21f1e00d8 | ||
|
|
8b74a2c5c7 | ||
|
|
853d351cab | ||
|
|
cf8f5aa104 | ||
|
|
ae94f7391c | ||
|
|
2e18d747ab | ||
|
|
5133306a0c | ||
|
|
17dfe530fa |
@ -7,9 +7,9 @@
|
|||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
**Version:** v0.77.1
|
**Version:** v0.78.4
|
||||||
|
|
||||||
**Last Updated:** 2025-11-19
|
**Last Updated:** 2025-11-27
|
||||||
|
|
||||||
**Compatible With:**
|
**Compatible With:**
|
||||||
|
|
||||||
@ -87,12 +87,12 @@ sha256sum du_setup.sh
|
|||||||
|
|
||||||
Compare the output hash to the one below. They must match exactly.
|
Compare the output hash to the one below. They must match exactly.
|
||||||
|
|
||||||
`3ea3416cf0916ea92c382e1c899de0ef2f29535c9c93d1fa7466b4a78e1bb26d`
|
`d7378f43082166cad26c7b232f3cd01e778a3377dea996c3f434e0f483317659`
|
||||||
|
|
||||||
Or echo the hash to check, it should output: `du_setup.sh: OK`
|
Or echo the hash to check, it should output: `du_setup.sh: OK`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
echo 3ea3416cf0916ea92c382e1c899de0ef2f29535c9c93d1fa7466b4a78e1bb26d du_setup.sh | sha256sum --check
|
echo d7378f43082166cad26c7b232f3cd01e778a3377dea996c3f434e0f483317659 du_setup.sh | sha256sum --check
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Run the Script
|
### 3. Run the Script
|
||||||
|
|||||||
684
du_setup.sh
684
du_setup.sh
@ -1,8 +1,19 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Debian and Ubuntu Server Hardening Interactive Script
|
# Debian and Ubuntu Server Hardening Interactive Script
|
||||||
# Version: 0.77.1 | 2025-11-19
|
# Version: 0.78.4 | 2025-11-27
|
||||||
# Changelog:
|
# Changelog:
|
||||||
|
# - v0.78.4: Improved configure_swap to detect swap partitions vs files.
|
||||||
|
# Prevents 'fallocate' crashes on physical partitions by offering to disable them or skip.
|
||||||
|
# - v0.78.3: Update the summary to try to show the right environment detection based on finding personal VMs and cloud VPS.
|
||||||
|
# Run update & upgrade in the final step to ensure system is fully updated after restart.
|
||||||
|
# - v0.78.2: In configure_system set choosen hostname from collect_config in the /etc/hosts
|
||||||
|
# - v0.78.1: Collect config failure fixed on IPv6 only VPS.
|
||||||
|
# - v0.78: Script tries to handles different environments: Direct Public IP, NAT/Router and Local VM only
|
||||||
|
# The configure_ssh function provides context-aware instructions based on different environments.
|
||||||
|
# In setup_user handle if group exists but user doesn't - attach user to existing group.
|
||||||
|
# - v0.77.2: Fixed an unbound variable for SSH when on a local virtual machine;
|
||||||
|
# check_dependencies should come before check_system to keep minimal servers from failing.
|
||||||
# - v0.77.1: Auto SSH connection whitelist feat & whitelist deduplication.
|
# - v0.77.1: Auto SSH connection whitelist feat & whitelist deduplication.
|
||||||
# - v0.77: User-configurable ignoreip functionality for configure_fail2ban function.
|
# - v0.77: User-configurable ignoreip functionality for configure_fail2ban function.
|
||||||
# Add a few more core packages in install_packages function.
|
# Add a few more core packages in install_packages function.
|
||||||
@ -84,7 +95,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# --- Update Configuration ---
|
# --- Update Configuration ---
|
||||||
CURRENT_VERSION="0.77.1"
|
CURRENT_VERSION="0.78.4"
|
||||||
SCRIPT_URL="https://raw.githubusercontent.com/buildplan/du_setup/refs/heads/main/du_setup.sh"
|
SCRIPT_URL="https://raw.githubusercontent.com/buildplan/du_setup/refs/heads/main/du_setup.sh"
|
||||||
CHECKSUM_URL="${SCRIPT_URL}.sha256"
|
CHECKSUM_URL="${SCRIPT_URL}.sha256"
|
||||||
|
|
||||||
@ -128,8 +139,13 @@ SKIP_CLEANUP=false # If true, skip cleanup tasks
|
|||||||
DETECTED_VIRT_TYPE=""
|
DETECTED_VIRT_TYPE=""
|
||||||
DETECTED_MANUFACTURER=""
|
DETECTED_MANUFACTURER=""
|
||||||
DETECTED_PRODUCT=""
|
DETECTED_PRODUCT=""
|
||||||
IS_CLOUD_PROVIDER=false
|
|
||||||
IS_CONTAINER=false
|
IS_CONTAINER=false
|
||||||
|
ENVIRONMENT_TYPE="unknown"
|
||||||
|
DETECTED_PROVIDER_NAME=""
|
||||||
|
|
||||||
|
SERVER_IP_V4="Unknown"
|
||||||
|
SERVER_IP_V6="Not available"
|
||||||
|
LOCAL_IP_V4=""
|
||||||
|
|
||||||
SSHD_BACKUP_FILE=""
|
SSHD_BACKUP_FILE=""
|
||||||
LOCAL_KEY_ADDED=false
|
LOCAL_KEY_ADDED=false
|
||||||
@ -235,7 +251,7 @@ print_header() {
|
|||||||
printf '%s\n' "${CYAN}╔═════════════════════════════════════════════════════════════════╗${NC}"
|
printf '%s\n' "${CYAN}╔═════════════════════════════════════════════════════════════════╗${NC}"
|
||||||
printf '%s\n' "${CYAN}║ ║${NC}"
|
printf '%s\n' "${CYAN}║ ║${NC}"
|
||||||
printf '%s\n' "${CYAN}║ DEBIAN/UBUNTU SERVER SETUP AND HARDENING SCRIPT ║${NC}"
|
printf '%s\n' "${CYAN}║ DEBIAN/UBUNTU SERVER SETUP AND HARDENING SCRIPT ║${NC}"
|
||||||
printf '%s\n' "${CYAN}║ v0.77.1 | 2025-11-19 ║${NC}"
|
printf '%s\n' "${CYAN}║ v0.78.4 | 2025-11-27 ║${NC}"
|
||||||
printf '%s\n' "${CYAN}║ ║${NC}"
|
printf '%s\n' "${CYAN}║ ║${NC}"
|
||||||
printf '%s\n' "${CYAN}╚═════════════════════════════════════════════════════════════════╝${NC}"
|
printf '%s\n' "${CYAN}╚═════════════════════════════════════════════════════════════════╝${NC}"
|
||||||
printf '\n'
|
printf '\n'
|
||||||
@ -471,7 +487,6 @@ detect_environment() {
|
|||||||
DETECTED_MANUFACTURER="$MANUFACTURER"
|
DETECTED_MANUFACTURER="$MANUFACTURER"
|
||||||
DETECTED_PRODUCT="$PRODUCT"
|
DETECTED_PRODUCT="$PRODUCT"
|
||||||
DETECTED_BIOS_VENDOR="${DETECTED_BIOS_VENDOR:-unknown}"
|
DETECTED_BIOS_VENDOR="${DETECTED_BIOS_VENDOR:-unknown}"
|
||||||
IS_CLOUD_PROVIDER="$IS_CLOUD_VPS"
|
|
||||||
|
|
||||||
log "Environment detection: VIRT=$VIRT_TYPE, MANUFACTURER=$MANUFACTURER, PRODUCT=$PRODUCT, IS_CLOUD=$IS_CLOUD_VPS, TYPE=$ENVIRONMENT_TYPE"
|
log "Environment detection: VIRT=$VIRT_TYPE, MANUFACTURER=$MANUFACTURER, PRODUCT=$PRODUCT, IS_CLOUD=$IS_CLOUD_VPS, TYPE=$ENVIRONMENT_TYPE"
|
||||||
}
|
}
|
||||||
@ -2545,11 +2560,6 @@ validate_timezone() {
|
|||||||
[[ -e "/usr/share/zoneinfo/$tz" ]]
|
[[ -e "/usr/share/zoneinfo/$tz" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_swap_size() {
|
|
||||||
local size_upper="${1^^}" # Convert to uppercase for case-insensitivity
|
|
||||||
[[ "$size_upper" =~ ^[0-9]+[MG]$ && "${size_upper%[MG]}" -ge 1 ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
validate_ufw_port() {
|
validate_ufw_port() {
|
||||||
local port="$1"
|
local port="$1"
|
||||||
# Matches port (e.g., 8080) or port/protocol (e.g., 8080/tcp, 123/udp)
|
# Matches port (e.g., 8080) or port/protocol (e.g., 8080/tcp, 123/udp)
|
||||||
@ -2600,17 +2610,25 @@ validate_ip_or_cidr() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_to_bytes() {
|
# Convert size (e.g., 2G) to MB for validation/dd
|
||||||
local size_upper="${1^^}" # Convert to uppercase for case-insensitivity
|
convert_to_mb() {
|
||||||
local unit="${size_upper: -1}"
|
local input="${1:-}"
|
||||||
local value="${size_upper%[MG]}"
|
local size="${input^^}"
|
||||||
if [[ "$unit" == "G" ]]; then
|
size="${size// /}"
|
||||||
echo $((value * 1024 * 1024 * 1024))
|
local num="${size%[MG]}"
|
||||||
elif [[ "$unit" == "M" ]]; then
|
local unit="${size: -1}"
|
||||||
echo $((value * 1024 * 1024))
|
if ! [[ "$num" =~ ^[0-9]+$ ]]; then
|
||||||
else
|
print_error "Invalid swap size format: '$input'. Expected format: 2G, 512M." >&2
|
||||||
echo 0
|
return 1
|
||||||
fi
|
fi
|
||||||
|
case "$unit" in
|
||||||
|
G) echo "$((num * 1024))" ;;
|
||||||
|
M) echo "$num" ;;
|
||||||
|
*)
|
||||||
|
print_error "Unknown or missing unit in swap size: '$input'. Use 'M' or 'G'." >&2
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- script update check ---
|
# --- script update check ---
|
||||||
@ -2731,8 +2749,9 @@ check_system() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f /etc/os-release ]]; then
|
if [[ -f /etc/os-release ]]; then
|
||||||
|
# shellcheck source=/dev/null
|
||||||
source /etc/os-release
|
source /etc/os-release
|
||||||
ID=$ID # Populate global ID variable
|
ID=${ID:-unknown} # Populate global ID variable
|
||||||
if [[ $ID == "debian" && $VERSION_ID =~ ^(12|13)$ ]] || \
|
if [[ $ID == "debian" && $VERSION_ID =~ ^(12|13)$ ]] || \
|
||||||
[[ $ID == "ubuntu" && $VERSION_ID =~ ^(20.04|22.04|24.04)$ ]]; then
|
[[ $ID == "ubuntu" && $VERSION_ID =~ ^(20.04|22.04|24.04)$ ]]; then
|
||||||
print_success "Compatible OS detected: $PRETTY_NAME"
|
print_success "Compatible OS detected: $PRETTY_NAME"
|
||||||
@ -2760,7 +2779,10 @@ check_system() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if curl -s --head https://deb.debian.org >/dev/null || curl -s --head https://archive.ubuntu.com >/dev/null; then
|
if curl -s --head https://deb.debian.org >/dev/null || \
|
||||||
|
curl -s --head https://archive.ubuntu.com >/dev/null || \
|
||||||
|
wget -q --spider https://deb.debian.org || \
|
||||||
|
wget -q --spider https://archive.ubuntu.com; then
|
||||||
print_success "Internet connectivity confirmed."
|
print_success "Internet connectivity confirmed."
|
||||||
else
|
else
|
||||||
print_error "No internet connectivity. Please check your network."
|
print_error "No internet connectivity. Please check your network."
|
||||||
@ -2791,6 +2813,7 @@ check_system() {
|
|||||||
|
|
||||||
collect_config() {
|
collect_config() {
|
||||||
print_section "Configuration Setup"
|
print_section "Configuration Setup"
|
||||||
|
# --- Input Collection ---
|
||||||
while true; do
|
while true; do
|
||||||
read -rp "$(printf '%s' "${CYAN}Enter username for new admin user: ${NC}")" USERNAME
|
read -rp "$(printf '%s' "${CYAN}Enter username for new admin user: ${NC}")" USERNAME
|
||||||
if validate_username "$USERNAME"; then
|
if validate_username "$USERNAME"; then
|
||||||
@ -2809,46 +2832,74 @@ collect_config() {
|
|||||||
if validate_hostname "$SERVER_NAME"; then break; else print_error "Invalid hostname."; fi
|
if validate_hostname "$SERVER_NAME"; then break; else print_error "Invalid hostname."; fi
|
||||||
done
|
done
|
||||||
read -rp "$(printf '%s' "${CYAN}Enter a 'pretty' hostname (optional): ${NC}")" PRETTY_NAME
|
read -rp "$(printf '%s' "${CYAN}Enter a 'pretty' hostname (optional): ${NC}")" PRETTY_NAME
|
||||||
|
[[ -z "$PRETTY_NAME" ]] && PRETTY_NAME="$SERVER_NAME"
|
||||||
|
# --- SSH Port Detection ---
|
||||||
PREVIOUS_SSH_PORT=$(ss -tlpn | grep sshd | grep -oP ':\K\d+' | head -n 1)
|
PREVIOUS_SSH_PORT=$(ss -tlpn | grep sshd | grep -oP ':\K\d+' | head -n 1)
|
||||||
local PROMPT_DEFAULT_PORT=${PREVIOUS_SSH_PORT:-2222}
|
local PROMPT_DEFAULT_PORT=${PREVIOUS_SSH_PORT:-2222}
|
||||||
[[ -z "$PRETTY_NAME" ]] && PRETTY_NAME="$SERVER_NAME"
|
|
||||||
while true; do
|
while true; do
|
||||||
read -rp "$(printf '%s' "${CYAN}Enter custom SSH port (1024-65535) [$PROMPT_DEFAULT_PORT]: ${NC}")" SSH_PORT
|
read -rp "$(printf '%s' "${CYAN}Enter custom SSH port (1024-65535) [$PROMPT_DEFAULT_PORT]: ${NC}")" SSH_PORT
|
||||||
SSH_PORT=${SSH_PORT:-$PROMPT_DEFAULT_PORT}
|
SSH_PORT=${SSH_PORT:-$PROMPT_DEFAULT_PORT}
|
||||||
if validate_port "$SSH_PORT" || [[ -n "$PREVIOUS_SSH_PORT" && "$SSH_PORT" == "$PREVIOUS_SSH_PORT" ]]; then
|
if validate_port "$SSH_PORT" || [[ -n "$PREVIOUS_SSH_PORT" && "$SSH_PORT" == "$PREVIOUS_SSH_PORT" ]]; then
|
||||||
break; else print_error "Invalid port. Choose a port between 1024-65535."; fi
|
break; else print_error "Invalid port. Choose a port between 1024-65535."; fi
|
||||||
done
|
done
|
||||||
SERVER_IP_V4=$(curl -4 -s https://ifconfig.me 2>/dev/null || echo "unknown")
|
# --- IP Detection ---
|
||||||
SERVER_IP_V6=$(curl -6 -s https://ifconfig.me 2>/dev/null || echo "not available")
|
print_info "Detecting network configuration..."
|
||||||
if [[ "$SERVER_IP_V4" != "unknown" ]]; then
|
# 1. Get the Local LAN IP (Explicit Check)
|
||||||
print_info "Detected server IPv4: $SERVER_IP_V4"
|
# This prevents crashing on IPv6-only servers
|
||||||
fi
|
if ip -4 route get 8.8.8.8 >/dev/null 2>&1; then
|
||||||
if [[ "$SERVER_IP_V6" != "not available" ]]; then
|
LOCAL_IP_V4=$(ip -4 route get 8.8.8.8 | head -1 | awk '{print $7}')
|
||||||
print_info "Detected server IPv6: $SERVER_IP_V6"
|
|
||||||
fi
|
|
||||||
printf '\n%s\n' "${YELLOW}Configuration Summary:${NC}"
|
|
||||||
printf " %-15s %s\n" "Username:" "$USERNAME"
|
|
||||||
printf " %-15s %s\n" "Hostname:" "$SERVER_NAME"
|
|
||||||
|
|
||||||
if [[ -n "$PREVIOUS_SSH_PORT" && "$SSH_PORT" != "$PREVIOUS_SSH_PORT" ]]; then
|
|
||||||
printf " %-15s %s (change from current: %s)\n" "SSH Port:" "$SSH_PORT" "$PREVIOUS_SSH_PORT"
|
|
||||||
else
|
else
|
||||||
printf " %-15s %s\n" "SSH Port:" "$SSH_PORT"
|
LOCAL_IP_V4=""
|
||||||
fi
|
fi
|
||||||
|
# 2. Get Public IPs with timeouts
|
||||||
|
SERVER_IP_V4=$(curl -4 -s --connect-timeout 4 --max-time 5 https://ifconfig.me 2>/dev/null || \
|
||||||
|
curl -4 -s --connect-timeout 4 --max-time 5 https://ip.me 2>/dev/null || \
|
||||||
|
curl -4 -s --connect-timeout 4 --max-time 5 https://icanhazip.com 2>/dev/null || \
|
||||||
|
echo "Unknown")
|
||||||
|
|
||||||
if [[ "$SERVER_IP_V4" != "unknown" ]]; then
|
SERVER_IP_V6=$(curl -6 -s --connect-timeout 4 --max-time 5 https://ifconfig.me 2>/dev/null || \
|
||||||
printf " %-15s %s\n" "Server IPv4:" "$SERVER_IP_V4"
|
curl -6 -s --connect-timeout 4 --max-time 5 https://ip.me 2>/dev/null || \
|
||||||
|
curl -6 -s --connect-timeout 4 --max-time 5 https://icanhazip.com 2>/dev/null || \
|
||||||
|
echo "Not available")
|
||||||
|
|
||||||
|
# --- Display Summary ---
|
||||||
|
printf '\n%s\n' "${YELLOW}Configuration Summary:${NC}"
|
||||||
|
printf " %-22s %s\n" "Username:" "$USERNAME"
|
||||||
|
printf " %-22s %s\n" "Hostname:" "$SERVER_NAME"
|
||||||
|
if [[ -n "$PREVIOUS_SSH_PORT" && "$SSH_PORT" != "$PREVIOUS_SSH_PORT" ]]; then
|
||||||
|
printf " %-22s %s (change from current: %s)\n" "SSH Port:" "$SSH_PORT" "$PREVIOUS_SSH_PORT"
|
||||||
|
else
|
||||||
|
printf " %-22s %s\n" "SSH Port:" "$SSH_PORT"
|
||||||
fi
|
fi
|
||||||
if [[ "$SERVER_IP_V6" != "not available" ]]; then
|
# --- IP Display Logic ---
|
||||||
printf " %-15s %s\n" "Server IPv6:" "$SERVER_IP_V6"
|
if [[ "$SERVER_IP_V4" != "Unknown" ]]; then
|
||||||
|
if [[ "$SERVER_IP_V4" == "$LOCAL_IP_V4" ]]; then
|
||||||
|
# 1: Direct Public IP
|
||||||
|
printf " %-22s %s (Direct)\n" "Server IPv4:" "$SERVER_IP_V4"
|
||||||
|
else
|
||||||
|
# 2: NAT
|
||||||
|
printf " %-22s %s (Internet)\n" "Public IPv4:" "$SERVER_IP_V4"
|
||||||
|
if [[ -n "$LOCAL_IP_V4" ]]; then
|
||||||
|
printf " %-22s %s (Internal)\n" "Local IPv4:" "$LOCAL_IP_V4"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Fallback if public check failed
|
||||||
|
if [[ -n "$LOCAL_IP_V4" ]]; then
|
||||||
|
printf " %-22s %s (Local)\n" "Server IPv4:" "$LOCAL_IP_V4"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ "$SERVER_IP_V6" != "Not available" ]]; then
|
||||||
|
printf " %-22s %s\n" "Public IPv6:" "$SERVER_IP_V6"
|
||||||
fi
|
fi
|
||||||
if ! confirm $'\nContinue with this configuration?' "y"; then print_info "Exiting."; exit 0; fi
|
if ! confirm $'\nContinue with this configuration?' "y"; then print_info "Exiting."; exit 0; fi
|
||||||
log "Configuration collected: USER=$USERNAME, HOST=$SERVER_NAME, PORT=$SSH_PORT, IPV4=$SERVER_IP_V4, IPV6=$SERVER_IP_V6"
|
log "Configuration collected: USER=$USERNAME, HOST=$SERVER_NAME, PORT=$SSH_PORT, IPV4=$SERVER_IP_V4, IPV6=$SERVER_IP_V6, LOCAL=$LOCAL_IP_V4"
|
||||||
}
|
}
|
||||||
|
|
||||||
install_packages() {
|
install_packages() {
|
||||||
print_section "Package Installation"
|
print_section "Package Installation"
|
||||||
print_info "Updating package lists and upgrading system..."
|
print_info "Updating package lists and upgrading system..."
|
||||||
|
print_info "This may take a moment. Please wait..."
|
||||||
if ! apt-get update -qq || ! DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq; then
|
if ! apt-get update -qq || ! DEBIAN_FRONTEND=noninteractive apt-get upgrade -y -qq; then
|
||||||
print_error "Failed to update or upgrade system packages."
|
print_error "Failed to update or upgrade system packages."
|
||||||
exit 1
|
exit 1
|
||||||
@ -2878,7 +2929,13 @@ setup_user() {
|
|||||||
|
|
||||||
if [[ $USER_EXISTS == false ]]; then
|
if [[ $USER_EXISTS == false ]]; then
|
||||||
print_info "Creating user '$USERNAME'..."
|
print_info "Creating user '$USERNAME'..."
|
||||||
if ! adduser --disabled-password --gecos "" "$USERNAME"; then
|
# Check if group exists but user doesn't (common with 'admin' on Ubuntu)
|
||||||
|
local -a ADDUSER_OPTS=("--disabled-password" "--gecos" "")
|
||||||
|
if getent group "$USERNAME" >/dev/null 2>&1; then
|
||||||
|
print_warning "Group '$USERNAME' already exists. Attaching new user to this existing group."
|
||||||
|
ADDUSER_OPTS+=("--ingroup" "$USERNAME")
|
||||||
|
fi
|
||||||
|
if ! adduser "${ADDUSER_OPTS[@]}" "$USERNAME"; then
|
||||||
print_error "Failed to create user '$USERNAME'."
|
print_error "Failed to create user '$USERNAME'."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -3121,18 +3178,59 @@ configure_system() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
print_info "Configuring hostname..."
|
print_info "Configuring hostname..."
|
||||||
|
|
||||||
|
# System Hostname
|
||||||
if [[ $(hostnamectl --static) != "$SERVER_NAME" ]]; then
|
if [[ $(hostnamectl --static) != "$SERVER_NAME" ]]; then
|
||||||
hostnamectl set-hostname "$SERVER_NAME"
|
hostnamectl set-hostname "$SERVER_NAME"
|
||||||
hostnamectl set-hostname "$PRETTY_NAME" --pretty
|
hostnamectl set-hostname "$PRETTY_NAME" --pretty
|
||||||
if grep -q "^127.0.1.1" /etc/hosts; then
|
print_success "Hostname updated to: $SERVER_NAME"
|
||||||
sed -i "s/^127.0.1.1.*/127.0.1.1\t$SERVER_NAME/" /etc/hosts
|
|
||||||
else
|
|
||||||
echo "127.0.1.1 $SERVER_NAME" >> /etc/hosts
|
|
||||||
fi
|
|
||||||
print_success "Hostname configured: $SERVER_NAME"
|
|
||||||
else
|
else
|
||||||
print_info "Hostname already set to $SERVER_NAME."
|
print_info "Hostname is already set to $SERVER_NAME."
|
||||||
fi
|
fi
|
||||||
|
if [[ -d /etc/cloud/cloud.cfg.d ]]; then
|
||||||
|
print_info "Disabling cloud-init host management via override file..."
|
||||||
|
echo "manage_etc_hosts: false" > /etc/cloud/cloud.cfg.d/99-du-setup-hosts.cfg
|
||||||
|
echo "preserve_hostname: true" >> /etc/cloud/cloud.cfg.d/99-du-setup-hosts.cfg
|
||||||
|
log "Created /etc/cloud/cloud.cfg.d/99-du-setup-hosts.cfg"
|
||||||
|
elif [[ -f /etc/cloud/cloud.cfg ]]; then
|
||||||
|
if grep -q "manage_etc_hosts: true" /etc/cloud/cloud.cfg; then
|
||||||
|
print_info "Disabling cloud-init 'manage_etc_hosts' in main config..."
|
||||||
|
sed -i 's/manage_etc_hosts: true/manage_etc_hosts: false/g' /etc/cloud/cloud.cfg
|
||||||
|
log "Disabled manage_etc_hosts in /etc/cloud/cloud.cfg"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Stop cloud-init from overwriting /etc/hosts
|
||||||
|
local TEMPLATE_FILE=""
|
||||||
|
if [[ -n "$ID" && -f "/etc/cloud/templates/hosts.${ID}.tmpl" ]]; then
|
||||||
|
TEMPLATE_FILE="/etc/cloud/templates/hosts.${ID}.tmpl"
|
||||||
|
elif [[ -f "/etc/cloud/templates/hosts.tmpl" ]]; then
|
||||||
|
TEMPLATE_FILE="/etc/cloud/templates/hosts.tmpl"
|
||||||
|
fi
|
||||||
|
if [[ -n "$TEMPLATE_FILE" ]]; then
|
||||||
|
print_info "Patching cloud-init hosts template ($TEMPLATE_FILE) to enforce persistence..."
|
||||||
|
cp "$TEMPLATE_FILE" "$BACKUP_DIR/$(basename "$TEMPLATE_FILE").backup"
|
||||||
|
sed -i "s/^127.0.1.1.*/127.0.1.1\t$SERVER_NAME/g" "$TEMPLATE_FILE"
|
||||||
|
log "Hardcoded hostname into $TEMPLATE_FILE"
|
||||||
|
else
|
||||||
|
if [[ -d /etc/cloud/templates ]]; then
|
||||||
|
print_warning "Could not locate a standard hosts template in /etc/cloud/templates."
|
||||||
|
log "Warning: Cloud-init template patching skipped (no matching template found)."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -q "^127.0.1.1" /etc/hosts; then
|
||||||
|
if ! grep -qE "^127.0.1.1[[:space:]]+$SERVER_NAME" /etc/hosts; then
|
||||||
|
sed -i "s/^127.0.1.1.*/127.0.1.1\t$SERVER_NAME/" /etc/hosts
|
||||||
|
print_success "Fixed /etc/hosts to map 127.0.1.1 to $SERVER_NAME."
|
||||||
|
else
|
||||||
|
print_info "/etc/hosts is already correct."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "127.0.1.1 $SERVER_NAME" >> /etc/hosts
|
||||||
|
print_success "Added missing 127.0.1.1 entry to /etc/hosts."
|
||||||
|
fi
|
||||||
|
|
||||||
log "System configuration completed."
|
log "System configuration completed."
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3148,9 +3246,7 @@ cleanup_and_exit() {
|
|||||||
else
|
else
|
||||||
print_warning "Could not determine previous SSH port for firewall rollback."
|
print_warning "Could not determine previous SSH port for firewall rollback."
|
||||||
fi
|
fi
|
||||||
|
if ! rollback_ssh_changes; then
|
||||||
rollback_ssh_changes
|
|
||||||
if [[ $? -ne 0 ]]; then
|
|
||||||
print_error "Rollback failed. SSH may not be accessible. Please check 'systemctl status $SSH_SERVICE' and 'journalctl -u $SSH_SERVICE'."
|
print_error "Rollback failed. SSH may not be accessible. Please check 'systemctl status $SSH_SERVICE' and 'journalctl -u $SSH_SERVICE'."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -3216,13 +3312,64 @@ configure_ssh() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
print_warning "SSH Key Authentication Required for Next Steps!"
|
print_warning "SSH Key Authentication Required for Next Steps!"
|
||||||
printf '%s\n' "${CYAN}Test SSH access from a SEPARATE terminal now:${NC}"
|
printf '%s\n' "${CYAN}Test SSH access from a SEPARATE terminal now.${NC}"
|
||||||
if [[ -n "$SERVER_IP_V4" && "$SERVER_IP_V4" != "unknown" ]]; then
|
|
||||||
printf '%s\n' "${CYAN} Using IPv4: ssh -p $CURRENT_SSH_PORT $USERNAME@$SERVER_IP_V4${NC}"
|
# --- Connection Display Function ---
|
||||||
fi
|
show_connection_options() {
|
||||||
if [[ -n "$SERVER_IP_V6" && "$SERVER_IP_V6" != "not available" ]]; then
|
local port="$1"
|
||||||
printf '%s\n' "${CYAN} Using IPv6: ssh -p $CURRENT_SSH_PORT $USERNAME@$SERVER_IP_V6${NC}"
|
local public_ip="$2"
|
||||||
fi
|
|
||||||
|
local TS_IP=""
|
||||||
|
if command -v tailscale >/dev/null 2>&1 && tailscale ip >/dev/null 2>&1; then
|
||||||
|
TS_IP=$(tailscale ip -4 2>/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\n"
|
||||||
|
|
||||||
|
# 1. Public IP (Internet)
|
||||||
|
# Only show if valid and not "Unknown"
|
||||||
|
if [[ -n "$public_ip" && "$public_ip" != "Unknown" ]]; then
|
||||||
|
printf " %-20s ${CYAN}ssh -p %s %s@%s${NC}\n" "Public (Internet):" "$port" "$USERNAME" "$public_ip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. Internal/LAN IPs
|
||||||
|
# scan all interfaces. exclude the Public IP (already shown) and Loopback.
|
||||||
|
local found_internal=false
|
||||||
|
while read -r ip_addr; do
|
||||||
|
# Remove subnet mask if present
|
||||||
|
local clean_ip="${ip_addr%/*}"
|
||||||
|
|
||||||
|
# Skip if empty, loopback, or matches the Public IP we just displayed
|
||||||
|
if [[ -n "$clean_ip" && "$clean_ip" != "127.0.0.1" && "$clean_ip" != "$public_ip" ]]; then
|
||||||
|
printf " %-20s ${CYAN}ssh -p %s %s@%s${NC}\n" "Internal/Private:" "$port" "$USERNAME" "$clean_ip"
|
||||||
|
found_internal=true
|
||||||
|
fi
|
||||||
|
done < <(ip -4 -o addr show scope global | awk '{print $4}')
|
||||||
|
|
||||||
|
# Fallback: If we found NO internal IPs and NO Public IP (local VM offline?),
|
||||||
|
# show the detected local IP from route (Home VM scenario)
|
||||||
|
if [[ "$found_internal" == false && "$public_ip" == "Unknown" ]]; then
|
||||||
|
local fallback_ip
|
||||||
|
fallback_ip=$(ip -4 route get 8.8.8.8 2>/dev/null | head -1 | awk '{print $7}')
|
||||||
|
if [[ -n "$fallback_ip" ]]; then
|
||||||
|
printf " %-20s ${CYAN}ssh -p %s %s@%s${NC}\n" "Local (LAN):" "$port" "$USERNAME" "$fallback_ip"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 3. IPv6
|
||||||
|
if [[ -n "$SERVER_IP_V6" && "$SERVER_IP_V6" != "Not available" ]]; then
|
||||||
|
printf " %-20s ${CYAN}ssh -p %s %s@%s${NC}\n" "IPv6:" "$port" "$USERNAME" "$SERVER_IP_V6"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. Tailscale IP (VPN)
|
||||||
|
if [[ -n "$TS_IP" ]]; then
|
||||||
|
printf " %-20s ${CYAN}ssh -p %s %s@%s${NC}\n" "Tailscale (VPN):" "$port" "$USERNAME" "$TS_IP"
|
||||||
|
fi
|
||||||
|
printf "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show options for CURRENT port
|
||||||
|
show_connection_options "$CURRENT_SSH_PORT" "$SERVER_IP_V4"
|
||||||
|
|
||||||
if ! confirm "Can you successfully log in using your SSH key?"; then
|
if ! confirm "Can you successfully log in using your SSH key?"; then
|
||||||
print_error "SSH key authentication is mandatory to proceed."
|
print_error "SSH key authentication is mandatory to proceed."
|
||||||
@ -3298,12 +3445,9 @@ EOF
|
|||||||
|
|
||||||
print_warning "CRITICAL: Test new SSH connection in a SEPARATE terminal NOW!"
|
print_warning "CRITICAL: Test new SSH connection in a SEPARATE terminal NOW!"
|
||||||
print_warning "ACTION REQUIRED: Check your VPS provider's edge/network firewall to allow $SSH_PORT/tcp."
|
print_warning "ACTION REQUIRED: Check your VPS provider's edge/network firewall to allow $SSH_PORT/tcp."
|
||||||
if [[ -n "$SERVER_IP_V4" && "$SERVER_IP_V4" != "unknown" ]]; then
|
|
||||||
print_info "Use IPv4: ssh -p $SSH_PORT $USERNAME@$SERVER_IP_V4"
|
# Show options for NEW port
|
||||||
fi
|
show_connection_options "$SSH_PORT" "$SERVER_IP_V4"
|
||||||
if [[ -n "$SERVER_IP_V6" && "$SERVER_IP_V6" != "not available" ]]; then
|
|
||||||
print_info "Use IPv6: ssh -p $SSH_PORT $USERNAME@$SERVER_IP_V6"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Retry loop for SSH connection test
|
# Retry loop for SSH connection test
|
||||||
local retry_count=0
|
local retry_count=0
|
||||||
@ -3656,21 +3800,37 @@ configure_fail2ban() {
|
|||||||
local -a INVALID_IPS=()
|
local -a INVALID_IPS=()
|
||||||
local prompt_change=""
|
local prompt_change=""
|
||||||
|
|
||||||
# NEW: Auto-detect and offer to whitelist current SSH connection
|
# Auto-detect and offer to whitelist current SSH connection
|
||||||
if [[ -n "$SSH_CONNECTION" ]]; then
|
local DETECTED_IP=""
|
||||||
local CURRENT_IP="${SSH_CONNECTION%% *}"
|
if [[ -n "${SSH_CONNECTION:-}" ]]; then
|
||||||
print_info "Detected SSH connection from: $CURRENT_IP"
|
DETECTED_IP="${SSH_CONNECTION%% *}"
|
||||||
|
fi
|
||||||
if confirm "Whitelist your current IP ($CURRENT_IP) in Fail2Ban?"; then
|
if [[ -z "$DETECTED_IP" ]]; then
|
||||||
if validate_ip_or_cidr "$CURRENT_IP"; then
|
local WHO_IP
|
||||||
IGNORE_IPS+=("$CURRENT_IP")
|
WHO_IP=$(who -m 2>/dev/null | awk '{print $NF}' | tr -d '()')
|
||||||
print_success "Added your current IP to whitelist."
|
if validate_ip_or_cidr "$WHO_IP"; then
|
||||||
log "Auto-whitelisted SSH connection IP: $CURRENT_IP"
|
DETECTED_IP="$WHO_IP"
|
||||||
else
|
|
||||||
print_warning "Could not validate current IP. Please add it manually."
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
prompt_change=" additional" # Modifies following prompt based on presence of SSH connection.
|
fi
|
||||||
|
if [[ -z "$DETECTED_IP" ]]; then
|
||||||
|
local SS_IP
|
||||||
|
SS_IP=$(ss -tnH state established '( dport = :22 or sport = :22 )' 2>/dev/null | head -n 1 | awk '{print $NF}' | cut -d: -f1 | cut -d] -f1)
|
||||||
|
if validate_ip_or_cidr "$SS_IP"; then
|
||||||
|
DETECTED_IP="$SS_IP"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ -n "$DETECTED_IP" ]]; then
|
||||||
|
print_info "Detected SSH connection from: $DETECTED_IP"
|
||||||
|
|
||||||
|
if confirm "Whitelist your current IP ($DETECTED_IP) in Fail2Ban?"; then
|
||||||
|
IGNORE_IPS+=("$DETECTED_IP")
|
||||||
|
print_success "Added your current IP to whitelist."
|
||||||
|
log "Auto-whitelisted SSH connection IP: $DETECTED_IP"
|
||||||
|
fi
|
||||||
|
prompt_change=" additional"
|
||||||
|
else
|
||||||
|
print_warning "Could not auto-detect current SSH IP. (This is normal in some VM/sudo environments)"
|
||||||
|
print_info "You can manually add your IP in the next step."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $VERBOSE != false ]] && \
|
if [[ $VERBOSE != false ]] && \
|
||||||
@ -3936,8 +4096,9 @@ install_docker() {
|
|||||||
apt-get remove -y -qq docker docker-engine docker.io containerd runc 2>/dev/null || true
|
apt-get remove -y -qq docker docker-engine docker.io containerd runc 2>/dev/null || true
|
||||||
print_info "Adding Docker's official GPG key and repository..."
|
print_info "Adding Docker's official GPG key and repository..."
|
||||||
install -m 0755 -d /etc/apt/keyrings
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
curl -fsSL https://download.docker.com/linux/${ID}/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
curl -fsSL "https://download.docker.com/linux/${ID}/gpg" | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||||
|
# shellcheck source=/dev/null
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${ID} $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/${ID} $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
|
||||||
print_info "Installing Docker packages..."
|
print_info "Installing Docker packages..."
|
||||||
if ! apt-get update -qq || ! apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
|
if ! apt-get update -qq || ! apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin; then
|
||||||
@ -4401,7 +4562,7 @@ setup_backup() {
|
|||||||
else
|
else
|
||||||
print_error "SSH connection test failed. Please ensure the key was copied correctly and the port is open."
|
print_error "SSH connection test failed. Please ensure the key was copied correctly and the port is open."
|
||||||
print_info " - Copy key: ssh-copy-id -p \"$BACKUP_PORT\" -i \"$ROOT_SSH_KEY.pub\" $SSH_COPY_ID_FLAGS \"$BACKUP_DEST\""
|
print_info " - Copy key: ssh-copy-id -p \"$BACKUP_PORT\" -i \"$ROOT_SSH_KEY.pub\" $SSH_COPY_ID_FLAGS \"$BACKUP_DEST\""
|
||||||
print_info " - Check port: nc -zv $(echo \"$BACKUP_DEST\" | cut -d'@' -f2) \"$BACKUP_PORT\""
|
print_info " - Check port: nc -zv $(echo "$BACKUP_DEST" | cut -d'@' -f2) \"$BACKUP_PORT\""
|
||||||
print_info " - Ensure key is in ~/.ssh/authorized_keys on the backup server."
|
print_info " - Ensure key is in ~/.ssh/authorized_keys on the backup server."
|
||||||
if [[ -n "$SSH_COPY_ID_FLAGS" ]]; then
|
if [[ -n "$SSH_COPY_ID_FLAGS" ]]; then
|
||||||
print_info " - For Hetzner, ensure ~/.ssh/ exists: ssh -p \"$BACKUP_PORT\" \"$BACKUP_DEST\" \"mkdir -p ~/.ssh && chmod 700 ~/.ssh\""
|
print_info " - For Hetzner, ensure ~/.ssh/ exists: ssh -p \"$BACKUP_PORT\" \"$BACKUP_DEST\" \"mkdir -p ~/.ssh && chmod 700 ~/.ssh\""
|
||||||
@ -4724,148 +4885,229 @@ test_backup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configure_swap() {
|
configure_swap() {
|
||||||
if [[ $IS_CONTAINER == true ]]; then
|
if [[ "$IS_CONTAINER" == true ]]; then
|
||||||
print_info "Swap configuration skipped in container."
|
print_info "Swap configuration skipped in container."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
print_section "Swap Configuration"
|
print_section "Swap Configuration"
|
||||||
# Check for existing swap partition
|
|
||||||
|
# Check for existing swap partition entries in fstab
|
||||||
if lsblk -r | grep -q '\[SWAP\]'; then
|
if lsblk -r | grep -q '\[SWAP\]'; then
|
||||||
print_warning "Existing swap partition found. Verify with 'lsblk -f'. Proceed with caution."
|
print_warning "Existing swap partition found on disk."
|
||||||
fi
|
fi
|
||||||
local existing_swap
|
|
||||||
existing_swap=$(swapon --show --noheadings | awk '{print $1}' || true)
|
# Detect active swap
|
||||||
|
local existing_swap swap_type
|
||||||
|
existing_swap=$(swapon --show=NAME,TYPE,SIZE --noheadings --bytes 2>/dev/null | head -n 1 | awk '{print $1}' || true)
|
||||||
|
|
||||||
if [[ -n "$existing_swap" ]]; then
|
if [[ -n "$existing_swap" ]]; then
|
||||||
local current_size
|
swap_type=$(swapon --show=NAME,TYPE,SIZE --noheadings | head -n 1 | awk '{print $2}')
|
||||||
current_size=$(du -h "$existing_swap" | awk '{print $1}')
|
local display_size
|
||||||
print_info "Existing swap file found: $existing_swap ($current_size)"
|
display_size=$(du -h "$existing_swap" 2>/dev/null | awk '{print $1}' || echo "Unknown")
|
||||||
if confirm "Modify existing swap file size?"; then
|
|
||||||
local SWAP_SIZE
|
print_info "Existing swap detected: $existing_swap (Type: $swap_type, Size: $display_size)"
|
||||||
while true; do
|
|
||||||
read -rp "$(printf '%s' "${CYAN}Enter new swap size (e.g., 2G, 512M) [current: $current_size]: ${NC}")" SWAP_SIZE
|
# --- Case 1: Partition detected ---
|
||||||
SWAP_SIZE=${SWAP_SIZE:-$current_size}
|
if [[ "$swap_type" == "partition" ]] || [[ "$existing_swap" =~ ^/dev/ ]]; then
|
||||||
if validate_swap_size "$SWAP_SIZE"; then
|
print_warning "The detected swap is a disk partition, which cannot be resized by this script."
|
||||||
break
|
|
||||||
else
|
if confirm "Disable this swap partition and create a standard /swapfile instead?" "n"; then
|
||||||
print_error "Invalid size. Use format like '2G' or '512M'."
|
print_info "Disabling swap partition $existing_swap..."
|
||||||
|
if ! swapoff "$existing_swap"; then
|
||||||
|
print_error "Failed to disable swap partition. Keeping it active."
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
|
||||||
local REQUIRED_SPACE
|
sed -i "s|^${existing_swap}[[:space:]]|#&|" /etc/fstab
|
||||||
REQUIRED_SPACE=$(convert_to_bytes "$SWAP_SIZE")
|
local swap_uuid
|
||||||
local AVAILABLE_SPACE
|
swap_uuid=$(blkid -s UUID -o value "$existing_swap" 2>/dev/null || true)
|
||||||
AVAILABLE_SPACE=$(df -k / | tail -n 1 | awk '{print $4}')
|
if [[ -n "$swap_uuid" ]]; then
|
||||||
if (( AVAILABLE_SPACE < REQUIRED_SPACE / 1024 )); then
|
sed -i "s|^UUID=${swap_uuid}[[:space:]]|#&|" /etc/fstab
|
||||||
print_error "Insufficient disk space for $SWAP_SIZE swap file. Available: $((AVAILABLE_SPACE / 1024))MB"
|
fi
|
||||||
exit 1
|
|
||||||
|
print_success "Swap partition disabled and removed from fstab."
|
||||||
|
existing_swap=""
|
||||||
|
else
|
||||||
|
print_info "Keeping existing swap partition."
|
||||||
|
configure_swap_settings
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
print_info "Disabling existing swap file..."
|
|
||||||
swapoff "$existing_swap" || { print_error "Failed to disable swap file."; exit 1; }
|
|
||||||
print_info "Resizing swap file to $SWAP_SIZE..."
|
|
||||||
if ! fallocate -l "$SWAP_SIZE" "$existing_swap" || ! chmod 600 "$existing_swap" || ! mkswap "$existing_swap" || ! swapon "$existing_swap"; then
|
|
||||||
print_error "Failed to resize or enable swap file."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
print_success "Swap file resized to $SWAP_SIZE."
|
|
||||||
else
|
else
|
||||||
print_info "Keeping existing swap file."
|
# --- Case 2: Resize Existing Swap File ---
|
||||||
|
if confirm "Modify existing swap file size?"; then
|
||||||
|
local SWAP_SIZE REQUIRED_MB
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
read -rp "$(printf '%s' "${CYAN}Enter new swap size (e.g., 2G, 512M) [current: $display_size]: ${NC}")" SWAP_SIZE
|
||||||
|
SWAP_SIZE=${SWAP_SIZE:-$display_size}
|
||||||
|
# 1. Validate Format
|
||||||
|
if ! REQUIRED_MB=$(convert_to_mb "$SWAP_SIZE"); then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# 2. Min Size
|
||||||
|
if (( REQUIRED_MB < 128 )); then
|
||||||
|
print_error "Swap size too small (minimum: 128M)."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# 3. Disk Space Check
|
||||||
|
local AVAILABLE_KB AVAILABLE_MB
|
||||||
|
AVAILABLE_KB=$(df -k / | tail -n 1 | awk '{print $4}')
|
||||||
|
AVAILABLE_MB=$((AVAILABLE_KB / 1024))
|
||||||
|
if (( AVAILABLE_MB < REQUIRED_MB )); then
|
||||||
|
print_error "Insufficient disk space. Required: ${REQUIRED_MB}MB, Available: ${AVAILABLE_MB}MB"
|
||||||
|
# Suggest Max Safe Size (80% of free space)
|
||||||
|
local MAX_SAFE_MB=$(( AVAILABLE_MB * 80 / 100 ))
|
||||||
|
if (( MAX_SAFE_MB >= 128 )); then
|
||||||
|
print_info "Suggested maximum: ${MAX_SAFE_MB}M (leaves 20% free space)"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
break
|
||||||
|
done
|
||||||
|
|
||||||
|
print_info "Disabling existing swap file..."
|
||||||
|
swapoff "$existing_swap" || { print_error "Failed to disable swap file."; exit 1; }
|
||||||
|
|
||||||
|
print_info "Resizing swap file to $SWAP_SIZE..."
|
||||||
|
# Try fallocate, fallback to dd
|
||||||
|
if ! fallocate -l "$SWAP_SIZE" "$existing_swap" 2>/dev/null; then
|
||||||
|
print_warning "fallocate failed. Using dd (slower)..."
|
||||||
|
rm -f "$existing_swap"
|
||||||
|
|
||||||
|
local dd_status=""
|
||||||
|
if dd --version 2>&1 | grep -q "progress"; then dd_status="status=progress"; fi
|
||||||
|
|
||||||
|
if ! dd if=/dev/zero of="$existing_swap" bs=1M count="$REQUIRED_MB" $dd_status; then
|
||||||
|
print_error "Failed to create swap file with dd."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! chmod 600 "$existing_swap" || ! mkswap "$existing_swap" >/dev/null || ! swapon "$existing_swap"; then
|
||||||
|
print_error "Failed to configure swap file."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
print_success "Swap file resized to $SWAP_SIZE."
|
||||||
|
else
|
||||||
|
print_info "Keeping existing swap file."
|
||||||
|
fi
|
||||||
|
configure_swap_settings
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
else
|
fi
|
||||||
|
|
||||||
|
# --- Case 3: Create New Swap ---
|
||||||
|
if [[ -z "$existing_swap" ]]; then
|
||||||
if ! confirm "Configure a swap file (recommended for < 4GB RAM)?"; then
|
if ! confirm "Configure a swap file (recommended for < 4GB RAM)?"; then
|
||||||
print_info "Skipping swap configuration."
|
print_info "Skipping swap configuration."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
local SWAP_SIZE
|
|
||||||
|
local SWAP_SIZE REQUIRED_MB
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
read -rp "$(printf '%s' "${CYAN}Enter swap file size (e.g., 2G, 512M) [2G]: ${NC}")" SWAP_SIZE
|
read -rp "$(printf '%s' "${CYAN}Enter swap file size (e.g., 2G, 512M) [2G]: ${NC}")" SWAP_SIZE
|
||||||
SWAP_SIZE=${SWAP_SIZE:-2G}
|
SWAP_SIZE=${SWAP_SIZE:-2G}
|
||||||
if validate_swap_size "$SWAP_SIZE"; then
|
# 1. Validate Format
|
||||||
break
|
if ! REQUIRED_MB=$(convert_to_mb "$SWAP_SIZE"); then
|
||||||
else
|
continue
|
||||||
print_error "Invalid size. Use format like '2G' or '512M'."
|
|
||||||
fi
|
fi
|
||||||
|
# 2. Min Size
|
||||||
|
if (( REQUIRED_MB < 128 )); then
|
||||||
|
print_error "Swap size too small (minimum: 128M)."
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
# 3. Disk Space Check
|
||||||
|
local AVAILABLE_KB AVAILABLE_MB
|
||||||
|
AVAILABLE_KB=$(df -k / | tail -n 1 | awk '{print $4}')
|
||||||
|
AVAILABLE_MB=$((AVAILABLE_KB / 1024))
|
||||||
|
if (( AVAILABLE_MB < REQUIRED_MB )); then
|
||||||
|
print_error "Insufficient disk space. Required: ${REQUIRED_MB}MB, Available: ${AVAILABLE_MB}MB"
|
||||||
|
# Suggest Max Safe Size
|
||||||
|
local MAX_SAFE_MB=$(( AVAILABLE_MB * 80 / 100 ))
|
||||||
|
if (( MAX_SAFE_MB >= 128 )); then
|
||||||
|
print_info "Suggested maximum: ${MAX_SAFE_MB}M (leaves 20% free space)"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
break
|
||||||
done
|
done
|
||||||
local REQUIRED_SPACE
|
|
||||||
REQUIRED_SPACE=$(convert_to_bytes "$SWAP_SIZE")
|
print_info "Creating $SWAP_SIZE swap file at /swapfile..."
|
||||||
local AVAILABLE_SPACE
|
if ! fallocate -l "$SWAP_SIZE" /swapfile 2>/dev/null; then
|
||||||
AVAILABLE_SPACE=$(df -k / | tail -n 1 | awk '{print $4}')
|
print_warning "fallocate failed. Using dd (slower)..."
|
||||||
if (( AVAILABLE_SPACE < REQUIRED_SPACE / 1024 )); then
|
local dd_status=""
|
||||||
print_error "Insufficient disk space for $SWAP_SIZE swap file. Available: $((AVAILABLE_SPACE / 1024))MB"
|
if dd --version 2>&1 | grep -q "progress"; then dd_status="status=progress"; fi
|
||||||
exit 1
|
if ! dd if=/dev/zero of=/swapfile bs=1M count="$REQUIRED_MB" $dd_status; then
|
||||||
|
print_error "Failed to create swap file."
|
||||||
|
rm -f /swapfile || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
print_info "Creating $SWAP_SIZE swap file..."
|
if ! chmod 600 /swapfile || ! mkswap /swapfile >/dev/null || ! swapon /swapfile; then
|
||||||
if ! fallocate -l "$SWAP_SIZE" /swapfile || ! chmod 600 /swapfile || ! mkswap /swapfile || ! swapon /swapfile; then
|
print_error "Failed to enable swap file."
|
||||||
print_error "Failed to create or enable swap file."
|
|
||||||
rm -f /swapfile || true
|
rm -f /swapfile || true
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
# Check for existing swap entry in /etc/fstab to prevent duplicates
|
if ! grep -q '^/swapfile ' /etc/fstab; then
|
||||||
if grep -q '^/swapfile ' /etc/fstab; then
|
|
||||||
print_info "Swap entry already exists in /etc/fstab. Skipping."
|
|
||||||
else
|
|
||||||
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
echo '/swapfile none swap sw 0 0' >> /etc/fstab
|
||||||
print_success "Swap entry added to /etc/fstab."
|
print_success "Swap entry added to /etc/fstab."
|
||||||
|
else
|
||||||
|
print_info "Swap entry already exists in /etc/fstab."
|
||||||
fi
|
fi
|
||||||
print_success "Swap file created: $SWAP_SIZE"
|
print_success "Swap file created: $SWAP_SIZE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
configure_swap_settings
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper: Apply Sysctl Settings for Swap
|
||||||
|
configure_swap_settings() {
|
||||||
print_info "Configuring swap settings..."
|
print_info "Configuring swap settings..."
|
||||||
local SWAPPINESS=10
|
local SWAPPINESS=10
|
||||||
local CACHE_PRESSURE=50
|
local CACHE_PRESSURE=50
|
||||||
|
|
||||||
if confirm "Customize swap settings (vm.swappiness and vm.vfs_cache_pressure)?"; then
|
if confirm "Customize swap settings (vm.swappiness and vm.vfs_cache_pressure)?"; then
|
||||||
while true; do
|
while true; do
|
||||||
read -rp "$(printf '%s' "${CYAN}Enter vm.swappiness (0-100) [default: $SWAPPINESS]: ${NC}")" INPUT_SWAPPINESS
|
read -rp "$(printf '%s' "${CYAN}Enter vm.swappiness (0-100) [default: $SWAPPINESS]: ${NC}")" INPUT
|
||||||
INPUT_SWAPPINESS=${INPUT_SWAPPINESS:-$SWAPPINESS}
|
INPUT=${INPUT:-$SWAPPINESS}
|
||||||
if [[ "$INPUT_SWAPPINESS" =~ ^[0-9]+$ && "$INPUT_SWAPPINESS" -ge 0 && "$INPUT_SWAPPINESS" -le 100 ]]; then
|
if [[ "$INPUT" =~ ^[0-9]+$ && "$INPUT" -ge 0 && "$INPUT" -le 100 ]]; then SWAPPINESS=$INPUT; break; fi
|
||||||
SWAPPINESS=$INPUT_SWAPPINESS
|
print_error "Invalid value (0-100)."
|
||||||
break
|
|
||||||
else
|
|
||||||
print_error "Invalid value for vm.swappiness. Must be between 0 and 100."
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
while true; do
|
while true; do
|
||||||
read -rp "$(printf '%s' "${CYAN}Enter vm.vfs_cache_pressure (1-1000) [default: $CACHE_PRESSURE]: ${NC}")" INPUT_CACHE_PRESSURE
|
read -rp "$(printf '%s' "${CYAN}Enter vm.vfs_cache_pressure (1-1000) [default: $CACHE_PRESSURE]: ${NC}")" INPUT
|
||||||
INPUT_CACHE_PRESSURE=${INPUT_CACHE_PRESSURE:-$CACHE_PRESSURE}
|
INPUT=${INPUT:-$CACHE_PRESSURE}
|
||||||
if [[ "$INPUT_CACHE_PRESSURE" =~ ^[0-9]+$ && "$INPUT_CACHE_PRESSURE" -ge 1 && "$INPUT_CACHE_PRESSURE" -le 1000 ]]; then
|
if [[ "$INPUT" =~ ^[0-9]+$ && "$INPUT" -ge 1 && "$INPUT" -le 1000 ]]; then CACHE_PRESSURE=$INPUT; break; fi
|
||||||
CACHE_PRESSURE=$INPUT_CACHE_PRESSURE
|
print_error "Invalid value (1-1000)."
|
||||||
break
|
|
||||||
else
|
|
||||||
print_error "Invalid value for vm.vfs_cache_pressure. Must be between 1 and 1000."
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
print_info "Using default swap settings (vm.swappiness=$SWAPPINESS, vm.vfs_cache_pressure=$CACHE_PRESSURE)."
|
print_info "Using default swap settings (vm.swappiness=$SWAPPINESS, vm.vfs_cache_pressure=$CACHE_PRESSURE)."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local NEW_SWAP_CONFIG
|
local NEW_SWAP_CONFIG
|
||||||
NEW_SWAP_CONFIG=$(mktemp)
|
NEW_SWAP_CONFIG=$(mktemp)
|
||||||
tee "$NEW_SWAP_CONFIG" > /dev/null <<EOF
|
tee "$NEW_SWAP_CONFIG" > /dev/null <<EOF
|
||||||
vm.swappiness=$SWAPPINESS
|
vm.swappiness=$SWAPPINESS
|
||||||
vm.vfs_cache_pressure=$CACHE_PRESSURE
|
vm.vfs_cache_pressure=$CACHE_PRESSURE
|
||||||
EOF
|
EOF
|
||||||
# Check if sysctl settings are already correct to prevent duplicates
|
|
||||||
if [[ -f /etc/sysctl.d/99-swap.conf ]] && cmp -s "$NEW_SWAP_CONFIG" /etc/sysctl.d/99-swap.conf; then
|
if [[ -f /etc/sysctl.d/99-swap.conf ]] && cmp -s "$NEW_SWAP_CONFIG" /etc/sysctl.d/99-swap.conf; then
|
||||||
print_info "Swap settings already correct in /etc/sysctl.d/99-swap.conf. Skipping."
|
print_info "Swap settings already correct. Skipping."
|
||||||
rm -f "$NEW_SWAP_CONFIG"
|
rm -f "$NEW_SWAP_CONFIG"
|
||||||
else
|
else
|
||||||
# Check for conflicting settings in /etc/sysctl.conf or other sysctl files
|
# Scan for conflicts
|
||||||
local sysctl_conflicts=false
|
|
||||||
for file in /etc/sysctl.conf /etc/sysctl.d/*.conf; do
|
for file in /etc/sysctl.conf /etc/sysctl.d/*.conf; do
|
||||||
if [[ -f "$file" && "$file" != "/etc/sysctl.d/99-swap.conf" ]]; then
|
[[ -f "$file" && "$file" != "/etc/sysctl.d/99-swap.conf" ]] && \
|
||||||
if grep -E '^(vm\.swappiness|vm\.vfs_cache_pressure)=' "$file" >/dev/null; then
|
grep -E '^(vm\.swappiness|vm\.vfs_cache_pressure)=' "$file" >/dev/null && \
|
||||||
print_warning "Existing swap settings found in $file. Manual review recommended."
|
print_warning "Note: Duplicate swap settings found in $file."
|
||||||
sysctl_conflicts=true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done
|
done
|
||||||
|
|
||||||
mv "$NEW_SWAP_CONFIG" /etc/sysctl.d/99-swap.conf
|
mv "$NEW_SWAP_CONFIG" /etc/sysctl.d/99-swap.conf
|
||||||
chmod 644 /etc/sysctl.d/99-swap.conf
|
chmod 644 /etc/sysctl.d/99-swap.conf
|
||||||
sysctl -p /etc/sysctl.d/99-swap.conf >/dev/null
|
sysctl -p /etc/sysctl.d/99-swap.conf >/dev/null
|
||||||
if [[ $sysctl_conflicts == true ]]; then
|
print_success "Swap settings applied to /etc/sysctl.d/99-swap.conf."
|
||||||
print_warning "Potential conflicting sysctl settings detected. Verify with 'sysctl -a | grep -E \"vm\.swappiness|vm\.vfs_cache_pressure\"'."
|
|
||||||
else
|
|
||||||
print_success "Swap settings applied to /etc/sysctl.d/99-swap.conf."
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
print_success "Swap configured successfully."
|
|
||||||
swapon --show | tee -a "$LOG_FILE"
|
swapon --show | tee -a "$LOG_FILE"
|
||||||
free -h | tee -a "$LOG_FILE"
|
free -h | tee -a "$LOG_FILE"
|
||||||
log "Swap configuration completed."
|
log "Swap configuration completed."
|
||||||
@ -4929,6 +5171,7 @@ configure_security_audit() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if system is Debian before running debsecan
|
# Check if system is Debian before running debsecan
|
||||||
|
# shellcheck source=/dev/null
|
||||||
source /etc/os-release
|
source /etc/os-release
|
||||||
if [[ "$ID" == "debian" ]]; then
|
if [[ "$ID" == "debian" ]]; then
|
||||||
if confirm "Also run debsecan to check for package vulnerabilities?"; then
|
if confirm "Also run debsecan to check for package vulnerabilities?"; then
|
||||||
@ -4963,16 +5206,30 @@ configure_security_audit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final_cleanup() {
|
final_cleanup() {
|
||||||
print_section "Final System Cleanup"
|
print_section "Final System Update & Cleanup"
|
||||||
print_info "Running final system update and cleanup..."
|
print_info "Performing final system upgrade (dist-upgrade) and cleanup..."
|
||||||
if ! apt-get update -qq; then
|
print_info "This may take a moment. Please wait..."
|
||||||
|
# Upgrade ALL packages (including kernels)
|
||||||
|
if ! apt-get update -qq >/dev/null 2>&1; then
|
||||||
print_warning "Failed to update package lists during final cleanup."
|
print_warning "Failed to update package lists during final cleanup."
|
||||||
|
log "Final apt-get update failed."
|
||||||
fi
|
fi
|
||||||
if ! apt-get upgrade -y -qq || ! apt-get --purge autoremove -y -qq || ! apt-get autoclean -y -qq; then
|
if ! DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y -qq -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" >> "$LOG_FILE" 2>&1; then
|
||||||
print_warning "Final system cleanup failed on one or more commands."
|
print_warning "Final system upgrade encountered issues. Check log for details."
|
||||||
|
log "Final apt-get dist-upgrade failed."
|
||||||
|
else
|
||||||
|
print_success "System packages (including kernels) upgraded successfully."
|
||||||
|
log "Final apt-get dist-upgrade completed."
|
||||||
|
fi
|
||||||
|
# Final cleanup
|
||||||
|
print_info "Removing unused packages..."
|
||||||
|
if ! apt-get --purge autoremove -y -qq >> "$LOG_FILE" 2>&1 || ! apt-get autoclean -y -qq >> "$LOG_FILE" 2>&1; then
|
||||||
|
print_warning "Cleanup commands encountered minor issues."
|
||||||
|
else
|
||||||
|
print_success "Unused packages removed."
|
||||||
fi
|
fi
|
||||||
systemctl daemon-reload
|
systemctl daemon-reload
|
||||||
print_success "Final system update and cleanup complete."
|
print_success "Final cleanup complete."
|
||||||
log "Final system cleanup completed."
|
log "Final system cleanup completed."
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5040,10 +5297,10 @@ generate_summary() {
|
|||||||
printf " %-15s %s\n" "Admin User:" "$USERNAME"
|
printf " %-15s %s\n" "Admin User:" "$USERNAME"
|
||||||
printf " %-15s %s\n" "Hostname:" "$SERVER_NAME"
|
printf " %-15s %s\n" "Hostname:" "$SERVER_NAME"
|
||||||
printf " %-15s %s\n" "SSH Port:" "$SSH_PORT"
|
printf " %-15s %s\n" "SSH Port:" "$SSH_PORT"
|
||||||
if [[ "$SERVER_IP_V4" != "unknown" ]]; then
|
if [[ "${SERVER_IP_V4:-}" != "unknown" && "${SERVER_IP_V4:-}" != "Unknown" ]]; then
|
||||||
printf " %-15s %s\n" "Server IPv4:" "$SERVER_IP_V4"
|
printf " %-15s %s\n" "Server IPv4:" "$SERVER_IP_V4"
|
||||||
fi
|
fi
|
||||||
if [[ "$SERVER_IP_V6" != "not available" ]]; then
|
if [[ "${SERVER_IP_V6:-}" != "not available" && "${SERVER_IP_V6:-}" != "Not available" ]]; then
|
||||||
printf " %-15s %s\n" "Server IPv6:" "$SERVER_IP_V6"
|
printf " %-15s %s\n" "Server IPv6:" "$SERVER_IP_V6"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -5123,28 +5380,73 @@ generate_summary() {
|
|||||||
fi
|
fi
|
||||||
printf '\n'
|
printf '\n'
|
||||||
|
|
||||||
print_separator "Environment Information"
|
# --- System & Environment Information ---
|
||||||
|
print_separator "System & Environment Information"
|
||||||
|
|
||||||
|
# OS and Kernel Info
|
||||||
|
printf "%-20s %s\n" "OS:" "${PRETTY_NAME:-Unknown}"
|
||||||
|
printf "%-20s %s\n" "Kernel:" "$(uname -r)"
|
||||||
|
printf "%-20s %s\n" "Uptime:" "$(uptime -p 2>/dev/null || uptime | sed 's/.*up //;s/,.*//')"
|
||||||
|
|
||||||
|
# Hardware/Virtualization Info
|
||||||
printf "%-20s %s\n" "Virtualization:" "${DETECTED_VIRT_TYPE:-unknown}"
|
printf "%-20s %s\n" "Virtualization:" "${DETECTED_VIRT_TYPE:-unknown}"
|
||||||
printf "%-20s %s\n" "Manufacturer:" "${DETECTED_MANUFACTURER:-unknown}"
|
if [[ "${DETECTED_MANUFACTURER:-unknown}" != "unknown" ]]; then
|
||||||
printf "%-20s %s\n" "Product:" "${DETECTED_PRODUCT:-unknown}"
|
printf "%-20s %s\n" "Manufacturer:" "$DETECTED_MANUFACTURER"
|
||||||
if [[ "$IS_CLOUD_PROVIDER" == "true" ]]; then
|
fi
|
||||||
printf "%-20s %s\n" "Environment:" "${YELLOW}Cloud VPS${NC}"
|
if [[ "${DETECTED_PRODUCT:-unknown}" != "unknown" ]]; then
|
||||||
elif [[ "$DETECTED_VIRT_TYPE" == "none" ]]; then
|
printf "%-20s %s\n" "Product:" "$DETECTED_PRODUCT"
|
||||||
printf "%-20s %s\n" "Environment:" "${GREEN}Bare Metal${NC}"
|
fi
|
||||||
else
|
if [[ "${DETECTED_BIOS_VENDOR:-unknown}" != "unknown" ]]; then
|
||||||
printf "%-20s %s\n" "Environment:" "${CYAN}Personal VM${NC}"
|
printf "%-20s %s\n" "BIOS Vendor:" "$DETECTED_BIOS_VENDOR"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Environment Classification
|
||||||
|
printf "%-20s " "Environment:"
|
||||||
|
case "$ENVIRONMENT_TYPE" in
|
||||||
|
commercial-cloud) printf "%sCloud VPS%s\n" "$YELLOW" "$NC" ;;
|
||||||
|
bare-metal) printf "%sBare Metal%s\n" "$GREEN" "$NC" ;;
|
||||||
|
uncertain-kvm) printf "%sGeneric KVM (Likely Cloud VPS)%s\n" "$YELLOW" "$NC" ;;
|
||||||
|
personal-vm) printf "%sPersonal VM%s\n" "$CYAN" "$NC" ;;
|
||||||
|
*) printf "Unknown\n" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ -n "$DETECTED_PROVIDER_NAME" ]]; then
|
||||||
|
printf "%-20s %s\n" "Detected Provider:" "$DETECTED_PROVIDER_NAME"
|
||||||
fi
|
fi
|
||||||
printf '\n'
|
printf '\n'
|
||||||
|
|
||||||
# --- Post-Reboot Verification Steps ---
|
# --- Post-Reboot Verification Steps ---
|
||||||
print_separator "Post-Reboot Verification Steps:"
|
print_separator "Post-Reboot Verification Steps:"
|
||||||
printf ' - SSH access:\n'
|
printf ' - SSH access:\n'
|
||||||
if [[ "$SERVER_IP_V4" != "unknown" ]]; then
|
|
||||||
printf " %-26s ${CYAN}%s${NC}\n" "- Using IPv4:" "ssh -p $SSH_PORT $USERNAME@$SERVER_IP_V4"
|
# 1. Public Access
|
||||||
|
if [[ "${SERVER_IP_V4:-}" != "unknown" && "${SERVER_IP_V4:-}" != "Unknown" ]]; then
|
||||||
|
printf " %-26s ${CYAN}%s${NC}\n" "- Public (Internet):" "ssh -p $SSH_PORT $USERNAME@$SERVER_IP_V4"
|
||||||
fi
|
fi
|
||||||
if [[ "$SERVER_IP_V6" != "not available" ]]; then
|
|
||||||
printf " %-26s ${CYAN}%s${NC}\n" "- Using IPv6:" "ssh -p $SSH_PORT $USERNAME@$SERVER_IP_V6"
|
# 2. Local Access
|
||||||
|
if [[ -n "${LOCAL_IP_V4:-}" ]]; then
|
||||||
|
# Show local if public is unknown OR if they are different IPs
|
||||||
|
if [[ "${SERVER_IP_V4:-}" == "Unknown" || "${SERVER_IP_V4:-}" == "unknown" || "${LOCAL_IP_V4:-}" != "${SERVER_IP_V4:-}" ]]; then
|
||||||
|
printf " %-26s ${CYAN}%s${NC}\n" "- Local (LAN):" "ssh -p $SSH_PORT $USERNAME@$LOCAL_IP_V4"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 3. Tailscale Access
|
||||||
|
if [[ -f /tmp/tailscale_ips.txt ]]; then
|
||||||
|
local TS_SUMMARY_IP
|
||||||
|
TS_SUMMARY_IP=$(grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' /tmp/tailscale_ips.txt | head -n 1)
|
||||||
|
if [[ -n "$TS_SUMMARY_IP" ]]; then
|
||||||
|
printf " %-26s ${CYAN}%s${NC}\n" "- Tailscale (VPN):" "ssh -p $SSH_PORT $USERNAME@$TS_SUMMARY_IP"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4. IPv6 Access
|
||||||
|
if [[ "${SERVER_IP_V6:-}" != "not available" && "${SERVER_IP_V6:-}" != "Not available" ]]; then
|
||||||
|
printf " %-26s ${CYAN}%s${NC}\n" "- IPv6:" "ssh -p $SSH_PORT $USERNAME@$SERVER_IP_V6"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Other verification commands
|
||||||
printf " %-28s ${CYAN}%s${NC}\n" "- Firewall rules:" "sudo ufw status verbose"
|
printf " %-28s ${CYAN}%s${NC}\n" "- Firewall rules:" "sudo ufw status verbose"
|
||||||
printf " %-28s ${CYAN}%s${NC}\n" "- Time sync:" "chronyc tracking"
|
printf " %-28s ${CYAN}%s${NC}\n" "- Time sync:" "chronyc tracking"
|
||||||
printf " %-28s ${CYAN}%s${NC}\n" "- Fail2Ban sshd jail:" "sudo fail2ban-client status sshd"
|
printf " %-28s ${CYAN}%s${NC}\n" "- Fail2Ban sshd jail:" "sudo fail2ban-client status sshd"
|
||||||
@ -5224,9 +5526,9 @@ main() {
|
|||||||
|
|
||||||
# --- PRELIMINARY CHECKS ---
|
# --- PRELIMINARY CHECKS ---
|
||||||
print_header
|
print_header
|
||||||
|
check_dependencies
|
||||||
check_system
|
check_system
|
||||||
run_update_check
|
run_update_check
|
||||||
check_dependencies
|
|
||||||
|
|
||||||
# --- HANDLE SPECIAL OPERATIONAL MODES ---
|
# --- HANDLE SPECIAL OPERATIONAL MODES ---
|
||||||
if [[ "$CLEANUP_ONLY" == "true" ]]; then
|
if [[ "$CLEANUP_ONLY" == "true" ]]; then
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
3ea3416cf0916ea92c382e1c899de0ef2f29535c9c93d1fa7466b4a78e1bb26d du_setup.sh
|
d7378f43082166cad26c7b232f3cd01e778a3377dea996c3f434e0f483317659 du_setup.sh
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user