#!/usr/bin/env bash # SnapReels One-Click VPS Installer # Target OS: Ubuntu 22.04 / 24.04 # App path expected: /var/www/snapreels set -Eeuo pipefail APP_NAME="snapreels" APP_DIR="/var/www/snapreels" APP_PORT="3000" DOMAIN="" EMAIL="" ENABLE_SSL="yes" MONGO_DB="snapreels" MONGO_USER="snapreels" MONGO_PASS="snapreels123456" LOG_FILE="/root/snapreels-install.log" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' log() { echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')] $*${NC}" | tee -a "$LOG_FILE" } warn() { echo -e "${YELLOW}[$(date '+%Y-%m-%d %H:%M:%S')] $*${NC}" | tee -a "$LOG_FILE" } err() { echo -e "${RED}[$(date '+%Y-%m-%d %H:%M:%S')] $*${NC}" | tee -a "$LOG_FILE" } on_error() { err "Installer failed on line $1. Check: $LOG_FILE" } trap 'on_error $LINENO' ERR require_root() { if [ "$(id -u)" -ne 0 ]; then err "Please run this installer as root." exit 1 fi } ask_inputs() { read -rp "Enter your domain (example.com): " DOMAIN while [ -z "${DOMAIN// }" ]; do read -rp "Domain cannot be empty. Enter your domain: " DOMAIN done read -rp "Enable SSL with Let's Encrypt? (yes/no) [yes]: " SSL_INPUT || true SSL_INPUT="${SSL_INPUT:-yes}" case "$SSL_INPUT" in yes|y|Y) ENABLE_SSL="yes" ;; no|n|N) ENABLE_SSL="no" ;; *) ENABLE_SSL="yes" ;; esac EMAIL="support@$DOMAIN" } check_app_files() { if [ ! -d "$APP_DIR" ]; then err "App directory not found: $APP_DIR" err "Upload/extract the SnapReels project there first." exit 1 fi if [ ! -f "$APP_DIR/package.json" ]; then err "package.json not found in $APP_DIR" exit 1 fi } install_base_packages() { log "Updating system packages..." export DEBIAN_FRONTEND=noninteractive apt-get update -y apt-get install -y ca-certificates curl wget gnupg unzip git nginx software-properties-common ufw } install_node() { if command -v node >/dev/null 2>&1; then log "Node already installed: $(node -v)" else log "Installing Node.js 20..." curl -fsSL https://deb.nodesource.com/setup_20.x | bash - apt-get install -y nodejs fi log "Node version: $(node -v)" log "NPM version: $(npm -v)" if command -v pm2 >/dev/null 2>&1; then log "PM2 already installed: $(pm2 -v)" else log "Installing PM2..." npm install -g pm2 hash -r log "PM2 version: $(pm2 -v)" fi } install_mongodb() { log "Installing MongoDB 7.0..." if [ ! -f /usr/share/keyrings/mongodb-server-7.0.gpg ]; then curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \ gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg --dearmor fi cat >/etc/apt/sources.list.d/mongodb-org-7.0.list </dev/null 2>&1; then break fi sleep 2 done if ! mongosh --quiet --eval "db.adminCommand('ping')" >/dev/null 2>&1; then err "MongoDB is running but not accepting connections." journalctl -u mongod --no-pager -n 50 || true exit 1 fi log "Creating MongoDB user if missing..." mongosh --quiet --eval " db = db.getSiblingDB('admin'); if (db.getUser('$MONGO_USER') == null) { db.createUser({ user: '$MONGO_USER', pwd: '$MONGO_PASS', roles: [ { role: 'userAdminAnyDatabase', db: 'admin' }, { role: 'readWriteAnyDatabase', db: 'admin' } ] }); print('Mongo user created'); } else { print('Mongo user already exists'); } " if ! grep -q '^security:' /etc/mongod.conf; then printf '\nsecurity:\n authorization: enabled\n' >> /etc/mongod.conf elif ! grep -q 'authorization: enabled' /etc/mongod.conf; then awk ' BEGIN{done=0} /^security:/ {print; print " authorization: enabled"; done=1; next} {print} END{if(done==0) print "security:\n authorization: enabled"} ' /etc/mongod.conf > /etc/mongod.conf.tmp mv /etc/mongod.conf.tmp /etc/mongod.conf fi systemctl restart mongod sleep 5 if ! systemctl is-active --quiet mongod; then err "MongoDB failed after enabling authorization." systemctl status mongod --no-pager || true journalctl -u mongod --no-pager -n 50 || true exit 1 fi for i in {1..15}; do if mongosh "mongodb://$MONGO_USER:$MONGO_PASS@127.0.0.1:27017/admin?authSource=admin" \ --quiet --eval "db.adminCommand('ping')" >/dev/null 2>&1; then log "MongoDB authentication verified." return 0 fi sleep 2 done err "MongoDB auth check failed." exit 1 } write_env_file() { log "Writing .env file..." cat >"$APP_DIR/.env" </dev/null 2>&1; then log "Restarting existing PM2 app..." pm2 restart "$APP_NAME" else log "Starting app with PM2..." pm2 start npm --name "$APP_NAME" -- start -- -p "$APP_PORT" fi pm2 save pm2 startup systemd >/tmp/pm2-startup.txt 2>/dev/null || true if grep -q "sudo" /tmp/pm2-startup.txt; then bash -c "$(grep 'sudo' /tmp/pm2-startup.txt | sed 's/^.*sudo/sudo/' | head -n 1)" || true fi sleep 5 if ! pm2 describe "$APP_NAME" >/dev/null 2>&1; then err "PM2 app failed to start." pm2 logs "$APP_NAME" --lines 50 || true exit 1 fi log "PM2 app started." } configure_nginx() { log "Configuring Nginx..." cat >/etc/nginx/sites-available/"$DOMAIN" </dev/null 2>&1 || true ufw allow 'Nginx Full' >/dev/null 2>&1 || true ufw --force enable >/dev/null 2>&1 || true } install_ssl() { if [ "$ENABLE_SSL" != "yes" ]; then warn "SSL skipped by choice." return 0 fi log "Installing Certbot packages..." apt-get install -y certbot python3-certbot-nginx log "Requesting SSL certificate..." if certbot --nginx -d "$DOMAIN" -d "www.$DOMAIN" --non-interactive --agree-tos -m "$EMAIL" --redirect; then log "SSL installed successfully." else warn "SSL step failed. The app is still installed." warn "Most common reason: domain DNS is not pointed to this server yet." fi } final_checks() { log "Running final checks..." systemctl is-active --quiet mongod && log "MongoDB: OK" || warn "MongoDB: NOT RUNNING" systemctl is-active --quiet nginx && log "Nginx: OK" || warn "Nginx: NOT RUNNING" if pm2 describe "$APP_NAME" >/dev/null 2>&1; then log "PM2 app: OK" else warn "PM2 app: NOT RUNNING" fi } show_summary() { echo echo "------------------------------------------------" echo " SnapReels installation completed" echo "------------------------------------------------" echo " Domain : $DOMAIN" echo " App path : $APP_DIR" echo " App port : $APP_PORT" echo " Setup page : http://$DOMAIN/install" if [ "$ENABLE_SSL" = "yes" ]; then echo " HTTPS URL : https://$DOMAIN/install" fi echo " Log file : $LOG_FILE" echo "------------------------------------------------" echo " Useful commands:" echo " pm2 status" echo " pm2 logs $APP_NAME --lines 100" echo " systemctl status mongod" echo " systemctl status nginx" echo "------------------------------------------------" } main() { require_root ask_inputs check_app_files install_base_packages install_node install_mongodb configure_mongodb_user write_env_file build_app start_app_pm2 configure_nginx configure_firewall install_ssl final_checks show_summary } main "$@"