#!/bin/bash # InInventer Deployment Script for Debian 12 # This script will deploy the application to a Linode server set -e # Exit on error echo "======================================" echo "InInventer Deployment Script" echo "======================================" # Variables DOMAIN_NAME="" EMAIL_FOR_SSL="" APP_DIR="/opt/ininventer" REPO_URL="" # Color codes 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}[STATUS]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # Check if running as root if [[ $EUID -ne 0 ]]; then print_error "This script must be run as root" exit 1 fi # Get domain name from user read -p "Enter your domain name (e.g., inventory.example.com): " DOMAIN_NAME read -p "Enter email for SSL certificate: " EMAIL_FOR_SSL print_status "Starting deployment for domain: $DOMAIN_NAME" # Update system print_status "Updating system packages..." apt-get update apt-get upgrade -y # Install required packages print_status "Installing required packages..." apt-get install -y \ apt-transport-https \ ca-certificates \ curl \ gnupg \ lsb-release \ git \ ufw # Install Docker print_status "Installing Docker..." if ! command -v docker &> /dev/null; then curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg echo \ "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \ $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null apt-get update apt-get install -y docker-ce docker-ce-cli containerd.io systemctl enable docker systemctl start docker else print_status "Docker is already installed" fi # Install Docker Compose print_status "Installing Docker Compose..." if ! command -v docker-compose &> /dev/null; then curl -L "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose else print_status "Docker Compose is already installed" fi # Configure firewall print_status "Configuring firewall..." ufw allow 22/tcp ufw allow 80/tcp ufw allow 443/tcp ufw --force enable # Create application directory print_status "Creating application directory..." mkdir -p $APP_DIR cd $APP_DIR # Copy application files print_status "Setting up application files..." # Note: You'll need to upload your files to the server first # Create production environment file print_status "Creating production environment configuration..." cat > .env.production << EOL # MongoDB Configuration MONGO_URI=mongodb://mongodb:27017/ininventer MONGO_INITDB_ROOT_USERNAME=admin MONGO_INITDB_ROOT_PASSWORD=$(openssl rand -base64 32) MONGO_INITDB_DATABASE=ininventer # JWT Configuration JWT_SECRET=$(openssl rand -base64 64) JWT_EXPIRATION=24h # Node Environment NODE_ENV=production PORT=5000 # Domain Configuration DOMAIN_NAME=$DOMAIN_NAME EMAIL_FOR_SSL=$EMAIL_FOR_SSL EOL # Create production docker-compose file print_status "Creating production docker-compose configuration..." cat > docker-compose.production.yml << 'EOL' services: mongodb: image: mongo:latest container_name: ininventer-mongodb-prod restart: always volumes: - mongodb_data:/data/db environment: - MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME} - MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD} - MONGO_INITDB_DATABASE=${MONGO_INITDB_DATABASE} networks: - ininventer-network backend: build: ./backend container_name: ininventer-backend-prod restart: always depends_on: - mongodb environment: - NODE_ENV=production - MONGO_URI=mongodb://${MONGO_INITDB_ROOT_USERNAME}:${MONGO_INITDB_ROOT_PASSWORD}@mongodb:27017/${MONGO_INITDB_DATABASE}?authSource=admin - JWT_SECRET=${JWT_SECRET} - JWT_EXPIRATION=${JWT_EXPIRATION} - PORT=5000 networks: - ininventer-network frontend: build: context: ./frontend args: - VITE_API_URL=/api container_name: ininventer-frontend-prod restart: always depends_on: - backend networks: - ininventer-network nginx: image: nginx:alpine container_name: ininventer-nginx-prod restart: always ports: - "80:80" - "443:443" volumes: - ./nginx/production.conf:/etc/nginx/conf.d/default.conf - ./certbot/conf:/etc/letsencrypt - ./certbot/www:/var/www/certbot depends_on: - frontend - backend networks: - ininventer-network command: '/bin/sh -c ''while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g "daemon off;"''' certbot: image: certbot/certbot container_name: ininventer-certbot restart: unless-stopped volumes: - ./certbot/conf:/etc/letsencrypt - ./certbot/www:/var/www/certbot entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'" volumes: mongodb_data: networks: ininventer-network: driver: bridge EOL # Create Nginx production configuration print_status "Creating Nginx production configuration..." mkdir -p nginx cat > nginx/production.conf << EOL server { listen 80; server_name $DOMAIN_NAME; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 301 https://\$server_name\$request_uri; } } server { listen 443 ssl; server_name $DOMAIN_NAME; ssl_certificate /etc/letsencrypt/live/$DOMAIN_NAME/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/$DOMAIN_NAME/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; client_max_body_size 10M; location / { proxy_pass http://frontend:80; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host \$host; proxy_cache_bypass \$http_upgrade; 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; } location /api { proxy_pass http://backend:5000; proxy_http_version 1.1; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host \$host; proxy_cache_bypass \$http_upgrade; 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; } } EOL # Create initial Nginx configuration for SSL setup cat > nginx/initial.conf << EOL server { listen 80; server_name $DOMAIN_NAME; location /.well-known/acme-challenge/ { root /var/www/certbot; } location / { return 200 'InInventer - Setting up SSL...'; add_header Content-Type text/plain; } } EOL print_status "Deployment preparation complete!" print_warning "Next steps:" echo "1. Upload your application code to $APP_DIR" echo "2. Run: cd $APP_DIR && ./start-production.sh" echo "" echo "The start script will:" echo "- Obtain SSL certificates" echo "- Start all services" echo "- Configure automatic SSL renewal"