#!/usr/bin/env bash # ────────────────────────────────────────────────────────────────────────────── # NixPanel Website — Deploy Script # Deploys nixpanel.io (PHP frontend + customer portal) to a server. # Run as root on the target server. # ────────────────────────────────────────────────────────────────────────────── 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" SITE_DIR="/var/www/nixpanel-website" GITHUB_REPO="NixReaper/nixpanel-website" SERVER_NAME="${1:-nixpanel.io}" echo "" echo -e "${BOLD}${CYAN} NixPanel Website — Deployer${RESET}" echo -e " Domain: ${SERVER_NAME}" echo "" # ── 1. System deps ──────────────────────────────────────────────────────────── step "Installing system dependencies" export DEBIAN_FRONTEND=noninteractive apt-get update -qq # ondrej/php PPA for latest PHP on Ubuntu 24.04 apt-get install -y -qq ca-certificates gnupg software-properties-common if ! grep -rq "ondrej/php" /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null; then add-apt-repository -y ppa:ondrej/php apt-get update -qq fi apt-get install -y -qq \ apache2 \ php8.3 php8.3-fpm php8.3-cli php8.3-mysql php8.3-curl \ php8.3-mbstring php8.3-xml php8.3-zip php8.3-gd php8.3-intl \ mariadb-server mariadb-client \ certbot python3-certbot-apache \ curl wget git unzip # Install Composer if ! command -v composer &>/dev/null; then info "Installing Composer…" curl -fsSL https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer fi success "Dependencies installed" # ── 2. MariaDB ──────────────────────────────────────────────────────────────── step "Configuring MariaDB" systemctl enable --now mariadb if ! mysql -u root -e "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='nixpanel_website'" 2>/dev/null | grep -q nixpanel_website; then DB_PASS=$(openssl rand -hex 24) mysql -u root < /root/.nixpanel_website_db_pass chmod 600 /root/.nixpanel_website_db_pass success "Database created (password saved to /root/.nixpanel_website_db_pass)" else DB_PASS=$(cat /root/.nixpanel_website_db_pass 2>/dev/null || echo "") info "Database already exists" fi # ── 3. Clone / update source ────────────────────────────────────────────────── step "Deploying source code" if [[ -d "$SITE_DIR/.git" ]]; then info "Updating existing deployment…" git -C "$SITE_DIR" pull --ff-only else git clone "https://github.com/${GITHUB_REPO}.git" "$SITE_DIR" fi success "Source at $SITE_DIR" # ── 4. Composer dependencies ────────────────────────────────────────────────── step "Installing PHP dependencies" cd "$SITE_DIR" composer install --no-dev --optimize-autoloader --quiet success "Composer packages installed" # ── 5. Run database migrations ──────────────────────────────────────────────── step "Running database migrations" if [[ -f "$SITE_DIR/migrations/001_schema.sql" ]]; then mysql -u nixpanel_web -p"${DB_PASS}" nixpanel_website < "$SITE_DIR/migrations/001_schema.sql" success "Migrations applied" else warn "No migration file found at migrations/001_schema.sql" fi # ── 6. Environment file ─────────────────────────────────────────────────────── step "Configuring environment" if [[ ! -f "$SITE_DIR/.env" ]]; then echo "" info "Setting up .env — press Enter to leave values blank (configure later)" echo "" read -rp " Stripe secret key (sk_live_...): " STRIPE_SK; STRIPE_SK="${STRIPE_SK:-}" read -rp " Stripe publishable key (pk_live_...): " STRIPE_PK; STRIPE_PK="${STRIPE_PK:-}" read -rp " Stripe webhook secret (whsec_...): " STRIPE_WH; STRIPE_WH="${STRIPE_WH:-}" echo "" info "Stripe Price IDs (leave blank to fill in later):" read -rp " STRIPE_PRICE_SOLO_MONTHLY: " P_SOLO_M; P_SOLO_M="${P_SOLO_M:-}" read -rp " STRIPE_PRICE_SOLO_ANNUAL: " P_SOLO_A; P_SOLO_A="${P_SOLO_A:-}" read -rp " STRIPE_PRICE_HOST_MONTHLY: " P_HOST_M; P_HOST_M="${P_HOST_M:-}" read -rp " STRIPE_PRICE_HOST_ANNUAL: " P_HOST_A; P_HOST_A="${P_HOST_A:-}" read -rp " STRIPE_PRICE_AGENCY_MONTHLY: " P_AGCY_M; P_AGCY_M="${P_AGCY_M:-}" read -rp " STRIPE_PRICE_AGENCY_ANNUAL: " P_AGCY_A; P_AGCY_A="${P_AGCY_A:-}" echo "" read -rp " SMTP host [smtp.mailgun.org]: " MAIL_HOST; MAIL_HOST="${MAIL_HOST:-smtp.mailgun.org}" read -rp " SMTP user: " MAIL_USER; MAIL_USER="${MAIL_USER:-}" read -rsp " SMTP password: " MAIL_PASS; MAIL_PASS="${MAIL_PASS:-}"; echo "" echo "" read -rp " Licensing server URL [https://license.nixpanel.io]: " LIC_URL LIC_URL="${LIC_URL:-https://license.nixpanel.io}" read -rp " Licensing server API key: " LIC_KEY; LIC_KEY="${LIC_KEY:-}" SESSION_SECRET=$(openssl rand -hex 64) cat > "$SITE_DIR/.env" </dev/null || true cat > /etc/apache2/sites-available/nixpanel-website.conf < ServerName ${SERVER_NAME} ServerAlias www.${SERVER_NAME} # DocumentRoot points directly to public/ — only one .htaccess needed DocumentRoot ${SITE_DIR}/public Options -Indexes +FollowSymLinks AllowOverride All Require all granted # Pass PHP to PHP-FPM SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost" # Security headers Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin" ErrorLog /var/log/apache2/nixpanel-website-error.log CustomLog /var/log/apache2/nixpanel-website-access.log combined # HTTPS — populated by certbot ServerName ${SERVER_NAME} ServerAlias www.${SERVER_NAME} DocumentRoot ${SITE_DIR}/public Options -Indexes +FollowSymLinks AllowOverride All Require all granted SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost" Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin" Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains" ErrorLog /var/log/apache2/nixpanel-website-error.log CustomLog /var/log/apache2/nixpanel-website-access.log combined # SSL — certbot will fill these in # SSLEngine on # SSLCertificateFile ... # SSLCertificateKeyFile ... APACHEEOF a2ensite nixpanel-website systemctl enable --now apache2 php8.3-fpm apache2ctl configtest && systemctl reload apache2 success "Apache configured" # ── 9. SSL ──────────────────────────────────────────────────────────────────── step "SSL certificate (Let's Encrypt)" echo "" echo -e " ${BOLD}Obtain SSL cert now?${RESET} (requires DNS pointing ${SERVER_NAME} → 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_NAME" -d "www.${SERVER_NAME}" \ --non-interactive --agree-tos -m "$LE_EMAIL" --redirect \ && success "SSL certificate installed" \ || warn "certbot failed — run manually: certbot --apache -d ${SERVER_NAME}" else info "Skipped — run later: certbot --apache -d ${SERVER_NAME}" fi # ── Done ────────────────────────────────────────────────────────────────────── SERVER_IP=$(hostname -I | awk '{print $1}') echo "" echo -e "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" echo -e "${BOLD}${GREEN} NixPanel Website Deployed!${RESET}" echo -e "${BOLD}${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}" echo "" echo -e " ${BOLD}URL:${RESET} https://${SERVER_NAME}" echo -e " ${BOLD}Root:${RESET} ${SITE_DIR}" echo -e " ${BOLD}Config:${RESET} ${SITE_DIR}/.env" echo -e " ${BOLD}Logs:${RESET} /var/log/apache2/nixpanel-website-*.log" echo "" echo -e " ${BOLD}To redeploy after code changes:${RESET}" echo -e " git -C ${SITE_DIR} pull && composer install -d ${SITE_DIR} --no-dev -o" echo "" if [[ -z "$(grep 'STRIPE_SECRET_KEY=sk_' "$SITE_DIR/.env" 2>/dev/null || true)" ]]; then echo -e " ${YELLOW}⚠ Stripe keys not yet configured — edit ${SITE_DIR}/.env${RESET}" fi echo ""