#!/usr/bin/env bash set -euo pipefail RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' info() { echo -e "${GREEN}[+]${NC} $*"; } warn() { echo -e "${YELLOW}[!]${NC} $*"; } die() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } header() { echo -e "\n${CYAN}══════════════════════════════════════════${NC}"; echo -e "${CYAN} $*${NC}"; echo -e "${CYAN}══════════════════════════════════════════${NC}"; } [ "$(id -u)" -eq 0 ] || die "Run as root" header "TinyBoard Hub Setup" read -rp "Hub username [armbian]: " HUB_USER HUB_USER="${HUB_USER:-armbian}" header "Detecting Package Manager" if command -v apt-get >/dev/null 2>&1; then PKG_MANAGER="apt" PKG_INSTALL="apt-get install -y -q" OPENSSH_PKG="openssh-server" FUSE_PKG="fuse" info "Detected: apt (Debian/Ubuntu)" apt-get update -q elif command -v dnf >/dev/null 2>&1; then PKG_MANAGER="dnf" PKG_INSTALL="dnf install -y -q" OPENSSH_PKG="openssh-server" FUSE_PKG="fuse" info "Detected: dnf (Fedora/RHEL/Alma/Rocky)" dnf check-update -q || true elif command -v yum >/dev/null 2>&1; then PKG_MANAGER="yum" PKG_INSTALL="yum install -y -q" OPENSSH_PKG="openssh-server" FUSE_PKG="fuse" info "Detected: yum (older RHEL/CentOS)" yum check-update -q || true elif command -v pacman >/dev/null 2>&1; then PKG_MANAGER="pacman" PKG_INSTALL="pacman -S --noconfirm --quiet" OPENSSH_PKG="openssh" FUSE_PKG="fuse3" info "Detected: pacman (Arch)" pacman -Sy --quiet else die "No supported package manager found (apt, dnf, yum, pacman)" fi header "Installing Packages" info "Installing curl if missing..." if ! command -v curl >/dev/null 2>&1; then $PKG_INSTALL curl fi $PKG_INSTALL "$OPENSSH_PKG" "$FUSE_PKG" git if ! command -v rclone >/dev/null 2>&1; then info "Installing rclone..." if [ "$PKG_MANAGER" = "pacman" ]; then $PKG_INSTALL rclone else curl -fsSL https://rclone.org/install.sh | bash fi else warn "rclone already installed, skipping." fi header "Armbian User Setup" if id "$HUB_USER" >/dev/null 2>&1; then warn "User '$HUB_USER' already exists, skipping creation." else info "Creating $HUB_USER user..." groupadd -g 1000 "$HUB_USER" 2>/dev/null || true useradd -m -u 1000 -g 1000 -s /bin/bash "$HUB_USER" ADDED_TO_GROUP=false if getent group sudo >/dev/null 2>&1; then if usermod -aG sudo "$HUB_USER" 2>/dev/null; then ADDED_TO_GROUP=true fi fi if [ "$ADDED_TO_GROUP" = false ] && getent group wheel >/dev/null 2>&1; then if usermod -aG wheel "$HUB_USER" 2>/dev/null; then ADDED_TO_GROUP=true fi fi if [ "$ADDED_TO_GROUP" = false ]; then warn "Neither sudo nor wheel group found — $HUB_USER user has no sudo access." fi info "$HUB_USER user created." echo "" warn "Set a password for the $HUB_USER user:" passwd "$HUB_USER" fi ARMBIAN_HOME="/home/$HUB_USER" SSH_DIR="$ARMBIAN_HOME/.ssh" mkdir -p "$SSH_DIR" touch "$SSH_DIR/authorized_keys" chown -R "$HUB_USER":"$HUB_USER" "$SSH_DIR" chmod 700 "$SSH_DIR" chmod 600 "$SSH_DIR/authorized_keys" header "SSH Server Configuration" SSHD_CONF="/etc/ssh/sshd_config" [ -f "$SSHD_CONF" ] || die "sshd_config not found at $SSHD_CONF" for DIRECTIVE in "GatewayPorts yes" "AllowTcpForwarding yes"; do KEY="${DIRECTIVE%% *}" if grep -q "^$KEY" "$SSHD_CONF"; then sed -i "s/^$KEY.*/$DIRECTIVE/" "$SSHD_CONF" else echo "$DIRECTIVE" >> "$SSHD_CONF" fi info "$DIRECTIVE set." done if systemctl enable ssh 2>/dev/null; then systemctl restart ssh elif systemctl enable sshd 2>/dev/null; then systemctl restart sshd else warn "Could not enable/restart SSH service — please start it manually." fi info "SSH server restarted." header "FUSE Configuration" FUSE_CONF="/etc/fuse.conf" if [ -f "$FUSE_CONF" ]; then if grep -q "^#user_allow_other" "$FUSE_CONF"; then sed -i 's/^#user_allow_other/user_allow_other/' "$FUSE_CONF" info "user_allow_other enabled in $FUSE_CONF." elif grep -q "^user_allow_other" "$FUSE_CONF"; then warn "user_allow_other already enabled." else echo "user_allow_other" >> "$FUSE_CONF" info "user_allow_other added to $FUSE_CONF." fi else echo "user_allow_other" > "$FUSE_CONF" info "$FUSE_CONF created with user_allow_other." fi groupadd fuse 2>/dev/null || true usermod -aG fuse "$HUB_USER" 2>/dev/null || true info "$HUB_USER added to fuse group." header "Rclone Setup" RCLONE_CONF="$ARMBIAN_HOME/.config/rclone/rclone.conf" mkdir -p "$(dirname "$RCLONE_CONF")" chown -R "$HUB_USER":"$HUB_USER" "$ARMBIAN_HOME/.config" if [ ! -f "$RCLONE_CONF" ]; then touch "$RCLONE_CONF" chown "$HUB_USER":"$HUB_USER" "$RCLONE_CONF" info "Empty rclone.conf created at $RCLONE_CONF." else warn "rclone.conf already exists, skipping." fi header "Mount Point Setup" read -rp "Mount point for spoke filesystems [/mnt/hub]: " MOUNT_POINT MOUNT_POINT="${MOUNT_POINT:-/mnt/hub}" mkdir -p "$MOUNT_POINT" chown "$HUB_USER":"$HUB_USER" "$MOUNT_POINT" info "Mount point created at $MOUNT_POINT." header "Crontab Setup" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" HELPER="$SCRIPT_DIR/../hubspoke-helper.sh" CRON_LINE="@reboot $HELPER hub start-background" EXISTING=$(crontab -u "$HUB_USER" -l 2>/dev/null || true) if echo "$EXISTING" | grep -qF "hub start-background"; then warn "Crontab entry already exists, skipping." else (echo "$EXISTING"; echo "$CRON_LINE") | crontab -u "$HUB_USER" - info "Added @reboot crontab entry for rclone mount." fi header "Hub Setup Complete" echo -e " Hub user: ${GREEN}$HUB_USER${NC}" echo -e " SSH config: ${GREEN}GatewayPorts yes, AllowTcpForwarding yes${NC}" echo -e " FUSE: ${GREEN}user_allow_other enabled${NC}" echo -e " rclone config: ${GREEN}$RCLONE_CONF${NC}" echo -e " Mount point: ${GREEN}$MOUNT_POINT${NC}" echo "" echo -e "${YELLOW}Next steps:${NC}" echo " For each spoke that connects, run:" echo " ./setup.sh (choose option 2)" echo ""