From d31fef2f24bb6332b91ebe0941bdcf3f545e7572 Mon Sep 17 00:00:00 2001 From: NixReaper Date: Sat, 29 Aug 2026 21:59:00 -0500 Subject: [PATCH] Add deploy script --- deploy.sh | 298 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 deploy.sh diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..8f8dfb9 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,298 @@ +#!/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 ""