setup: Ubuntu GNOME-on-Xorg desktop + setup.sh hardening
setup-desktop.sh now installs ubuntu-desktop + gdm3 + x11vnc and forces the Xorg session (WaylandEnable=false) with auto-login — x11vnc can only mirror an Xorg :0, not Wayland. vnc-manager.ts resolves the X authority from the GDM per-session path (/run/user/<uid>/gdm/Xauthority) with a ~/.Xauthority fallback. setup.sh fixes: - desktop step gates on `dpkg -s ubuntu-desktop` (was the decommissioned officer-vnc service, which never matched so setup-desktop re-ran every time) - remove Pi (install, --list-models validation, verification check) - export GOPATH before the cliamp build so `go install` lands where it's checked even when Go was already present this run - write PUBLIC_BUILD_ENV=production and quote all .env values - guard the interactive .env block behind a TTY check so non-interactive runs skip cleanly instead of aborting on read EOF under set -e - restart systemd-logind only when a key actually changed - sed prefix-strip instead of `tr -d` (which deletes characters, not a prefix) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+42
-37
@@ -299,8 +299,13 @@ else
|
||||
fi
|
||||
|
||||
# Configure logind to ignore idle — patch individual keys, don't overwrite the file
|
||||
LOGIND_CHANGED=0
|
||||
set_logind_key() {
|
||||
local key="$1" val="$2" file="/etc/systemd/logind.conf"
|
||||
# Already set (uncommented) to the desired value → nothing to do.
|
||||
if grep -qE "^${key}=${val}$" "$file" 2>/dev/null; then
|
||||
return
|
||||
fi
|
||||
if grep -qE "^${key}=" "$file" 2>/dev/null; then
|
||||
sudo sed -i "s|^${key}=.*|${key}=${val}|" "$file"
|
||||
elif grep -qE "^#${key}=" "$file" 2>/dev/null; then
|
||||
@@ -308,6 +313,7 @@ set_logind_key() {
|
||||
else
|
||||
echo "${key}=${val}" | sudo tee -a "$file" > /dev/null
|
||||
fi
|
||||
LOGIND_CHANGED=1
|
||||
}
|
||||
|
||||
set_logind_key HandleLidSwitch ignore
|
||||
@@ -316,8 +322,13 @@ set_logind_key HandlePowerKey ignore
|
||||
set_logind_key IdleAction none
|
||||
set_logind_key RuntimeDirectorySize 10%
|
||||
|
||||
sudo systemctl restart systemd-logind
|
||||
ok "Configured logind to disable auto-suspend"
|
||||
# Only restart logind when something actually changed — a needless restart can disrupt live sessions.
|
||||
if [ "$LOGIND_CHANGED" = "1" ]; then
|
||||
sudo systemctl restart systemd-logind
|
||||
ok "Configured logind to disable auto-suspend"
|
||||
else
|
||||
skip "logind auto-suspend settings"
|
||||
fi
|
||||
|
||||
# ─── 5. Node.js 22 (system-wide) ─────────────────────────────────────────────
|
||||
echo ""
|
||||
@@ -337,7 +348,7 @@ case $PM in
|
||||
apt)
|
||||
NEED_INSTALL=0
|
||||
if [ -f "$SYSTEM_NODE" ]; then
|
||||
SYS_MAJOR=$("$SYSTEM_NODE" -v 2>/dev/null | cut -d. -f1 | tr -d 'v')
|
||||
SYS_MAJOR=$("$SYSTEM_NODE" -v 2>/dev/null | cut -d. -f1 | sed 's/^v//')
|
||||
if [ "$SYS_MAJOR" = "22" ]; then
|
||||
skip "node v$("$SYSTEM_NODE" -v) (system-wide at $SYSTEM_NODE)"
|
||||
else
|
||||
@@ -354,7 +365,7 @@ case $PM in
|
||||
fi
|
||||
if [ "$NEED_INSTALL" = "1" ]; then
|
||||
install_node22_apt
|
||||
if [ -f "$SYSTEM_NODE" ] && [ "$("$SYSTEM_NODE" -v 2>/dev/null | cut -d. -f1 | tr -d 'v')" = "22" ]; then
|
||||
if [ -f "$SYSTEM_NODE" ] && [ "$("$SYSTEM_NODE" -v 2>/dev/null | cut -d. -f1 | sed 's/^v//')" = "22" ]; then
|
||||
ok "node v$("$SYSTEM_NODE" -v) installed at $SYSTEM_NODE"
|
||||
if has node && [ "$(command -v node)" != "$SYSTEM_NODE" ]; then
|
||||
warn "Shell resolves 'node' to $(command -v node) — system node is at $SYSTEM_NODE"
|
||||
@@ -367,7 +378,7 @@ case $PM in
|
||||
fi
|
||||
;;
|
||||
pacman)
|
||||
if has node && [ "$(node -v 2>/dev/null | cut -d. -f1 | tr -d 'v')" = "22" ]; then
|
||||
if has node && [ "$(node -v 2>/dev/null | cut -d. -f1 | sed 's/^v//')" = "22" ]; then
|
||||
skip "node v$(node -v)"
|
||||
else
|
||||
install_pkg nodejs npm
|
||||
@@ -375,7 +386,7 @@ case $PM in
|
||||
fi
|
||||
;;
|
||||
brew)
|
||||
if has node && [ "$(node -v 2>/dev/null | cut -d. -f1 | tr -d 'v')" = "22" ]; then
|
||||
if has node && [ "$(node -v 2>/dev/null | cut -d. -f1 | sed 's/^v//')" = "22" ]; then
|
||||
skip "node v$(node -v)"
|
||||
else
|
||||
install_pkg node
|
||||
@@ -412,7 +423,7 @@ echo ""
|
||||
echo "── Go ──"
|
||||
|
||||
echo " Fetching latest Go version..."
|
||||
GOLANG_VERSION=$(curl -fsSL "https://go.dev/dl/?mode=json" | jq -r '.[0].version' | tr -d 'go')
|
||||
GOLANG_VERSION=$(curl -fsSL "https://go.dev/dl/?mode=json" | jq -r '.[0].version' | sed 's/^go//')
|
||||
if [ -z "$GOLANG_VERSION" ]; then
|
||||
warn "Could not fetch latest Go version — falling back to 1.23.6"
|
||||
GOLANG_VERSION=1.23.6
|
||||
@@ -445,7 +456,7 @@ install_go() {
|
||||
}
|
||||
|
||||
if has go; then
|
||||
INSTALLED_GO=$(go version 2>/dev/null | awk '{print $3}' | tr -d 'go')
|
||||
INSTALLED_GO=$(go version 2>/dev/null | awk '{print $3}' | sed 's/^go//')
|
||||
if [ "$INSTALLED_GO" = "$GOLANG_VERSION" ]; then
|
||||
skip "go $INSTALLED_GO"
|
||||
else
|
||||
@@ -528,7 +539,11 @@ fi
|
||||
echo ""
|
||||
echo "── cliamp ──"
|
||||
|
||||
GOPATH_BIN="${GOPATH:-$HOME/.local/go-path}/bin"
|
||||
# Export GOPATH (not just PATH) so `go install` lands in GOPATH_BIN — even when Go was already present
|
||||
# this run and install_go (which sets GOPATH) never ran. Otherwise go uses its default ~/go/bin and the
|
||||
# check below wrongly reports a build failure.
|
||||
export GOPATH="${GOPATH:-$HOME/.local/go-path}"
|
||||
GOPATH_BIN="$GOPATH/bin"
|
||||
export PATH="$GOPATH_BIN:$PATH"
|
||||
|
||||
if has cliamp; then
|
||||
@@ -619,7 +634,7 @@ else
|
||||
case $PM in
|
||||
apt)
|
||||
echo " Fetching latest eza version..."
|
||||
EZA_VERSION=$(curl -fsSL "https://api.github.com/repos/eza-community/eza/releases/latest" | jq -r '.tag_name' | tr -d 'v')
|
||||
EZA_VERSION=$(curl -fsSL "https://api.github.com/repos/eza-community/eza/releases/latest" | jq -r '.tag_name' | sed 's/^v//')
|
||||
if [ -z "$EZA_VERSION" ]; then warn "Could not fetch eza version — skipping"; else
|
||||
ARCH=$(uname -m)
|
||||
case $ARCH in
|
||||
@@ -647,7 +662,7 @@ else
|
||||
case $PM in
|
||||
apt)
|
||||
echo " Fetching latest lazygit version..."
|
||||
LAZYGIT_VERSION=$(curl -fsSL "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | jq -r '.tag_name' | tr -d 'v')
|
||||
LAZYGIT_VERSION=$(curl -fsSL "https://api.github.com/repos/jesseduffield/lazygit/releases/latest" | jq -r '.tag_name' | sed 's/^v//')
|
||||
if [ -z "$LAZYGIT_VERSION" ]; then warn "Could not fetch lazygit version — skipping"; else
|
||||
ARCH=$(uname -m)
|
||||
case $ARCH in
|
||||
@@ -710,24 +725,6 @@ else
|
||||
npm config set prefix "$HOME/.local"
|
||||
ok "npm prefix set to $HOME/.local"
|
||||
|
||||
# Pi (coding agent)
|
||||
if has pi; then
|
||||
skip "pi (@mariozechner/pi-coding-agent)"
|
||||
else
|
||||
echo " Installing pi..."
|
||||
npm install -g @mariozechner/pi-coding-agent
|
||||
if has pi; then ok "pi installed"; else warn "pi install failed"; fi
|
||||
fi
|
||||
|
||||
# Validate Pi works
|
||||
if has pi; then
|
||||
if pi --list-models > /dev/null 2>&1; then
|
||||
ok "pi validated (--list-models works)"
|
||||
else
|
||||
warn "pi installed but --list-models failed — check API keys in ~/.pi/agent/auth.json"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Claude Code (uses Anthropic's own installer for auto-update support)
|
||||
if has claude; then
|
||||
skip "claude (claude-code)"
|
||||
@@ -765,7 +762,15 @@ echo "── Environment (.env) ──"
|
||||
|
||||
GENERATE_ENV=true
|
||||
|
||||
if [ -f "$PROJECT_DIR/.env" ]; then
|
||||
if [ ! -t 0 ]; then
|
||||
# Non-interactive shell: the prompts below would hit EOF and abort the whole script under `set -e`.
|
||||
GENERATE_ENV=false
|
||||
if [ -f "$PROJECT_DIR/.env" ]; then
|
||||
skip ".env (kept existing — non-interactive shell)"
|
||||
else
|
||||
warn "No .env and not a terminal — re-run setup.sh interactively to generate it"
|
||||
fi
|
||||
elif [ -f "$PROJECT_DIR/.env" ]; then
|
||||
echo -n " .env already exists. Regenerate? (y/n) [n]: "
|
||||
read -r REGEN
|
||||
if [[ "$REGEN" != "y" && "$REGEN" != "Y" ]]; then
|
||||
@@ -820,12 +825,13 @@ if [ "$GENERATE_ENV" = true ]; then
|
||||
|
||||
# Write .env
|
||||
cat > "$PROJECT_DIR/.env" <<ENVFILE
|
||||
PORT=$ENV_PORT
|
||||
PORT="$ENV_PORT"
|
||||
JWT_SECRET="$JWT_SECRET"
|
||||
MAIL_TRANSPORT="$ENV_MAIL_TRANSPORT"
|
||||
PUBLIC_URL=$ENV_PUBLIC_URL
|
||||
DATA_PATH=$ENV_DATA_PATH
|
||||
HOME_DIR=$HOME
|
||||
PUBLIC_URL="$ENV_PUBLIC_URL"
|
||||
PUBLIC_BUILD_ENV="production"
|
||||
DATA_PATH="$ENV_DATA_PATH"
|
||||
HOME_DIR="$HOME"
|
||||
POSTGRES_URL="$POSTGRES_URL"
|
||||
DISCORD_BUG_REPORT_WEBHOOK="$ENV_DISCORD_WEBHOOK"
|
||||
ENVFILE
|
||||
@@ -837,8 +843,8 @@ fi
|
||||
echo ""
|
||||
echo "── Remote Desktop (XFCE + VNC) ──"
|
||||
|
||||
if systemctl is-active --quiet officer-vnc 2>/dev/null; then
|
||||
skip "remote desktop (officer-vnc service already running)"
|
||||
if dpkg -s ubuntu-desktop &>/dev/null 2>&1; then
|
||||
skip "remote desktop (ubuntu-desktop already installed)"
|
||||
else
|
||||
case $PM in
|
||||
apt)
|
||||
@@ -901,7 +907,6 @@ check cliamp
|
||||
|
||||
echo ""
|
||||
echo "AI agents:"
|
||||
check pi
|
||||
check claude
|
||||
|
||||
echo ""
|
||||
|
||||
Reference in New Issue
Block a user