Automation Tools
Production-ready deployment scripts and automation tools for managing containerized portfolio applications. These tools streamline the deployment process and ensure consistent, reliable application management.
Portfolio App Deployment Script
A comprehensive bash script for deploying React/Vite applications as Docker containers with nginx integration. This script handles the entire deployment lifecycle from building to testing and provides detailed feedback throughout the process.
đ Overview
The deploy-portfolio-app.sh script automates the deployment of portfolio applications by:
- Building Docker images with proper environment configuration
- Managing container lifecycle (stop, remove, start)
- Performing health checks and validation
- Providing nginx configuration guidance
- Testing JavaScript asset delivery
- Offering comprehensive deployment feedback
đ Key Features
Intelligent Port Management
- Port Conflict Detection: Automatically detects if the specified port is already in use
- Container Recognition: Identifies if the port is used by the same app (for rebuilds) or different container
- Interactive Rebuilds: Prompts user for rebuild confirmation when container exists
- Force Rebuild Option: Supports
rebuildparameter for automated rebuilds
Comprehensive Validation
- Directory Validation: Ensures app directory exists before deployment
- Required Files Check: Validates presence of Dockerfile and package.json
- Container Health Checks: Tests container responsiveness after deployment
- Asset Validation: Verifies JavaScript files are serving correctly
Production-Ready Features
- Error Handling: Graceful failure handling with helpful error messages
- Colored Output: Clear, color-coded status messages for better readability
- Restart Policies: Configures containers with
unless-stoppedrestart policy - nginx Integration: Provides complete nginx configuration templates
đ Usage Examples
# Deploy a new application
./deploy-portfolio-app.sh my-app 3003
# Force rebuild an existing application
./deploy-portfolio-app.sh chord-genesis 3001 rebuild
# Deploy with automatic rebuild confirmation
./deploy-portfolio-app.sh fineline 3008 rebuild
đ Deployment Workflow
- Validation Phase
- Validate command line arguments
- Check app directory exists
- Verify required files present
- Check port availability
- Container Management
- Stop existing container if rebuilding
- Remove old container and cleanup
- Build new Docker image with proper base path
- Deployment Phase
- Start new container with correct port mapping
- Configure restart policy for production
- Wait for container initialization
- Testing & Validation
- Perform container health check
- Test nginx proxy accessibility
- Validate JavaScript asset delivery
- Generate deployment summary
đŦ Output Features
Color-Coded Messages
- đĩ Info: General process information
- đĸ Success: Successful operations
- đĄ Warning: Non-critical issues requiring attention
- đ´ Error: Critical failures requiring action
Deployment Summary
The script provides a comprehensive deployment summary including:
- App name and container details
- Port mappings and URLs
- Container status and health
- Useful management commands
- nginx configuration guidance
đ nginx Integration
When nginx configuration is needed, the script automatically generates the required configuration block:
# Auto-generated nginx configuration
location /app-name {
return 301 /app-name/;
}
location /app-name/ {
proxy_pass http://127.0.0.1:PORT/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
đĄī¸ Error Handling & Recovery
Common Issues & Solutions
Port Already in Use
- Script detects port conflicts automatically
- Offers interactive rebuild for same-app conflicts
- Prevents accidental overwrites of different apps
Missing Dependencies
- Validates Dockerfile and package.json presence
- Provides helpful guidance for missing files
- References integration templates for setup
Container Health Issues
- Performs automatic health checks after deployment
- Provides debugging commands when issues occur
- Tests both direct container access and nginx proxy
đ§ Management Commands
The script provides useful commands for ongoing app management:
# View application logs
docker logs app-name
# Restart application
docker restart app-name
# Rebuild application
./deploy-portfolio-app.sh app-name port rebuild
# Access container shell
docker exec -it app-name sh
# Monitor all containers
docker ps | grep 300
đ Best Practices
Port Assignment Strategy
- Range: Use ports 3008-3020 for portfolio apps
- Documentation: Keep a record of port assignments
- Conflicts: Always check for conflicts before deployment
- Testing: Test both direct and nginx access after deployment
Container Management
- Naming: Use consistent container names matching app names
- Restart Policies: Always use
unless-stoppedfor production - Resource Limits: Consider adding memory/CPU limits for production
- Logs: Regularly monitor container logs for issues
Deployment Safety
- Testing: Always test deployment in development first
- Backups: Consider backup strategies for persistent data
- Rollback: Keep previous images for quick rollback if needed
- Monitoring: Set up monitoring for production deployments
đ Script Location & Access
File Path: /var/www/zaylegend/deploy-portfolio-app.sh
Usage Instructions:
- Navigate to the zaylegend directory:
cd /var/www/zaylegend - Make script executable:
chmod +x deploy-portfolio-app.sh - Run deployment:
./deploy-portfolio-app.sh <app-name> <port> [rebuild]
đ Complete Script Source
Below is the complete source code of the portfolio deployment script:
#!/bin/bash
set -e
# Portfolio App Deployment Script
# Usage: ./deploy-portfolio-app.sh <app-name> <port> [rebuild]
APP_NAME="$1"
APP_PORT="$2"
REBUILD_FORCE="$3"
# 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
# Helper functions
log_info() { echo -e "${BLUE}âšī¸ $1${NC}"; }
log_success() { echo -e "${GREEN}â
$1${NC}"; }
log_warning() { echo -e "${YELLOW}â ī¸ $1${NC}"; }
log_error() { echo -e "${RED}â $1${NC}"; }
# Validation
if [[ -z "$APP_NAME" || -z "$APP_PORT" ]]; then
log_error "Usage: $0 <app-name> <port> [rebuild]"
echo ""
echo "Examples:"
echo " $0 fineline 3003 rebuild # Force rebuild fineline"
echo " $0 new-app 3008 # Deploy new app"
echo ""
echo "Available ports: 3008-3020 (check with: docker ps | grep 300)"
exit 1
fi
APP_DIR="/var/www/zaylegend/apps/${APP_NAME}"
BASE_PATH="/${APP_NAME}/"
# Check if app directory exists
if [[ ! -d "$APP_DIR" ]]; then
log_error "App directory not found: $APP_DIR"
log_info "Create the app directory and add your Vite project first"
exit 1
fi
# Check if port is available
if docker ps | grep -q ":${APP_PORT}->"; then
if [[ "$REBUILD_FORCE" != "rebuild" ]]; then
log_warning "Port $APP_PORT is already in use"
EXISTING_CONTAINER=$(docker ps --format "table {{.Names}}\t{{.Ports}}" | grep ":${APP_PORT}->" | awk '{print $1}')
if [[ "$EXISTING_CONTAINER" == "$APP_NAME" ]]; then
log_info "Existing container '$APP_NAME' found on port $APP_PORT"
read -p "Do you want to rebuild it? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Deployment cancelled"
exit 0
fi
REBUILD_FORCE="rebuild"
else
log_error "Port $APP_PORT is used by different container: $EXISTING_CONTAINER"
exit 1
fi
fi
fi
log_info "Starting deployment of '$APP_NAME' on port $APP_PORT..."
# Step 1: Navigate to app directory
cd "$APP_DIR"
log_info "Working in: $(pwd)"
# Step 2: Check for required files
if [[ ! -f "Dockerfile" ]]; then
log_error "Dockerfile not found in $APP_DIR"
log_info "Create a Dockerfile using the template in APP-INTEGRATION-TEMPLATE.md"
exit 1
fi
if [[ ! -f "package.json" ]]; then
log_error "package.json not found - is this a Node.js app?"
exit 1
fi
# Step 3: Stop and remove existing container if rebuilding
if [[ "$REBUILD_FORCE" == "rebuild" ]] || docker ps -a | grep -q "\\b${APP_NAME}\\b"; then
log_info "Stopping existing container..."
docker stop "$APP_NAME" 2>/dev/null || true
docker rm "$APP_NAME" 2>/dev/null || true
log_success "Existing container removed"
fi
# Step 4: Build new image
log_info "Building Docker image..."
docker build \
--build-arg VITE_BASE_PATH="$BASE_PATH" \
-t "${APP_NAME}:latest" \
.
log_success "Docker image built successfully"
# Step 5: Start new container
log_info "Starting container on port $APP_PORT..."
docker run -d \
--name "$APP_NAME" \
-p "${APP_PORT}:80" \
--restart unless-stopped \
"${APP_NAME}:latest"
# Step 6: Wait for container to be ready
log_info "Waiting for container to start..."
sleep 3
# Step 7: Test container health
if curl -f -s "http://localhost:${APP_PORT}/" > /dev/null; then
log_success "Container is healthy and responding"
else
log_error "Container health check failed"
log_info "Check logs with: docker logs $APP_NAME"
exit 1
fi
# Step 8: Test through nginx (if nginx is configured)
NGINX_URL="https://zaylegend.com${BASE_PATH}"
if curl -f -s "$NGINX_URL" > /dev/null; then
log_success "App accessible through nginx: $NGINX_URL"
else
log_warning "App not accessible through nginx yet"
log_info "You may need to add nginx configuration:"
echo ""
echo "Add this to /etc/nginx/conf.d/portfolio.conf:"
echo ""
echo " # $APP_NAME"
echo " location /$APP_NAME {"
echo " return 301 /$APP_NAME/;"
echo " }"
echo ""
echo " location /$APP_NAME/ {"
echo " proxy_pass http://127.0.0.1:$APP_PORT/;"
echo " proxy_set_header Host \$host;"
echo " proxy_set_header X-Real-IP \$remote_addr;"
echo " proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;"
echo " proxy_set_header X-Forwarded-Proto \$scheme;"
echo " proxy_set_header X-Forwarded-Host \$host;"
echo " proxy_set_header X-Forwarded-Port \$server_port;"
echo " proxy_http_version 1.1;"
echo " proxy_set_header Upgrade \$http_upgrade;"
echo " proxy_set_header Connection \"upgrade\";"
echo " proxy_connect_timeout 30s;"
echo " proxy_send_timeout 30s;"
echo " proxy_read_timeout 30s;"
echo " }"
echo ""
echo "Then run: sudo nginx -t && sudo systemctl reload nginx"
fi
# Step 9: Show deployment summary
echo ""
log_success "đ Deployment completed successfully!"
echo ""
echo "đ Deployment Summary:"
echo " App Name: $APP_NAME"
echo " Container Port: $APP_PORT"
echo " Base Path: $BASE_PATH"
echo " Container Status: $(docker inspect --format='{{.State.Status}}' $APP_NAME)"
echo " Direct Access: http://localhost:$APP_PORT/"
echo " Public URL: $NGINX_URL"
echo ""
echo "đ§ Useful Commands:"
echo " View logs: docker logs $APP_NAME"
echo " Restart: docker restart $APP_NAME"
echo " Rebuild: $0 $APP_NAME $APP_PORT rebuild"
echo " Shell access: docker exec -it $APP_NAME sh"
echo ""
# Step 10: Optional - Test JavaScript assets
log_info "Testing JavaScript assets..."
CONTAINER_HTML=$(curl -s "http://localhost:${APP_PORT}/")
JS_FILE=$(echo "$CONTAINER_HTML" | grep -o 'src="/[^"]*\.js"' | head -1 | sed 's/src="//; s/"//')
if [[ -n "$JS_FILE" ]]; then
if curl -f -s "http://localhost:${APP_PORT}${JS_FILE}" | head -c 100 | grep -q "var\|function\|import\|export"; then
log_success "JavaScript assets are serving correctly"
else
log_warning "JavaScript assets may not be serving correctly"
fi
else
log_warning "No JavaScript files detected in HTML"
fi
log_info "Deployment script completed! đ"
đ§ Additional Automation Tools
Container Management Commands
Essential Docker commands for managing deployed applications:
# Monitor all portfolio containers
docker ps | grep -E "300[0-9]"
# View logs for specific app
docker logs -f app-name
# Restart all containers
docker restart $(docker ps -q)
# Clean up unused images
docker image prune -f
# Check container resource usage
docker stats
nginx Management
Commands for managing nginx configuration and testing:
# Test nginx configuration
sudo nginx -t
# Reload nginx configuration
sudo systemctl reload nginx
# Check nginx status
sudo systemctl status nginx
# View nginx error logs
sudo tail -f /var/log/nginx/error.log
# Check proxy configuration
curl -I https://zaylegend.com/app-name/
Monitoring & Health Checks
Scripts for monitoring application health and performance:
# Quick health check for all apps
for port in {3001..3020}; do
if curl -f -s "http://localhost:$port/" > /dev/null; then
echo "Port $port: â
Healthy"
else
echo "Port $port: â Not responding"
fi
done
# Check disk usage
df -h /var/www/zaylegend/
# Monitor system resources
htop
These automation tools provide a robust foundation for managing containerized portfolio applications with Docker and nginx. The deployment script ensures consistent, reliable deployments while providing comprehensive feedback and error handling throughout the process.