Tested by: morgan (via Claude Code)
Date: 2026-03-08
Script source: https://raw.githubusercontent.com/sayhar/lobster/main/install.sh
Test mode: --non-interactive
| Property | Value |
|---|---|
| Provider | Hetzner Cloud |
| Server type | CAX21 (ARM Ampere) |
| Location | Nuremberg, Germany (nbg1) |
| OS | Ubuntu 24.04 (aarch64) |
| Kernel | 6.8.0-90-generic |
| RAM | 7.5 GB |
| Disk | 75 GB |
| Architecture | aarch64 (ARM64) |
This is the first known test on ARM64. The existing golden image path targets x86 Debian 12 on AWS Lightsail.
The installer completed successfully after patching one bug. All components installed and verified on ARM64.
Lines affected: 962, 977, 1002
Symptom: Script silently stops at "Setting up health monitoring..." with no error message.
Root cause: The script uses set -euo pipefail (line 16). The crontab update pattern is:
(crontab -l 2>/dev/null | grep -v "$MARKER" | grep -v "some-pattern"; \
echo "new-cron-entry") | crontab -On a fresh install, crontab -l outputs nothing. grep -v receives empty input and exits with code 1 (no matches). With pipefail enabled, the subshell inherits that exit code, and set -e terminates the script.
Fix: Wrap each crontab update block with set +o pipefail / set -o pipefail:
+set +o pipefail
(crontab -l 2>/dev/null | grep -v "$HEALTH_MARKER" | grep -v "health-check"; \
echo "*/2 * * * * $INSTALL_DIR/scripts/health-check-v3.sh $HEALTH_MARKER") | crontab -
+set -o pipefailApply this to all three crontab blocks (lines 962, 977, 1002).
Alternative fix: Use { grep -v "$MARKER" || true; } but this is less clean because the { } grouping interacts poorly with the outer subshell piped to crontab -.
BUG 2 (Blocker for bash <(curl ...) invocation): exec sudo -u lobster bash "$0" fails with process substitution
Line affected: 329
Symptom: bash: /dev/fd/63: No such file or directory
Root cause: When run as bash <(curl -fsSL ...), $0 is /dev/fd/63 (a process substitution file descriptor). The script detects it's running as root, creates a lobster user, then does:
exec sudo -u lobster bash "$0" "$@"The file descriptor /dev/fd/63 belongs to the root process. After exec sudo -u lobster, the fd is no longer accessible to the new user/process.
Workaround: Download the script first:
curl -fsSL https://raw.githubusercontent.com/sayhar/lobster/main/install.sh -o /tmp/install.sh
bash /tmp/install.shSuggested fix: Copy the script to a temporary file before re-execing:
if [ "$(id -u)" = "0" ]; then
# ... create lobster user ...
# If running from a pipe/fd, copy to a real file first
if [[ "$0" == /dev/fd/* || "$0" == /proc/self/fd/* ]]; then
SELF_COPY=$(mktemp /tmp/lobster-install.XXXXXX.sh)
cat "$0" > "$SELF_COPY"
chmod +x "$SELF_COPY"
exec sudo -u lobster bash "$SELF_COPY" "$@"
else
exec sudo -u lobster bash "$0" "$@"
fi
fiLines affected: 2078-2083 and 2084-2088
The "IMPORTANT: If 'claude' or 'lobster' commands are not found, run: source ~/.bashrc" block is printed twice verbatim.
Everything works on ARM64 out of the box. Specific observations:
| Component | ARM64 Status | Notes |
|---|---|---|
| System packages (apt) | OK | All packages available for arm64 |
| Claude Code CLI | OK | Installed via claude.ai/install.sh, ARM64 native build |
| uv (Python package manager) | OK | aarch64-unknown-linux-gnu build |
| Python venv + packages | OK | All pip packages installed cleanly |
| fastembed | OK | Installed without issues (was flagged as potential ARM risk) |
| sqlite-vec | OK | Stable release loaded correctly (no ELFCLASS32 bug on this version) |
| whisper.cpp | OK | Built from source with cmake, ~2 min compile time |
| Whisper model download | OK | 465MB model downloaded at ~400MB/s |
| Node.js / npm | OK | Not directly installed by this script (Claude Code handles it) |
| Syncthing | N/A | Not installed by this script (hyperlobster adds it) |
| systemd services | OK | Generated from templates, installed correctly |
Verdict: The installer is ARM64-ready. No architecture-specific changes needed.
- The tarball install mode falls back to git clone when no GitHub release exists (
No release found, falling back to git clone...). This works but means every "tarball" install is actually a full git clone. DEBIAN_FRONTEND=noninteractiveandNEEDRESTART_MODE=a(lines 19-20) are good — they prevent the debconf TTY errors from blocking the install. The debconf warnings still appear in output but don't cause failures.- The
lobsteruser creation + sudo setup (lines 314-330) is clean. SSH keys are correctly copied from root. - MCP server registration worked on first try.
- The
--non-interactiveflag correctly skips all credential prompts while still completing the full mechanical install.