#!/usr/bin/env bash # ────────────────────────────────────────────────────────────────────────────── # NixPanel Licensing Server — Deploy Script # Run this on the server that will host license.nixpanel.io # Requires: Ubuntu 22.04+ / Debian 12+, run as root # ────────────────────────────────────────────────────────────────────────────── set -euo pipefail RED='\033[0;31m'; GREEN='\033[0;32m'; CYAN='\033[0;36m' YELLOW='\033[1;33m'; BOLD='\033[1m'; RESET='\033[0m' info() { echo -e "${CYAN}[INFO]${RESET} $*"; } success() { echo -e "${GREEN}[ OK ]${RESET} $*"; } warn() { echo -e "${YELLOW}[WARN]${RESET} $*"; } error() { echo -e "${RED}[ERR ]${RESET} $*" >&2; exit 1; } step() { echo -e "\n${BOLD}${CYAN}━━━ $* ━━━${RESET}"; } [[ $EUID -ne 0 ]] && error "Must be run as root" INSTALL_DIR="/opt/nixpanel-licensing" BIN_DIR="$INSTALL_DIR/bin" KEYS_DIR="$INSTALL_DIR/keys" LOG_DIR="/var/log/nixpanel-licensing" SRC_DIR="$INSTALL_DIR/src" STEP_DIR="/var/lib/nixpanel-licensing/install" GITHUB_REPO="NixReaper/nixpanel-licensing" mkdir -p "$INSTALL_DIR" "$BIN_DIR" "$KEYS_DIR" "$LOG_DIR" "$SRC_DIR" "$STEP_DIR" chmod 700 "$KEYS_DIR" mark_done() { touch "$STEP_DIR/$1.done"; } step_done() { [[ -f "$STEP_DIR/$1.done" ]]; } echo "" echo -e "${BOLD}${CYAN} NixPanel Licensing Server — Deployer${RESET}" echo -e " Repo: https://github.com/${GITHUB_REPO}" echo "" # ── 1. System deps ──────────────────────────────────────────────────────────── step "Installing system dependencies" if ! step_done "sys_deps"; then export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y -qq \ build-essential pkg-config libssl-dev libmariadb-dev \ curl wget git unzip ca-certificates gnupg \ mariadb-server mariadb-client \ apache2 certbot python3-certbot-apache \ openssl mark_done "sys_deps" fi success "System dependencies installed" # ── 2. Rust ─────────────────────────────────────────────────────────────────── step "Installing Rust toolchain" if ! step_done "rust"; then curl -fsSL https://sh.rustup.rs | sh -s -- -y --default-toolchain stable --profile minimal mark_done "rust" fi source "$HOME/.cargo/env" 2>/dev/null || true CARGO=$(command -v cargo) || error "cargo not found" success "Rust $(rustc --version)" # ── 3. MariaDB ──────────────────────────────────────────────────────────────── step "Configuring MariaDB" if ! step_done "mariadb"; then systemctl enable --now mariadb DB_PASS=$(openssl rand -hex 24) mysql -u root < "$INSTALL_DIR/.db_pass" chmod 600 "$INSTALL_DIR/.db_pass" mark_done "mariadb" else DB_PASS=$(cat "$INSTALL_DIR/.db_pass") fi success "MariaDB ready" # ── 4. Clone / update source ────────────────────────────────────────────────── step "Fetching source" if [[ -d "$SRC_DIR/.git" ]]; then info "Updating existing checkout…" git -C "$SRC_DIR" pull --ff-only else git clone "https://github.com/${GITHUB_REPO}.git" "$SRC_DIR" fi success "Source at $SRC_DIR" # ── 5. Build ────────────────────────────────────────────────────────────────── step "Building binaries (release)" cd "$SRC_DIR" $CARGO build --release cp target/release/nixpanel-licensing "$BIN_DIR/nixpanel-licensing" cp target/release/keygen "$BIN_DIR/nixpanel-keygen" chmod 755 "$BIN_DIR/nixpanel-licensing" "$BIN_DIR/nixpanel-keygen" success "Binaries built → $BIN_DIR" # ── 6. RSA keys ─────────────────────────────────────────────────────────────── step "RSA-4096 license signing keys" if ! step_done "keygen"; then info "Generating RSA-4096 keypair (this takes a moment)…" mkdir -p "$SRC_DIR/keys" "$BIN_DIR/nixpanel-keygen" cp "$SRC_DIR/keys/private.pem" "$KEYS_DIR/license_private.pem" cp "$SRC_DIR/keys/public.pem" "$KEYS_DIR/license_public.pem" chmod 600 "$KEYS_DIR/license_private.pem" chmod 644 "$KEYS_DIR/license_public.pem" mark_done "keygen" fi success "Keys → $KEYS_DIR" info "Public key (distribute to panel nodes):" echo "" cat "$KEYS_DIR/license_public.pem" echo "" # ── 7. Secrets + env ────────────────────────────────────────────────────────── step "Generating secrets" if ! step_done "secrets"; then JWT_SECRET=$(openssl rand -hex 64) API_KEY=$(openssl rand -hex 32) echo "$JWT_SECRET" > "$INSTALL_DIR/.jwt_secret" echo "$API_KEY" > "$INSTALL_DIR/.api_key" chmod 600 "$INSTALL_DIR/.jwt_secret" "$INSTALL_DIR/.api_key" mark_done "secrets" else JWT_SECRET=$(cat "$INSTALL_DIR/.jwt_secret") API_KEY=$(cat "$INSTALL_DIR/.api_key") fi echo "" info "Enter your server's public hostname (e.g. license.nixpanel.io):" read -rp " Hostname: " SERVER_HOST SERVER_HOST="${SERVER_HOST:-license.nixpanel.io}" cat > "$INSTALL_DIR/licensing.env" </dev/null || true export $(grep -v '^#' "$INSTALL_DIR/licensing.env" | xargs) "$BIN_DIR/nixpanel-licensing" & SERVER_PID=$! sleep 3 # Create admin via API HTTP_STATUS=$(curl -s -o /tmp/admin_create_resp.json -w "%{http_code}" \ -X POST "http://127.0.0.1:3000/api/v1/admin/bootstrap" \ -H "Content-Type: application/json" \ -d "{\"username\":\"${ADMIN_USER}\",\"password\":\"${ADMIN_PASS}\",\"email\":\"${ADMIN_EMAIL}\"}") kill "$SERVER_PID" 2>/dev/null || true if [[ "$HTTP_STATUS" == "200" || "$HTTP_STATUS" == "201" ]]; then success "Admin account created" else warn "Bootstrap returned HTTP $HTTP_STATUS — admin may already exist, or set one up manually" cat /tmp/admin_create_resp.json 2>/dev/null || true echo "" fi mark_done "admin" fi # ── 9. systemd service ──────────────────────────────────────────────────────── step "Installing systemd service" cat > /etc/systemd/system/nixpanel-licensing.service < /etc/apache2/sites-available/nixpanel-licensing.conf < ServerName ${SERVER_HOST} # Redirect all HTTP to HTTPS (certbot will update this after SSL) RewriteEngine On RewriteRule ^(.*)$ https://%{HTTP_HOST}%1 [R=301,L] ServerName ${SERVER_HOST} ProxyPreserveHost On ProxyPass / http://127.0.0.1:3000/ ProxyPassReverse / http://127.0.0.1:3000/ # Security headers Header always set X-Frame-Options "DENY" Header always set X-Content-Type-Options "nosniff" Header always set X-XSS-Protection "1; mode=block" ErrorLog ${LOG_DIR}/apache-error.log CustomLog ${LOG_DIR}/apache-access.log combined # SSL placeholder — certbot will fill these in # SSLEngine on # SSLCertificateFile ... # SSLCertificateKeyFile ... APACHEEOF a2ensite nixpanel-licensing a2dissite 000-default 2>/dev/null || true systemctl enable --now apache2 apache2ctl configtest && systemctl reload apache2 success "Apache configured for ${SERVER_HOST}" # ── 11. SSL ─────────────────────────────────────────────────────────────────── step "SSL certificate (Let's Encrypt)" echo "" echo -e " ${BOLD}Obtain SSL cert now?${RESET} (requires DNS A record pointing ${SERVER_HOST} → this server)" read -rp " Get SSL cert? [Y/n]: " DO_SSL DO_SSL="${DO_SSL:-Y}" if [[ "${DO_SSL,,}" == "y" ]]; then read -rp " Email for Let's Encrypt notices: " LE_EMAIL certbot --apache -d "$SERVER_HOST" --non-interactive --agree-tos -m "$LE_EMAIL" \ && success "SSL certificate installed" \ || warn "certbot failed — run manually: certbot --apache -d ${SERVER_HOST}" else info "Skipped — run later: certbot --apache -d ${SERVER_HOST}" fi # ── Done ────────────────────────────────────────────────────────────────────── SERVER_IP=$(hostname -I | awk '{print $1}') echo "" echo -e "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" echo -e "${BOLD}${GREEN} Licensing Server Deployed!${RESET}" echo -e "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" echo "" echo -e " ${BOLD}API:${RESET} https://${SERVER_HOST}" echo -e " ${BOLD}Health check:${RESET} curl https://${SERVER_HOST}/health" echo -e " ${BOLD}Logs:${RESET} ${LOG_DIR}/" echo -e " ${BOLD}Config:${RESET} ${INSTALL_DIR}/licensing.env" echo -e " ${BOLD}Public key:${RESET} ${KEYS_DIR}/license_public.pem" echo "" echo -e " ${BOLD}Internal API key${RESET} (add to website.env LICENSING_SERVER_API_KEY):" echo -e " ${YELLOW}$(cat "$INSTALL_DIR/.api_key")${RESET}" echo "" echo -e " ${BOLD}Next steps:${RESET}" echo -e " 1. Copy public key to panel nodes: ${KEYS_DIR}/license_public.pem" echo -e " 2. Set LICENSING_SERVER_URL=https://${SERVER_HOST} in nixpanel.io website.env" echo -e " 3. Create license plans via: POST https://${SERVER_HOST}/api/v1/admin/plans" echo -e " 4. Status: systemctl status nixpanel-licensing" echo ""