#!/bin/bash # AI Town Game Production Deployment Script # Usage: ./deploy.sh [environment] set -e # Configuration ENVIRONMENT=${1:-production} PROJECT_NAME="ai-town-game" BACKUP_DIR="/opt/backups/$PROJECT_NAME" DEPLOY_DIR="/opt/$PROJECT_NAME" WEB_DIR="$DEPLOY_DIR/web" SERVER_DIR="$DEPLOY_DIR/server" # 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 "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" } error() { echo -e "${RED}[ERROR]${NC} $1" >&2 } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # Check if running as root check_root() { if [[ $EUID -eq 0 ]]; then error "This script should not be run as root" exit 1 fi } # Check system requirements check_requirements() { log "Checking system requirements..." # Check Docker if ! command -v docker &> /dev/null; then error "Docker is not installed" exit 1 fi # Check Docker Compose if ! command -v docker-compose &> /dev/null; then error "Docker Compose is not installed" exit 1 fi # Check Node.js (for local builds) if ! command -v node &> /dev/null; then warning "Node.js is not installed (required for local builds)" fi # Check available disk space (at least 2GB) AVAILABLE_SPACE=$(df / | tail -1 | awk '{print $4}') if [[ $AVAILABLE_SPACE -lt 2097152 ]]; then error "Insufficient disk space (need at least 2GB)" exit 1 fi success "System requirements check passed" } # Create backup of current deployment create_backup() { log "Creating backup of current deployment..." if [[ -d "$DEPLOY_DIR" ]]; then BACKUP_NAME="backup_$(date +%Y%m%d_%H%M%S)" mkdir -p "$BACKUP_DIR" # Backup data directory if [[ -d "$SERVER_DIR/data" ]]; then tar -czf "$BACKUP_DIR/${BACKUP_NAME}_data.tar.gz" -C "$SERVER_DIR" data/ success "Data backup created: ${BACKUP_NAME}_data.tar.gz" fi # Backup configuration if [[ -f "$DEPLOY_DIR/.env" ]]; then cp "$DEPLOY_DIR/.env" "$BACKUP_DIR/${BACKUP_NAME}_env" success "Configuration backup created: ${BACKUP_NAME}_env" fi # Clean old backups (keep last 5) cd "$BACKUP_DIR" ls -t backup_*_data.tar.gz 2>/dev/null | tail -n +6 | xargs rm -f ls -t backup_*_env 2>/dev/null | tail -n +6 | xargs rm -f else log "No existing deployment found, skipping backup" fi } # Setup deployment directory setup_directories() { log "Setting up deployment directories..." sudo mkdir -p "$DEPLOY_DIR" sudo mkdir -p "$WEB_DIR" sudo mkdir -p "$SERVER_DIR" sudo mkdir -p "$BACKUP_DIR" sudo mkdir -p "/var/log/$PROJECT_NAME" # Set permissions sudo chown -R $USER:$USER "$DEPLOY_DIR" sudo chown -R $USER:$USER "$BACKUP_DIR" success "Directories created and configured" } # Deploy server application deploy_server() { log "Deploying server application..." # Copy server files cp -r server/* "$SERVER_DIR/" # Copy Docker configuration cp docker-compose.prod.yml "$DEPLOY_DIR/" cp nginx/nginx.conf "$DEPLOY_DIR/nginx/" # Setup environment configuration if [[ ! -f "$DEPLOY_DIR/.env" ]]; then cp .env.production "$DEPLOY_DIR/.env" warning "Please edit $DEPLOY_DIR/.env with your production settings" fi # Build and start services cd "$DEPLOY_DIR" docker-compose -f docker-compose.prod.yml build docker-compose -f docker-compose.prod.yml up -d success "Server application deployed" } # Deploy web client deploy_web() { log "Deploying web client..." # Check if web build exists if [[ ! -d "web" ]]; then error "Web build not found. Please export from Godot first." exit 1 fi # Copy web files cp -r web/* "$WEB_DIR/" # Set proper permissions sudo chown -R www-data:www-data "$WEB_DIR" sudo chmod -R 755 "$WEB_DIR" success "Web client deployed" } # Configure system services configure_services() { log "Configuring system services..." # Create systemd service for monitoring sudo tee /etc/systemd/system/ai-town-monitor.service > /dev/null < /dev/null <<'EOF' #!/bin/bash cd /opt/ai-town-game if ! docker-compose -f docker-compose.prod.yml ps | grep -q "Up"; then echo "AI Town services are down, restarting..." docker-compose -f docker-compose.prod.yml up -d fi EOF chmod +x "$DEPLOY_DIR/monitor.sh" # Setup cron job for monitoring (crontab -l 2>/dev/null; echo "*/5 * * * * /opt/ai-town-game/monitor.sh") | crontab - success "System services configured" } # Setup SSL certificates (Let's Encrypt) setup_ssl() { if [[ -z "$DOMAIN" ]]; then warning "DOMAIN not set, skipping SSL setup" return fi log "Setting up SSL certificates for $DOMAIN..." # Install certbot sudo apt-get update sudo apt-get install -y certbot python3-certbot-nginx # Get certificate sudo certbot --nginx -d "$DOMAIN" --non-interactive --agree-tos --email "$EMAIL" # Setup auto-renewal (crontab -l 2>/dev/null; echo "0 12 * * * /usr/bin/certbot renew --quiet") | crontab - success "SSL certificates configured" } # Health check health_check() { log "Performing health check..." # Wait for services to start sleep 30 # Check server health if curl -f http://localhost:8080/health > /dev/null 2>&1; then success "Server health check passed" else error "Server health check failed" return 1 fi # Check web client if curl -f http://localhost/ > /dev/null 2>&1; then success "Web client health check passed" else error "Web client health check failed" return 1 fi # Check admin API if curl -f http://localhost:8081/api/status > /dev/null 2>&1; then success "Admin API health check passed" else warning "Admin API health check failed (may require authentication)" fi success "Health check completed" } # Rollback function rollback() { error "Deployment failed, initiating rollback..." cd "$DEPLOY_DIR" docker-compose -f docker-compose.prod.yml down # Restore from latest backup LATEST_BACKUP=$(ls -t "$BACKUP_DIR"/backup_*_data.tar.gz 2>/dev/null | head -1) if [[ -n "$LATEST_BACKUP" ]]; then log "Restoring from backup: $LATEST_BACKUP" tar -xzf "$LATEST_BACKUP" -C "$SERVER_DIR" fi # Restart services docker-compose -f docker-compose.prod.yml up -d error "Rollback completed" exit 1 } # Main deployment function main() { log "Starting AI Town Game deployment (Environment: $ENVIRONMENT)" # Trap errors for rollback trap rollback ERR check_root check_requirements create_backup setup_directories deploy_server deploy_web configure_services # Setup SSL if domain is provided if [[ -n "$DOMAIN" ]]; then setup_ssl fi # Health check if ! health_check; then rollback fi success "Deployment completed successfully!" log "Access your application at:" log " Web Client: http://localhost/ (or https://$DOMAIN)" log " Admin Panel: http://localhost:8081/admin/" log " Server API: http://localhost:8080/" log "Important files:" log " Configuration: $DEPLOY_DIR/.env" log " Logs: /var/log/$PROJECT_NAME/" log " Backups: $BACKUP_DIR/" log "Next steps:" log " 1. Edit $DEPLOY_DIR/.env with your production settings" log " 2. Configure your domain DNS to point to this server" log " 3. Set up monitoring and alerting" log " 4. Test all functionality" } # Script entry point if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi