From e6c9751f7d314635fc92950b6297ce4b6eb03441 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath <2+defunkt@users.noreply.github.com> Date: Fri, 30 Jan 2026 15:28:52 -0800 Subject: [PATCH] rpi deploy scripts/setup --- package.json | 10 +++++- scripts/config.sh | 8 +++++ scripts/deploy.sh | 23 +++++++++++++ scripts/install.sh | 71 +++++++++++++++++++++++++++++++++++++++ scripts/remote-install.sh | 12 +++++++ scripts/remote-restart.sh | 9 +++++ scripts/remote-start.sh | 9 +++++ scripts/remote-stop.sh | 9 +++++ scripts/toes.service | 19 +++++++++++ 9 files changed, 169 insertions(+), 1 deletion(-) create mode 100755 scripts/config.sh create mode 100755 scripts/deploy.sh create mode 100755 scripts/install.sh create mode 100755 scripts/remote-install.sh create mode 100755 scripts/remote-restart.sh create mode 100755 scripts/remote-start.sh create mode 100755 scripts/remote-stop.sh create mode 100644 scripts/toes.service diff --git a/package.json b/package.json index cc89ceb..121cf27 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,15 @@ "cli:build": "bun run scripts/build.ts", "cli:build:all": "bun run scripts/build.ts --all", "cli:install": "bun cli:build && sudo cp dist/toes /usr/local/bin", - "cli:uninstall": "sudo rm /usr/local/bin" + "cli:uninstall": "sudo rm /usr/local/bin", + "deploy": "./scripts/deploy.sh", + "dev": "bun run --hot src/server/index.tsx", + "remote:install": "./scripts/remote-install.sh", + "remote:restart": "./scripts/remote-restart.sh", + "remote:start": "./scripts/remote-start.sh", + "remote:stop": "./scripts/remote-stop.sh", + "start": "bun run src/server/index.tsx", + "test": "bun test" }, "devDependencies": { "@types/bun": "latest" diff --git a/scripts/config.sh b/scripts/config.sh new file mode 100755 index 0000000..24eae03 --- /dev/null +++ b/scripts/config.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +# It isn't enough to modify this yet. +# You also need to manually update the toes.service file. +HOST="${HOST:-toes@toes.local}" +URL="${URL:-http://toes.local}" +DEST="${DEST:-~/.toes}" +APPS_DIR="${APPS_DIR:-~/apps}" diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 0000000..75dbbc4 --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -e + +# Get absolute path of this script's directory +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$SCRIPT_DIR/.." + +# Load config +source "$ROOT_DIR/scripts/config.sh" + +# Make sure we're up-to-date +if [ -n "$(git status --porcelain)" ]; then + echo "=> You have unsaved (git) changes" + exit 1 +fi + +git push origin main + +# SSH to target and update +ssh "$HOST" "cd $DEST && git pull origin main && bun run build && sudo systemctl restart toes.service" + +echo "=> Deployed to $HOST" +echo "=> Visit $URL" diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..702cc70 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +## +# installs systemd files to keep toes running on your Raspberry Pi + +set -euo pipefail + +quiet() { "$@" > /dev/null 2>&1; } + +SYSTEMD_DIR="/etc/systemd/system" +SERVICE_NAME="toes" +SERVICE_FILE="$(dirname "$0")/${SERVICE_NAME}.service" +SYSTEMD_PATH="${SYSTEMD_DIR}/${SERVICE_NAME}.service" + +BUN_SYMLINK="/usr/local/bin/bun" +BUN_REAL="$HOME/.bun/bin/bun" + +echo ">> Updating system libraries" +quiet sudo apt-get update +quiet sudo apt-get install -y libcap2-bin +quiet sudo apt-get install -y avahi-utils + +echo ">> Ensuring bun is available in /usr/local/bin" +if [ ! -x "$BUN_SYMLINK" ]; then + if [ -x "$BUN_REAL" ]; then + quiet sudo ln -sf "$BUN_REAL" "$BUN_SYMLINK" + echo "Symlinked $BUN_REAL -> $BUN_SYMLINK" + else + echo ">> Installing bun at $BUN_REAL" + quiet sudo apt install unzip + quiet curl -fsSL https://bun.sh/install | bash + quiet sudo ln -sf "$BUN_REAL" "$BUN_SYMLINK" + echo "Symlinked $BUN_REAL -> $BUN_SYMLINK" + fi +else + echo "bun already available at $BUN_SYMLINK" +fi + +echo ">> Setting CAP_NET_BIND_SERVICE on $BUN_REAL" +quiet sudo setcap 'cap_net_bind_service=+ep' "$BUN_REAL" +quiet /usr/sbin/getcap "$BUN_REAL" || true + +echo ">> Creating apps directory" +mkdir -p ~/apps + +echo ">> Building client bundle" +bun run build + +echo ">> Installing toes service" +quiet sudo install -m 644 -o root -g root "$SERVICE_FILE" "$SYSTEMD_PATH" + +echo ">> Reloading systemd daemon" +quiet sudo systemctl daemon-reload + +echo ">> Enabling $SERVICE_NAME to start at boot" +quiet sudo systemctl enable "$SERVICE_NAME" + +echo ">> Starting (or restarting) $SERVICE_NAME" +quiet sudo systemctl restart "$SERVICE_NAME" + +echo ">> Enabling kiosk mode" +quiet mkdir -p ~/.config/labwc +cat > ~/.config/labwc/autostart <<'EOF' +chromium-browser --noerrdialogs --disable-infobars --kiosk http://localhost +EOF + +echo ">> Done! Rebooting in 5 seconds..." +quiet systemctl status "$SERVICE_NAME" --no-pager -l +sleep 5 +quiet sudo nohup reboot >/dev/null 2>&1 & +exit 0 diff --git a/scripts/remote-install.sh b/scripts/remote-install.sh new file mode 100755 index 0000000..6813a8b --- /dev/null +++ b/scripts/remote-install.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -e + +# Get absolute path of this script's directory +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$SCRIPT_DIR/.." + +# Load config +source "$ROOT_DIR/scripts/config.sh" + +# Run remote install on the target +ssh "$HOST" "git clone https://git.nose.space/defunkt/toes $DEST && cd $DEST && ./scripts/install.sh" diff --git a/scripts/remote-restart.sh b/scripts/remote-restart.sh new file mode 100755 index 0000000..5421cf9 --- /dev/null +++ b/scripts/remote-restart.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$SCRIPT_DIR/.." + +source "$ROOT_DIR/scripts/config.sh" + +ssh "$HOST" "sudo systemctl restart toes.service" diff --git a/scripts/remote-start.sh b/scripts/remote-start.sh new file mode 100755 index 0000000..2375626 --- /dev/null +++ b/scripts/remote-start.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$SCRIPT_DIR/.." + +source "$ROOT_DIR/scripts/config.sh" + +ssh "$HOST" "sudo systemctl start toes.service" diff --git a/scripts/remote-stop.sh b/scripts/remote-stop.sh new file mode 100755 index 0000000..fb0e5a2 --- /dev/null +++ b/scripts/remote-stop.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$SCRIPT_DIR/.." + +source "$ROOT_DIR/scripts/config.sh" + +ssh "$HOST" "sudo systemctl stop toes.service" diff --git a/scripts/toes.service b/scripts/toes.service new file mode 100644 index 0000000..33d5f9b --- /dev/null +++ b/scripts/toes.service @@ -0,0 +1,19 @@ +[Unit] +Description=Toes - Personal Web Appliance +After=network-online.target +Wants=network-online.target + +[Service] +User=toes +WorkingDirectory=/home/toes/.toes/ +Environment=PORT=80 +Environment=NODE_ENV=production +Environment=APPS_DIR=/home/toes/apps/ +ExecStart=/home/toes/.bun/bin/bun start +Restart=always +RestartSec=1 +CapabilityBoundingSet=CAP_NET_BIND_SERVICE +AmbientCapabilities=CAP_NET_BIND_SERVICE + +[Install] +WantedBy=multi-user.target