Skip to content

Instantly share code, notes, and snippets.

@arjenzhou
Last active March 25, 2026 03:07
Show Gist options
  • Select an option

  • Save arjenzhou/beec5a72453f7ca0bc3553f1302dadf9 to your computer and use it in GitHub Desktop.

Select an option

Save arjenzhou/beec5a72453f7ca0bc3553f1302dadf9 to your computer and use it in GitHub Desktop.
setup_debian.sh

πŸš€ Debian Node Initializer

bash -c "$(curl -sSL https://gist.githubusercontent.com/arjenzhou/beec5a72453f7ca0bc3553f1302dadf9/raw/setup_debian.sh)"
#!/bin/bash
# ================= CONFIGURATION =================
VERSION="V6.7-2026.03.23"
USER_NAME="arjenzhou"
GIT_USER_NAME="arjenzhou"
GIT_USER_EMAIL="github@arjenzhou.com"
MAC_PUBLIC_KEY="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCxvvxGGZmqH+L/aV3ppsCzYVKqBKtlxl11k/guc+l7zziL+0Hn9sBO2gLOfr3YvMwwJYAwwr1pj1SrqaBVJyu9tXrC2AH8k52WeXn1AtJpWTBV5ZO4CtER9jbaelB21Axf5dWvWgbFRVaw3k2FZc2gpKTeJlvHLH+tMh+jZG9ten18W1FdAKES9SIaIU+DEx5nKC58iov3Qa7bDCI6PjqHIr0xDuoVuIoRNBSzXGWAKl/LpMmh9wh/G9ntgxIAdw0M7oJB6eVRct6CMJRkAQU2a1AGfMwWD/ccL60fzoaYyP1qC8KmE5B9vCsXvS5KaRX0o8/FprJ/s9rvX2QLR9MOBqzt7U5tHHhm1YnZfJ6CrTIa5bA5G7lobRL97vTclwURBwHd/88DtyvsIZDeMBrPy6+28+woRd5iIUaYNLj1FUtJeKc56uOY2fkQU2jpz063pDL9KclXUTR8C2kcuUmBU+ZG8/qAdn9uHMLozmJLrC0BHrf7FdDNXzsPXIUs/Sc= arjenzhou@localhost"
CLUSTER_KEY_NAME="id_ed25519_debian_cluster"
# =================================================
# 0. Header & Permissions Check
echo "--- [ πŸš€ Pro Node $VERSION Full Master ] ---"
if [ "$EUID" -ne 0 ]; then
echo "❌ Error: Please run as root (sudo bash setup_debian.sh)"
exit 1
fi
# 1. SSH Private Key Injection
echo "--- 1. SSH Private Key Injection ---"
echo "Please paste your cluster private key, then press [Enter] and [Ctrl + D]."
if [ ! -t 0 ]; then
CLUSTER_PRIVATE_KEY=$(cat < /dev/tty)
else
CLUSTER_PRIVATE_KEY=$(cat)
fi
echo "--- 2. System Update & Base APT Tools ---"
export DEBIAN_FRONTEND=noninteractive
echo "iperf3 iperf3/start_daemon boolean false" | debconf-set-selections
# Anti-conflict Patch: Temporarily block service actions to prevent iperf3 install errors
echo -e '#!/bin/sh\nexit 101' > /usr/sbin/policy-rc.d
chmod +x /usr/sbin/policy-rc.d
apt update && apt upgrade -y
apt install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" \
vim tmux curl git sudo wget openssh-server qemu-guest-agent \
htop btop iperf3 zoxide build-essential libssl-dev zlib1g-dev \
duf ncdu net-tools sudo
# Restore service action permissions
rm -f /usr/sbin/policy-rc.d
# System-wide Starship prompt
command -v starship >/dev/null || curl -sS https://starship.rs/install.sh | sh -s -- -y
echo "--- 3. User & Cluster-Aware Configuration ---"
# Set unique hostname based on IP (e.g., 192.168.6.15 -> node-15)
IP_SUFFIX=$(hostname -I | awk '{print $1}' | cut -d. -f4)
NEW_HOSTNAME="node-$IP_SUFFIX"
hostnamectl set-hostname "$NEW_HOSTNAME"
sed -i "s/127.0.1.1.*/127.0.1.1 $NEW_HOSTNAME/g" /etc/hosts
# Create the user if they do not exist
if ! id "$USER_NAME" &>/dev/null; then
echo "User '$USER_NAME' not found. Creating user..."
adduser --disabled-password --gecos "" "$USER_NAME"
else
echo "User '$USER_NAME' already exists."
fi
# Grant sudo privileges if not already configured
# This checks for the specific sudoers.d file to prevent duplicates
SUDO_FILE="/etc/sudoers.d/$USER_NAME"
if [ ! -f "$SUDO_FILE" ]; then
echo "Granting sudo privileges to '$USER_NAME'..."
echo "$USER_NAME ALL=(ALL) NOPASSWD:ALL" > "$SUDO_FILE"
chmod 0440 "$SUDO_FILE"
else
echo "User '$USER_NAME' already has sudo privileges configured."
fi
USER_HOME="/home/$USER_NAME"
mkdir -p "$USER_HOME/.ssh"
echo "$MAC_PUBLIC_KEY" > "$USER_HOME/.ssh/authorized_keys"
if [ -n "$CLUSTER_PRIVATE_KEY" ]; then
CLUSTER_KEY_PATH="$USER_HOME/.ssh/$CLUSTER_KEY_NAME"
echo "$CLUSTER_PRIVATE_KEY" > "$CLUSTER_KEY_PATH"
chmod 600 "$CLUSTER_KEY_PATH"
# Cluster Trust: Derive public key and authorize it for intra-cluster SSH
CLUSTER_PUB=$(ssh-keygen -y -f "$CLUSTER_KEY_PATH")
grep -q "$CLUSTER_PUB" "$USER_HOME/.ssh/authorized_keys" || echo "$CLUSTER_PUB" >> "$USER_HOME/.ssh/authorized_keys"
# Configure global SSH config for all hosts
if ! grep -q "$CLUSTER_KEY_NAME" /etc/ssh/ssh_config; then
cat >> /etc/ssh/ssh_config <<EOF
# Universal SSH Identity
Host *
IdentityFile ~/.ssh/$CLUSTER_KEY_NAME
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
EOF
fi
fi
chown -R "$USER_NAME:$USER_NAME" "$USER_HOME/.ssh"
chmod 700 "$USER_HOME/.ssh"
# Hardening: Key-based login only
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/g' /etc/ssh/sshd_config
systemctl restart ssh 2>/dev/null || true
echo "--- 4. UI & XDG Development Environment ---"
sudo -u "$USER_NAME" -i bash -s "$GIT_USER_NAME" "$GIT_USER_EMAIL" <<'EOF'
G_NAME="$1"
G_EMAIL="$2"
# Ensure .bashrc exists to avoid grep error
touch ~/.bashrc
# Enforce XDG Base Directory Specification
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_DATA_HOME="$HOME/.local/share"
mkdir -p "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$HOME/.local/bin"
# Git Global Configuration
git config --global user.name "$G_NAME"
git config --global user.email "$G_EMAIL"
git config --global core.quotepath false
# Install Mise
if [ ! -f "$HOME/.local/bin/mise" ]; then
curl https://mise.jdx.dev/install.sh | sh
fi
export PATH="$HOME/.local/bin:$PATH"
eval "$(mise activate bash)"
# Provision tools via Mise (XDG Compliant)
echo "Provisioning tools via Mise..."
mise use --global python@latest node@lts eza@latest gping@latest bat@latest fzf@latest uv@latest
eval "$(mise activate bash)"
# NPM XDG hygiene
npm config set prefix "$HOME/.local"
export PATH="$HOME/.local/bin:$PATH"
# Install tldr
echo "Installing tldr..."
npm install -g tldr --loglevel=error
# Starship Layout (XDG Location)
cat > "$XDG_CONFIG_HOME/starship.toml" <<'STARSHIP_CONF'
format = """
[$username](bold blue)\
${custom.address}\
$directory\
$git_branch\
$git_status\
$python\
$nodejs\
$fill\
$cmd_duration $line_break\
$character"""
[custom.address]
command = "hostname -I | awk '{print $1}'"
when = "true"
shell = ["bash", "--noprofile", "--norc"]
format = "[πŸ”— $output](bold yellow) "
[fill]
symbol = " "
STARSHIP_CONF
# Idempotent Bashrc Injection
if ! grep -q "Custom Config START" ~/.bashrc; then
cat >> ~/.bashrc <<'BASHRC_BLOCK'
# >>> Custom Config START >>>
# 1. XDG Base Directory Support
export XDG_CONFIG_HOME="$HOME/.config"
export XDG_DATA_HOME="$HOME/.local/share"
# 2. Path Configuration
export PATH="$HOME/.local/bin:$PATH"
# 3. Tool Initialization
[ -f "$HOME/.local/bin/mise" ] && eval "$($HOME/.local/bin/mise activate bash)"
command -v zoxide >/dev/null && eval "$(zoxide init bash)"
command -v starship >/dev/null && eval "$(starship init bash)"
command -v fzf >/dev/null && eval "$(fzf --bash)"
# 4. Productivity Aliases
command -v eza >/dev/null && alias ls='eza --icons'
command -v eza >/dev/null && alias ll='eza -lh --icons'
command -v eza >/dev/null && alias l='eza -1 --icons'
command -v btop >/dev/null && alias top='btop'
command -v duf >/dev/null && alias df='duf'
command -v bat >/dev/null && alias cat='bat --paging=never'
command -v uv >/dev/null && alias venv='uv venv'
command -v uv >/dev/null && alias pip='uv pip'
# 5. Pure Dynamic Quick Jump Function
s() {
if [ -z "$1" ]; then
echo "Usage: s <ip_suffix> (e.g., s 13)"
return 1
fi
# 1. Get current username
local CURRENT_USER=$(whoami)
# 2. Extract subnet prefix dynamically
# Use 'hostname -I' and pick the first non-loopback IP
local PRIMARY_IP=$(hostname -I | awk '{print $1}')
if [ -z "$PRIMARY_IP" ]; then
echo "❌ Error: Could not detect a valid internal IP address."
return 1
fi
local SUBNET=$(echo "$PRIMARY_IP" | cut -d. -f1-3)
echo "πŸ”— Jumping to ${SUBNET}.$1 as $CURRENT_USER..."
# 3. Execute SSH
ssh "${CURRENT_USER}@${SUBNET}.$1"
}
# <<< Custom Config END <<<
BASHRC_BLOCK
fi
EOF
echo "--- 5. Cleanup ---"
apt autoremove -y && apt clean
history -c
echo ""
echo "--- [ βœ… $NEW_HOSTNAME Setup Complete ] ---"
echo "πŸ’‘ User: $USER_NAME"
echo "πŸ’‘ SSH Auth: Key-based only"
exec su - "$USER_NAME"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment