11#! /bin/bash
22
33# Debian and Ubuntu Server Hardening Interactive Script
4- # Version: 0.81.3 | 2026-08-09
4+ # Version: 0.81.4 | 2026-08-12
55# Changelog:
6+ # - v0.81.4: Fix silent script abort on IPv6-only servers, improve local IP detection and IPv6 route fallbacks.
7+ # Safely handle immutable/locked /etc/resolv.conf files (common on VPS providers) to prevent aborts during Secure DNS setup.
68# - v0.81.3: Switch Fail2Ban UFW banaction to native nftables (nftables-allports) for maximum performance and modern standard compliance.
79# Ensure 'nftables' package is installed for minimal server compatibility.
810# - v0.81.2: Switch Fail2Ban UFW banaction to ipset for improved performance when handling large ban lists.
120122set -euo pipefail
121123
122124# --- Update Configuration ---
123- CURRENT_VERSION=" 0.81.1 "
125+ CURRENT_VERSION=" 0.81.4 "
124126SCRIPT_URL=" https://raw.githubusercontent.com/buildplan/du_setup/refs/heads/main/du_setup.sh"
125127CHECKSUM_URL=" ${SCRIPT_URL} .sha256"
126128
@@ -284,7 +286,7 @@ print_header() {
284286 printf ' %s\n' " ${CYAN} ╔═════════════════════════════════════════════════════════════════╗${NC} "
285287 printf ' %s\n' " ${CYAN} ║ ║${NC} "
286288 printf ' %s\n' " ${CYAN} ║ DEBIAN/UBUNTU SERVER SETUP AND HARDENING SCRIPT ║${NC} "
287- printf ' %s\n' " ${CYAN} ║ v0.81.3 | 2026-08-09 ║${NC} "
289+ printf ' %s\n' " ${CYAN} ║ v0.81.4 | 2026-08-12 ║${NC} "
288290 printf ' %s\n' " ${CYAN} ║ ║${NC} "
289291 printf ' %s\n' " ${CYAN} ╚═════════════════════════════════════════════════════════════════╝${NC} "
290292 printf ' \n'
@@ -1485,13 +1487,13 @@ sysinfo() {
14851487 public_ipv4=$(curl -4 -sf -m 2 --connect-timeout 1 https://ip.wiredalter.com 2>/dev/null || \
14861488 curl -4 -sf -m 2 --connect-timeout 1 https://checkip.amazonaws.com 2>/dev/null || \
14871489 curl -4 -sf -m 2 --connect-timeout 1 https://ipconfig.io 2>/dev/null || \
1488- curl -4 -sf -m 2 --connect-timeout 1 https://api.ipify.org 2>/dev/null)
1490+ curl -4 -sf -m 2 --connect-timeout 1 https://api.ipify.org 2>/dev/null || true )
14891491 # If no IPv4, try IPv6
14901492 if [ -z "$public_ipv4" ]; then
14911493 public_ipv6=$(curl -6 -sf -m 2 --connect-timeout 1 https://ip.wiredalter.com 2>/dev/null || \
14921494 curl -6 -sf -m 2 --connect-timeout 1 https://ipconfig.io 2>/dev/null || \
14931495 curl -6 -sf -m 2 --connect-timeout 1 https://icanhazip.co 2>/dev/null || \
1494- curl -6 -sf -m 2 --connect-timeout 1 https://api64.ipify.org 2>/dev/null)
1496+ curl -6 -sf -m 2 --connect-timeout 1 https://api64.ipify.org 2>/dev/null || true )
14951497 fi
14961498 # Get local/internal IP as fallback
14971499 for iface in eth0 ens3 enp0s3 enp0s6 wlan0 ens33 eno1; do
@@ -2912,7 +2914,7 @@ collect_config() {
29122914 # 1. Get the Local LAN IP (Explicit Check)
29132915 # This prevents crashing on IPv6-only servers
29142916 if ip -4 route get 8.8.8.8 > /dev/null 2>&1 ; then
2915- LOCAL_IP_V4=$( ip -4 route get 8.8.8.8 | head -1 | awk ' {print $7 }' )
2917+ LOCAL_IP_V4=$( ip -4 route get 8.8.8.8 | head -1 | awk -F ' src ' ' {print $2} ' | awk ' {print $1 }' )
29162918 else
29172919 LOCAL_IP_V4=" "
29182920 fi
@@ -3365,12 +3367,12 @@ show_connection_options() {
33653367
33663368 local TS_IP=" "
33673369 if command -v tailscale > /dev/null 2>&1 && tailscale ip > /dev/null 2>&1 ; then
3368- TS_IP=$( tailscale ip -4 2> /dev/null)
3370+ TS_IP=$( tailscale ip -4 2> /dev/null || true )
33693371 fi
33703372
33713373 local NB_IP=" "
33723374 if command -v netbird > /dev/null 2>&1 && netbird status 2> /dev/null | grep -q " Connected" ; then
3373- NB_IP=$( ip -4 addr show wt0 2> /dev/null | awk ' /inet / {print $2}' | cut -d/ -f1 | head -1)
3375+ NB_IP=$( ip -4 addr show wt0 2> /dev/null | awk ' /inet / {print $2}' | cut -d/ -f1 | head -1 || true )
33743376 fi
33753377
33763378 printf " \n"
@@ -3393,7 +3395,10 @@ show_connection_options() {
33933395 # show the detected local IP from route (Home VM scenario)
33943396 if [[ " $found_internal " == false && " $public_ip " == " Unknown" ]]; then
33953397 local fallback_ip
3396- fallback_ip=$( ip -4 route get 8.8.8.8 2> /dev/null | head -1 | awk ' {print $7}' )
3398+ fallback_ip=$( ip -4 route get 8.8.8.8 2> /dev/null | head -1 | awk -F' src ' ' {print $2}' | awk ' {print $1}' || true)
3399+ if [[ -z " $fallback_ip " ]]; then
3400+ fallback_ip=$( ip -6 route get 2001:4860:4860::8888 2> /dev/null | head -1 | awk -F' src ' ' {print $2}' | awk ' {print $1}' || true)
3401+ fi
33973402 if [[ -n " $fallback_ip " ]]; then
33983403 printf " %-20s ${CYAN} ssh -p %s %s@%s${NC} \n" " Local (LAN):" " $port " " $USERNAME " " $fallback_ip "
33993404 fi
@@ -4494,8 +4499,14 @@ SECURE_DNS_CONFIG
44944499 # Ensure the OS is actually pointing to systemd-resolved for DNS queries
44954500 if [[ ! -L /etc/resolv.conf ]] || [[ " $( readlink /etc/resolv.conf) " != " ../run/systemd/resolve/stub-resolv.conf" && " $( readlink /etc/resolv.conf) " != " /run/systemd/resolve/stub-resolv.conf" ]]; then
44964501 print_info " Symlinking /etc/resolv.conf to the secure stub resolver..."
4497- rm -f /etc/resolv.conf
4498- ln -s /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
4502+ # Attempt to unlock the file if it's protected (common on VPS providers)
4503+ chattr -i /etc/resolv.conf 2> /dev/null || true
4504+
4505+ if rm -f /etc/resolv.conf 2> /dev/null; then
4506+ ln -s /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf || true
4507+ else
4508+ print_warning " Could not modify /etc/resolv.conf (locked by provider). Secure DNS may not apply locally."
4509+ fi
44994510 fi
45004511
45014512 print_success " Secure DNS configured and activated."
0 commit comments