diff --git a/du_setup.sh b/du_setup.sh index d2f28f9..f210136 100644 --- a/du_setup.sh +++ b/du_setup.sh @@ -1,8 +1,10 @@ #!/bin/bash # Debian and Ubuntu Server Hardening Interactive Script -# Version: 0.73 | 2025-10-22 +# Version: 0.74 | 2025-11-06 # Changelog: +# - v0.74: Add optional dtop (https://github.com/amir20/dtop) after docker installation. +#. Update .bashrc # - v0.73: Revised/improved logic in .bashrc for memory and system updates. # - v0.72: Added configure_custom_bashrc() function that creates and installs a feature-rich .bashrc file during user creation. # - v0.71: Simplify test backup function to work reliably with Hetzner storagebox @@ -77,7 +79,7 @@ set -euo pipefail # --- Update Configuration --- -CURRENT_VERSION="0.73" +CURRENT_VERSION="0.74" SCRIPT_URL="https://raw.githubusercontent.com/buildplan/du_setup/refs/heads/main/du_setup.sh" CHECKSUM_URL="${SCRIPT_URL}.sha256" @@ -228,7 +230,7 @@ print_header() { 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}║ v0.73 | 2025-10-22 ║${NC}" + printf '%s\n' "${CYAN}║ v0.74 | 2025-11-06 ║${NC}" printf '%s\n' "${CYAN}║ ║${NC}" printf '%s\n' "${CYAN}╚═════════════════════════════════════════════════════════════════╝${NC}" printf '\n' @@ -1238,16 +1240,15 @@ __bash_prompt_command() { PROMPT_COMMAND=__bash_prompt_command # --- Editor Configuration --- -# Set default editor with fallback chain. if command -v vim &>/dev/null; then export EDITOR=vim export VISUAL=vim -elif command -v vi &>/dev/null; then - export EDITOR=vi - export VISUAL=vi -else +elif command -v nano &>/dev/null; then export EDITOR=nano export VISUAL=nano +else + export EDITOR=vi + export VISUAL=vi fi # --- Additional Environment Variables --- @@ -1265,7 +1266,7 @@ mkcd() { # Create a backup of a file with timestamp. backup() { if [ -f "$1" ]; then - local backup_file="$1.backup-$(date +%Y%m%d-%H%M%S)" + local backup_file; backup_file="$1.backup-$(date +%Y%m%d-%H%M%S)" cp "$1" "$backup_file" echo "Backup created: $backup_file" else @@ -1278,19 +1279,19 @@ backup() { extract() { if [ -f "$1" ]; then case "$1" in - *.tar.bz2) tar xjf "$1" ;; - *.tar.gz) tar xzf "$1" ;; - *.tar.xz) tar xJf "$1" ;; - *.bz2) bunzip2 "$1" ;; - *.rar) unrar x "$1" ;; - *.gz) gunzip "$1" ;; - *.tar) tar xf "$1" ;; - *.tbz2) tar xjf "$1" ;; - *.tgz) tar xzf "$1" ;; - *.zip) unzip "$1" ;; - *.Z) uncompress "$1" ;; - *.7z) 7z x "$1" ;; - *.deb) ar x "$1" ;; + *.tar.bz2) tar xjf "$1" ;; + *.tar.gz) tar xzf "$1" ;; + *.tar.xz) tar xJf "$1" ;; + *.bz2) bunzip2 "$1" ;; + *.rar) unrar x "$1" ;; + *.gz) gunzip "$1" ;; + *.tar) tar xf "$1" ;; + *.tbz2) tar xjf "$1" ;; + *.tgz) tar xzf "$1" ;; + *.zip) unzip "$1" ;; + *.Z) uncompress "$1" ;; + *.7z) 7z x "$1" ;; + *.deb) ar x "$1" ;; *.tar.zst) if command -v zstd &>/dev/null; then zstd -dc "$1" | tar xf - @@ -1300,7 +1301,7 @@ extract() { ;; *) echo "'$1' cannot be extracted via extract()" >&2 - return 1 + return 1 # Add return 1 for consistency ;; esac else @@ -1334,6 +1335,9 @@ ftext() { grep -rnw . -e "$1" 2>/dev/null } +# Search history easily +hgrep() { history | grep -i --color=auto "$@"; } + # Create a tarball of a directory. targz() { if [ -d "$1" ]; then @@ -1357,7 +1361,36 @@ sizeof() { # Show most used commands from history. histop() { - history | awk '{CMD[$2]++;count++;}END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | grep -v "./" | column -c3 -s " " -t | sort -nr | nl | head -n20 + history | awk -v ig="$HISTIGNORE" 'BEGIN{OFS="\t";gsub(/:/,"|",ig);ir="^("ig")($| )";sr="(^|\\s)\\./"} + {cmd=$4;for(i=5;i<=NF;i++)cmd=cmd" "$i} + (cmd==""||cmd~ir||cmd~sr){next} + {C[cmd]++;t++} + END{if(t>0)for(a in C)printf"%d\t%.2f%%\t%s\n",C[a],(C[a]/t*100),a}' | + sort -nr | head -n20 | + awk 'BEGIN{ + FS="\t"; + maxc=length("COUNT"); + maxp=length("PERCENT"); + } + { + data[NR]=$0; + len1=length($1); + len2=length($2); + if(len1>maxc)maxc=len1; + if(len2>maxp)maxp=len2; + } + END{ + fmt=" %-4s %-*s %-*s %s\n"; + printf fmt,"RANK",maxc,"COUNT",maxp,"PERCENT","COMMAND"; + sep_c=sep_p=""; + for(i=1;i<=maxc;i++)sep_c=sep_c"-"; + for(i=1;i<=maxp;i++)sep_p=sep_p"-"; + printf fmt,"----",maxc,sep_c,maxp,sep_p,"-------"; + for(i=1;i<=NR;i++){ + split(data[i],f,"\t"); + printf fmt,i".",maxc,f[1],maxp,f[2],f[3] + } + }' } # Quick server info display @@ -1392,18 +1425,45 @@ sysinfo() { cpu_info=$(lscpu | awk -F: '/Model name/ {print $2; exit}' | xargs || grep -m1 'model name' /proc/cpuinfo | cut -d ':' -f2 | xargs) [ -z "$cpu_info" ] && cpu_info="Unknown" - # --- IP Detection (preferred interfaces first) --- - local ip_addr - for iface in eth0 wlan0 ens33 eno1 enp0s3 enp3s0; do + # --- IP Detection --- + local ip_addr public_ipv4 public_ipv6 + + # Try to get public IPv4 first + public_ipv4=$(curl -4 -s -m 2 --connect-timeout 1 https://checkip.amazonaws.com 2>/dev/null || \ + curl -4 -s -m 2 --connect-timeout 1 https://ipconfig.io 2>/dev/null || \ + curl -4 -s -m 2 --connect-timeout 1 https://api.ipify.org 2>/dev/null) + # If no IPv4, try IPv6 + if [ -z "$public_ipv4" ]; then + public_ipv6=$(curl -6 -s -m 2 --connect-timeout 1 https://ipconfig.io 2>/dev/null || \ + curl -6 -s -m 2 --connect-timeout 1 https://icanhazip.co 2>/dev/null || \ + curl -6 -s -m 2 --connect-timeout 1 https://api64.ipify.org 2>/dev/null) + fi + # Get local/internal IP as fallback + for iface in eth0 ens3 enp0s3 enp0s6 wlan0 ens33 eno1; do ip_addr=$(ip -4 addr show "$iface" 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1) [ -n "$ip_addr" ] && break done - [ -z "$ip_addr" ] && ip_addr=$(ip -4 addr show scope global | awk '/inet/ {print $2}' | cut -d/ -f1 | head -n1) + [ -z "$ip_addr" ] && ip_addr=$(ip -4 addr show scope global 2>/dev/null | awk '/inet/ {print $2}' | cut -d/ -f1 | head -n1) # --- System Info --- - if [ -n "$ip_addr" ]; then + if [ -n "$public_ipv4" ]; then + # Show public IPv4 (preferred) + printf "${CYAN}%-15s${RESET} %s ${YELLOW}[%s]${RESET}" "Hostname:" "$(hostname)" "$public_ipv4" + # Show local IP if different from public + if [ -n "$ip_addr" ] && [ "$ip_addr" != "$public_ipv4" ]; then + printf " ${DIM}(local: %s)${RESET}\n" "$ip_addr" + else + printf "\n" + fi + elif [ -n "$public_ipv6" ]; then + # Show public IPv6 if no IPv4 + printf "${CYAN}%-15s${RESET} %s ${YELLOW}[%s]${RESET}" "Hostname:" "$(hostname)" "$public_ipv6" + [ -n "$ip_addr" ] && printf " ${DIM}(local: %s)${RESET}\n" "$ip_addr" || printf "\n" + elif [ -n "$ip_addr" ]; then + # Show local IP only printf "${CYAN}%-15s${RESET} %s ${YELLOW}[%s]${RESET}\n" "Hostname:" "$(hostname)" "$ip_addr" else + # No IP detected printf "${CYAN}%-15s${RESET} %s\n" "Hostname:" "$(hostname)" fi printf "${CYAN}%-15s${RESET} %s\n" "OS:" "$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d'"' -f2 || echo 'Unknown')" @@ -1424,7 +1484,7 @@ sysinfo() { if [ -f /var/run/reboot-required ]; then printf "${CYAN}%-15s${RESET} ${BOLD_RED}⚠ REBOOT REQUIRED${RESET}\n" "System:" [ -s /var/run/reboot-required.pkgs ] && \ - printf " ${DIM}Reason:${RESET} %s\n" "$(paste -sd ' ' /var/run/reboot-required.pkgs)" + printf " ${DIM}Reason:${RESET} %s\n" "$(paste -sd ' ' /var/run/reboot-required.pkgs)" fi # --- Available Updates (APT) --- @@ -1439,19 +1499,23 @@ sysinfo() { security="${apt_check_output##*;}" fi fi + # Fallback if apt-check didn't provide values if [ -z "$total" ] && [ -r /var/lib/update-notifier/updates-available ]; then total=$(awk '/[0-9]+ (update|package)s? can be (updated|applied|installed)/ {print $1; exit}' /var/lib/update-notifier/updates-available 2>/dev/null) security=$(awk '/[0-9]+ (update|package)s? .*security/ {print $1; exit}' /var/lib/update-notifier/updates-available 2>/dev/null) fi + # Final fallback if [ -z "$total" ]; then total=$(apt list --upgradable 2>/dev/null | grep -c upgradable) security=$(apt list --upgradable 2>/dev/null | grep -ci security) fi + total="${total:-0}" security="${security:-0}" + # Display updates if available if [ -n "$total" ] && [ "$total" -gt 0 ] 2>/dev/null; then printf "${CYAN}%-15s${RESET} " "Updates:" if [ -n "$security" ] && [ "$security" -gt 0 ] 2>/dev/null; then @@ -1466,11 +1530,11 @@ sysinfo() { security_list=$(printf "%s\n" "${upgradable_all[@]}" | grep -i security | head -n5 | awk -F/ '{print $1}') [ -n "$upgradable_list" ] && \ - printf " ${DIM}Upgradable:${RESET} %s" "$(echo "$upgradable_list" | paste -sd ', ')" + printf " ${DIM}Upgradable:${RESET} %s" "$(echo "$upgradable_list" | paste -sd ', ')" [ "$total" -gt 5 ] && printf " ... (+%s more)\n" $((total - 5)) || printf "\n" [ -n "$security_list" ] && \ - printf " ${YELLOW}Security:${RESET} %s" "$(echo "$security_list" | paste -sd ', ')" + printf " ${YELLOW}Security:${RESET} %s" "$(echo "$security_list" | paste -sd ', ')" [ "$security" -gt 5 ] && printf " ... (+%s more)\n" $((security - 5)) || printf "\n" fi fi @@ -1485,6 +1549,28 @@ sysinfo() { fi fi + # --- Tailscale Info (if installed and connected) --- + if command -v tailscale &>/dev/null; then + local ts_ipv4 ts_ipv6 ts_hostname + # Get Tailscale IPs + ts_ipv4=$(tailscale ip -4 2>/dev/null) + ts_ipv6=$(tailscale ip -6 2>/dev/null) + # Only show if connected + if [ -n "$ts_ipv4" ] || [ -n "$ts_ipv6" ]; then + # Get hostname from status (FIXED: use head -n1 to get only first line) + ts_hostname=$(tailscale status --self --peers=false 2>/dev/null | head -n1 | awk '{print $2}') + printf "${CYAN}%-15s${RESET} " "Tailscale:" + printf "${GREEN}Connected${RESET}" + [ -n "$ts_ipv4" ] && printf " - %s" "$ts_ipv4" + [ -n "$ts_hostname" ] && printf " ${DIM}(%s)${RESET}" "$ts_hostname" + printf "\n" + # Optional: Show IPv6 on second line if available + if [ -n "$ts_ipv6" ]; then + printf " ${DIM}IPv6: %s${RESET}\n" "$ts_ipv6" + fi + fi + fi + printf "\n" } @@ -1501,6 +1587,47 @@ checkupdates() { fi } +# Disk space alert (warns if any partition > 80%) +diskcheck() { + df -h | awk ' + NR > 1 { + usage = $5 + gsub(/%/, "", usage) + if (usage > 80) { + printf "⚠️ %s\n", $0 + found = 1 + } + } + END { + if (!found) print "✓ All disks below 80%" + } + ' +} + +# Directory bookmarks +export MARKPATH=$HOME/.marks +[ -d "$MARKPATH" ] || mkdir -p "$MARKPATH" +mark() { ln -sfn "$(pwd)" "$MARKPATH/${1:-$(basename "$PWD")}"; } +jump() { cd -P "$MARKPATH/$1" 2>/dev/null || ls -l "$MARKPATH"; } + +# Service status shortcut (cleaner output) +svc() { sudo systemctl status "$1" --no-pager -l | head -20; } +alias failed='systemctl --failed --no-pager' + +# Show top 10 processes by CPU +topcpu() { ps aux --sort=-%cpu | head -11; } + +# Show top 10 processes by memory +topmem() { ps aux --sort=-%mem | head -11; } + +# Network connections summary +netsum() { + echo "=== Active Connections ===" + ss -s + echo -e "\n=== Listening Ports ===" + sudo ss -tulnp | grep LISTEN | awk '{print $5, $7}' | sort -u +} + # --- Aliases --- # Enable color support for common commands. if [ -x /usr/bin/dircolors ]; then @@ -1519,9 +1646,12 @@ fi alias ll='ls -alFh' alias la='ls -A' alias l='ls -CF' -alias lt='ls -alFht' # Sort by modification time, newest first -alias ltr='ls -alFhtr' # Sort by modification time, oldest first -alias lS='ls -alFhS' # Sort by size, largest first +alias lt='ls -alFht' # Sort by modification time, newest first +alias ltr='ls -alFhtr' # Sort by modification time, oldest first +alias lS='ls -alFhS' # Sort by size, largest first + +# Last command with sudo +alias please='sudo $(history -p !!)' # Safety aliases to prompt before overwriting. alias rm='rm -i' @@ -1534,7 +1664,7 @@ alias ..='cd ..' alias ...='cd ../..' alias ....='cd ../../..' alias .....='cd ../../../..' -alias -- -='cd -' # Go to previous directory +alias -- -='cd -' # Go to previous directory alias ~='cd ~' alias h='history' alias c='clear' @@ -1582,6 +1712,7 @@ alias myip='curl -s ifconfig.me || curl -s icanhazip.com' # Alternatives: api.ip localip() { ip -4 addr | awk '/inet/ {print $2}' | cut -d/ -f1 | grep -v '127.0.0.1' } + alias netstat='ss' alias ping='ping -c 5' alias fastping='ping -c 100 -i 0.2' @@ -1635,12 +1766,14 @@ if command -v docker &>/dev/null; then # Docker stats alias dstats='docker stats --no-stream' alias dstatsa='docker stats' - dtop() { + dst() { docker stats --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}' } # Safe stop all (shows command instead of executing) - alias dstopall='echo "To stop all containers, run: docker stop \$(docker ps -q)"' + alias dstopa='echo "To stop all containers, run: docker stop \$(docker ps -q)"' + # Start all stopped containers + alias dstarta='docker start $(docker ps -aq)' # Docker Compose v2 aliases (check if the compose plugin exists) if docker compose version &>/dev/null; then @@ -1816,11 +1949,11 @@ fi # Enable programmable completion features. if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then - # shellcheck disable=SC1091 - . /usr/share/bash-completion/bash_completion + # shellcheck disable=SC1091 + . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then - # shellcheck disable=SC1091 - . /etc/bash_completion + # shellcheck disable=SC1091 + . /etc/bash_completion fi fi @@ -1861,7 +1994,7 @@ bashhelp() { cat << 'HELPTEXT' ╔════════════════════════════════════════════════════════╗ -║ .bashrc - Quick Reference ║ +║ .bashrc - Quick Reference ║ ╚════════════════════════════════════════════════════════╝ Usage: bashhelp [category] @@ -1870,179 +2003,194 @@ Categories: navigation, files, system, docker, git, network ═══════════════════════════════════════════════════════════════════ 📁 NAVIGATION & DIRECTORY ═══════════════════════════════════════════════════════════════════ - .. Go up one directory - ... Go up two directories - .... Go up three directories - ..... Go up four directories - - Go to previous directory - ~ Go to home directory + .. Go up one directory + ... Go up two directories + .... Go up three directories + ..... Go up four directories + - Go to previous directory + ~ Go to home directory - mkcd Create directory and cd into it - up Go up N directories (e.g., up 3) - path Display PATH variable (one per line) + mkcd Create directory and cd into it + up Go up N directories (e.g., up 3) + path Display PATH variable (one per line) + mark Bookmark current directory + jump Jump to a bookmarked directory ═══════════════════════════════════════════════════════════════════ 📄 FILE OPERATIONS ═══════════════════════════════════════════════════════════════════ - ll List all files with details (human-readable) - la List all files including hidden - l List files in column format - lt List by time, newest first - ltr List by time, oldest first - lS List by size, largest first - lsd List only directories - lsf List only files + ll List all files with details (human-readable) + la List all files including hidden + l List files in column format + lt List by time, newest first + ltr List by time, oldest first + lS List by size, largest first + lsd List only directories + lsf List only files - ff Find files by name (case-insensitive) - fd Find directories by name (case-insensitive) - ftext Search for text in files recursively + ff Find files by name (case-insensitive) + fd Find directories by name (case-insensitive) + ftext Search for text in files recursively - extract Extract any archive (tar, zip, 7z, etc.) - targz Create tar.gz of directory - backup Create timestamped backup of file + extract Extract any archive (tar, zip, 7z, etc.) + targz Create tar.gz of directory + backup Create timestamped backup of file - sizeof Get size of file or directory - duh [path] Disk usage sorted by size - count Count files in current directory - cpv Copy with progress bar (rsync) + sizeof Get size of file or directory + duh [path] Disk usage sorted by size + count Count files in current directory + cpv Copy with progress bar (rsync) ═══════════════════════════════════════════════════════════════════ 💻 SYSTEM & MONITORING ═══════════════════════════════════════════════════════════════════ - sysinfo Display comprehensive system information - checkupdates Check for available system updates + sysinfo Display comprehensive system information + checkupdates Check for available system updates + diskcheck Check for disk partitions over 80% - psgrep Search for process by name - psmem Show top 10 processes by memory usage - pscpu Show top 10 processes by CPU usage - top10 Show top 10 memory-consuming processes + psgrep Search for process by name + topcpu Show top 10 processes by CPU + topmem Show top 10 processes by Memory + pscpu Show top 10 processes by CPU (tree view) + psmem Show top 10 processes by Memory (tree view) - ports Show all listening ports (TCP/UDP) - listening Show listening ports with process info - meminfo Display detailed memory information + ports Show all listening ports (TCP/UDP) + listening Show listening ports with process info + meminfo Display detailed memory information - h Show command history - histop Show most used commands - reload Reload bashrc configuration + h Show command history + hgrep Search command history + histop Show most used commands + c, cls Clear the screen + reload Reload bashrc configuration ═══════════════════════════════════════════════════════════════════ 🐳 DOCKER & DOCKER COMPOSE ═══════════════════════════════════════════════════════════════════ Docker Commands: - d docker (shortcut) - dps List running containers - dpsa List all containers - di List images - dv List volumes - dn List networks - dex Execute interactive shell in container - dlog Follow container logs + d docker (shortcut) + dps List running containers + dpsa List all containers + di List images + dv List volumes + dn List networks + dex Execute interactive shell in container + dlog Follow container logs - dsh Enter container shell (bash/sh) - dip [id] Show container IP addresses - dsize Show disk usage by containers - dbinds [id] Show bind mounts for containers - denv Show environment variables - dfollow Follow logs with tail (default 100 lines) + dsh Enter container shell (bash/sh) + dip [id] Show container IP addresses + dsize Show disk usage by containers + dbinds [id] Show bind mounts for containers + denv Show environment variables + dfollow Follow logs with tail (default 100 lines) - dstats Container stats snapshot - dstatsa Container stats live - dtop Container stats formatted table + dstats Container stats snapshot + dstatsa Container stats live + dst Container stats formatted table - dprune Prune system (remove unused data) - dprunea Prune all (including images) - dvprune Prune unused volumes - diprune Prune unused images - drmall Remove all stopped containers + dprune Prune system (remove unused data) + dprunea Prune all (including images) + dvprune Prune unused volumes + diprune Prune unused images + drmall Remove all stopped containers Docker Compose: - dc docker compose (shortcut) - dcup Start services in background - dcdown Stop and remove services - dclogs Follow compose logs - dcps List compose services - dcex Execute command in service - dcsh Enter service shell (bash/sh) + dc docker compose (shortcut) + dcup Start services in background + dcdown Stop and remove services + dclogs Follow compose logs + dcps List compose services + dcex Execute command in service + dcsh Enter service shell (bash/sh) - dcbuild Build services - dcbn Build with no cache - dcrestart Restart services - dcrecreate Recreate services - dcpull Pull service images - dcstop Stop services - dcstart Start services + dcbuild Build services + dcbn Build with no cache + dcrestart Restart services + dcrecreate Recreate services + dcpull Pull service images + dcstop Stop services + dcstart Start services - dcstatus Show service status & resource usage - dcreload Restart service and follow logs - dcupdate Pull, restart service, follow logs + dcstatus Show service status & resource usage + dcreload Restart service and follow logs + dcupdate Pull, restart service, follow logs dcgrep Filter service logs - dcconfig Show resolved compose configuration - dcvalidate Validate compose file syntax + dcconfig Show resolved compose configuration + dcvalidate Validate compose file syntax ═══════════════════════════════════════════════════════════════════ 🔀 GIT SHORTCUTS ═══════════════════════════════════════════════════════════════════ - gs git status - ga git add - gc git commit - gp git push - gl git log (graph view) - gd git diff - gb git branch - gco git checkout + gs git status + ga git add + gc git commit + gp git push + gl git log (graph view) + gd git diff + gb git branch + gco git checkout ═══════════════════════════════════════════════════════════════════ 🌐 NETWORK ═══════════════════════════════════════════════════════════════════ - myip Show external IP address - localip Show local IP address(es) - ping Ping with 5 packets (default) - fastping Fast ping (100 packets, 0.2s interval) - netstat Show network connections (ss) + myip Show external IP address + localip Show local IP address(es) + netsum Network connections summary + kssh SSH wrapper for kitty terminal + ping Ping with 5 packets (default) + fastping Fast ping (100 packets, 0.2s interval) + netstat Show network connections (ss) ═══════════════════════════════════════════════════════════════════ ⚙️ SYSTEM ADMINISTRATION ═══════════════════════════════════════════════════════════════════ Systemd: - sysstart Start service - sysstop Stop service - sysrestart Restart service - sysstatus Show service status - sysenable Enable service - sysdisable Disable service - sysreload Reload systemd daemon + svc Show service status (brief) + failed List failed systemd services + sysstart Start service + sysstop Stop service + sysrestart Restart service + sysstatus Show service status + sysenable Enable service + sysdisable Disable service + sysreload Reload systemd daemon APT (Debian/Ubuntu): - aptup Update and upgrade packages - aptin Install package - aptrm Remove package - aptsearch Search for packages - aptshow Show package information - aptclean Remove unused packages - aptlist List installed packages + aptup Update and upgrade packages + aptin Install package + aptrm Remove package + aptsearch Search for packages + aptshow Show package information + aptclean Remove unused packages + aptlist List installed packages + +Sudo: + please Run last command with sudo ═══════════════════════════════════════════════════════════════════ 🕒 DATE & TIME ═══════════════════════════════════════════════════════════════════ - now Current date and time (YYYY-MM-DD HH:MM:SS) - nowdate Current date (YYYY-MM-DD) - timestamp Unix timestamp + now Current date and time (YYYY-MM-DD HH:MM:SS) + nowdate Current date (YYYY-MM-DD) + timestamp Unix timestamp ═══════════════════════════════════════════════════════════════════ ℹ️ HELP & INFORMATION ═══════════════════════════════════════════════════════════════════ - bashhelp Show this help (all categories) + bashhelp Show this help (all categories) + bh Alias for bashhelp + commands List all custom functions and aliases bashhelp navigation Show navigation commands only - bashhelp files Show file operation commands - bashhelp system Show system monitoring commands - bashhelp docker Show docker commands only - bashhelp git Show git shortcuts - bashhelp network Show network commands + bashhelp files Show file operation commands + bashhelp system Show system monitoring commands + bashhelp docker Show docker commands only + bashhelp git Show git shortcuts + bashhelp network Show network commands ═══════════════════════════════════════════════════════════════════ 💡 TIP: Most commands support --help or -h for more information - The prompt shows: ✗ for failed commands, git branch when in repo + The prompt shows: ✗ for failed commands, (git branch) when in repo HELPTEXT ;; @@ -2052,21 +2200,24 @@ HELPTEXT ═══ NAVIGATION & DIRECTORY COMMANDS ═══ - .. Go up one directory - ... Go up two directories - .... Go up three directories - ..... Go up four directories - - Go to previous directory - ~ Go to home directory + .. Go up one directory + ... Go up two directories + .... Go up three directories + ..... Go up four directories + - Go to previous directory + ~ Go to home directory - mkcd Create directory and cd into it - up Go up N directories - path Display PATH variable + mkcd Create directory and cd into it + up Go up N directories + path Display PATH variable + mark Bookmark current directory + jump Jump to a bookmarked directory Examples: - mkcd ~/projects/newapp # Create and enter directory - up 3 # Go up 3 levels - cd - # Return to previous directory + mkcd ~/projects/newapp # Create and enter directory + up 3 # Go up 3 levels + mark proj1 # Bookmark current dir as 'proj1' + jump proj1 # Jump back to 'proj1' HELPTEXT ;; @@ -2080,23 +2231,23 @@ Listing: ll, la, l, lt, ltr, lS, lsd, lsf Finding: - ff Find files by name - fd Find directories by name - ftext Search text in files + ff Find files by name + fd Find directories by name + ftext Search text in files Archives: - extract Extract any archive type - targz Create tar.gz archive - backup Create timestamped backup + extract Extract any archive type + targz Create tar.gz archive + backup Create timestamped backup Size Info: - sizeof Get size of file/directory - duh [path] Disk usage sorted by size - count Count files in directory - cpv Copy with progress (rsync) + sizeof Get size of file/directory + duh [path] Disk usage sorted by size + count Count files in directory + cpv Copy with progress (rsync) Examples: - ff README # Find files named *README* + ff README # Find files named *README* extract data.tar.gz backup ~/.bashrc @@ -2109,27 +2260,31 @@ HELPTEXT ═══ SYSTEM MONITORING COMMANDS ═══ Overview: - sysinfo Comprehensive system info - checkupdates Check for package updates + sysinfo Comprehensive system info + checkupdates Check for package updates + diskcheck Check for disks > 80% Processes: - psgrep Search processes - psmem Top 10 by memory - pscpu Top 10 by CPU - top10 Top memory consumers + psgrep Search processes + topcpu Top 10 by CPU + topmem Top 10 by Memory + pscpu Top 10 by CPU (tree view) + psmem Top 10 by Memory (tree view) Network: - ports Listening ports - listening Ports with process info + ports Listening ports + listening Ports with process info Memory: - meminfo Detailed memory info - free Free memory (human-readable) + meminfo Detailed memory info + free Free memory (human-readable) -History: - h Show history - histop Most used commands - reload Reload bashrc +Shell: + h Show history + hgrep Search history + histop Most used commands + c, cls Clear screen + reload Reload bashrc Examples: psgrep nginx @@ -2147,26 +2302,26 @@ Basic: dps, dpsa, di, dv, dn, dex, dlog Management: - dsh Enter container shell - dip [id] Show IP addresses - dsize Show disk usage - dbinds [id] Show bind mounts - denv Show environment variables - dfollow Follow logs + dsh Enter container shell + dip [id] Show IP addresses + dsize Show disk usage + dbinds [id] Show bind mounts + denv Show environment variables + dfollow Follow logs Stats & Cleanup: - dstats, dstatsa, dtop + dstats, dstatsa, dst dprune, dprunea, dvprune, diprune - drmall Remove stopped containers + drmall Remove stopped containers Docker Compose: dcup, dcdown, dclogs, dcps, dcex, dcsh dcbuild, dcrestart, dcrecreate - dcstatus Status & resource usage - dcreload Restart & follow logs - dcupdate Pull & update service - dcgrep

