374 lines
9.8 KiB
Bash
374 lines
9.8 KiB
Bash
#!/bin/bash
|
|
# Monaco USA Portal - Production Deployment Script
|
|
# For Debian/Ubuntu Linux servers
|
|
#
|
|
# Usage: ./deploy.sh [command]
|
|
# Commands:
|
|
# setup - First-time setup (install Docker, configure firewall)
|
|
# deploy - Build and start all services
|
|
# update - Pull latest changes and rebuild portal
|
|
# logs - View logs
|
|
# status - Check service status
|
|
# backup - Backup database
|
|
# restore - Restore database from backup
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Configuration
|
|
COMPOSE_FILE="docker-compose.yml"
|
|
PROJECT_NAME="monacousa"
|
|
REGISTRY="code.letsbe.solutions/letsbe"
|
|
|
|
log_info() {
|
|
echo -e "${GREEN}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
# Check if running as root
|
|
check_root() {
|
|
if [ "$EUID" -ne 0 ]; then
|
|
log_error "Please run as root (sudo ./deploy.sh)"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Install Docker and Docker Compose on Debian
|
|
install_docker() {
|
|
log_info "Installing Docker..."
|
|
|
|
# Remove old versions
|
|
apt-get remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true
|
|
|
|
# Install dependencies
|
|
apt-get update
|
|
apt-get install -y \
|
|
apt-transport-https \
|
|
ca-certificates \
|
|
curl \
|
|
gnupg \
|
|
lsb-release
|
|
|
|
# Add Docker's official GPG key
|
|
install -m 0755 -d /etc/apt/keyrings
|
|
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
chmod a+r /etc/apt/keyrings/docker.gpg
|
|
|
|
# Add repository
|
|
echo \
|
|
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
|
|
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
|
|
tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
|
|
# Install Docker
|
|
apt-get update
|
|
apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
|
|
|
# Start and enable Docker
|
|
systemctl start docker
|
|
systemctl enable docker
|
|
|
|
log_info "Docker installed successfully"
|
|
}
|
|
|
|
# Configure firewall
|
|
configure_firewall() {
|
|
log_info "Configuring firewall..."
|
|
|
|
# Install ufw if not present
|
|
apt-get install -y ufw
|
|
|
|
# Allow SSH, HTTP, HTTPS
|
|
ufw allow ssh
|
|
ufw allow http
|
|
ufw allow https
|
|
|
|
# Enable firewall
|
|
ufw --force enable
|
|
|
|
log_info "Firewall configured (SSH, HTTP, HTTPS allowed)"
|
|
}
|
|
|
|
# First-time setup
|
|
setup() {
|
|
check_root
|
|
log_info "Starting first-time setup..."
|
|
|
|
# Update system
|
|
apt-get update && apt-get upgrade -y
|
|
|
|
# Install Docker
|
|
install_docker
|
|
|
|
# Configure firewall
|
|
configure_firewall
|
|
|
|
# Install useful tools
|
|
apt-get install -y htop nano git apache2-utils
|
|
|
|
# Check for .env file
|
|
if [ ! -f .env ]; then
|
|
log_warn ".env file not found!"
|
|
log_info "Copy .env.production.example to .env and configure it:"
|
|
echo " cp .env.production.example .env"
|
|
echo " nano .env"
|
|
fi
|
|
|
|
log_info "Setup complete! Next steps:"
|
|
echo " 1. Configure .env file: nano .env"
|
|
echo " 2. Deploy: ./deploy.sh deploy"
|
|
}
|
|
|
|
# Generate secrets helper
|
|
generate_secrets() {
|
|
log_info "Generating secrets..."
|
|
echo ""
|
|
echo "JWT_SECRET=$(openssl rand -base64 32)"
|
|
echo "POSTGRES_PASSWORD=$(openssl rand -base64 32)"
|
|
echo "SECRET_KEY_BASE=$(openssl rand -base64 64)"
|
|
echo ""
|
|
log_info "Copy these values to your .env file"
|
|
}
|
|
|
|
# Build custom Docker images (run from dev machine)
|
|
build_images() {
|
|
log_info "Building custom Docker images..."
|
|
|
|
# Sync latest SQL files into build contexts
|
|
cp supabase/docker/00-init-schemas.sql docker/db/00-init-schemas.sql
|
|
cp supabase/docker/migrate.sh docker/db/migrate.sh
|
|
cp deploy/init.sql docker/migrate/init.sql
|
|
cp deploy/post-deploy.sql docker/migrate/post-deploy.sql
|
|
|
|
docker build -t ${REGISTRY}/monacousa-db:latest docker/db/
|
|
docker build -t ${REGISTRY}/monacousa-kong:latest docker/kong/
|
|
docker build -t ${REGISTRY}/monacousa-migrate:latest docker/migrate/
|
|
|
|
log_info "All images built successfully"
|
|
}
|
|
|
|
# Push custom Docker images to registry
|
|
push_images() {
|
|
log_info "Pushing images to ${REGISTRY}..."
|
|
|
|
docker push ${REGISTRY}/monacousa-db:latest
|
|
docker push ${REGISTRY}/monacousa-kong:latest
|
|
docker push ${REGISTRY}/monacousa-migrate:latest
|
|
|
|
log_info "All images pushed successfully"
|
|
}
|
|
|
|
# Deploy/start services
|
|
deploy() {
|
|
log_info "Deploying Monaco USA Portal..."
|
|
|
|
# Check for .env file
|
|
if [ ! -f .env ]; then
|
|
log_error ".env file not found! Create .env with required variables first."
|
|
exit 1
|
|
fi
|
|
|
|
# Pull latest images and start all services
|
|
# Kong config is generated at startup from env vars
|
|
# Migrations run automatically via the migrate container
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME pull
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME up -d
|
|
|
|
log_info "Waiting for services to start..."
|
|
sleep 10
|
|
|
|
# Show status
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME ps
|
|
|
|
log_info "Migrations run automatically via the migrate container."
|
|
log_info "Check migrate logs: docker compose -f $COMPOSE_FILE -p $PROJECT_NAME logs migrate"
|
|
log_info "Portal should be available at https://\$(grep DOMAIN .env | cut -d '=' -f2)"
|
|
}
|
|
|
|
# Update all services (pull latest images and restart)
|
|
update() {
|
|
log_info "Updating Monaco USA Portal..."
|
|
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME pull
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME up -d
|
|
|
|
log_info "Update complete!"
|
|
}
|
|
|
|
# View logs
|
|
logs() {
|
|
local service=${1:-""}
|
|
if [ -z "$service" ]; then
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME logs -f --tail=100
|
|
else
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME logs -f --tail=100 $service
|
|
fi
|
|
}
|
|
|
|
# Check status
|
|
status() {
|
|
log_info "Service Status:"
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME ps
|
|
echo ""
|
|
log_info "Resource Usage:"
|
|
docker stats --no-stream $(docker compose -f $COMPOSE_FILE -p $PROJECT_NAME ps -q)
|
|
}
|
|
|
|
# Backup database
|
|
backup() {
|
|
local backup_file="backup_$(date +%Y%m%d_%H%M%S).sql"
|
|
log_info "Backing up database to $backup_file..."
|
|
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME exec -T db \
|
|
pg_dump -U postgres postgres > "$backup_file"
|
|
|
|
# Compress
|
|
gzip "$backup_file"
|
|
|
|
log_info "Backup complete: ${backup_file}.gz"
|
|
}
|
|
|
|
# Restore database
|
|
restore() {
|
|
local backup_file=$1
|
|
if [ -z "$backup_file" ]; then
|
|
log_error "Usage: ./deploy.sh restore <backup_file.sql.gz>"
|
|
exit 1
|
|
fi
|
|
|
|
log_warn "This will overwrite the current database!"
|
|
read -p "Are you sure? (y/N) " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
|
|
log_info "Restoring database from $backup_file..."
|
|
|
|
# Decompress if needed
|
|
if [[ "$backup_file" == *.gz ]]; then
|
|
gunzip -c "$backup_file" | docker compose -f $COMPOSE_FILE -p $PROJECT_NAME exec -T db \
|
|
psql -U postgres postgres
|
|
else
|
|
cat "$backup_file" | docker compose -f $COMPOSE_FILE -p $PROJECT_NAME exec -T db \
|
|
psql -U postgres postgres
|
|
fi
|
|
|
|
log_info "Restore complete!"
|
|
}
|
|
|
|
# Stop all services
|
|
stop() {
|
|
log_info "Stopping all services..."
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME down
|
|
log_info "All services stopped"
|
|
}
|
|
|
|
# Restart all services
|
|
restart() {
|
|
log_info "Restarting all services..."
|
|
docker compose -f $COMPOSE_FILE -p $PROJECT_NAME restart
|
|
log_info "All services restarted"
|
|
}
|
|
|
|
# Clean up unused Docker resources
|
|
cleanup() {
|
|
log_info "Cleaning up unused Docker resources..."
|
|
docker system prune -af --volumes
|
|
log_info "Cleanup complete"
|
|
}
|
|
|
|
# Show help
|
|
help() {
|
|
echo "Monaco USA Portal - Deployment Script"
|
|
echo ""
|
|
echo "Usage: ./deploy.sh [command]"
|
|
echo ""
|
|
echo "Server Commands (only need .env + docker-compose.yml):"
|
|
echo " setup First-time server setup (install Docker, firewall)"
|
|
echo " generate-secrets Generate random secrets for .env"
|
|
echo " deploy Pull images and start all services"
|
|
echo " update Pull latest images and restart"
|
|
echo " stop Stop all services"
|
|
echo " restart Restart all services"
|
|
echo " status Show service status and resource usage"
|
|
echo " logs [service] View logs (optionally for specific service)"
|
|
echo " backup Backup database to file"
|
|
echo " restore <file> Restore database from backup"
|
|
echo " cleanup Remove unused Docker resources"
|
|
echo ""
|
|
echo "Dev Commands (run from the repo with docker/ directory):"
|
|
echo " build-images Build custom Docker images (db, kong, migrate)"
|
|
echo " push-images Push custom images to registry"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " sudo ./deploy.sh setup # First-time setup"
|
|
echo " ./deploy.sh deploy # Deploy the portal"
|
|
echo " ./deploy.sh logs portal # View portal logs"
|
|
echo " ./deploy.sh build-images # Build custom images (dev)"
|
|
echo " ./deploy.sh push-images # Push images to registry (dev)"
|
|
}
|
|
|
|
# Main command handler
|
|
case "${1:-help}" in
|
|
setup)
|
|
setup
|
|
;;
|
|
generate-secrets)
|
|
generate_secrets
|
|
;;
|
|
build-images)
|
|
build_images
|
|
;;
|
|
push-images)
|
|
push_images
|
|
;;
|
|
deploy)
|
|
deploy
|
|
;;
|
|
update)
|
|
update
|
|
;;
|
|
stop)
|
|
stop
|
|
;;
|
|
restart)
|
|
restart
|
|
;;
|
|
status)
|
|
status
|
|
;;
|
|
logs)
|
|
logs $2
|
|
;;
|
|
backup)
|
|
backup
|
|
;;
|
|
restore)
|
|
restore $2
|
|
;;
|
|
cleanup)
|
|
cleanup
|
|
;;
|
|
help|--help|-h)
|
|
help
|
|
;;
|
|
*)
|
|
log_error "Unknown command: $1"
|
|
help
|
|
exit 1
|
|
;;
|
|
esac
|