Updated deploy.sh to copy .env file to frontend directory before building, ensuring Vite can access environment variables (including VITE_REDIRECT_URI) during the production build process. The temporary .env is cleaned up after build completes. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
491 lines
14 KiB
Bash
Executable file
491 lines
14 KiB
Bash
Executable file
#!/bin/bash
|
||
|
||
################################################################################
|
||
# BAIC Dashboard Deployment Script
|
||
#
|
||
# This script automates the deployment of the BAIC Dashboard application
|
||
# on an Ubuntu server with Apache and systemd.
|
||
#
|
||
# Prerequisites:
|
||
# - Repository cloned to /opt/baic_dashboard
|
||
# - .env file configured in repository root
|
||
# - Run this script from /opt/baic_dashboard directory
|
||
# - Execute with sudo/root privileges
|
||
#
|
||
# Usage: sudo bash deploy.sh
|
||
################################################################################
|
||
|
||
set -e # Exit on any error
|
||
|
||
# Color codes for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# Expected deployment directory
|
||
EXPECTED_DIR="/opt/baic_dashboard"
|
||
SERVICE_NAME="baic-dashboard"
|
||
SERVICE_USER="www-data"
|
||
|
||
################################################################################
|
||
# Helper Functions
|
||
################################################################################
|
||
|
||
print_header() {
|
||
echo -e "\n${BLUE}========================================${NC}"
|
||
echo -e "${BLUE}$1${NC}"
|
||
echo -e "${BLUE}========================================${NC}\n"
|
||
}
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}✓ $1${NC}"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}✗ ERROR: $1${NC}"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠ WARNING: $1${NC}"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "${BLUE}ℹ $1${NC}"
|
||
}
|
||
|
||
exit_with_error() {
|
||
print_error "$1"
|
||
exit 1
|
||
}
|
||
|
||
################################################################################
|
||
# Pre-flight Checks
|
||
################################################################################
|
||
|
||
print_header "Pre-flight Checks"
|
||
|
||
# Check if running as root
|
||
if [[ $EUID -ne 0 ]]; then
|
||
exit_with_error "This script must be run as root (use sudo)"
|
||
fi
|
||
print_success "Running as root"
|
||
|
||
# Check if we're in the correct directory
|
||
CURRENT_DIR=$(pwd)
|
||
if [[ "$CURRENT_DIR" != "$EXPECTED_DIR" ]]; then
|
||
exit_with_error "Script must be run from $EXPECTED_DIR (currently in $CURRENT_DIR)"
|
||
fi
|
||
print_success "Running from correct directory: $EXPECTED_DIR"
|
||
|
||
# Check for required commands
|
||
REQUIRED_COMMANDS=("python3" "npm" "systemctl")
|
||
for cmd in "${REQUIRED_COMMANDS[@]}"; do
|
||
if ! command -v $cmd &> /dev/null; then
|
||
exit_with_error "$cmd is not installed. Please install it first."
|
||
fi
|
||
print_success "$cmd is installed"
|
||
done
|
||
|
||
# Check if .env file exists
|
||
if [[ ! -f ".env" ]]; then
|
||
exit_with_error ".env file not found in current directory. Please create it before running this script."
|
||
fi
|
||
print_success ".env file found"
|
||
|
||
# Check if apache2 is installed (warn if not, but don't fail)
|
||
if ! command -v apache2 &> /dev/null; then
|
||
print_warning "apache2 is not installed. You'll need to install and configure it manually."
|
||
else
|
||
print_success "apache2 is installed"
|
||
fi
|
||
|
||
################################################################################
|
||
# Backend Setup
|
||
################################################################################
|
||
|
||
print_header "Backend Setup"
|
||
|
||
# Create Python virtual environment
|
||
print_info "Creating Python virtual environment..."
|
||
if [[ -d "venv" ]]; then
|
||
print_warning "Virtual environment already exists. Removing and recreating..."
|
||
rm -rf venv
|
||
fi
|
||
|
||
python3 -m venv venv
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to create virtual environment"
|
||
fi
|
||
print_success "Virtual environment created"
|
||
|
||
# Activate virtual environment and install dependencies
|
||
print_info "Installing Python dependencies from requirements.txt..."
|
||
source venv/bin/activate
|
||
|
||
if [[ ! -f "backend/requirements.txt" ]]; then
|
||
exit_with_error "backend/requirements.txt not found"
|
||
fi
|
||
|
||
pip install --upgrade pip > /dev/null 2>&1
|
||
pip install -r backend/requirements.txt
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to install Python dependencies"
|
||
fi
|
||
print_success "Python dependencies installed"
|
||
|
||
# Test that Flask can be imported
|
||
python3 -c "import flask" 2>/dev/null
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Flask installation verification failed"
|
||
fi
|
||
print_success "Flask installation verified"
|
||
|
||
deactivate
|
||
|
||
# Set ownership to www-data
|
||
print_info "Setting ownership to $SERVICE_USER..."
|
||
chown -R $SERVICE_USER:$SERVICE_USER venv
|
||
chown -R $SERVICE_USER:$SERVICE_USER backend
|
||
print_success "Ownership set to $SERVICE_USER"
|
||
|
||
################################################################################
|
||
# Frontend Build
|
||
################################################################################
|
||
|
||
print_header "Frontend Build"
|
||
|
||
# Check if frontend directory exists
|
||
if [[ ! -d "frontend" ]]; then
|
||
exit_with_error "frontend directory not found"
|
||
fi
|
||
|
||
cd frontend
|
||
|
||
# Install npm dependencies
|
||
print_info "Installing npm dependencies..."
|
||
npm install
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to install npm dependencies"
|
||
fi
|
||
print_success "npm dependencies installed"
|
||
|
||
# Copy .env file to frontend directory for Vite to read during build
|
||
print_info "Copying .env to frontend directory for build..."
|
||
cp ../.env ./.env
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to copy .env file"
|
||
fi
|
||
print_success ".env file copied"
|
||
|
||
# Build frontend
|
||
print_info "Building frontend for production (this may take a minute)..."
|
||
npm run build
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Frontend build failed"
|
||
fi
|
||
|
||
# Remove .env from frontend directory (cleanup)
|
||
print_info "Cleaning up temporary .env file..."
|
||
rm -f ./.env
|
||
print_success "Cleanup complete"
|
||
|
||
# Verify dist directory was created
|
||
if [[ ! -d "dist" ]]; then
|
||
exit_with_error "Build completed but dist/ directory not found"
|
||
fi
|
||
print_success "Frontend built successfully"
|
||
|
||
cd ..
|
||
|
||
################################################################################
|
||
# Frontend Deployment
|
||
################################################################################
|
||
|
||
print_header "Frontend Deployment"
|
||
|
||
# Prompt user for frontend deployment path
|
||
echo -e "${BLUE}Please enter the full path where the frontend files should be deployed${NC}"
|
||
echo -e "${BLUE}(e.g., /var/www/html/dashboard or /var/www/mysite.com/dashboard)${NC}"
|
||
read -p "Deployment path: " FRONTEND_DEPLOY_PATH
|
||
|
||
# Validate input
|
||
if [[ -z "$FRONTEND_DEPLOY_PATH" ]]; then
|
||
exit_with_error "No deployment path provided"
|
||
fi
|
||
|
||
# Create directory if it doesn't exist
|
||
if [[ ! -d "$FRONTEND_DEPLOY_PATH" ]]; then
|
||
print_info "Creating directory: $FRONTEND_DEPLOY_PATH"
|
||
mkdir -p "$FRONTEND_DEPLOY_PATH"
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to create deployment directory"
|
||
fi
|
||
fi
|
||
|
||
# Copy frontend files
|
||
print_info "Copying frontend files to $FRONTEND_DEPLOY_PATH..."
|
||
cp -r frontend/dist/* "$FRONTEND_DEPLOY_PATH/"
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to copy frontend files"
|
||
fi
|
||
print_success "Frontend files copied"
|
||
|
||
# Set ownership and permissions
|
||
print_info "Setting ownership and permissions..."
|
||
chown -R $SERVICE_USER:$SERVICE_USER "$FRONTEND_DEPLOY_PATH"
|
||
find "$FRONTEND_DEPLOY_PATH" -type d -exec chmod 755 {} \;
|
||
find "$FRONTEND_DEPLOY_PATH" -type f -exec chmod 644 {} \;
|
||
print_success "Ownership and permissions set"
|
||
|
||
################################################################################
|
||
# Systemd Service Creation
|
||
################################################################################
|
||
|
||
print_header "Systemd Service Setup"
|
||
|
||
# Read BACKEND_PORT from .env or use default
|
||
BACKEND_PORT=$(grep "^BACKEND_PORT=" .env | cut -d'=' -f2 | tr -d ' ')
|
||
if [[ -z "$BACKEND_PORT" ]]; then
|
||
BACKEND_PORT="5001"
|
||
print_warning "BACKEND_PORT not found in .env, using default: 5001"
|
||
else
|
||
print_info "Using BACKEND_PORT from .env: $BACKEND_PORT"
|
||
fi
|
||
|
||
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||
|
||
print_info "Creating systemd service file: $SERVICE_FILE"
|
||
|
||
cat > "$SERVICE_FILE" << EOF
|
||
[Unit]
|
||
Description=BAIC Dashboard Backend Service
|
||
After=network.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=$SERVICE_USER
|
||
Group=$SERVICE_USER
|
||
WorkingDirectory=$EXPECTED_DIR/backend
|
||
EnvironmentFile=$EXPECTED_DIR/.env
|
||
ExecStart=$EXPECTED_DIR/venv/bin/python app.py
|
||
|
||
# Restart policy
|
||
Restart=always
|
||
RestartSec=10
|
||
|
||
# Security settings
|
||
NoNewPrivileges=true
|
||
PrivateTmp=true
|
||
|
||
# Logging
|
||
StandardOutput=journal
|
||
StandardError=journal
|
||
SyslogIdentifier=$SERVICE_NAME
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to create systemd service file"
|
||
fi
|
||
print_success "Systemd service file created"
|
||
|
||
################################################################################
|
||
# Service Management
|
||
################################################################################
|
||
|
||
print_header "Service Management"
|
||
|
||
# Reload systemd daemon
|
||
print_info "Reloading systemd daemon..."
|
||
systemctl daemon-reload
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to reload systemd daemon"
|
||
fi
|
||
print_success "Systemd daemon reloaded"
|
||
|
||
# Enable service
|
||
print_info "Enabling service to start on boot..."
|
||
systemctl enable $SERVICE_NAME
|
||
if [[ $? -ne 0 ]]; then
|
||
exit_with_error "Failed to enable service"
|
||
fi
|
||
print_success "Service enabled"
|
||
|
||
# Start service
|
||
print_info "Starting service..."
|
||
systemctl start $SERVICE_NAME
|
||
if [[ $? -ne 0 ]]; then
|
||
print_error "Failed to start service. Check logs with: journalctl -u $SERVICE_NAME -n 50"
|
||
exit 1
|
||
fi
|
||
print_success "Service started"
|
||
|
||
# Wait a moment for service to initialize
|
||
sleep 2
|
||
|
||
# Check service status
|
||
print_info "Checking service status..."
|
||
if systemctl is-active --quiet $SERVICE_NAME; then
|
||
print_success "Service is running"
|
||
echo ""
|
||
systemctl status $SERVICE_NAME --no-pager -l
|
||
else
|
||
print_error "Service failed to start properly"
|
||
print_info "Showing recent logs:"
|
||
journalctl -u $SERVICE_NAME -n 20 --no-pager
|
||
exit 1
|
||
fi
|
||
|
||
################################################################################
|
||
# Apache Configuration Generation
|
||
################################################################################
|
||
|
||
print_header "Apache Configuration"
|
||
|
||
# Get domain and base path from .env
|
||
DOMAIN=$(grep "^DOMAIN=" .env | cut -d'=' -f2 | tr -d ' ')
|
||
BASE_PATH=$(grep "^BASE_PATH=" .env | cut -d'=' -f2 | tr -d ' ')
|
||
|
||
if [[ -z "$DOMAIN" ]]; then
|
||
DOMAIN="yourdomain.com"
|
||
print_warning "DOMAIN not found in .env, using placeholder in config"
|
||
fi
|
||
|
||
if [[ -z "$BASE_PATH" ]]; then
|
||
BASE_PATH="/dashboard/"
|
||
print_warning "BASE_PATH not found in .env, using default: /dashboard/"
|
||
fi
|
||
|
||
# Remove trailing slash from BASE_PATH for cleaner config
|
||
BASE_PATH_NO_SLASH=${BASE_PATH%/}
|
||
|
||
APACHE_CONFIG_FILE="$EXPECTED_DIR/apache-config.conf"
|
||
|
||
print_info "Generating Apache configuration: $APACHE_CONFIG_FILE"
|
||
|
||
cat > "$APACHE_CONFIG_FILE" << EOF
|
||
# Apache Configuration for BAIC Dashboard
|
||
#
|
||
# Add this configuration to your Apache virtual host file
|
||
# (e.g., /etc/apache2/sites-available/000-default.conf or your custom site config)
|
||
#
|
||
# Required Apache modules (enable with a2enmod):
|
||
# - proxy
|
||
# - proxy_http
|
||
# - headers
|
||
# - rewrite
|
||
#
|
||
# Enable modules:
|
||
# sudo a2enmod proxy proxy_http headers rewrite
|
||
# sudo systemctl restart apache2
|
||
|
||
<VirtualHost *:443>
|
||
ServerName $DOMAIN
|
||
|
||
# SSL Configuration (adjust paths to your certificates)
|
||
# SSLEngine on
|
||
# SSLCertificateFile /etc/letsencrypt/live/$DOMAIN/fullchain.pem
|
||
# SSLCertificateKeyFile /etc/letsencrypt/live/$DOMAIN/privkey.pem
|
||
|
||
# Frontend static files
|
||
Alias $BASE_PATH_NO_SLASH $FRONTEND_DEPLOY_PATH
|
||
<Directory $FRONTEND_DEPLOY_PATH>
|
||
Options -Indexes +FollowSymLinks
|
||
AllowOverride All
|
||
Require all granted
|
||
|
||
# Handle client-side routing (React Router)
|
||
<IfModule mod_rewrite.c>
|
||
RewriteEngine On
|
||
RewriteBase $BASE_PATH_NO_SLASH/
|
||
RewriteRule ^index\.html$ - [L]
|
||
RewriteCond %{REQUEST_FILENAME} !-f
|
||
RewriteCond %{REQUEST_FILENAME} !-d
|
||
RewriteRule . $BASE_PATH_NO_SLASH/index.html [L]
|
||
</IfModule>
|
||
</Directory>
|
||
|
||
# Backend API reverse proxy
|
||
ProxyPreserveHost On
|
||
ProxyTimeout 300
|
||
|
||
<Location $BASE_PATH_NO_SLASH/back/api>
|
||
ProxyPass http://localhost:$BACKEND_PORT/api
|
||
ProxyPassReverse http://localhost:$BACKEND_PORT/api
|
||
|
||
# Add headers for proper proxying
|
||
RequestHeader set X-Forwarded-Proto "https"
|
||
RequestHeader set X-Forwarded-Port "443"
|
||
</Location>
|
||
|
||
# Error and Access logs
|
||
ErrorLog \${APACHE_LOG_DIR}/${SERVICE_NAME}-error.log
|
||
CustomLog \${APACHE_LOG_DIR}/${SERVICE_NAME}-access.log combined
|
||
</VirtualHost>
|
||
|
||
# Optional: Redirect HTTP to HTTPS
|
||
<VirtualHost *:80>
|
||
ServerName $DOMAIN
|
||
Redirect permanent / https://$DOMAIN/
|
||
</VirtualHost>
|
||
EOF
|
||
|
||
if [[ $? -ne 0 ]]; then
|
||
print_error "Failed to create Apache configuration file"
|
||
else
|
||
print_success "Apache configuration file created"
|
||
fi
|
||
|
||
################################################################################
|
||
# Deployment Complete
|
||
################################################################################
|
||
|
||
print_header "Deployment Complete!"
|
||
|
||
echo -e "${GREEN}✓ Backend virtual environment created and dependencies installed${NC}"
|
||
echo -e "${GREEN}✓ Frontend built and deployed to: $FRONTEND_DEPLOY_PATH${NC}"
|
||
echo -e "${GREEN}✓ Systemd service created and started: $SERVICE_NAME${NC}"
|
||
echo -e "${GREEN}✓ Apache configuration generated: $APACHE_CONFIG_FILE${NC}"
|
||
|
||
echo ""
|
||
print_header "Next Steps"
|
||
|
||
echo -e "${YELLOW}1. Review the Apache configuration:${NC}"
|
||
echo -e " cat $APACHE_CONFIG_FILE"
|
||
echo ""
|
||
echo -e "${YELLOW}2. Enable required Apache modules:${NC}"
|
||
echo -e " sudo a2enmod proxy proxy_http headers rewrite"
|
||
echo ""
|
||
echo -e "${YELLOW}3. Add the configuration to your Apache virtual host:${NC}"
|
||
echo -e " - Edit: /etc/apache2/sites-available/your-site.conf"
|
||
echo -e " - Or copy: sudo cp $APACHE_CONFIG_FILE /etc/apache2/sites-available/${SERVICE_NAME}.conf"
|
||
echo -e " - Enable: sudo a2ensite ${SERVICE_NAME}"
|
||
echo ""
|
||
echo -e "${YELLOW}4. Test Apache configuration:${NC}"
|
||
echo -e " sudo apache2ctl configtest"
|
||
echo ""
|
||
echo -e "${YELLOW}5. Reload Apache:${NC}"
|
||
echo -e " sudo systemctl reload apache2"
|
||
echo ""
|
||
echo -e "${YELLOW}6. Configure SSL/TLS certificates (if not already done):${NC}"
|
||
echo -e " sudo apt install certbot python3-certbot-apache"
|
||
echo -e " sudo certbot --apache -d $DOMAIN"
|
||
echo ""
|
||
|
||
print_header "Useful Commands"
|
||
|
||
echo -e "${BLUE}Service Management:${NC}"
|
||
echo -e " sudo systemctl status $SERVICE_NAME # Check service status"
|
||
echo -e " sudo systemctl restart $SERVICE_NAME # Restart service"
|
||
echo -e " sudo systemctl stop $SERVICE_NAME # Stop service"
|
||
echo -e " sudo journalctl -u $SERVICE_NAME -f # View live logs"
|
||
echo -e " sudo journalctl -u $SERVICE_NAME -n 100 # View last 100 log lines"
|
||
echo ""
|
||
|
||
print_success "Deployment script completed successfully!"
|
||
|
||
exit 0
|