Add deploy script
This commit is contained in:
@@ -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 <<SQL
|
||||
CREATE DATABASE IF NOT EXISTS nixpanel_licensing CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE USER IF NOT EXISTS 'nixpanel_license'@'127.0.0.1' IDENTIFIED BY '${DB_PASS}';
|
||||
GRANT ALL PRIVILEGES ON nixpanel_licensing.* TO 'nixpanel_license'@'127.0.0.1';
|
||||
FLUSH PRIVILEGES;
|
||||
SQL
|
||||
|
||||
echo "$DB_PASS" > "$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" <<EOF
|
||||
HOST=127.0.0.1
|
||||
PORT=3000
|
||||
RUST_LOG=nixpanel_licensing=info,tower_http=warn
|
||||
DATABASE_URL=mysql://nixpanel_license:${DB_PASS}@127.0.0.1:3306/nixpanel_licensing
|
||||
JWT_SECRET=${JWT_SECRET}
|
||||
JWT_EXPIRES_IN_SECS=86400
|
||||
LICENSE_PRIVATE_KEY_PATH=${KEYS_DIR}/license_private.pem
|
||||
LICENSE_PUBLIC_KEY_PATH=${KEYS_DIR}/license_public.pem
|
||||
LICENSE_TOKEN_TTL_DAYS=30
|
||||
LICENSE_GRACE_PERIOD_DAYS=7
|
||||
SERVER_URL=https://${SERVER_HOST}
|
||||
EOF
|
||||
chmod 600 "$INSTALL_DIR/licensing.env"
|
||||
success "Environment written → $INSTALL_DIR/licensing.env"
|
||||
|
||||
# ── 8. First admin account ────────────────────────────────────────────────────
|
||||
step "Creating initial admin account"
|
||||
if ! step_done "admin"; then
|
||||
echo ""
|
||||
read -rp " Admin username [admin]: " ADMIN_USER; ADMIN_USER="${ADMIN_USER:-admin}"
|
||||
read -rsp " Admin password: " ADMIN_PASS; echo ""
|
||||
read -rsp " Confirm password: " ADMIN_PASS2; echo ""
|
||||
[[ "$ADMIN_PASS" != "$ADMIN_PASS2" ]] && error "Passwords do not match"
|
||||
read -rp " Admin email: " ADMIN_EMAIL
|
||||
|
||||
# Start the server temporarily to run migrations, then use the API to create admin
|
||||
info "Starting server for first-run migration + admin creation…"
|
||||
source "$INSTALL_DIR/licensing.env" 2>/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 <<EOF
|
||||
[Unit]
|
||||
Description=NixPanel Licensing Server
|
||||
After=network.target mariadb.service
|
||||
Wants=mariadb.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
ExecStart=${BIN_DIR}/nixpanel-licensing
|
||||
WorkingDirectory=${INSTALL_DIR}
|
||||
EnvironmentFile=${INSTALL_DIR}/licensing.env
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
StandardOutput=append:${LOG_DIR}/server.log
|
||||
StandardError=append:${LOG_DIR}/server-error.log
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl enable nixpanel-licensing
|
||||
systemctl restart nixpanel-licensing
|
||||
success "nixpanel-licensing service running"
|
||||
|
||||
# ── 10. Apache reverse proxy ──────────────────────────────────────────────────
|
||||
step "Configuring Apache reverse proxy"
|
||||
a2enmod proxy proxy_http headers ssl rewrite
|
||||
cat > /etc/apache2/sites-available/nixpanel-licensing.conf <<APACHEEOF
|
||||
<VirtualHost *:80>
|
||||
ServerName ${SERVER_HOST}
|
||||
# Redirect all HTTP to HTTPS (certbot will update this after SSL)
|
||||
RewriteEngine On
|
||||
RewriteRule ^(.*)$ https://%{HTTP_HOST}%1 [R=301,L]
|
||||
</VirtualHost>
|
||||
|
||||
<VirtualHost *:443>
|
||||
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 ...
|
||||
</VirtualHost>
|
||||
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 ""
|
||||
Reference in New Issue
Block a user