fix: deployment corrections from independent review
Six fixes addressing operational correctness on a real Debian host:
1. Ownership after git operations: chown -R zopu:zopu on the checkout
after clone/update/rollback before running bun install/build as the
service user. .env kept at 0600 with explicit chmod after each
operation.
2. sudo replaced with runuser: minimal Debian does not include sudo.
runuser is part of util-linux (essential) and always available.
All three scripts (bootstrap, update, rollback) now use runuser -u.
3. cron.d entry fixed: /etc/cron.d format requires a username field.
Added ${SERVICE_USER} between the time fields and the command path.
4. Firewall: added explicit `ufw allow in on tailscale0` rule so the
deny-incoming default does not block Tailscale private-overlay
reachability. Removed inaccurate claim that direct private IP works
by default; documented that an explicit per-interface rule is needed.
5. SupplementaryGroups=docker added to zopu-agent.service: the Orb
sandbox runtime lives in the agent process, not just the daemon.
6. zopu-health.service: added Environment=ENV_FILE=__INSTALL_DIR__/.env
so health-check.sh sources the correct .env at custom install paths.
Verified Flue build output: bun run build:agents produces
packages/agents/dist/server.mjs (confirmed by running the build).
Agent unit ExecStart path is correct.
Validated: bash -n on all 6 shell scripts; mocked health-check smoke
against live RivetKit engine on port 6420; systemd unit structural
checks. No JS/TS/agent files changed.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# Run as root on a fresh Debian 12 host:
|
||||
#
|
||||
# sudo bash bootstrap.sh
|
||||
# bash bootstrap.sh
|
||||
#
|
||||
# Environment overrides (set before running):
|
||||
# ZOPU_REPO_URL — SSH clone URL (default: ssh://git@git.openputer.com:2222/puter/zopu-code.git)
|
||||
@@ -38,6 +38,12 @@ log() { echo -e "${GREEN}[bootstrap]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[bootstrap]${NC} $*"; }
|
||||
err() { echo -e "${RED}[bootstrap]${NC} $*" >&2; }
|
||||
|
||||
# runuser is part of util-linux (essential on Debian) and always available.
|
||||
# sudo is NOT assumed on minimal Debian installs.
|
||||
run_as_service() {
|
||||
runuser -u "$SERVICE_USER" -- "$@"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pre-flight
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -64,9 +70,9 @@ apt-get install -y \
|
||||
ufw \
|
||||
git \
|
||||
jq \
|
||||
netcat-openbsd \
|
||||
openssh-client \
|
||||
unattended-upgrades \
|
||||
netcat-openbsd \
|
||||
rsyslog
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -137,17 +143,23 @@ else
|
||||
cd "$INSTALL_DIR"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5b. Hand ownership of the checkout to the service user
|
||||
# ---------------------------------------------------------------------------
|
||||
log "Setting ownership of $INSTALL_DIR to $SERVICE_USER..."
|
||||
chown -R "$SERVICE_USER":"$SERVICE_USER" "$INSTALL_DIR"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 6. Install dependencies and build
|
||||
# ---------------------------------------------------------------------------
|
||||
log "Running bun install..."
|
||||
sudo -u "$SERVICE_USER" bun install
|
||||
run_as_service bun install
|
||||
|
||||
log "Building daemon binary..."
|
||||
sudo -u "$SERVICE_USER" bun run build:daemon
|
||||
run_as_service bun run build:daemon
|
||||
|
||||
log "Building agent service..."
|
||||
sudo -u "$SERVICE_USER" bun run build:agents
|
||||
run_as_service bun run build:agents
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 7. Environment file
|
||||
@@ -161,6 +173,9 @@ if [[ ! -f "$ENV_FILE" ]]; then
|
||||
warn "Edit $ENV_FILE with real values before starting services."
|
||||
else
|
||||
log ".env already exists at $ENV_FILE"
|
||||
# Ensure correct ownership and permissions on existing .env
|
||||
chown "$SERVICE_USER":"$SERVICE_USER" "$ENV_FILE"
|
||||
chmod 600 "$ENV_FILE"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -190,19 +205,25 @@ done
|
||||
systemctl daemon-reload
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 10. Firewall (deny-by-default posture)
|
||||
# 10. Firewall (deny-by-default, explicit allow for Tailscale)
|
||||
# ---------------------------------------------------------------------------
|
||||
log "Configuring firewall..."
|
||||
if ! ufw status 2>/dev/null | grep -q "Status: active"; then
|
||||
ufw allow 22/tcp
|
||||
ufw default deny incoming
|
||||
ufw default allow outgoing
|
||||
|
||||
# Allow all traffic on the Tailscale interface (if present)
|
||||
# This lets the agent and engine ports be reached over the private overlay.
|
||||
ufw allow in on tailscale0 || warn "tailscale0 not present yet; rule will activate when interface appears"
|
||||
|
||||
ufw --force enable
|
||||
log "Firewall enabled: SSH (22) allowed, all other incoming denied."
|
||||
warn "Agent and RivetKit ports are NOT exposed publicly."
|
||||
warn "Access is via Tailscale or direct private IP only."
|
||||
log "Firewall enabled: SSH (22) allowed, tailscale0 allowed."
|
||||
warn "Agent and RivetKit ports are NOT exposed on public interfaces."
|
||||
warn "Reachability is via Tailscale (tailscale0) only."
|
||||
else
|
||||
log "Firewall already active."
|
||||
log "Firewall already active. Ensuring tailscale0 rule..."
|
||||
ufw allow in on tailscale0 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -217,15 +238,22 @@ if [[ -n "${TAILSCALE_AUTHKEY:-}" ]]; then
|
||||
--hostname "${TAILSCALE_HOSTNAME:-zopu-runtime}" \
|
||||
--accept-routes
|
||||
log "Tailscale configured: $(tailscale ip -4 2>/dev/null || echo 'waiting for IP')"
|
||||
|
||||
# Re-apply the tailscale0 firewall rule now that the interface exists
|
||||
ufw allow in on tailscale0 2>/dev/null || true
|
||||
else
|
||||
warn "TAILSCALE_AUTHKEY not set — skipping Tailscale setup."
|
||||
warn "Without Tailscale, services are reachable only via localhost."
|
||||
warn "To use a private network interface, add an explicit UFW rule:"
|
||||
warn " ufw allow in on <interface>"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 12. Disk-space monitoring cron
|
||||
# /etc/cron.d format REQUIRES a username field.
|
||||
# ---------------------------------------------------------------------------
|
||||
log "Installing disk-space monitor (daily at 06:00)..."
|
||||
CRON_LINE="0 6 * * * $DEPLOY_DIR/scripts/disk-monitor.sh --warn-percent 80 >> /var/log/zopu/disk-monitor.log 2>&1"
|
||||
CRON_LINE="0 6 * * * ${SERVICE_USER} ${DEPLOY_DIR}/scripts/disk-monitor.sh --warn-percent 80 >> /var/log/zopu/disk-monitor.log 2>&1"
|
||||
echo "$CRON_LINE" > /etc/cron.d/zopu-disk-monitor
|
||||
chmod 644 /etc/cron.d/zopu-disk-monitor
|
||||
|
||||
|
||||
Reference in New Issue
Block a user