Filter logs - dcvalidate Validate compose file + dcstatus Status & resource usage + dcreload Restart & follow logs + dcupdate Pull & update service + dcgrep

Filter logs + dcvalidate Validate compose file Examples: dsh mycontainer @@ -2182,20 +2337,20 @@ HELPTEXT ═══ GIT SHORTCUTS ═══ - gs git status - ga git add - gc git commit - gp git push - gl git log (graph) - gd git diff - gb git branch - gco git checkout + gs git status + ga git add + gc git commit + gp git push + gl git log (graph) + gd git diff + gb git branch + gco git checkout Examples: - gs # Check status - ga . # Add all changes - gc -m "Update docs" # Commit - gp # Push to remote + gs # Check status + ga . # Add all changes + gc -m "Update docs" # Commit + gp # Push to remote HELPTEXT ;; @@ -2205,16 +2360,18 @@ HELPTEXT ═══ NETWORK COMMANDS ═══ - myip Show external IP - localip Show local IP(s) - ports Show listening ports - listening Ports with process info - ping Ping (5 packets) - fastping Fast ping (100 packets) - netstat Network connections + myip Show external IP + localip Show local IP(s) + netsum Network connection summary + kssh SSH wrapper for kitty + ports Show listening ports + listening Ports with process info + ping Ping (5 packets) + fastping Fast ping (100 packets) + netstat Network connections (ss) Examples: - myip # Get public IP + myip # Get public IP listening | grep 80 ping google.com @@ -2231,6 +2388,7 @@ HELPTEXT } # Preserve Bash's builtin `help` while integrating bashhelp +# This wrapper routes custom help to bashhelp, bash builtins to builtin help help() { case "${1:-}" in ""|all|navigation|files|system|docker|git|network) @@ -3680,6 +3838,68 @@ EOF fi print_warning "NOTE: '$USERNAME' must log out and back in to use Docker without sudo." log "Docker installation completed." + # Offer dtop installation + install_dtop_optional +} + +install_dtop_optional() { + if sudo sh -c 'command -v dtop' >/dev/null 2>&1 || command -v dtop >/dev/null 2>&1; then + print_info "dtop is already installed." + return 0 + fi + if ! confirm "Install 'dtop' (Docker container monitoring TUI)?"; then + print_info "Skipping dtop installation." + return 0 + fi + print_info "Installing dtop for user '$USERNAME'..." + local DTOP_INSTALLER="/tmp/dtop-installer.sh" + if ! curl -fsSL "https://github.com/amir20/dtop/releases/latest/download/dtop-installer.sh" -o "$DTOP_INSTALLER"; then + print_warning "Failed to download dtop installer. Continuing setup..." + log "Failed to download dtop installer." + return 0 + fi + chmod +x "$DTOP_INSTALLER" + trap 'rm -f "$DTOP_INSTALLER"' RETURN + local USER_HOME + USER_HOME=$(getent passwd "$USERNAME" | cut -d: -f6) + local USER_LOCAL_BIN="$USER_HOME/.local/bin" + if [[ ! -d "$USER_LOCAL_BIN" ]]; then + print_info "Creating $USER_LOCAL_BIN..." + if ! sudo -u "$USERNAME" mkdir -p "$USER_LOCAL_BIN"; then + print_warning "Failed to create $USER_LOCAL_BIN. Skipping dtop." + return 0 + fi + fi + if sudo -u "$USERNAME" bash "$DTOP_INSTALLER" < /dev/null >> "$LOG_FILE" 2>&1; then + # Verify installation + if [[ -f "$USER_LOCAL_BIN/dtop" ]]; then + sudo -u "$USERNAME" chmod +x "$USER_LOCAL_BIN/dtop" + local BASHRC="$USER_HOME/.bashrc" + if [[ -f "$BASHRC" ]] && ! grep -q "\.local/bin" "$BASHRC"; then + print_info "Adding ~/.local/bin to PATH in $BASHRC..." + { + echo '' + echo '# Add local bin to PATH' + # shellcheck disable=SC2016 + echo 'if [ -d "$HOME/.local/bin" ]; then PATH="$HOME/.local/bin:$PATH"; fi' + } >> "$BASHRC" + chown "$USERNAME:$USERNAME" "$BASHRC" + if grep -q "\.local/bin" "$BASHRC"; then + print_info "PATH configuration updated successfully." + else + print_warning "Failed to update PATH, but dtop is still installed." + fi + fi + print_success "dtop installed successfully to $USER_LOCAL_BIN." + log "dtop installed to $USER_LOCAL_BIN for user $USERNAME" + else + print_warning "dtop installer finished, but binary not found at $USER_LOCAL_BIN/dtop" + log "dtop binary missing after user installation attempt." + fi + else + print_warning "dtop installation script failed. Continuing setup..." + log "dtop installation script failed." + fi } install_tailscale() {