diff --git a/lib/common.sh b/lib/common.sh index 89851cb..351f554 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -66,6 +66,9 @@ load_site_config() { while IFS='=' read -r key val; do [[ "$key" =~ ^[[:space:]]*# ]] && continue [[ -z "${key// }" ]] && continue + # Strip leading/trailing whitespace from both sides so hand-edited files work + key="${key#"${key%%[^[:space:]]*}"}"; key="${key%"${key##*[^[:space:]]}"}" + val="${val#"${val%%[^[:space:]]*}"}"; val="${val%"${val##*[^[:space:]]}"}" case "$key" in SITE_TZ) SITE_TZ="$val" ;; SITE_DOMAIN) SITE_DOMAIN="$val" ;; @@ -328,10 +331,11 @@ configure_caddy_for_service() { # Domain prompt — pre-fill from SITE_DOMAIN when available echo "" local _default_domain="" - if [ -n "$SITE_DOMAIN" ] && [ "$SITE_DOMAIN" != "example.com" ]; then + if [ -n "$SITE_DOMAIN" ]; then _default_domain="${DEFAULT_SUBDOMAIN}.${SITE_DOMAIN}" echo " Default: $_default_domain" else + echo " No base domain set — run: sudo ./setup.sh configure" echo " Examples: ${DEFAULT_SUBDOMAIN}.example.com, ${DEFAULT_SUBDOMAIN}.yourdomain.com" fi echo "" diff --git a/services/base.sh b/services/base.sh index 7d351f2..f06d1ec 100644 --- a/services/base.sh +++ b/services/base.sh @@ -1,21 +1,127 @@ #!/bin/bash -# services/base.sh — essential CLI packages installed on every box. +# services/base.sh — essential CLI packages, Docker, SSH hardening, and NetBird. # Part of the modular post-install system (sourced by setup.sh). register_service base base "Essential CLI packages (net-tools, git, htop, btop, glow, …)" install_base() { log_info "Installing essential packages..." + + if [ "$DRY_RUN" = true ]; then + echo "[DRY-RUN] Would install core apt packages" + echo "[DRY-RUN] Would install glow from Charm repo" + echo "[DRY-RUN] Would install Docker CE + Compose plugin" + echo "[DRY-RUN] Would install/configure openssh-server" + echo "[DRY-RUN] Would offer SSH key import from GitHub/Launchpad" + echo "[DRY-RUN] Would offer to disable SSH password auth" + echo "[DRY-RUN] Would offer NetBird install with --allow-server-ssh" + return 0 + fi + run_cmd apt-get update -y # Core utilities present on every install. run_cmd apt-get install -y \ net-tools ncdu git curl wget htop btop tree zip unzip \ - ca-certificates gnupg jq rsync || log_warning "Some essential packages failed to install" + ca-certificates gnupg jq rsync ssh-import-id \ + || log_warning "Some essential packages failed to install" # glow — terminal markdown reader (charmbracelet). Not in Ubuntu repos, # so add Charm's apt repository first. install_glow + + # ── Docker ─────────────────────────────────────────────────────────────── + require_docker + + # ── OpenSSH server ─────────────────────────────────────────────────────── + _base_setup_ssh + + # ── NetBird ────────────────────────────────────────────────────────────── + _base_setup_netbird +} + +_base_setup_ssh() { + log_info "Configuring SSH server..." + + if ! dpkg -l openssh-server &>/dev/null; then + run_cmd apt-get install -y openssh-server + fi + run_cmd systemctl enable --now ssh + + # Import SSH public keys from GitHub and/or Launchpad. + local GH_USER="" LP_USER="" _keys_imported=false + + prompt_text "GitHub username to import SSH keys from (blank to skip):" "" GH_USER + if [ -n "$GH_USER" ]; then + if ssh-import-id "gh:$GH_USER"; then + log_success "Imported SSH keys from GitHub: $GH_USER" + _keys_imported=true + else + log_warning "Could not import keys from GitHub: $GH_USER" + fi + fi + + prompt_text "Launchpad username to import SSH keys from (blank to skip):" "" LP_USER + if [ -n "$LP_USER" ]; then + if ssh-import-id "lp:$LP_USER"; then + log_success "Imported SSH keys from Launchpad: $LP_USER" + _keys_imported=true + else + log_warning "Could not import keys from Launchpad: $LP_USER" + fi + fi + + # Only offer to disable password auth if at least one key was imported. + if [ "$_keys_imported" = true ]; then + local DISABLE_PW="" + prompt_yn "Disable SSH password authentication (key login only)? (y/n):" "y" DISABLE_PW + if [[ "$DISABLE_PW" =~ ^[Yy]$ ]]; then + sed -i \ + -e 's/^#*\s*PasswordAuthentication\s.*/PasswordAuthentication no/' \ + -e 's/^#*\s*KbdInteractiveAuthentication\s.*/KbdInteractiveAuthentication no/' \ + /etc/ssh/sshd_config + # Ubuntu 22.04+ may also have a drop-in that re-enables password auth. + local _dropin="/etc/ssh/sshd_config.d/50-cloud-init.conf" + if [ -f "$_dropin" ]; then + sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' "$_dropin" + fi + systemctl restart ssh + log_success "SSH password authentication disabled — key login only" + fi + fi +} + +_base_setup_netbird() { + local INSTALL_NB="" + prompt_yn "Install NetBird overlay network? (y/n):" "n" INSTALL_NB + [[ "$INSTALL_NB" =~ ^[Yy]$ ]] || return 0 + + log_info "Installing NetBird..." + if curl -fsSL https://pkgs.netbird.io/install.sh | sh; then + log_success "NetBird installed" + else + log_warning "NetBird install failed — see https://netbird.io" + return 1 + fi + + local NB_SSH="" + prompt_yn "Enable NetBird's built-in SSH server (--allow-server-ssh)? (y/n):" "y" NB_SSH + + local NB_KEY="" + prompt_text "NetBird setup key (blank to run 'netbird up' manually later):" "" NB_KEY + + local _up_args="" + [[ "$NB_SSH" =~ ^[Yy]$ ]] && _up_args="--allow-server-ssh" + + if [ -n "$NB_KEY" ]; then + if netbird up --setup-key "$NB_KEY" $_up_args; then + log_success "NetBird connected${NB_SSH:+ with SSH server enabled}" + else + log_warning "NetBird up failed — run manually: netbird up --setup-key ${NB_SSH:+ --allow-server-ssh}" + fi + else + log_info "Run when ready: netbird up${_up_args:+ $_up_args}" + fi } # glow is also exposed as its own module so it can be (re)installed on its own. diff --git a/setup.sh b/setup.sh index a534991..cea74e5 100755 --- a/setup.sh +++ b/setup.sh @@ -231,7 +231,10 @@ if ! grep -q '^SITE_TZ=' "$DOCKER_DIR/.config" 2>/dev/null; then echo " and Caddy network for every service — you type them once, not every time." OFFER_CONFIG="" prompt_yn "Configure site defaults now? (y/n):" "y" OFFER_CONFIG - [ "$OFFER_CONFIG" = "y" ] || [ "$OFFER_CONFIG" = "Y" ] && run_site_configure + if [ "$OFFER_CONFIG" = "y" ] || [ "$OFFER_CONFIG" = "Y" ]; then + run_site_configure + load_site_config # reload so subsequent service prompts see the new values + fi fi # 4) Offer Caddy first (most services proxy through it).