diff --git a/package.json b/package.json index a301d3c..33efdfb 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "start": "bun src/server.tsx", "dev": "env BUN_HOT=1 bun --hot src/server.tsx", "deploy": "./scripts/deploy.sh", - "push": "./scripts/deploy.sh" + "push": "./scripts/deploy.sh", + "install": "./scripts/install.sh", }, "alias": { "@utils": "./src/utils.tsx", diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 6321f83..f1065b8 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -1,23 +1,56 @@ #!/usr/bin/env bash + +## +# deploys from your dev machine to your NOSEputer +# installs NOSE on the NOSEputer if it hasn't been installed yet + set -euo pipefail HOST="chris@nose-pluto.local" DEST="~/pluto" SOCK="$HOME/.ssh/cm-%r@%h:%p" -# 1) Open a master connection (prompts once) -ssh -MNf -o ControlMaster=yes -o ControlPersist=120 \ +# 0) Open a master SSH connection (one auth prompt) +ssh -MNf -o ControlMaster=yes -o ControlPersist=180 \ -o ControlPath="$SOCK" "$HOST" -# 2) rsync (reuses the connection) +# 1) Sync repo (exclude junk) rsync -az --delete \ -e "ssh -o ControlPath=$SOCK" \ --exclude 'node_modules/' \ --exclude '.git/' \ + --exclude '.DS_Store' \ ./ "$HOST:$DEST/" -# 3) remote install (reuses the connection) -ssh -o ControlPath="$SOCK" "$HOST" "cd $DEST && bun install --frozen-lockfile" +# 2) First-time setup if needed, then install deps and restart service +ssh -t -o ControlPath="$SOCK" "$HOST" bash -lc " + set -euo pipefail + cd $DEST -# 4) close the master connection + # Ensure bun on PATH (/usr/local/bin) if user-installed in ~/.bun + if ! command -v bun >/dev/null 2>&1; then + if [ -x \"\$HOME/.bun/bin/bun\" ]; then + echo '>> Symlinking bun to /usr/local/bin' + sudo ln -sf \"\$HOME/.bun/bin/bun\" /usr/local/bin/bun + else + echo 'ERROR: bun not found (expected at ~/.bun/bin/bun)'; exit 1 + fi + fi + + # If service not present yet, run install (sets caps, installs unit, enables) + if ! systemctl list-unit-files | grep -q '^nose-pluto.service'; then + echo '>> Running first-time install for systemd unit' + bash scripts/install.sh + fi + + echo '>> bun install' + bun install --frozen-lockfile + + echo '>> Restarting service' + sudo systemctl restart nose-pluto.service +" + +# 3) Close the master connection ssh -O exit -o ControlPath="$SOCK" "$HOST" + +echo "Deploy complete ✅" diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..cc229fe --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +## +# installs systemd files to keep NOSE running on your NOSEputer + +set -euo pipefail + +SERVICE_NAME="nose-pluto" +SERVICE_FILE="$(dirname "$0")/${SERVICE_NAME}.service" +SYSTEMD_PATH="/etc/systemd/system/${SERVICE_NAME}.service" +BUN_BIN="/usr/local/bin/bun" + +echo ">> Ensuring bun is available in /usr/local/bin" +if [ ! -x "$BUN_BIN" ]; then + if [ -x "$HOME/.bun/bin/bun" ]; then + sudo ln -sf "$HOME/.bun/bin/bun" "$BUN_BIN" + echo "Symlinked $HOME/.bun/bin/bun -> $BUN_BIN" + else + echo "Error: bun not found in ~/.bun/bin" + exit 1 + fi +else + echo "bun already available at $BUN_BIN" +fi + +echo ">> Setting CAP_NET_BIND_SERVICE on $BUN_BIN" +sudo setcap 'cap_net_bind_service=+ep' "$BUN_BIN" +getcap "$BUN_BIN" || true + +echo ">> Installing systemd unit to $SYSTEMD_PATH" +sudo cp "$SERVICE_FILE" "$SYSTEMD_PATH" +sudo chown root:root "$SYSTEMD_PATH" +sudo chmod 644 "$SYSTEMD_PATH" + +echo ">> Reloading systemd daemon" +sudo systemctl daemon-reload + +echo ">> Enabling $SERVICE_NAME to start at boot" +sudo systemctl enable "$SERVICE_NAME" + +echo ">> Starting (or restarting) $SERVICE_NAME" +sudo systemctl restart "$SERVICE_NAME" + +echo ">> Done!" +systemctl status "$SERVICE_NAME" --no-pager -l diff --git a/scripts/nose-pluto.service b/scripts/nose-pluto.service new file mode 100644 index 0000000..3e06856 --- /dev/null +++ b/scripts/nose-pluto.service @@ -0,0 +1,19 @@ +[Unit] +Description=NOSE Pluto +After=network-online.target +Wants=network-online.target + +[Service] +User=chris +WorkingDirectory=/home/chris/pluto +Environment=PORT=80 +Environment=NODE_ENV=production +ExecStart=/usr/local/bin/bun start +Restart=on-failure +RestartSec=2 +CapabilityBoundingSet=CAP_NET_BIND_SERVICE +AmbientCapabilities=CAP_NET_BIND_SERVICE +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target