From a800cae80fa6eeab0773a418758333f922a351fe Mon Sep 17 00:00:00 2001 From: hex Date: Tue, 29 Apr 2025 14:13:26 -0700 Subject: [PATCH] deployment script --- deploy.sh | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ update.sh | 90 +++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100755 deploy.sh create mode 100755 update.sh diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..b740f91 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,197 @@ +#!/bin/bash +# Deployment script for Hex's Garage Sale Catalog +# This script automates the deployment process on a Debian server + +set -e # Exit immediately if a command exits with a non-zero status + +# Color codes for better readability +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Function to print colored messages +print_message() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if running as root +if [ "$(id -u)" != "0" ]; then + print_error "This script must be run as root" + exit 1 +fi + +# Get deployment configuration +read -p "Enter domain name (e.g., garagesale.example.com): " DOMAIN_NAME +read -p "Enter admin password (default: admin123): " ADMIN_PASSWORD +ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin123} +read -p "Use PostgreSQL instead of SQLite? (y/N): " USE_POSTGRES +USE_POSTGRES=${USE_POSTGRES:-n} + +# Generate a secure secret key +SECRET_KEY=$(openssl rand -hex 24) + +print_message "Beginning deployment process..." + +# Update system packages +print_message "Updating system packages..." +apt update && apt upgrade -y + +# Install required packages +print_message "Installing required packages..." +apt install -y python3 python3-venv python3-pip nginx wkhtmltopdf + +# Setup PostgreSQL if requested +if [[ "$USE_POSTGRES" =~ ^[Yy]$ ]]; then + print_message "Setting up PostgreSQL..." + apt install -y postgresql postgresql-contrib + systemctl start postgresql + systemctl enable postgresql + + # Generate a secure PostgreSQL password + PG_PASSWORD=$(openssl rand -hex 12) + + # Create PostgreSQL user and database + su -c "psql -c \"CREATE DATABASE garagesale;\"" postgres + su -c "psql -c \"CREATE USER garagesaleuser WITH PASSWORD '$PG_PASSWORD';\"" postgres + su -c "psql -c \"GRANT ALL PRIVILEGES ON DATABASE garagesale TO garagesaleuser;\"" postgres + + DB_URL="postgresql://garagesaleuser:$PG_PASSWORD@localhost/garagesale" + print_message "PostgreSQL setup complete." + print_warning "PostgreSQL password: $PG_PASSWORD (Please save this somewhere secure)" +else + DB_URL="sqlite:////var/www/garagesale/garage_sale.db" + print_message "Using SQLite for database." +fi + +# Create a dedicated user for the application +print_message "Creating application user..." +useradd -m -s /bin/bash garagesale || print_warning "User already exists, continuing..." + +# Set up application directory +print_message "Setting up application directory..." +mkdir -p /var/www/garagesale +cp -r $(dirname "$0")/* /var/www/garagesale/ +chown -R garagesale:www-data /var/www/garagesale +chmod -R 755 /var/www/garagesale + +# Create uploads directory with proper permissions +mkdir -p /var/www/garagesale/app/static/uploads +chown -R garagesale:www-data /var/www/garagesale/app/static/uploads +chmod -R 775 /var/www/garagesale/app/static/uploads + +# Set up virtual environment and install dependencies +print_message "Setting up Python virtual environment and dependencies..." +cd /var/www/garagesale +su -c "python3 -m venv venv" garagesale +su -c "source venv/bin/activate && pip install -r requirements.txt && pip install gunicorn" garagesale + +if [[ "$USE_POSTGRES" =~ ^[Yy]$ ]]; then + su -c "source venv/bin/activate && pip install psycopg2-binary" garagesale +fi + +# Create environment file +print_message "Creating environment file..." +cat > /var/www/garagesale/.env << EOF +SECRET_KEY="$SECRET_KEY" +ADMIN_PASSWORD="$ADMIN_PASSWORD" +DATABASE_URL="$DB_URL" +EOF +chown garagesale:garagesale /var/www/garagesale/.env +chmod 600 /var/www/garagesale/.env + +# Create wsgi.py file +print_message "Creating WSGI file..." +cat > /var/www/garagesale/wsgi.py << 'EOF' +from app import create_app + +app = create_app() + +if __name__ == "__main__": + app.run() +EOF +chown garagesale:garagesale /var/www/garagesale/wsgi.py + +# Initialize the database +print_message "Initializing the database..." +cd /var/www/garagesale +su -c "source venv/bin/activate && python init_db.py" garagesale + +# Set up Gunicorn service +print_message "Setting up Gunicorn service..." +cat > /etc/systemd/system/garagesale.service << EOF +[Unit] +Description=Gunicorn instance to serve Hex's Garage Sale Catalog +After=network.target + +[Service] +User=garagesale +Group=www-data +WorkingDirectory=/var/www/garagesale +Environment="PATH=/var/www/garagesale/venv/bin" +EnvironmentFile=/var/www/garagesale/.env +ExecStart=/var/www/garagesale/venv/bin/gunicorn --workers 3 --bind unix:garagesale.sock -m 007 wsgi:app + +[Install] +WantedBy=multi-user.target +EOF + +# Enable and start Gunicorn service +print_message "Starting Gunicorn service..." +systemctl daemon-reload +systemctl start garagesale +systemctl enable garagesale + +# Set up Nginx +print_message "Setting up Nginx..." +cat > /etc/nginx/sites-available/garagesale << EOF +server { + listen 80; + server_name $DOMAIN_NAME; + + location /static { + alias /var/www/garagesale/app/static; + } + + location / { + proxy_pass http://unix:/var/www/garagesale/garagesale.sock; + proxy_set_header Host \$host; + proxy_set_header X-Real-IP \$remote_addr; + } +} +EOF + +# Enable the Nginx site +ln -sf /etc/nginx/sites-available/garagesale /etc/nginx/sites-enabled/ +nginx -t && systemctl restart nginx + +print_message "Basic deployment complete!" + +# Set up SSL with Let's Encrypt +read -p "Do you want to set up SSL with Let's Encrypt? (y/N): " SETUP_SSL +SETUP_SSL=${SETUP_SSL:-n} + +if [[ "$SETUP_SSL" =~ ^[Yy]$ ]]; then + print_message "Setting up SSL with Let's Encrypt..." + apt install -y certbot python3-certbot-nginx + certbot --nginx -d "$DOMAIN_NAME" + print_message "SSL setup complete!" +fi + +print_message "Deployment completed successfully!" +print_message "You can now access your application at: http://$DOMAIN_NAME" +if [[ "$SETUP_SSL" =~ ^[Yy]$ ]]; then + print_message "Or securely at: https://$DOMAIN_NAME" +fi +print_message "Admin interface is available at: http://$DOMAIN_NAME/admin" +print_message "Admin password: $ADMIN_PASSWORD" + +exit 0 diff --git a/update.sh b/update.sh new file mode 100755 index 0000000..cbc8606 --- /dev/null +++ b/update.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# Update script for Hex's Garage Sale Catalog +# This script updates an existing deployment with the latest code + +set -e # Exit immediately if a command exits with a non-zero status + +# Color codes for better readability +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Function to print colored messages +print_message() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if running as root +if [ "$(id -u)" != "0" ]; then + print_error "This script must be run as root" + exit 1 +fi + +# Get deployment configuration +APP_DIR=${1:-/var/www/garagesale} +BACKUP_DIR="/var/backups/garagesale/$(date +%Y%m%d_%H%M%S)" + +print_message "Beginning update process..." + +# Create backup directory +mkdir -p "$BACKUP_DIR" + +# Backup the current database and uploads +print_message "Creating backup..." +if [ -f "$APP_DIR/garage_sale.db" ]; then + cp "$APP_DIR/garage_sale.db" "$BACKUP_DIR/" + print_message "SQLite database backed up to $BACKUP_DIR/garage_sale.db" +fi + +# Backup uploads directory +if [ -d "$APP_DIR/app/static/uploads" ]; then + cp -r "$APP_DIR/app/static/uploads" "$BACKUP_DIR/" + print_message "Uploads directory backed up to $BACKUP_DIR/uploads" +fi + +# Copy environment file +if [ -f "$APP_DIR/.env" ]; then + cp "$APP_DIR/.env" "$BACKUP_DIR/" + print_message "Environment file backed up to $BACKUP_DIR/.env" +fi + +# Copy new code +print_message "Updating application code..." +rsync -av --exclude 'venv' --exclude '.env' --exclude 'garage_sale.db' \ + --exclude 'app/static/uploads' "$(dirname "$0")/" "$APP_DIR/" + +# Set correct ownership and permissions +print_message "Setting correct permissions..." +chown -R garagesale:www-data "$APP_DIR" +chmod -R 755 "$APP_DIR" +chmod -R 775 "$APP_DIR/app/static/uploads" + +# Install or update dependencies +print_message "Updating Python dependencies..." +cd "$APP_DIR" +su -c "source venv/bin/activate && pip install -r requirements.txt" garagesale + +# Run database migrations if needed +print_message "Running database updates..." +cd "$APP_DIR" +su -c "source venv/bin/activate && python update_database.py" garagesale + +# Restart services +print_message "Restarting services..." +systemctl restart garagesale +systemctl restart nginx + +print_message "Update completed successfully!" +print_message "Backup created at: $BACKUP_DIR" +print_message "If you encounter any issues, you can restore from the backup." + +exit 0