286 lines
7.5 KiB
Bash
Executable File
286 lines
7.5 KiB
Bash
Executable File
#!/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" |