#!/bin/bash # Next Workspace (NextWks) - Bare-Metal Installer # Deploys compiled binaries to /opt/nextwks/ for production use # # Usage: # ./install.sh # Build and install # ./install.sh --skip-build # Install existing binaries only # ./install.sh --config-only # Generate config only # ./install.sh --uninstall # Remove installation set -euo pipefail # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' error() { echo -e "${RED}Error:${NC} $1" >&2; } success() { echo -e "${GREEN}$1${NC}"; } info() { echo -e "${BLUE}$1${NC}"; } warn() { echo -e "${YELLOW}Warning:${NC} $1"; } # Configuration REPO_DIR="$(cd "$(dirname "$0")" && pwd)" INSTALL_DIR="/opt/nextwks" BIN_DIR="${INSTALL_DIR}/bin" DATA_DIR="${INSTALL_DIR}/data" MODULES_DIR="${INSTALL_DIR}/modules" CONFIG_FILE="${INSTALL_DIR}/config.yaml" SERVICE_FILE="/etc/systemd/system/nextwks.service" # Parse arguments SKIP_BUILD=false CONFIG_ONLY=false UNINSTALL=false for arg in "$@"; do case "$arg" in --skip-build) SKIP_BUILD=true ;; --config-only) CONFIG_ONLY=true ;; --uninstall) UNINSTALL=true ;; *) error "Unknown argument: $arg"; exit 1 ;; esac done # --- Uninstall --- if [ "$UNINSTALL" = true ]; then info "Uninstalling Next Workspace..." if [ -f "$SERVICE_FILE" ]; then systemctl stop nextwks 2>/dev/null || true systemctl disable nextwks 2>/dev/null || true rm -f "$SERVICE_FILE" systemctl daemon-reload info "Removed systemd service" fi if [ -d "$INSTALL_DIR" ]; then rm -rf "$INSTALL_DIR" success "Removed $INSTALL_DIR" else info "No installation found at $INSTALL_DIR" fi success "Uninstall complete" exit 0 fi # --- Check Authelia --- if [ ! -f "/opt/authelia/authelia" ]; then warn "Authelia is not installed at /opt/authelia/" warn "User management requires Authelia to function." warn "Install with: bash scripts/install-authelia.sh" echo "" fi # --- Build --- if [ "$SKIP_BUILD" = false ] && [ "$CONFIG_ONLY" = false ]; then info "Building Next Workspace core..." if ! command -v go &>/dev/null; then error "Go is not installed. Install Go 1.22+ first." exit 1 fi cd "$REPO_DIR/src" # Build the core binary go build -o "$REPO_DIR/app/core" -ldflags="-s -w" . success "Core binary built: app/core" fi # --- Install --- if [ "$CONFIG_ONLY" = false ]; then info "Installing to $INSTALL_DIR..." # Create directory structure mkdir -p "$BIN_DIR" "$DATA_DIR" "$MODULES_DIR" # Copy binary if [ -f "$REPO_DIR/app/core" ]; then cp "$REPO_DIR/app/core" "$BIN_DIR/core" chmod 755 "$BIN_DIR/core" success "Installed binary to $BIN_DIR/core" else error "Binary not found. Run without --skip-build or build manually." exit 1 fi # Copy modules if any exist if [ -d "$REPO_DIR/app/modules" ] && [ "$(ls -A "$REPO_DIR/app/modules" 2>/dev/null)" ]; then cp -r "$REPO_DIR/app/modules"/* "$MODULES_DIR/" success "Installed modules" fi fi # --- Configuration --- info "Generating configuration..." if [ ! -f "$CONFIG_FILE" ]; then # Generate unique secrets ADMIN_SECRET=$(openssl rand -hex 32 2>/dev/null || head -c 32 /dev/urandom | xxd -p -c 32) SESSION_SECRET=$(openssl rand -hex 32 2>/dev/null || head -c 32 /dev/urandom | xxd -p -c 32) cat > "$CONFIG_FILE" << CONFIGEOF # Next Workspace (NextWks) - Production Configuration # Auto-generated by install.sh on $(date) server: host: "0.0.0.0" port: 8080 admin: secret_token: "${ADMIN_SECRET}" database: type: "sqlite" path: "${DATA_DIR}/nextwks.db" authelia: host: "http://127.0.0.1:9091" config_path: "/opt/authelia/configuration.yml" users_db_path: "/opt/authelia/users_database.yml" oidc: client_id: "nextwks" client_secret: "" redirect_url: "https://sechpoint.app/auth/callback" domain: "sechpoint.app" smtp: host: "" port: 587 username: "" password: "" from: "noreply@nextwks.local" session: secret: "${SESSION_SECRET}" expiry_minutes: 60 CONFIGEOF chmod 600 "$CONFIG_FILE" success "Configuration generated: $CONFIG_FILE" warn "Admin secret token: ${ADMIN_SECRET}" warn "Save this token! You need it for admin API access." else info "Configuration already exists at $CONFIG_FILE (not overwritten)" fi # --- Systemd Service --- if [ "$CONFIG_ONLY" = false ]; then info "Setting up systemd service..." cat > "$SERVICE_FILE" << SERVICEEOF [Unit] Description=Next Workspace (NextWks) Core After=network.target authelia.service Wants=authelia.service [Service] Type=simple User=root WorkingDirectory=${INSTALL_DIR} ExecStart=${BIN_DIR}/core -config ${CONFIG_FILE} Restart=always RestartSec=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target SERVICEEOF systemctl daemon-reload success "Systemd service created: $SERVICE_FILE" info "Enable with: systemctl enable --now nextwks" info "Start with: systemctl start nextwks" info "Status with: systemctl status nextwks" fi # --- Summary --- echo "" success "═══════════════════════════════════════════" success " Next Workspace (NextWks) installed!" success "═══════════════════════════════════════════" echo "" info " Binary: ${BIN_DIR}/core" info " Config: ${CONFIG_FILE}" info " Data: ${DATA_DIR}/" info " Service: nextwks" echo "" info " Admin UI: http://localhost:8080/admin" info " Health API: http://localhost:8080/api/health" echo "" info " Start with: systemctl start nextwks" info " Logs: journalctl -u nextwks -f" echo ""