#!/bin/sh # Installs (or upgrades) Basking as a systemd service. # # curl -fsSL https://git.veillax.com/Veillax/basking/raw/branch/main/deploy/install.sh | sudo sh # sudo sh install.sh [--start] [--version v0.1.0] [--listen 127.0.0.1:8490] [--source] # sudo sh install.sh --uninstall [--purge] # # What it does: # 1. downloads the release archive for this machine and checks its SHA-256 (or, with --source, # clones the repository and builds it with Go), # 2. installs the binary to /usr/local/bin/basking, # 3. creates a "basking" user, /etc/basking (settings) and /var/lib/basking (data), # 4. writes /etc/basking/basking.env and the systemd service, # 5. tells you what to do next: edit the env file, start the service, watch the log. # # Running it again upgrades the binary and keeps your settings; a service that is already running # is restarted. Add --start to start it straight away instead of editing the env file first. set -eu REPO_URL=${BASKING_REPO_URL:-https://git.veillax.com/Veillax/basking} API_URL=${BASKING_API_URL:-https://git.veillax.com/api/v1/repos/Veillax/basking} BIN=/usr/local/bin/basking CONF_DIR=/etc/basking DATA_DIR=/var/lib/basking ENV_FILE=$CONF_DIR/basking.env CONF_FILE=$CONF_DIR/basking.json UNIT=/etc/systemd/system/basking.service USER_NAME=basking VERSION="" LISTEN="127.0.0.1:8490" SOURCE=0 START=0 UNINSTALL=0 PURGE=0 say() { printf '%s\n' "$*"; } die() { printf 'install.sh: %s\n' "$*" >&2; exit 1; } while [ $# -gt 0 ]; do case $1 in --version) VERSION=${2:?--version needs a value}; shift ;; --listen) LISTEN=${2:?--listen needs a value}; shift ;; --source) SOURCE=1 ;; --start) START=1 ;; --uninstall) UNINSTALL=1 ;; --purge) PURGE=1 ;; -h|--help) sed -n '2,19p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) die "unknown option $1" ;; esac shift done [ "$(id -u)" -eq 0 ] || die "run as root (sudo sh install.sh)" [ "$(uname -s)" = Linux ] || die "this installer is for Linux; on Windows, download the .zip from the releases page" command -v systemctl >/dev/null 2>&1 || HAVE_SYSTEMD=0 HAVE_SYSTEMD=${HAVE_SYSTEMD:-1} if [ "$UNINSTALL" -eq 1 ]; then if [ "$HAVE_SYSTEMD" -eq 1 ]; then systemctl disable --now basking 2>/dev/null || true rm -f "$UNIT" systemctl daemon-reload fi rm -f "$BIN" if [ "$PURGE" -eq 1 ]; then rm -rf "$CONF_DIR" "$DATA_DIR" userdel "$USER_NAME" 2>/dev/null || true say "Basking removed, including its settings and data." else say "Basking removed. Settings ($CONF_DIR) and data ($DATA_DIR) were kept; add --purge to delete them." fi exit 0 fi fetch() { # fetch URL DEST if command -v curl >/dev/null 2>&1; then curl -fsSL -o "$2" "$1" elif command -v wget >/dev/null 2>&1; then wget -qO "$2" "$1" else die "need curl or wget"; fi } TMP=$(mktemp -d) trap 'rm -rf "$TMP"' EXIT # ---- 1. get the binary ---- if [ "$SOURCE" -eq 1 ]; then command -v git >/dev/null 2>&1 || die "--source needs git" command -v go >/dev/null 2>&1 || die "--source needs Go (https://go.dev/dl/)" say "Cloning $REPO_URL ..." git clone --quiet ${VERSION:+--branch "$VERSION"} --depth 1 "$REPO_URL" "$TMP/src" (cd "$TMP/src" && CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.version=${VERSION:-source}" -o "$TMP/basking" ./cmd/basking) else case $(uname -m) in x86_64|amd64) ARCH=amd64 ;; aarch64|arm64) ARCH=arm64 ;; *) die "no release build for $(uname -m); try --source" ;; esac if [ -z "$VERSION" ]; then fetch "$API_URL/releases/latest" "$TMP/latest.json" VERSION=$(sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$TMP/latest.json" | head -n 1) [ -n "$VERSION" ] || die "could not find the latest release; use --version or --source" fi ARCHIVE="basking_${VERSION}_linux_${ARCH}.tar.gz" say "Downloading Basking $VERSION ($ARCH) ..." fetch "$REPO_URL/releases/download/$VERSION/$ARCHIVE" "$TMP/$ARCHIVE" fetch "$REPO_URL/releases/download/$VERSION/SHA256SUMS" "$TMP/SHA256SUMS" want=$(grep " $ARCHIVE\$" "$TMP/SHA256SUMS" | cut -d' ' -f1) [ -n "$want" ] || die "$ARCHIVE is not listed in SHA256SUMS" got=$(sha256sum "$TMP/$ARCHIVE" | cut -d' ' -f1) [ "$want" = "$got" ] || die "checksum mismatch for $ARCHIVE; refusing to install" tar -xzf "$TMP/$ARCHIVE" -C "$TMP" cp "$TMP/basking_${VERSION}_linux_${ARCH}/basking" "$TMP/basking" fi # ---- 2. install it ---- UPGRADE=0 [ -x "$BIN" ] && UPGRADE=1 if [ "$UPGRADE" -eq 1 ] && [ "$HAVE_SYSTEMD" -eq 1 ]; then systemctl stop basking 2>/dev/null || true; fi install -m 0755 "$TMP/basking" "$BIN" say "Installed $("$BIN" version) to $BIN" # ---- 3. user and folders ---- id "$USER_NAME" >/dev/null 2>&1 || useradd --system --home-dir "$DATA_DIR" --shell /usr/sbin/nologin "$USER_NAME" 2>/dev/null \ || adduser --system --home "$DATA_DIR" --shell /usr/sbin/nologin "$USER_NAME" 2>/dev/null \ || die "could not create the $USER_NAME user" # The dashboard rewrites its settings file, so the service must own the folder that holds it. mkdir -p "$CONF_DIR" "$DATA_DIR" chown "$USER_NAME" "$CONF_DIR" "$DATA_DIR" chmod 0750 "$CONF_DIR" "$DATA_DIR" # ---- 4. settings and environment file ---- if [ ! -f "$CONF_FILE" ]; then printf '{\n "listen": "%s",\n "data_dir": "%s"\n}\n' "$LISTEN" "$DATA_DIR" > "$CONF_FILE" chown "$USER_NAME" "$CONF_FILE" chmod 0600 "$CONF_FILE" fi if [ ! -f "$ENV_FILE" ]; then cat > "$ENV_FILE" < "$UNIT" </dev/null 2>&1 if [ "$START" -eq 1 ] || systemctl is-active --quiet basking; then systemctl restart basking sleep 3 if systemctl is-active --quiet basking; then say "Basking is running." else say "Basking did not start. Look at: journalctl -u basking -n 50" exit 1 fi fi say "Installed $("$BIN" version)." say "Next:" say " 1. sudoedit $ENV_FILE (optional: the address to listen on and where notes are kept)" say " 2. systemctl start basking (or run this again with --start)" say " 3. journalctl -u basking -f to watch it; a first install prints the password here, once" say "" say "The dashboard is at http://$LISTEN" case $LISTEN in 127.*|localhost*|[::1]*) say "It only listens on this machine. To reach it elsewhere, put an HTTPS reverse proxy (or Hammerhead) in front of it." ;; esac