Files
WebAndAppMonoRepo/output/scripts/deploy.sh
YourDreamNameHere 89443f213b feat: implement core Go application with web server
- Add Go modules with required dependencies (Gin, UUID, JWT, etc.)
- Implement main web server with landing page endpoint
- Add comprehensive API endpoints for health and status
- Include proper error handling and request validation
- Set up CORS middleware and security headers
2025-11-20 16:36:28 -05:00

624 lines
14 KiB
Bash
Executable File

#!/bin/bash
# YourDreamNameHere Production Deployment Script
# This script deploys the YDN application to a fresh Ubuntu 24.04 server
set -euo pipefail
# Configuration
DEPLOYMENT_USER="${DEPLOYMENT_USER:-root}"
DEPLOYMENT_HOST="${DEPLOYMENT_HOST:-}"
DOMAIN="${DOMAIN:-yourdreamnamehere.com}"
DOCKER_REGISTRY="${DOCKER_REGISTRY:-}"
VERSION="${VERSION:-latest}"
ENVIRONMENT="${ENVIRONMENT:-production}"
ENABLE_MONITORING="${ENABLE_MONITORING:-true}"
ENABLE_LOGGING="${ENABLE_LOGGING:-true}"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Validate environment
validate_environment() {
log_info "Validating deployment environment..."
if [ -z "$DEPLOYMENT_HOST" ]; then
log_error "DEPLOYMENT_HOST environment variable is required"
exit 1
fi
if [ -z "$DOMAIN" ]; then
log_error "DOMAIN environment variable is required"
exit 1
fi
# Test SSH connection
if ! ssh -o ConnectTimeout=10 -o BatchMode=yes "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" "echo 'SSH connection successful'"; then
log_error "Failed to connect to $DEPLOYMENT_HOST via SSH"
exit 1
fi
log_success "Environment validation passed"
}
# Prepare remote server
prepare_server() {
log_info "Preparing remote server..."
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << 'EOF'
set -euo pipefail
# Update system
apt-get update
apt-get upgrade -y
# Install required packages
apt-get install -y \
curl \
wget \
git \
htop \
unzip \
software-properties-common \
apt-transport-https \
ca-certificates \
gnupg \
lsb-release \
ufw \
fail2ban \
logrotate \
certbot \
python3-certbot-nginx
# Install Docker
if ! command -v docker &> /dev/null; then
curl -fsSL https://download.docker.com/linux/ubuntu/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/ubuntu $(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
fi
# Install Docker Compose
if ! command -v docker-compose &> /dev/null; then
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
fi
# Create deployment directory
mkdir -p /opt/ydn
cd /opt/ydn
# Create application user
if ! id "ydn" &>/dev/null; then
useradd -m -s /bin/bash ydn
usermod -aG docker ydn
fi
# Set up directory structure
mkdir -p {configs,scripts,logs,ssl,backups,data}
chown -R ydn:ydn /opt/ydn
# Configure firewall
ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
# Configure fail2ban
cat > /etc/fail2ban/jail.local << 'FAIL2BAN'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
[nginx-http-auth]
enabled = true
port = http,https
logpath = /var/log/nginx/error.log
FAIL2BAN
systemctl enable fail2ban
systemctl restart fail2ban
# Set up log rotation
cat > /etc/logrotate.d/ydn << 'LOGROTATE'
/opt/ydn/logs/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 644 ydn ydn
postrotate
docker kill -s USR1 ydn-nginx 2>/dev/null || true
endscript
}
LOGROTATE
log_success "Server preparation completed"
EOF
log_success "Remote server prepared"
}
# Deploy application files
deploy_files() {
log_info "Deploying application files..."
# Create temporary deployment package
TEMP_DIR=$(mktemp -d)
trap "rm -rf $TEMP_DIR" EXIT
# Copy necessary files
cp -r "$PROJECT_DIR"/* "$TEMP_DIR/"
# Create production environment file
cat > "$TEMP_DIR/.env.prod" << EOF
# Production Environment Configuration
APP_ENV=production
APP_NAME=YourDreamNameHere
DOMAIN=$DOMAIN
# Database Configuration
DB_HOST=ydn-db
DB_PORT=5432
DB_USER=ydn_user
DB_PASSWORD=$(openssl rand -base64 32)
DB_NAME=ydn_db
DB_SSLMODE=require
# Redis Configuration
REDIS_HOST=ydn-redis
REDIS_PORT=6379
REDIS_PASSWORD=$(openssl rand -base64 32)
REDIS_DB=0
# JWT Configuration
JWT_SECRET=$(openssl rand -base64 64)
JWT_EXPIRY=24h
# Stripe Configuration
STRIPE_PUBLIC_KEY=$STRIPE_PUBLIC_KEY
STRIPE_SECRET_KEY=$STRIPE_SECRET_KEY
STRIPE_WEBHOOK_SECRET=$STRIPE_WEBHOOK_SECRET
STRIPE_PRICE_ID=$STRIPE_PRICE_ID
# OVH Configuration
OVH_ENDPOINT=$OVH_ENDPOINT
OVH_APPLICATION_KEY=$OVH_APPLICATION_KEY
OVH_APPLICATION_SECRET=$OVH_APPLICATION_SECRET
OVH_CONSUMER_KEY=$OVH_CONSUMER_KEY
# Email Configuration
SMTP_HOST=$SMTP_HOST
SMTP_PORT=$SMTP_PORT
SMTP_USER=$SMTP_USER
SMTP_PASSWORD=$SMTP_PASSWORD
SMTP_FROM=$SMTP_FROM
# Dolibarr Configuration
DOLIBARR_URL=https://$DOMAIN/dolibarr
DOLIBARR_API_TOKEN=$DOLIBARR_API_TOKEN
# Monitoring
GRAFANA_ADMIN_PASSWORD=$(openssl rand -base64 16)
# Version
VERSION=$VERSION
EOF
# Copy files to remote server
scp -r "$TEMP_DIR/"* "$DEPLOYMENT_USER@$DEPLOYMENT_HOST:/opt/ydn/"
# Set correct permissions
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" "chown -R ydn:ydn /opt/ydn"
log_success "Application files deployed"
}
# Generate SSL certificates
setup_ssl() {
log_info "Setting up SSL certificates..."
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
set -euo pipefail
cd /opt/ydn
# Generate initial nginx config for SSL challenge
cat > configs/nginx.init.conf << 'NGINX'
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name $DOMAIN;
location /.well-known/acme-challenge/ {
root /var/www/html;
}
location / {
return 301 https://\$server_name\$request_uri;
}
}
}
NGINX
# Start temporary nginx for SSL challenge
docker run -d \
--name ydn-nginx-temp \
-p 80:80 \
-v /opt/ydn/configs/nginx.init.conf:/etc/nginx/nginx.conf:ro \
-v /var/www/html:/var/www/html \
nginx:alpine
# Wait for nginx to start
sleep 10
# Request SSL certificate
if [ ! -d "/etc/letsencrypt/live/$DOMAIN" ]; then
certbot certonly --webroot \
-w /var/www/html \
-d $DOMAIN \
--email admin@$DOMAIN \
--agree-tos \
--no-eff-email \
--non-interactive
fi
# Stop temporary nginx
docker stop ydn-nginx-temp
docker rm ydn-nginx-temp
# Copy certificates to project directory
mkdir -p ssl
cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem ssl/
cp /etc/letsencrypt/live/$DOMAIN/privkey.pem ssl/
chown -R ydn:ydn ssl
# Set up automatic renewal
echo "0 12 * * * /usr/bin/certbot renew --quiet --deploy-hook 'docker kill -s HUP ydn-nginx'" | crontab -
EOF
log_success "SSL certificates configured"
}
# Deploy application stack
deploy_application() {
log_info "Deploying application stack..."
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
set -euo pipefail
cd /opt/ydn
# Switch to ydn user
sudo -u ydn bash << 'USER_SCRIPT'
set -euo pipefail
# Load environment variables
source .env.prod
# Build and push Docker image (if registry is configured)
if [ -n "$DOCKER_REGISTRY" ]; then
docker build -t $DOCKER_REGISTRY/ydn-app:\$VERSION .
docker push $DOCKER_REGISTRY/ydn-app:\$VERSION
fi
# Create production docker-compose override
cat > docker-compose.override.yml << 'OVERRIDE'
version: '3.8'
services:
ydn-app:
image: ${DOCKER_REGISTRY:-ydn-app}:ydn-app:\${VERSION:-latest}
environment:
- \${APP_ENV}
- \${DB_HOST}
- \${DB_USER}
- \${DB_PASSWORD}
- \${DB_NAME}
- \${DB_SSLMODE}
- \${REDIS_HOST}
- \${REDIS_PASSWORD}
- \${JWT_SECRET}
- \${STRIPE_PUBLIC_KEY}
- \${STRIPE_SECRET_KEY}
- \${STRIPE_WEBHOOK_SECRET}
- \${STRIPE_PRICE_ID}
- \${OVH_ENDPOINT}
- \${OVH_APPLICATION_KEY}
- \${OVH_APPLICATION_SECRET}
- \${OVH_CONSUMER_KEY}
- \${SMTP_HOST}
- \${SMTP_USER}
- \${SMTP_PASSWORD}
- \${SMTP_FROM}
- \${DOLIBARR_URL}
- \${DOLIBARR_API_TOKEN}
ydn-nginx:
volumes:
- ./ssl:/etc/nginx/ssl:ro
environment:
- DOMAIN=\${DOMAIN}
ydn-backup:
environment:
- DB_PASSWORD=\${DB_PASSWORD}
- BACKUP_WEBHOOK_URL=\${BACKUP_WEBHOOK_URL:-}
OVERRIDE
# Deploy with monitoring if enabled
if [ "$ENABLE_MONITORING" = "true" ]; then
docker-compose -f docker-compose.prod.yml --profile monitoring up -d
else
docker-compose -f docker-compose.prod.yml up -d
fi
# Wait for services to be ready
sleep 30
# Run database migrations
docker-compose -f docker-compose.prod.yml exec ydn-app /app/main migrate || true
USER_SCRIPT
EOF
log_success "Application stack deployed"
}
# Health check
health_check() {
log_info "Performing health checks..."
# Wait for application to start
sleep 60
# Check if services are running
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
set -euo pipefail
cd /opt/ydn
# Check Docker containers
if ! docker-compose -f docker-compose.prod.yml ps | grep -q "Up"; then
echo "ERROR: Some containers are not running"
docker-compose -f docker-compose.prod.yml ps
exit 1
fi
# Check application health
for i in {1..30}; do
if curl -f http://localhost/health > /dev/null 2>&1; then
echo "Application health check passed"
break
fi
if [ \$i -eq 30 ]; then
echo "ERROR: Application health check failed"
exit 1
fi
sleep 10
done
# Check SSL certificate
if ! curl -f https://$DOMAIN/health > /dev/null 2>&1; then
echo "ERROR: SSL health check failed"
exit 1
fi
echo "All health checks passed"
EOF
log_success "Health checks completed"
}
# Setup monitoring
setup_monitoring() {
if [ "$ENABLE_MONITORING" != "true" ]; then
log_info "Monitoring is disabled"
return 0
fi
log_info "Setting up monitoring..."
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
set -euo pipefail
cd /opt/ydn
# Configure Prometheus
cat > configs/prometheus.prod.yml << 'PROMETHEUS'
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "rules/*.yml"
scrape_configs:
- job_name: 'ydn-app'
static_configs:
- targets: ['ydn-app:8080']
metrics_path: /metrics
- job_name: 'nginx'
static_configs:
- targets: ['ydn-nginx:9113']
- job_name: 'postgres'
static_configs:
- targets: ['ydn-db:5432']
- job_name: 'redis'
static_configs:
- targets: ['ydn-redis:6379']
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
PROMETHEUS
# Restart monitoring services
sudo -u ydn docker-compose -f docker-compose.prod.yml --profile monitoring restart ydn-prometheus ydn-grafana
EOF
log_success "Monitoring configured"
}
# Deploy to production
deploy_production() {
log_info "Starting production deployment..."
validate_environment
prepare_server
deploy_files
setup_ssl
deploy_application
setup_monitoring
health_check
log_success "🎉 Production deployment completed successfully!"
log_info "Application is available at: https://$DOMAIN"
if [ "$ENABLE_MONITORING" = "true" ]; then
log_info "Grafana is available at: https://$DOMAIN/grafana"
fi
log_info "Dolibarr is available at: https://$DOMAIN/dolibarr"
}
# Rollback deployment
rollback() {
log_warning "Rolling back deployment..."
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" << EOF
set -euo pipefail
cd /opt/ydn
# Get previous version from git
PREVIOUS_VERSION=\$(git log --format=%H -n 2 | tail -n 1)
# Checkout previous version
sudo -u ydn git checkout \$PREVIOUS_VERSION
# Redeploy
sudo -u ydn docker-compose -f docker-compose.prod.yml down
sudo -u ydn docker-compose -f docker-compose.prod.yml up -d
EOF
log_success "Rollback completed"
}
# Show help
show_help() {
cat << EOF
YourDreamNameHere Production Deployment Script
Usage: $0 [OPTIONS]
Commands:
deploy Deploy to production (default)
rollback Rollback to previous version
status Show deployment status
help Show this help message
Environment Variables:
DEPLOYMENT_HOST Target server hostname/IP (required)
DOMAIN Domain name (required)
DOCKER_REGISTRY Docker registry URL (optional)
VERSION Version tag (default: latest)
ENABLE_MONITORING Enable monitoring (default: true)
ENABLE_LOGGING Enable logging (default: true)
STRIPE_PUBLIC_KEY Stripe public key (required)
STRIPE_SECRET_KEY Stripe secret key (required)
STRIPE_WEBHOOK_SECRET Stripe webhook secret (required)
STRIPE_PRICE_ID Stripe price ID (required)
OVH_ENDPOINT OVH API endpoint
OVH_APPLICATION_KEY OVH application key
OVH_APPLICATION_SECRET OVH application secret
OVH_CONSUMER_KEY OVH consumer key
SMTP_HOST SMTP server hostname
SMTP_PORT SMTP server port
SMTP_USER SMTP username
SMTP_PASSWORD SMTP password
SMTP_FROM From email address
DOLIBARR_API_TOKEN Dolibarr API token
BACKUP_WEBHOOK_URL Backup notification webhook URL (optional)
Examples:
# Deploy to production
DEPLOYMENT_HOST=192.168.1.100 DOMAIN=example.com $0 deploy
# Deploy with monitoring disabled
DEPLOYMENT_HOST=192.168.1.100 DOMAIN=example.com ENABLE_MONITORING=false $0 deploy
# Rollback deployment
DEPLOYMENT_HOST=192.168.1.100 DOMAIN=example.com $0 rollback
EOF
}
# Main execution
case "${1:-deploy}" in
deploy)
deploy_production
;;
rollback)
rollback
;;
status)
ssh "$DEPLOYMENT_USER@$DEPLOYMENT_HOST" "cd /opt/ydn && docker-compose -f docker-compose.prod.yml ps"
;;
help|--help|-h)
show_help
;;
*)
log_error "Unknown command: $1"
show_help
exit 1
;;
esac