#!/bin/bash # SolarBank IoT Dashboard - Production Deployment Script # This script handles the complete deployment process set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Function to print colored output print_status() { echo -e "${GREEN}[INFO]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } # Function to check if Docker and Docker Compose are installed check_requirements() { print_status "Checking requirements..." if ! command -v docker &> /dev/null; then print_error "Docker is not installed. Please install Docker first." exit 1 fi if ! command -v docker-compose &> /dev/null; then print_error "Docker Compose is not installed. Please install Docker Compose first." exit 1 fi print_status "Requirements check passed." } # Function to check environment configuration check_environment() { print_status "Checking environment configuration..." if [ ! -f .env.prod ]; then print_error ".env.prod file not found. Please create it from environment.prod.example" print_status "Run: cp environment.prod.example .env.prod" print_status "Then edit .env.prod with your production values" exit 1 fi # Load environment variables export $(cat .env.prod | grep -v '#' | awk '/=/ {print $1}') # Check critical variables if [ -z "$DOMAIN_NAME" ] || [ "$DOMAIN_NAME" == "yourdomain.com" ]; then print_error "DOMAIN_NAME must be set to your actual domain in .env.prod" exit 1 fi if [ -z "$EMAIL" ] || [ "$EMAIL" == "your-email@domain.com" ]; then print_error "EMAIL must be set to your actual email in .env.prod" exit 1 fi if [ "$SECRET_KEY" == "REPLACE_WITH_SECURE_RANDOM_STRING_32_CHARS" ]; then print_error "SECRET_KEY must be replaced with a secure random string in .env.prod" print_status "Generate one with: python -c \"import secrets; print(secrets.token_urlsafe(32))\"" exit 1 fi if [ "$JWT_SECRET_KEY" == "REPLACE_WITH_SECURE_RANDOM_STRING_32_CHARS" ]; then print_error "JWT_SECRET_KEY must be replaced with a secure random string in .env.prod" exit 1 fi print_status "Environment configuration check passed." } # Function to setup SSL certificates setup_ssl() { print_status "Setting up SSL certificates..." if [ ! -f scripts/init-letsencrypt.sh ]; then print_error "SSL setup script not found!" exit 1 fi chmod +x scripts/init-letsencrypt.sh ./scripts/init-letsencrypt.sh print_status "SSL certificates setup completed." } # Function to build and start services deploy_services() { print_status "Building and deploying services..." # Pull latest images docker-compose -f docker-compose.prod.yml pull # Build services docker-compose -f docker-compose.prod.yml build --no-cache # Start services docker-compose -f docker-compose.prod.yml up -d print_status "Services deployed successfully." } # Function to run database migrations run_migrations() { print_status "Running database migrations..." # Wait for database to be ready sleep 10 # Run migrations docker-compose -f docker-compose.prod.yml exec backend alembic upgrade head print_status "Database migrations completed." } # Function to setup monitoring setup_monitoring() { print_status "Setting up monitoring and health checks..." # Wait for services to be fully ready sleep 30 # Check service health print_status "Checking service health..." # Check backend health if curl -f http://localhost/api/health > /dev/null 2>&1; then print_status "Backend health check: PASSED" else print_warning "Backend health check: FAILED (this might be normal if SSL is required)" fi # Check frontend health if curl -f http://localhost/health > /dev/null 2>&1; then print_status "Frontend health check: PASSED" else print_warning "Frontend health check: FAILED" fi print_status "Health checks completed." } # Function to setup backup cron job setup_backup() { print_status "Setting up automated backups..." chmod +x scripts/backup-database.sh # Add cron job for daily backups at 2 AM (crontab -l 2>/dev/null; echo "0 2 * * * $(pwd)/scripts/backup-database.sh >> $(pwd)/logs/backup.log 2>&1") | crontab - print_status "Automated backup setup completed." } # Function to display final status show_status() { print_status "===================================" print_status "DEPLOYMENT COMPLETED SUCCESSFULLY!" print_status "===================================" echo print_status "Your SolarBank IoT Dashboard is now running at:" print_status "🌐 https://$DOMAIN_NAME" echo print_status "Services status:" docker-compose -f docker-compose.prod.yml ps echo print_status "To monitor logs: docker-compose -f docker-compose.prod.yml logs -f" print_status "To stop services: docker-compose -f docker-compose.prod.yml down" print_status "To update deployment: ./scripts/deploy.sh --update" echo print_status "Important next steps:" print_status "1. Test your application thoroughly" print_status "2. Set up monitoring and alerting" print_status "3. Configure firewall rules" print_status "4. Set up regular backups verification" } # Function to update existing deployment update_deployment() { print_status "Updating existing deployment..." # Create backup before update print_status "Creating backup before update..." ./scripts/backup-database.sh # Pull latest changes and rebuild docker-compose -f docker-compose.prod.yml down docker-compose -f docker-compose.prod.yml pull docker-compose -f docker-compose.prod.yml build --no-cache docker-compose -f docker-compose.prod.yml up -d # Run migrations run_migrations print_status "Deployment update completed." } # Main deployment function main() { print_status "Starting SolarBank IoT Dashboard production deployment..." case "$1" in --update) check_requirements check_environment update_deployment setup_monitoring show_status ;; --ssl-only) check_requirements check_environment setup_ssl ;; *) check_requirements check_environment # Check if this is a fresh installation if [ ! -d "./nginx/certbot/conf/live" ]; then setup_ssl else print_status "SSL certificates already exist. Skipping SSL setup." print_status "Use --ssl-only flag to regenerate certificates." fi deploy_services run_migrations setup_monitoring setup_backup show_status ;; esac } # Create logs directory mkdir -p logs # Run main function with all arguments main "$@"