hostinger-django-demo/deploy-django-project.sh
2025-08-30 09:42:19 +05:30

300 lines
9.1 KiB
Bash
Executable File

#!/bin/bash
# Multi-Project Django Deployment Script
# Automatically extracts GitHub repo name for project naming
# Usage: sudo bash deploy-django-project.sh <GITHUB_REPO_URL>
# Example: sudo bash deploy-django-project.sh https://github.com/user/my-django-app.git
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}🚀 Multi-Project Django Deployment Script${NC}"
echo -e "${BLUE}===========================================${NC}"
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}❌ Please run this script as root (use sudo)${NC}"
exit 1
fi
# Get repository URL from argument
REPO_URL="$1"
if [ -z "$REPO_URL" ]; then
echo -e "${YELLOW}📝 Enter your GitHub repository URL:${NC}"
read -p "Repository URL: " REPO_URL
fi
if [ -z "$REPO_URL" ]; then
echo -e "${RED}❌ Repository URL is required${NC}"
exit 1
fi
# Extract project name from GitHub URL
# Examples:
# https://github.com/user/project-name.git -> project-name
# https://github.com/user/project-name -> project-name
# git@github.com:user/project-name.git -> project-name
PROJECT_NAME=$(echo "$REPO_URL" | sed -E 's|.*/([^/]+)/?$|\1|' | sed 's|\.git$||')
if [ -z "$PROJECT_NAME" ]; then
echo -e "${RED}❌ Could not extract project name from URL: $REPO_URL${NC}"
exit 1
fi
# Configuration
VPS_IP=$(curl -s ifconfig.me 2>/dev/null || echo "YOUR_VPS_IP")
PROJECT_PATH="/var/www/$PROJECT_NAME"
echo -e "${GREEN}✅ Configuration:${NC}"
echo -e "Repository: $REPO_URL"
echo -e "Project Name: $PROJECT_NAME"
echo -e "Deploy Path: $PROJECT_PATH"
echo -e "VPS IP: $VPS_IP"
echo
# Confirmation
echo -e "${YELLOW}🤔 Continue with deployment? (y/n)${NC}"
read -p "Confirm: " CONFIRM
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
echo -e "${YELLOW}❌ Deployment cancelled${NC}"
exit 0
fi
# Helper functions
print_status() {
echo -e "${GREEN}$1${NC}"
}
print_progress() {
echo -e "${YELLOW}🔄 $1${NC}"
}
# Step 1: Install system packages (only if first deployment)
if [ ! -f "/var/www/.system_setup_done" ]; then
print_progress "Installing system packages (first time setup)..."
apt update
apt install -y python3 python3-pip python3-venv python3-dev \
nginx postgresql postgresql-contrib libpq-dev \
build-essential curl git ufw
# Create django user if doesn't exist
if ! id "django" &>/dev/null; then
adduser django --disabled-password --gecos ''
usermod -aG sudo django
print_status "Django user created"
fi
# Copy SSH keys if they exist
if [ -d "/root/.ssh" ] && [ -f "/root/.ssh/authorized_keys" ]; then
mkdir -p /home/django/.ssh
cp /root/.ssh/authorized_keys /home/django/.ssh/
chown -R django:django /home/django/.ssh
chmod 700 /home/django/.ssh
chmod 600 /home/django/.ssh/authorized_keys
fi
# Create /var/www directory
mkdir -p /var/www
chown django:www-data /var/www
# Mark system setup as done
touch /var/www/.system_setup_done
print_status "System setup complete"
else
print_status "System already configured, skipping package installation"
fi
# Step 2: Clone or update project
print_progress "Setting up project: $PROJECT_NAME..."
if [ -d "$PROJECT_PATH" ]; then
print_progress "Updating existing project..."
sudo -u django bash -c "cd $PROJECT_PATH && git pull origin main"
print_status "Project updated"
else
print_progress "Cloning new project..."
sudo -u django bash -c "cd /var/www && git clone $REPO_URL $PROJECT_NAME"
print_status "Project cloned"
fi
# Step 3: Virtual environment
print_progress "Setting up virtual environment..."
sudo -u django bash -c "cd $PROJECT_PATH && python3 -m venv venv"
print_status "Virtual environment created"
# Step 4: Install dependencies
print_progress "Installing Python dependencies..."
sudo -u django bash -c "cd $PROJECT_PATH && source venv/bin/activate && pip install --upgrade pip && pip install -r requirements.txt"
print_status "Dependencies installed"
# Step 5: Django setup
print_progress "Setting up Django..."
# Create environment file if it doesn't exist
if [ ! -f "$PROJECT_PATH/.env" ]; then
print_progress "Creating environment file..."
SECRET_KEY=$(python3 -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())")
cat > "$PROJECT_PATH/.env" << EOF
SECRET_KEY=$SECRET_KEY
DEBUG=False
ALLOWED_HOSTS=$VPS_IP,localhost,127.0.0.1
DATABASE_URL=
EOF
chown django:django "$PROJECT_PATH/.env"
chmod 600 "$PROJECT_PATH/.env"
print_status "Environment file created"
fi
# Run Django management commands
sudo -u django bash -c "cd $PROJECT_PATH && source venv/bin/activate && python manage.py migrate"
sudo -u django bash -c "cd $PROJECT_PATH && source venv/bin/activate && python manage.py collectstatic --noinput"
print_status "Django setup complete"
# Step 6: Gunicorn configuration
print_progress "Setting up Gunicorn for $PROJECT_NAME..."
# Detect Django project directory name (the one with settings.py)
DJANGO_PROJECT_DIR=$(sudo -u django find "$PROJECT_PATH" -name "settings.py" -exec dirname {} \; | head -1)
DJANGO_PROJECT_NAME=$(basename "$DJANGO_PROJECT_DIR")
# Create Gunicorn configuration
mkdir -p "$PROJECT_PATH/config"
cat > "$PROJECT_PATH/config/gunicorn.conf.py" << EOF
# Gunicorn configuration for $PROJECT_NAME
bind = "unix:/run/gunicorn-$PROJECT_NAME.sock"
workers = 3
user = "django"
group = "www-data"
timeout = 30
keepalive = 2
max_requests = 1000
max_requests_jitter = 100
EOF
# Create systemd socket file
cat > "/etc/systemd/system/gunicorn-$PROJECT_NAME.socket" << EOF
[Unit]
Description=gunicorn socket for $PROJECT_NAME
[Socket]
ListenStream=/run/gunicorn-$PROJECT_NAME.sock
[Install]
WantedBy=sockets.target
EOF
# Create systemd service file
cat > "/etc/systemd/system/gunicorn-$PROJECT_NAME.service" << EOF
[Unit]
Description=gunicorn daemon for $PROJECT_NAME
Requires=gunicorn-$PROJECT_NAME.socket
After=network.target
[Service]
Type=notify
User=django
Group=www-data
RuntimeDirectory=gunicorn-$PROJECT_NAME
WorkingDirectory=$PROJECT_PATH
Environment=PYTHONPATH=$PROJECT_PATH
EnvironmentFile=$PROJECT_PATH/.env
ExecStart=$PROJECT_PATH/venv/bin/gunicorn \\
--config $PROJECT_PATH/config/gunicorn.conf.py \\
$DJANGO_PROJECT_NAME.wsgi:application
ExecReload=/bin/kill -s HUP \$MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
print_status "Gunicorn configuration created"
# Step 7: Nginx configuration
print_progress "Setting up Nginx for $PROJECT_NAME..."
# Create Nginx site configuration
cat > "/etc/nginx/sites-available/$PROJECT_NAME" << EOF
server {
listen 80;
server_name $VPS_IP;
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Root location for this project
location /$PROJECT_NAME/ {
include proxy_params;
proxy_pass http://unix:/run/gunicorn-$PROJECT_NAME.sock/;
# Remove the project name from the path when passing to Django
rewrite ^/$PROJECT_NAME/(.*) /\$1 break;
}
# Static files for this project
location /$PROJECT_NAME/static/ {
alias $PROJECT_PATH/staticfiles/;
expires 1y;
add_header Cache-Control "public, immutable";
}
# Media files for this project
location /$PROJECT_NAME/media/ {
alias $PROJECT_PATH/media/;
expires 1y;
add_header Cache-Control "public";
}
}
EOF
# Enable the site
ln -sf "/etc/nginx/sites-available/$PROJECT_NAME" "/etc/nginx/sites-enabled/$PROJECT_NAME"
print_status "Nginx configuration created"
# Step 8: Start services
print_progress "Starting services for $PROJECT_NAME..."
systemctl daemon-reload
systemctl enable "gunicorn-$PROJECT_NAME.socket"
systemctl start "gunicorn-$PROJECT_NAME.socket"
systemctl enable "gunicorn-$PROJECT_NAME.service"
# Test nginx configuration
nginx -t
systemctl restart nginx
print_status "Services started"
# Step 9: Test deployment
print_progress "Testing deployment..."
sleep 3
if systemctl is-active --quiet "gunicorn-$PROJECT_NAME.service"; then
print_status "$PROJECT_NAME deployed successfully!"
echo
echo -e "${GREEN}🎉 Deployment Complete!${NC}"
echo -e "${YELLOW}📋 Project Details:${NC}"
echo -e "Project Name: $PROJECT_NAME"
echo -e "Project Path: $PROJECT_PATH"
echo -e "Project URL: http://$VPS_IP/$PROJECT_NAME/"
echo -e "Static Files: http://$VPS_IP/$PROJECT_NAME/static/"
echo
echo -e "${YELLOW}🔧 Management Commands:${NC}"
echo -e "Check status: systemctl status gunicorn-$PROJECT_NAME.service"
echo -e "View logs: journalctl -u gunicorn-$PROJECT_NAME.service -f"
echo -e "Restart: systemctl restart gunicorn-$PROJECT_NAME.service"
echo
else
echo -e "${RED}❌ Deployment failed for $PROJECT_NAME${NC}"
echo "Check logs: journalctl -u gunicorn-$PROJECT_NAME.service -f"
exit 1
fi