feat(installer): run as root with sudo where needed, systemd service user-aware

This commit is contained in:
Claus Lohmar 2026-06-14 16:00:41 +00:00
parent 7cdff22565
commit 17170c762a

View file

@ -20,6 +20,18 @@ info() { echo -e "${BLUE}$1${NC}"; }
warn() { echo -e "${YELLOW}$1${NC}"; }
header() { echo -e "\n${BOLD}${CYAN}$1${NC}"; }
# ============================================================
# USER & SUDO
# ============================================================
SYS_USER="${SUDO_USER:-$USER}"
SYS_HOME=$(eval echo "~$SYS_USER")
[ "$EUID" -eq 0 ] && SUDO="" || SUDO="sudo"
if [ -z "$SUDO" ] && [ "$EUID" -ne 0 ]; then
error "This script needs root for /opt/ and systemd. Use: sudo bash install.sh"
exit 1
fi
# ============================================================
# PATHS
# ============================================================
@ -29,7 +41,7 @@ BIN_DIR="${INSTALL_DIR}/bin"
DATA_DIR="${INSTALL_DIR}/data"
STATIC_DIR="${INSTALL_DIR}/static"
CONFIG_FILE="${INSTALL_DIR}/config.yaml"
ENV_FILE="${REPO_DIR}/.env"
ENV_FILE="${SYS_HOME}/.nextwks-env"
AUTHELIA_DIR="/opt/authelia"
AUTHELIA_CONFIG="${AUTHELIA_DIR}/configuration.yml"
SERVICE_FILE="/etc/systemd/system/nextwks.service"
@ -69,9 +81,10 @@ if [ ! -f "$REPO_DIR/src/main.go" ]; then
error "git is required. Install it first: apt install git"
exit 1
fi
CLONE_DIR="/tmp/nextwks-install"
CLONE_DIR="${SYS_HOME}/nextwks"
rm -rf "$CLONE_DIR" 2>/dev/null
git clone --depth 1 "$REPO_URL" "$CLONE_DIR"
chown -R "$SYS_USER:$SYS_USER" "$CLONE_DIR" 2>/dev/null || true
REPO_DIR="$CLONE_DIR"
success "Cloned to $REPO_DIR"
fi
@ -98,11 +111,11 @@ done
# ============================================================
if [ "$MODE" = "uninstall" ]; then
info "Uninstalling Next Workspace..."
systemctl stop nextwks 2>/dev/null || true
systemctl disable nextwks 2>/dev/null || true
rm -f "$SERVICE_FILE"
systemctl daemon-reload
[ -d "$INSTALL_DIR" ] && { rm -rf "$INSTALL_DIR"; success "Removed $INSTALL_DIR"; }
$SUDO systemctl stop nextwks 2>/dev/null || true
$SUDO systemctl disable nextwks 2>/dev/null || true
$SUDO rm -f "$SERVICE_FILE"
$SUDO systemctl daemon-reload
[ -d "$INSTALL_DIR" ] && { $SUDO rm -rf "$INSTALL_DIR"; success "Removed $INSTALL_DIR"; }
success "Uninstall complete"
exit 0
fi
@ -114,8 +127,8 @@ if [ "$MODE" = "status" ]; then
echo ""; header "Next Workspace Status"
[ -f "${BIN_DIR}/core" ] && success "✓ Binary: ${BIN_DIR}/core" || warn "✗ Binary: not found"
[ -f "$CONFIG_FILE" ] && success "✓ Config: $CONFIG_FILE" || warn "✗ Config: not found"
systemctl is-active --quiet nextwks 2>/dev/null && success "✓ Service: running" || info " Service: stopped"
systemctl is-active --quiet authelia 2>/dev/null && success "✓ Authelia: running" || info " Authelia: stopped"
$SUDO systemctl is-active --quiet nextwks 2>/dev/null && success "✓ Service: running" || info " Service: stopped"
$SUDO systemctl is-active --quiet authelia 2>/dev/null && success "✓ Authelia: running" || info " Authelia: stopped"
command -v curl &>/dev/null && [ "$(curl -s --max-time 2 http://localhost:8080/api/health 2>/dev/null)" = '{"status":"ok"}' ] && success "✓ API: OK" || info " API: not responding"
echo ""; exit 0
fi
@ -241,9 +254,11 @@ success "Binary built: app/core (${VERSION})"
# INSTALL
# ============================================================
header "── Installing ──"
mkdir -p "$BIN_DIR" "$DATA_DIR" "$STATIC_DIR"
cp "$REPO_DIR/app/core" "$BIN_DIR/core" && chmod 755 "$BIN_DIR/core"
[ -d "$REPO_DIR/app/static" ] && cp -r "$REPO_DIR/app/static"/* "$STATIC_DIR/"
$SUDO mkdir -p "$BIN_DIR" "$DATA_DIR" "$STATIC_DIR"
$SUDO cp "$REPO_DIR/app/core" "$BIN_DIR/core"
$SUDO chmod 755 "$BIN_DIR/core"
$SUDO chown -R "$SYS_USER:$SYS_USER" "$DATA_DIR" 2>/dev/null || true
[ -d "$REPO_DIR/app/static" ] && $SUDO cp -r "$REPO_DIR/app/static"/* "$STATIC_DIR/"
success "Copied files to $INSTALL_DIR/"
# ============================================================
@ -253,7 +268,7 @@ header "── Configuration ──"
ADMIN_TOKEN=$(openssl rand -hex 32 2>/dev/null || head -c32 /dev/urandom | xxd -p -c32)
SESSION_KEY=$(openssl rand -hex 32 2>/dev/null || head -c32 /dev/urandom | xxd -p -c32)
cat > "$CONFIG_FILE" << CONFIGEOF
$SUDO tee "$CONFIG_FILE" > /dev/null << CONFIGEOF
# Next Workspace — $(date +%Y-%m-%d)
server:
host: "0.0.0.0"
@ -283,14 +298,14 @@ session:
secret: "${SESSION_KEY}"
expiry_minutes: 60
CONFIGEOF
chmod 600 "$CONFIG_FILE"
$SUDO chmod 600 "$CONFIG_FILE"
success "Config: $CONFIG_FILE"
# ============================================================
# SYSTEMD
# ============================================================
header "── Systemd ──"
cat > "$SERVICE_FILE" << SERVICEEOF
$SUDO tee "$SERVICE_FILE" > /dev/null << SERVICEEOF
[Unit]
Description=Next Workspace (NextWks) Core
After=network.target authelia.service
@ -298,7 +313,7 @@ Wants=authelia.service
[Service]
Type=simple
User=root
User=${SYS_USER}
WorkingDirectory=${INSTALL_DIR}
ExecStart=${BIN_DIR}/core -config ${CONFIG_FILE}
Restart=always
@ -316,7 +331,7 @@ ReadOnlyPaths=${INSTALL_DIR}/config.yaml ${INSTALL_DIR}/static
[Install]
WantedBy=multi-user.target
SERVICEEOF
systemctl daemon-reload
$SUDO systemctl daemon-reload
success "Service: $SERVICE_FILE"
# ============================================================
@ -337,7 +352,7 @@ if [ -f "${AUTHELIA_DIR}/authelia" ]; then
# Hash current admin password (if users exist) or generate one
ADMIN_HASH=$("${AUTHELIA_DIR}/authelia" crypto hash generate --password "$(openssl rand -base64 12)" 2>/dev/null | awk '{print $NF}' || echo "\$argon2id\$v=19\$m=65536,t=3,p=4\$placeholder\$placeholder")
cat > "$AUTHELIA_CONFIG" << AUTHEOF
$SUDO tee "$AUTHELIA_CONFIG" > /dev/null << AUTHEOF
theme: light
server:
host: 0.0.0.0
@ -405,7 +420,7 @@ $(echo "$OIDC_KEY" | sed 's/^/ /')
pre_configured_consent_duration: "1 year"
userinfo_signed_response_alg: "none"
AUTHEOF
chmod 600 "$AUTHELIA_CONFIG"
$SUDO chmod 600 "$AUTHELIA_CONFIG"
success "Authelia config written"
# Create initial users_database.yml (needed for Authelia to start)
@ -422,11 +437,11 @@ users:
email: "${ADMIN_EMAIL:-admin@local}"
groups: [admins]
USERSDB
chmod 600 "${AUTHELIA_DIR}/users_database.yml"
$SUDO chmod 600 "${AUTHELIA_DIR}/users_database.yml"
success "Users database created"
fi
systemctl restart authelia 2>/dev/null && info "Authelia restarted" || info "Authelia not running (will start later)"
$SUDO systemctl restart authelia 2>/dev/null && info "Authelia restarted" || info "Authelia not running (will start later)"
fi
# ============================================================
@ -477,8 +492,8 @@ info " Workspace: ${NEXTWKS_URL}"
info " Auth: ${AUTH_URL}"
info " Admin UI: ${NEXTWKS_URL}/admin"
echo ""
info " Start: systemctl enable --now nextwks"
info " Logs: journalctl -u nextwks -f"
info " Start: sudo systemctl enable --now nextwks"
info " Logs: sudo journalctl -u nextwks -f"
info " Status: ./install.sh --status"
echo ""
if [ -n "${ADMIN_PASS:-}" ]; then