Skip to content

Instantly share code, notes, and snippets.

@shadowfax92
Last active April 17, 2026 21:25
Show Gist options
  • Select an option

  • Save shadowfax92/84fd358466a97565a1be9b8e7da6f102 to your computer and use it in GitHub Desktop.

Select an option

Save shadowfax92/84fd358466a97565a1be9b8e7da6f102 to your computer and use it in GitHub Desktop.
BrowserOS server updater (darwin-arm64)
#!/usr/bin/env bash
#
# BrowserOS server updater (darwin-arm64)
#
# Downloads the latest BrowserOS server resources bundle and drops it into
# the installed BrowserOS.app. Safe to re-run.
#
# Usage:
# curl -fsSL https://gist.githubusercontent.com/shadowfax92/84fd358466a97565a1be9b8e7da6f102/raw/install-browseros-server.sh | sudo bash
# sudo install-browseros-server.sh # from ~/bin
#
set -euo pipefail
CDN_URL="https://cdn.browseros.com/artifacts/server/latest/browseros-server-resources-darwin-arm64.zip"
APP_PATH="/Applications/BrowserOS.app"
INSTALL_DIR="${APP_PATH}/Contents/Resources/BrowserOSServer/default"
PROC_PATTERN='BrowserOS.app/Contents/MacOS/BrowserOS$'
if [[ -t 1 ]]; then
C_RED=$'\033[0;31m'
C_GREEN=$'\033[0;32m'
C_YELLOW=$'\033[0;33m'
C_BLUE=$'\033[0;34m'
C_MAGENTA=$'\033[0;35m'
C_CYAN=$'\033[0;36m'
C_GREY=$'\033[0;90m'
C_BOLD=$'\033[1m'
C_DIM=$'\033[2m'
C_RESET=$'\033[0m'
else
C_RED="" C_GREEN="" C_YELLOW="" C_BLUE="" C_MAGENTA=""
C_CYAN="" C_GREY="" C_BOLD="" C_DIM="" C_RESET=""
fi
STEP=0
TOTAL_STEPS=6
banner() {
printf '%s' "$C_MAGENTA"
cat <<'EOF'
┌──────────────────────────────────────────────┐
│ BrowserOS Server · darwin-arm64 │
│ latest release │
└──────────────────────────────────────────────┘
EOF
printf '%s\n' "$C_RESET"
}
step() {
STEP=$((STEP + 1))
printf '\n%s[%d/%d]%s %s%s%s\n' \
"$C_CYAN" "$STEP" "$TOTAL_STEPS" "$C_RESET" \
"$C_BOLD" "$*" "$C_RESET"
}
info() { printf ' %s%s%s\n' "$C_GREY" "$*" "$C_RESET"; }
ok() { printf ' %s✓%s %s\n' "$C_GREEN" "$C_RESET" "$*"; }
warn() { printf ' %s!%s %s\n' "$C_YELLOW" "$C_RESET" "$*"; }
die() { printf '\n%s✗ %s%s\n' "$C_RED" "$*" "$C_RESET" >&2; exit 1; }
banner
step "Checking host"
[[ "$(uname -s)" == "Darwin" ]] || die "This script only runs on macOS."
[[ "$(uname -m)" == "arm64" ]] || die "This script only supports Apple Silicon (arm64)."
[[ $EUID -eq 0 ]] || die "Must run as root. Try: curl -fsSL <url> | sudo bash"
ok "macOS $(sw_vers -productVersion) · arm64 · root"
step "Locating BrowserOS install"
[[ -d "$APP_PATH" ]] || die "BrowserOS is not installed at ${APP_PATH}."
[[ -d "$INSTALL_DIR" ]] || die "Expected install dir not found: ${INSTALL_DIR}"
info "$INSTALL_DIR"
if pgrep -f "$PROC_PATTERN" >/dev/null 2>&1; then
warn "BrowserOS is currently running — that's fine, just restart it after."
fi
ok "Target verified"
WORK_DIR="$(mktemp -d -t browseros-server-update.XXXXXX)"
trap 'rm -rf "$WORK_DIR"' EXIT
ZIP_PATH="${WORK_DIR}/server.zip"
STAGE_DIR="${WORK_DIR}/stage"
mkdir -p "$STAGE_DIR"
step "Downloading latest server bundle"
info "$CDN_URL"
if ! curl -fL --progress-bar --retry 3 -o "$ZIP_PATH" "$CDN_URL"; then
die "Download failed."
fi
SIZE_BYTES=$(stat -f%z "$ZIP_PATH" 2>/dev/null || echo 0)
SIZE_MB=$(awk -v b="$SIZE_BYTES" 'BEGIN { printf "%.1f", b/1048576 }')
ok "Downloaded ${SIZE_MB} MB"
step "Extracting archive"
unzip -q "$ZIP_PATH" -d "$STAGE_DIR"
[[ -d "${STAGE_DIR}/resources" ]] \
|| die "Archive did not contain a resources/ folder."
[[ -x "${STAGE_DIR}/resources/bin/browseros_server" ]] \
|| die "Archive is missing resources/bin/browseros_server."
ok "Archive contents verified"
step "Installing resources"
info "replacing ${INSTALL_DIR}/resources"
if [[ -d "${INSTALL_DIR}/resources" ]]; then
rm -rf "${INSTALL_DIR}/resources"
fi
if ! cp -R "${STAGE_DIR}/resources" "${INSTALL_DIR}/resources" 2>/dev/null; then
printf '\n%sCopy failed — likely blocked by macOS App Management.%s\n' "$C_RED" "$C_RESET" >&2
printf '%sGrant your terminal access:%s\n' "$C_YELLOW" "$C_RESET" >&2
printf ' System Settings → Privacy & Security → App Management → enable your terminal\n' >&2
printf ' then fully quit the terminal, relaunch, and re-run this installer.\n\n' >&2
die "Aborted."
fi
xattr -rd com.apple.quarantine "${INSTALL_DIR}/resources" 2>/dev/null || true
BIN="${INSTALL_DIR}/resources/bin/browseros_server"
[[ -x "$BIN" ]] || die "Installed binary is missing or not executable: $BIN"
ok "Files in place"
step "Verifying server version"
VERSION_OUTPUT="$("$BIN" --version 2>&1 || true)"
VERSION_LINE="$(printf '%s\n' "$VERSION_OUTPUT" | head -n1)"
ok "browseros_server reports: ${C_BOLD}${VERSION_LINE}${C_RESET}"
printf '\n%s%s┌────────────────────────────────────────────────┐%s\n' "$C_GREEN" "$C_BOLD" "$C_RESET"
printf '%s%s│ Installed ✓ │%s\n' "$C_GREEN" "$C_BOLD" "$C_RESET"
printf '%s%s└────────────────────────────────────────────────┘%s\n\n' "$C_GREEN" "$C_BOLD" "$C_RESET"
printf '%sVersion%s %s%s%s\n\n' "$C_DIM" "$C_RESET" "$C_BOLD" "$VERSION_LINE" "$C_RESET"
if pgrep -f "$PROC_PATTERN" >/dev/null 2>&1; then
printf '%sBrowserOS is running.%s Restart it to load the new server.\n\n' "$C_BOLD" "$C_RESET"
REPLY=""
if [[ -r /dev/tty ]]; then
printf '%sKill BrowserOS now?%s [y/N] ' "$C_YELLOW" "$C_RESET"
read -r REPLY </dev/tty || REPLY=""
fi
if [[ "$REPLY" =~ ^[Yy]$ ]]; then
pkill -f "$PROC_PATTERN" && ok "BrowserOS killed — reopen it from /Applications."
else
printf '\n %s# kill it manually when ready%s\n' "$C_GREY" "$C_RESET"
printf " %spkill -f '%s'%s\n\n" "$C_CYAN" "$PROC_PATTERN" "$C_RESET"
fi
else
printf '%sBrowserOS is not running — just launch it from /Applications.%s\n\n' "$C_DIM" "$C_RESET"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment