File: /var/www/indoadvisory_new/web/webapp/deploy.sh
#!/bin/bash
# Indo Advisory Deployment Script for VPS
# Enterprise-grade deployment with security and monitoring
# Usage: chmod +x deploy.sh && ./deploy.sh [production|staging]
set -e # Exit on any error
# Configuration
APP_NAME="indo-advisory"
APP_USER="www-data"
APP_DIR="/var/www/$APP_NAME"
REPO_URL="https://github.com/your-username/indo-advisory.git" # Update this
BRANCH="main"
NODE_VERSION="18"
PM2_INSTANCES="max"
BACKUP_DIR="/var/backups/$APP_NAME"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging function
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
}
warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
# Check if running as root
check_root() {
if [[ $EUID -eq 0 ]]; then
error "This script should not be run as root for security reasons"
error "Please run as a regular user with sudo privileges"
exit 1
fi
}
# Install system dependencies
install_dependencies() {
log "Installing system dependencies..."
# Update package list
sudo apt update
# Install required packages
sudo apt install -y \
curl \
wget \
git \
build-essential \
nginx \
postgresql \
postgresql-contrib \
ufw \
fail2ban \
certbot \
python3-certbot-nginx \
htop \
unzip
# Install Node.js via NodeSource
if ! command -v node &> /dev/null; then
log "Installing Node.js $NODE_VERSION..."
curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | sudo -E bash -
sudo apt-get install -y nodejs
fi
# Install PM2 globally
if ! command -v pm2 &> /dev/null; then
log "Installing PM2..."
sudo npm install -g pm2
pm2 install pm2-logrotate
fi
log "System dependencies installed successfully"
}
# Setup PostgreSQL database
setup_database() {
log "Setting up PostgreSQL database..."
# Create database user and database
sudo -u postgres psql -c "CREATE DATABASE ${APP_NAME}_production;" 2>/dev/null || true
sudo -u postgres psql -c "CREATE USER ${APP_NAME}_user WITH PASSWORD 'secure_production_password';" 2>/dev/null || true
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE ${APP_NAME}_production TO ${APP_NAME}_user;" 2>/dev/null || true
sudo -u postgres psql -c "ALTER USER ${APP_NAME}_user CREATEDB;" 2>/dev/null || true
log "Database setup completed"
}
# Setup application directory and permissions
setup_app_directory() {
log "Setting up application directory..."
# Create application directory
sudo mkdir -p $APP_DIR
sudo mkdir -p $APP_DIR/{logs,uploads,backups}
# Set proper ownership
sudo chown -R $USER:$APP_USER $APP_DIR
sudo chmod -R 755 $APP_DIR
sudo chmod -R 775 $APP_DIR/{logs,uploads,backups}
log "Application directory setup completed"
}
# Clone or update repository
deploy_code() {
log "Deploying application code..."
if [ -d "$APP_DIR/.git" ]; then
log "Updating existing repository..."
cd $APP_DIR
git fetch origin
git reset --hard origin/$BRANCH
else
log "Cloning repository..."
sudo rm -rf $APP_DIR/*
git clone -b $BRANCH $REPO_URL $APP_DIR
cd $APP_DIR
fi
# Set proper permissions
sudo chown -R $USER:$APP_USER $APP_DIR
log "Code deployment completed"
}
# Install Node.js dependencies
install_node_dependencies() {
log "Installing Node.js dependencies..."
cd $APP_DIR
# Install production dependencies
npm ci --only=production
log "Node.js dependencies installed"
}
# Setup environment configuration
setup_environment() {
log "Setting up environment configuration..."
cd $APP_DIR
# Create production environment file
if [ ! -f ".env" ]; then
cp .env.example .env
# Update environment variables for production
sed -i "s/NODE_ENV=development/NODE_ENV=production/" .env
sed -i "s/DB_HOST=localhost/DB_HOST=localhost/" .env
sed -i "s/DB_NAME=indo_advisory/DB_NAME=${APP_NAME}_production/" .env
sed -i "s/DB_USER=indo_user/DB_USER=${APP_NAME}_user/" .env
warning "Please update the .env file with your production values:"
warning "- Database password"
warning "- Session secrets"
warning "- SMTP settings"
warning "- Domain name"
fi
log "Environment configuration completed"
}
# Run database migrations
run_migrations() {
log "Running database migrations..."
cd $APP_DIR
# Run migrations
npm run migrate
# Seed initial data (only if needed)
read -p "Do you want to seed initial data? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
npm run seed
fi
log "Database migrations completed"
}
# Setup Nginx configuration
setup_nginx() {
log "Setting up Nginx configuration..."
# Copy Nginx configuration
sudo cp $APP_DIR/nginx.conf /etc/nginx/sites-available/$APP_NAME
# Enable site
sudo ln -sf /etc/nginx/sites-available/$APP_NAME /etc/nginx/sites-enabled/
# Remove default site
sudo rm -f /etc/nginx/sites-enabled/default
# Test Nginx configuration
sudo nginx -t
# Restart Nginx
sudo systemctl restart nginx
sudo systemctl enable nginx
log "Nginx setup completed"
}
# Setup SSL certificate
setup_ssl() {
log "Setting up SSL certificate..."
read -p "Enter your domain name (e.g., indoadvisory.com): " domain
if [ ! -z "$domain" ]; then
# Obtain SSL certificate
sudo certbot --nginx -d $domain -d www.$domain
# Auto-renewal
sudo systemctl enable certbot.timer
log "SSL certificate setup completed"
else
warning "Skipping SSL setup - no domain provided"
fi
}
# Setup firewall
setup_firewall() {
log "Setting up firewall..."
# Reset UFW to defaults
sudo ufw --force reset
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow essential services
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
# Allow specific ports if needed
# sudo ufw allow 3000 # Node.js (only if direct access needed)
# Enable firewall
sudo ufw --force enable
log "Firewall setup completed"
}
# Setup Fail2Ban
setup_fail2ban() {
log "Setting up Fail2Ban..."
# Create custom jail configuration
sudo tee /etc/fail2ban/jail.local > /dev/null <<EOF
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5
[nginx-http-auth]
enabled = true
[nginx-limit-req]
enabled = true
logpath = /var/log/nginx/*error.log
[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
maxretry = 3
EOF
# Restart Fail2Ban
sudo systemctl restart fail2ban
sudo systemctl enable fail2ban
log "Fail2Ban setup completed"
}
# Start application with PM2
start_application() {
log "Starting application with PM2..."
cd $APP_DIR
# Stop existing processes
pm2 delete $APP_NAME 2>/dev/null || true
# Start application
pm2 start ecosystem.config.js --env production
# Save PM2 configuration
pm2 save
# Setup PM2 startup script
sudo env PATH=$PATH:/usr/bin pm2 startup systemd -u $USER --hp /home/$USER
log "Application started successfully"
}
# Create backup script
setup_backup() {
log "Setting up backup system..."
# Create backup directory
sudo mkdir -p $BACKUP_DIR
sudo chown $USER:$APP_USER $BACKUP_DIR
# Create backup script
sudo tee /usr/local/bin/indo-advisory-backup.sh > /dev/null <<EOF
#!/bin/bash
BACKUP_DIR="$BACKUP_DIR"
TIMESTAMP=\$(date +%Y%m%d_%H%M%S)
# Database backup
pg_dump -h localhost -U ${APP_NAME}_user -d ${APP_NAME}_production > \$BACKUP_DIR/database_\$TIMESTAMP.sql
# Application backup
tar -czf \$BACKUP_DIR/app_\$TIMESTAMP.tar.gz -C /var/www $APP_NAME
# Keep only last 7 days of backups
find \$BACKUP_DIR -name "*.sql" -mtime +7 -delete
find \$BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
echo "Backup completed: \$TIMESTAMP"
EOF
sudo chmod +x /usr/local/bin/indo-advisory-backup.sh
# Setup daily backup cron
(crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/indo-advisory-backup.sh") | crontab -
log "Backup system setup completed"
}
# Health check
health_check() {
log "Performing health check..."
sleep 5 # Wait for application to start
# Check if application is responding
if curl -f http://localhost:3000 > /dev/null 2>&1; then
log "✓ Application is responding"
else
error "✗ Application is not responding"
pm2 logs $APP_NAME --lines 20
exit 1
fi
# Check database connection
cd $APP_DIR
if npm run db:check > /dev/null 2>&1; then
log "✓ Database connection successful"
else
warning "⚠ Database connection check failed"
fi
log "Health check completed"
}
# Main deployment function
deploy() {
local environment=${1:-production}
log "Starting deployment for $environment environment..."
check_root
install_dependencies
setup_database
setup_app_directory
deploy_code
install_node_dependencies
setup_environment
run_migrations
setup_nginx
if [ "$environment" = "production" ]; then
setup_ssl
setup_firewall
setup_fail2ban
setup_backup
fi
start_application
health_check
log "🎉 Deployment completed successfully!"
log "🌐 Application available at: http://your-domain.com"
log "🔐 Admin panel: http://your-domain.com/admin"
log "📊 PM2 status: pm2 status"
log "📋 Logs: pm2 logs $APP_NAME"
info "Next steps:"
info "1. Update DNS records to point to this server"
info "2. Test SSL certificate renewal: sudo certbot renew --dry-run"
info "3. Monitor application logs: pm2 logs"
info "4. Setup monitoring and alerting"
}
# Script execution
case "${1:-production}" in
production|staging)
deploy $1
;;
*)
echo "Usage: $0 [production|staging]"
exit 1
;;
esac