Restore multi-project deployment system

- Restored MULTI_PROJECT_SETUP.md with research-based approach
- Restored deploy-project.sh with GitHub repo name extraction
- Restored webhook-router.py for centralized webhook handling
- Cleaned up confusing documentation files
- Multi-project system supports unlimited Django projects
- Auto-extracts repo names: my-app.git → /var/www/my-app/
- Path-based routing: yourip.com/project1/, yourip.com/project2/
- Follows 2024 Django deployment best practices
This commit is contained in:
thecyberlearn 2025-08-30 09:24:15 +05:30
parent f721b0a87e
commit 61d8656da5
14 changed files with 1613 additions and 1193 deletions

View File

@ -1,146 +0,0 @@
# VPS Deployment Guide
## Prerequisites
Before starting, make sure you have:
- [ ] Ubuntu 20.04+ VPS with root/sudo access
- [ ] Your VPS IP address
- [ ] SSH key or password for VPS access
- [ ] Domain name (optional, can use IP address)
## Step 1: Prepare Local Files
Clean up your local project:
```bash
rm -rf venv/
rm -f db.sqlite3
rm -rf staticfiles/
rm -f requirements_full.txt
```
## Step 2: Upload to VPS
### Option A: Using SCP (if you have the files locally)
```bash
# Replace YOUR_VPS_IP with your actual IP
scp -r . root@YOUR_VPS_IP:/home/ubuntu/django-demo
```
### Option B: Using Git (recommended)
```bash
# On your VPS, clone the repository
ssh root@YOUR_VPS_IP
cd /home/ubuntu
git clone YOUR_REPO_URL django-demo
```
## Step 3: Run Deployment Script
SSH into your VPS and run:
```bash
ssh root@YOUR_VPS_IP
cd /home/ubuntu/django-demo
sudo bash deploy/deploy.sh
```
## Step 4: Configure Environment
Edit the `.env` file:
```bash
sudo nano /home/ubuntu/django-demo/.env
```
Set these values:
```env
SECRET_KEY=your-super-secret-key-here-make-it-long-and-random
DEBUG=False
ALLOWED_HOSTS=your-domain.com,www.your-domain.com,YOUR_VPS_IP
DATABASE_URL=postgresql://demo_user:your_password@localhost:5432/demo_db
SECURE_SSL_REDIRECT=False # Set to True after SSL setup
```
## Step 5: Update Domain in Nginx
Edit nginx configuration:
```bash
sudo nano /etc/nginx/sites-available/django-demo
```
Replace `yourdomain.com` with your actual domain or IP.
## Step 6: Restart Services
```bash
sudo systemctl restart django-demo
sudo systemctl restart nginx
```
## Step 7: Test Deployment
Check if everything is working:
```bash
# Check service status
sudo systemctl status django-demo
sudo systemctl status nginx
# View logs if there are issues
sudo journalctl -u django-demo -f
```
Visit your website: `http://YOUR_VPS_IP` or `http://your-domain.com`
## Troubleshooting
### Common Issues:
1. **Service won't start**:
```bash
sudo journalctl -u django-demo -f
```
2. **Static files not loading**:
```bash
cd /home/ubuntu/django-demo
source venv/bin/activate
python manage.py collectstatic --noinput
sudo systemctl restart django-demo
```
3. **Database errors**:
- Check PostgreSQL is running: `sudo systemctl status postgresql`
- Verify database settings in `.env`
4. **Permission errors**:
```bash
sudo chown -R www-data:www-data /home/ubuntu/django-demo
```
## Optional: SSL Certificate (Let's Encrypt)
```bash
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
```
After SSL setup, update `.env`:
```env
SECURE_SSL_REDIRECT=True
```
## Management Commands
```bash
# Restart Django
sudo systemctl restart django-demo
# View logs
sudo journalctl -u django-demo -f
# Update application
sudo bash /home/ubuntu/django-demo/deploy/update.sh
# Access Django shell
cd /home/ubuntu/django-demo
source venv/bin/activate
python manage.py shell
```

View File

@ -1,89 +0,0 @@
# Hostinger VPS Deployment Commands
## VPS Details
- **IP**: 69.62.81.168
- **SSH**: ssh root@69.62.81.168
- **Provider**: Hostinger
## Step-by-Step Deployment
### 1. Connect to VPS
```bash
ssh root@69.62.81.168
```
### 2. Clone Repository
```bash
cd /home/ubuntu || cd /root
mkdir -p /home/ubuntu
cd /home/ubuntu
git clone https://github.com/YOUR_USERNAME/YOUR_REPO_NAME.git django-demo
cd django-demo
```
### 3. Run Deployment Script
```bash
sudo bash deploy/deploy.sh
```
### 4. Configure Environment
```bash
sudo nano .env
```
**Set these values:**
```env
SECRET_KEY=your-super-secret-key-change-this-to-something-long-and-random
DEBUG=False
ALLOWED_HOSTS=69.62.81.168,localhost,127.0.0.1
DATABASE_URL=postgresql://demo_user:your_secure_password@localhost:5432/demo_db
SECURE_SSL_REDIRECT=False
```
### 5. Update Nginx Configuration
```bash
sudo nano /etc/nginx/sites-available/django-demo
```
Replace `yourdomain.com` with `69.62.81.168` in the server_name line.
### 6. Restart Services
```bash
sudo systemctl restart django-demo
sudo systemctl restart nginx
```
### 7. Check Status
```bash
sudo systemctl status django-demo
sudo systemctl status nginx
```
### 8. Test Application
Visit: http://69.62.81.168
## Troubleshooting Commands
```bash
# View Django logs
sudo journalctl -u django-demo -f
# View Nginx logs
sudo tail -f /var/log/nginx/error.log
# Restart services
sudo systemctl restart django-demo nginx
# Check if ports are open
sudo netstat -tlnp | grep :80
sudo netstat -tlnp | grep :8000
```
## Creating Admin User
```bash
cd /home/ubuntu/django-demo
source venv/bin/activate
python manage.py createsuperuser
```
Access admin at: http://69.62.81.168/admin

238
MULTI_PROJECT_SETUP.md Normal file
View File

@ -0,0 +1,238 @@
# Multi-Project Django VPS Setup Guide
## 🚀 Research-Based Multi-Project System
This system follows **2024 Django deployment best practices** and supports unlimited Django projects on a single VPS with automatic GitHub repo name extraction.
## ✨ Features
- ✅ **Auto-Extract GitHub Repo Names** → No manual project naming
- ✅ **Unlimited Django Projects**`/var/www/project1/`, `/var/www/project2/`, etc.
- ✅ **Path-Based Routing**`yourip.com/project1/`, `yourip.com/project2/`
- ✅ **Centralized Webhook Router** → One webhook URL handles all projects
- ✅ **Individual Services** → Separate `gunicorn-project.service` per project
- ✅ **Auto-Discovery** → Automatically detects existing Django projects
## 🏗️ Architecture
```
VPS Structure:
/var/www/
├── hostinger-django-demo/ ← From: github.com/user/hostinger-django-demo
├── my-blog-site/ ← From: github.com/user/my-blog-site
├── ecommerce-app/ ← From: github.com/user/ecommerce-app
└── webhook-manager/ ← Centralized webhook router
URLs:
http://YOUR_IP/ → Project list & health check
http://YOUR_IP/hostinger-django-demo/ → First project
http://YOUR_IP/my-blog-site/ → Second project
http://YOUR_IP/ecommerce-app/ → Third project
http://YOUR_IP/webhook → GitHub webhooks (all projects)
http://YOUR_IP/deploy-status → Deployment status (all projects)
```
## 🚀 Quick Setup (3 Commands)
### Step 1: Upload & Setup Multi-Project System
```bash
# Upload this project to your VPS (django user home)
scp -r . akvps:/home/django/hostinger-django-demo
# Setup multi-project webhook system
ssh akvps
cd /home/django/hostinger-django-demo
sudo bash deploy/setup-multi-webhook.sh
```
### Step 2: Deploy Your First Project
```bash
# Deploy current project (auto-extracts name: hostinger-django-demo)
sudo bash deploy/deploy-project.sh https://github.com/thecyberlearn/hostinger-django-demo.git
# Your project is now live at: http://YOUR_IP/hostinger-django-demo/
```
### Step 3: Configure GitHub Webhook
```bash
# Use the webhook secret from Step 1
# Go to: https://github.com/thecyberlearn/hostinger-django-demo/settings/hooks
# Add webhook:
# - URL: http://YOUR_IP/webhook
# - Secret: [from setup script]
# - Content-type: application/json
# - Events: Just push event
```
## 📦 Add More Projects
### Deploy Additional Projects
```bash
# Each new project gets deployed automatically with correct naming
sudo bash deploy/deploy-project.sh https://github.com/yourusername/my-blog-app.git
sudo bash deploy/deploy-project.sh https://github.com/yourusername/portfolio-site.git
sudo bash deploy/deploy-project.sh https://github.com/yourusername/api-backend.git
# Projects auto-deploy to:
# http://YOUR_IP/my-blog-app/
# http://YOUR_IP/portfolio-site/
# http://YOUR_IP/api-backend/
```
### GitHub Webhook Configuration
**Single webhook handles ALL projects!**
- Each repo needs the SAME webhook URL: `http://YOUR_IP/webhook`
- Same secret for all repositories
- Router automatically detects which project to deploy based on repo name
## 🔧 Management Commands
### Check All Projects Status
```bash
curl http://YOUR_IP/deploy-status
# Shows all projects, services, and commit hashes
```
### Individual Project Management
```bash
# Check specific project service
systemctl status gunicorn-hostinger-django-demo.service
systemctl status gunicorn-my-blog-app.service
# View logs for specific project
journalctl -u gunicorn-hostinger-django-demo.service -f
journalctl -u gunicorn-my-blog-app.service -f
# Restart specific project
systemctl restart gunicorn-hostinger-django-demo.service
```
### Webhook Router Management
```bash
# Check webhook router status
systemctl status django-webhook-router.service
# View webhook router logs
journalctl -u django-webhook-router.service -f
# Restart webhook router
systemctl restart django-webhook-router.service
```
## 🧪 Testing Auto-Deploy
### Test Project Deployment
```bash
# Make a change in any project repository
echo "# Multi-project test" >> README.md
git add .
git commit -m "Test multi-project auto-deploy"
git push origin main
# Watch deployment happen
journalctl -u django-webhook-router.service -f
```
### Verify Deployment
```bash
# Check if all services are running
curl http://YOUR_IP/deploy-status
# Test each project URL
curl http://YOUR_IP/hostinger-django-demo/
curl http://YOUR_IP/my-blog-app/
curl http://YOUR_IP/portfolio-site/
```
## 🔍 Monitoring & Logs
### Centralized Monitoring
```bash
# All projects status
curl http://YOUR_IP/deploy-status | jq
# Webhook router health
curl http://YOUR_IP/health | jq
# Project discovery
curl http://YOUR_IP/health
```
### Log Locations
```bash
# Webhook router logs
tail -f /var/log/django/webhook-router.log
# Individual project logs
journalctl -u gunicorn-PROJECT_NAME.service -f
# Nginx logs
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
```
## 🎯 Benefits
### For Developers
- **No Manual Configuration** → Just provide GitHub URL
- **Unlimited Projects** → Add as many Django apps as you want
- **Consistent Naming** → Uses actual repository names
- **Single Webhook** → One URL handles all your repositories
### For Operations
- **Industry Standard** → Follows 2024 Django deployment best practices
- **Resource Efficient** → Shared nginx, individual gunicorn processes
- **Easy Monitoring** → Centralized status and logging
- **Auto-Discovery** → Automatically detects existing projects
## 🚨 Troubleshooting
### Project Not Deploying
```bash
# Check if project was discovered
curl http://YOUR_IP/health
# Check project service
systemctl status gunicorn-PROJECT_NAME.service
# Check deployment logs
journalctl -u django-webhook-router.service -f
```
### Webhook Not Triggering
```bash
# Verify webhook secret in GitHub matches
cat /var/www/webhook-manager/.env
# Check webhook router logs
journalctl -u django-webhook-router.service -f
# Test webhook manually
curl -X POST http://YOUR_IP/webhook \
-H "Content-Type: application/json" \
-d '{"test": "webhook"}'
```
### Service Issues
```bash
# Reload systemd if services don't start
systemctl daemon-reload
# Check nginx configuration
nginx -t
# Restart all services
systemctl restart django-webhook-router.service
systemctl restart nginx
```
## 🎉 Success!
You now have a **production-ready multi-project Django VPS** that:
- Auto-extracts GitHub repository names
- Supports unlimited Django projects
- Auto-deploys on git push (like Render/Vercel)
- Follows industry best practices for 2024
- Scales effortlessly as you add more projects
**Just push to GitHub and watch your projects deploy automatically!** 🚀

View File

@ -1,337 +0,0 @@
# Production Django Deployment Guide
A comprehensive, battle-tested guide for deploying Django applications on VPS with proper security and performance.
## 🎯 **Overview**
This guide follows Django best practices and avoids common pitfalls we encountered:
- ❌ **Avoid**: Running as root, wrong directories, TCP sockets, hardcoded paths
- ✅ **Use**: Non-root user, `/var/www/`, Unix sockets, proper systemd configuration
## 📋 **Prerequisites**
- Ubuntu 20.04+ VPS with root access
- Domain name (optional, can use IP address)
- Git repository with Django project
## 🚀 **Step 1: VPS Initial Setup**
### Connect and Update System
```bash
ssh root@YOUR_VPS_IP
apt update && apt upgrade -y
```
### Install Required Packages
```bash
apt install -y python3 python3-pip python3-venv python3-dev \
nginx postgresql postgresql-contrib libpq-dev \
build-essential curl git ufw
```
### Create Non-Root User
```bash
adduser django --disabled-password --gecos ''
usermod -aG sudo django
```
### Configure SSH for New User (Optional)
```bash
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
```
## 🗂️ **Step 2: Project Setup**
### Create Project Directory
```bash
mkdir -p /var/www
chown django:www-data /var/www
```
### Clone Project (as django user)
```bash
sudo -u django bash -c "
cd /var/www
git clone YOUR_REPO_URL django-app
cd django-app
"
```
### Create Virtual Environment
```bash
sudo -u django bash -c "
cd /var/www/django-app
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
"
```
## ⚙️ **Step 3: Django Configuration**
### Environment Variables
```bash
sudo -u django bash -c "
cd /var/www/django-app
cp .env.example .env
# Edit .env with production settings
"
```
**Required .env settings:**
```env
SECRET_KEY=your-super-secret-key-generate-new-one
DEBUG=False
ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com,YOUR_VPS_IP
DATABASE_URL=postgresql://dbuser:dbpassword@localhost/dbname
SECURE_SSL_REDIRECT=False # Set True after SSL setup
```
### Run Django Setup
```bash
sudo -u django bash -c "
cd /var/www/django-app
source venv/bin/activate
python manage.py collectstatic --noinput
python manage.py migrate
python manage.py createsuperuser
"
```
## 🔧 **Step 4: Gunicorn with systemd**
### Create Gunicorn Socket
```bash
cat > /etc/systemd/system/gunicorn.socket << 'EOF'
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
EOF
```
### Create Gunicorn Service
```bash
cat > /etc/systemd/system/gunicorn.service << 'EOF'
[Unit]
Description=Gunicorn daemon for Django app
Requires=gunicorn.socket
After=network.target
[Service]
User=django
Group=www-data
WorkingDirectory=/var/www/django-app
Environment=DJANGO_SETTINGS_MODULE=PROJECT_NAME.settings
EnvironmentFile=/var/www/django-app/.env
ExecStart=/var/www/django-app/venv/bin/gunicorn \
--workers 3 \
--bind unix:/run/gunicorn.sock \
PROJECT_NAME.wsgi:application
Restart=always
[Install]
WantedBy=multi-user.target
EOF
```
**⚠️ Replace `PROJECT_NAME` with your actual Django project name!**
### Start Services
```bash
systemctl daemon-reload
systemctl start gunicorn.socket
systemctl enable gunicorn.socket
systemctl status gunicorn.socket
```
## 🌐 **Step 5: Nginx Configuration**
### Create Nginx Site Config
```bash
cat > /etc/nginx/sites-available/django-app << 'EOF'
server {
listen 80;
server_name YOUR_DOMAIN.com www.YOUR_DOMAIN.com YOUR_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;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
location /static/ {
alias /var/www/django-app/staticfiles/;
expires 1y;
add_header Cache-Control "public, immutable";
}
location /media/ {
alias /var/www/django-app/media/;
expires 1y;
add_header Cache-Control "public";
}
# Block access to sensitive files
location ~* /\.(?!well-known\/) {
deny all;
}
location ~* /(requirements\.txt|\.env|deploy/|\.git/) {
deny all;
}
}
EOF
```
### Enable Site
```bash
ln -s /etc/nginx/sites-available/django-app /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl restart nginx
```
## 🔒 **Step 6: Security & Firewall**
### Configure UFW Firewall
```bash
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
ufw allow 'Nginx Full'
ufw --force enable
ufw status
```
## 🔐 **Step 7: SSL Certificate (Optional)**
### Install Certbot
```bash
apt install certbot python3-certbot-nginx -y
```
### Get SSL Certificate
```bash
certbot --nginx -d yourdomain.com -d www.yourdomain.com
```
### Update Environment for HTTPS
```bash
# In /var/www/django-app/.env
SECURE_SSL_REDIRECT=True
```
## ✅ **Step 8: Verification**
### Test Application
```bash
curl -I http://YOUR_VPS_IP # Should return 200 OK
```
### Check Services
```bash
systemctl status gunicorn.socket
systemctl status gunicorn.service
systemctl status nginx
```
### View Logs
```bash
journalctl -u gunicorn.service -f # Django logs
tail -f /var/log/nginx/error.log # Nginx logs
```
## 🔄 **Deployment Updates**
### Update Code
```bash
sudo -u django bash -c "
cd /var/www/django-app
git pull origin main
source venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py collectstatic --noinput
"
systemctl restart gunicorn.service
```
## 🚨 **Common Issues & Solutions**
### Issue: 502 Bad Gateway
**Cause**: Gunicorn not running or socket issues
**Solution**:
```bash
systemctl status gunicorn.service
systemctl restart gunicorn.socket
```
### Issue: Static files not loading
**Cause**: Nginx can't access staticfiles directory
**Solution**:
```bash
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py collectstatic --noinput"
```
### Issue: Permission denied
**Cause**: Wrong file ownership
**Solution**:
```bash
chown -R django:www-data /var/www/django-app
```
### Issue: ModuleNotFoundError
**Cause**: Virtual environment not recreated after moving files
**Solution**:
```bash
sudo -u django bash -c "cd /var/www/django-app && rm -rf venv && python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt"
```
## 📝 **Quick Commands Reference**
```bash
# Service management
systemctl restart gunicorn.service
systemctl restart nginx
systemctl status gunicorn.service
# View logs
journalctl -u gunicorn.service -f
tail -f /var/log/nginx/access.log
# Django management
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py COMMAND"
```
## 🎯 **Key Differences from Our Initial Approach**
1. **User**: Use `django` user instead of `root`
2. **Location**: Use `/var/www/django-app` instead of `/root/django-demo`
3. **Socket**: Use Unix socket instead of TCP
4. **Virtual Environment**: Always recreate in target location
5. **Systemd**: Use socket activation with proper service file
6. **Security**: Proper file permissions and firewall rules
This configuration is production-ready, secure, and follows Django best practices.

View File

@ -1,223 +0,0 @@
# Django VPS Quick Start Guide
🚀 **One-command deployment for Django on VPS!**
## ⚡ **Super Quick Start (5 minutes)**
1. **SSH into your VPS:**
```bash
ssh root@YOUR_VPS_IP
```
2. **Run the automated deployment:**
```bash
curl -sSL https://raw.githubusercontent.com/thecyberlearn/hostinger-django-demo/main/deploy/production-deploy.sh | sudo bash
```
3. **Follow the prompts:**
- Enter your Git repository URL
- Enter your domain name (optional)
- Enter your VPS IP address
4. **Done!** Your Django app will be live at `http://YOUR_VPS_IP`
## 📋 **Manual Quick Start (10 minutes)**
If you prefer step-by-step control:
### **Step 1: System Setup (2 minutes)**
```bash
# Update system
apt update && apt upgrade -y
# Install packages
apt install -y python3 python3-pip python3-venv python3-dev \
nginx postgresql postgresql-contrib libpq-dev \
build-essential curl git ufw
# Create user
adduser django --disabled-password --gecos ''
usermod -aG sudo django
```
### **Step 2: Clone Project (1 minute)**
```bash
# Setup directory
mkdir -p /var/www && chown django:www-data /var/www
# Clone your project
sudo -u django bash -c "cd /var/www && git clone YOUR_REPO_URL django-app"
```
### **Step 3: Python Setup (2 minutes)**
```bash
sudo -u django bash -c "
cd /var/www/django-app
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
"
```
### **Step 4: Django Configuration (2 minutes)**
```bash
# Copy environment file
sudo -u django bash -c "cd /var/www/django-app && cp .env.example .env"
# Edit .env file with your settings
nano /var/www/django-app/.env
# Run Django setup
sudo -u django bash -c "
cd /var/www/django-app
source venv/bin/activate
python manage.py migrate
python manage.py collectstatic --noinput
"
```
### **Step 5: Services Setup (3 minutes)**
```bash
# Create Gunicorn socket
cat > /etc/systemd/system/gunicorn.socket << 'EOF'
[Unit]
Description=gunicorn socket
[Socket]
ListenStream=/run/gunicorn.sock
[Install]
WantedBy=sockets.target
EOF
# Create Gunicorn service (replace demo_project with your project name)
cat > /etc/systemd/system/gunicorn.service << 'EOF'
[Unit]
Description=Gunicorn daemon for Django app
Requires=gunicorn.socket
After=network.target
[Service]
User=django
Group=www-data
WorkingDirectory=/var/www/django-app
Environment=DJANGO_SETTINGS_MODULE=demo_project.settings
EnvironmentFile=/var/www/django-app/.env
ExecStart=/var/www/django-app/venv/bin/gunicorn \
--workers 3 \
--bind unix:/run/gunicorn.sock \
demo_project.wsgi:application
Restart=always
[Install]
WantedBy=multi-user.target
EOF
# Start services
systemctl daemon-reload
systemctl start gunicorn.socket
systemctl enable gunicorn.socket
# Configure Nginx (replace YOUR_VPS_IP)
cat > /etc/nginx/sites-available/django-app << 'EOF'
server {
listen 80;
server_name YOUR_VPS_IP;
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
location /static/ {
alias /var/www/django-app/staticfiles/;
}
}
EOF
# Enable Nginx
ln -sf /etc/nginx/sites-available/django-app /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl restart nginx
# Configure firewall
ufw allow ssh && ufw allow 'Nginx Full' && ufw --force enable
```
## ✅ **Verification**
Your Django app should now be live! Test with:
```bash
curl -I http://YOUR_VPS_IP
```
You should see `HTTP/1.1 200 OK`
## 🔧 **Post-Deployment**
1. **Create superuser:**
```bash
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py createsuperuser"
```
2. **Access admin:** `http://YOUR_VPS_IP/admin`
3. **Add SSL certificate (optional):**
```bash
apt install certbot python3-certbot-nginx
certbot --nginx -d yourdomain.com
```
## 🚨 **If Something Goes Wrong**
1. **Check service status:**
```bash
systemctl status gunicorn.service nginx
```
2. **View logs:**
```bash
journalctl -u gunicorn.service -f
tail -f /var/log/nginx/error.log
```
3. **Common fixes:**
```bash
# Restart services
systemctl restart gunicorn.service nginx
# Fix permissions
chown -R django:www-data /var/www/django-app
# Recreate virtual environment
sudo -u django bash -c "cd /var/www/django-app && rm -rf venv && python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt"
```
## 📚 **What's Different from Before**
Our **old problematic approach:**
- ❌ Used root user
- ❌ Wrong directory (`/root/django-demo`)
- ❌ TCP socket instead of Unix socket
- ❌ Hardcoded paths in virtual environment
Our **new bulletproof approach:**
- ✅ Non-root `django` user
- ✅ Standard `/var/www/django-app` directory
- ✅ Unix socket for better performance
- ✅ Proper file permissions and security
- ✅ Follows Django deployment best practices
## 🎯 **Why This Works Better**
1. **Security:** Non-root user with minimal privileges
2. **Performance:** Unix sockets are faster than TCP
3. **Reliability:** Socket activation prevents startup issues
4. **Maintainability:** Standard directory structure
5. **Scalability:** Proper systemd integration
This setup is **production-ready** and follows **Django best practices**!
---
**Need help?** Check `TROUBLESHOOTING.md` for detailed solutions to common issues.

34
SIMPLE_DEPLOY.md Normal file
View File

@ -0,0 +1,34 @@
# Simple Django VPS Deployment
## 🎯 What This Is
A Django demo project that deploys to any VPS with one command.
## 🚀 Deploy to VPS
### After VPS Reset:
```bash
# 1. Fix SSH key
ssh-keygen -f '/home/amit/.ssh/known_hosts' -R '69.62.81.168'
# 2. Setup django user
scp setup-django-user.sh akvps:/root/
ssh akvps "sudo bash /root/setup-django-user.sh"
# 3. Clone and deploy
ssh akvps "cd /home/django && git clone https://github.com/thecyberlearn/hostinger-django-demo.git"
ssh akvps "cd /home/django/hostinger-django-demo && echo -e 'https://github.com/thecyberlearn/hostinger-django-demo.git\n\n69.62.81.168' | sudo bash deploy/production-deploy.sh"
```
## 🔧 Update After Changes
```bash
# Push changes to GitHub first
git add . && git commit -m "update" && git push
# Then update VPS
ssh akvps "cd /var/www/django-app && sudo -u django git pull && sudo systemctl restart gunicorn nginx"
```
## 📱 Your Site
**URL**: http://69.62.81.168/
That's it! 🎉

View File

@ -1,398 +0,0 @@
# Django VPS Deployment Troubleshooting Guide
A comprehensive guide to diagnose and fix common issues during Django VPS deployment.
## 🔍 **Quick Diagnosis Commands**
Before diving into specific issues, run these commands to get an overview:
```bash
# Check all services status
systemctl status gunicorn.socket gunicorn.service nginx
# Test HTTP response
curl -I http://YOUR_VPS_IP
# Check disk space
df -h
# Check memory usage
free -m
# View recent logs
journalctl -u gunicorn.service -n 20
tail -20 /var/log/nginx/error.log
```
## 🚨 **Common Issues & Solutions**
### **Issue 1: 502 Bad Gateway**
**Symptoms:**
- Nginx returns 502 Bad Gateway
- Website is unreachable
**Diagnosis:**
```bash
systemctl status gunicorn.service
curl http://unix:/run/gunicorn.sock # Test socket directly
```
**Common Causes & Solutions:**
#### 1.1 Gunicorn Service Not Running
```bash
# Check status
systemctl status gunicorn.service
# If failed, check logs
journalctl -u gunicorn.service -n 50
# Restart service
systemctl restart gunicorn.socket
systemctl restart gunicorn.service
```
#### 1.2 Socket Permission Issues
```bash
# Check socket permissions
ls -la /run/gunicorn.sock
# Fix permissions if needed
sudo chown django:www-data /run/gunicorn.sock
```
#### 1.3 Virtual Environment Issues
```bash
# Recreate virtual environment
sudo -u django bash -c "
cd /var/www/django-app
rm -rf venv
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
"
systemctl restart gunicorn.service
```
---
### **Issue 2: 500 Internal Server Error**
**Symptoms:**
- Django returns 500 error
- HTTP 500 in curl response
**Diagnosis:**
```bash
# Check Django logs
journalctl -u gunicorn.service -f
# Check Django settings
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py check --deploy"
```
**Common Causes & Solutions:**
#### 2.1 ModuleNotFoundError
**Error:** `No module named 'your_project.urls'`
**Solution:**
```bash
# Check project structure
ls -la /var/www/django-app/
# Ensure DJANGO_SETTINGS_MODULE is correct in systemd service
grep DJANGO_SETTINGS_MODULE /etc/systemd/system/gunicorn.service
# Update if wrong project name
sed -i 's/demo_project/YOUR_ACTUAL_PROJECT_NAME/g' /etc/systemd/system/gunicorn.service
systemctl daemon-reload
systemctl restart gunicorn.service
```
#### 2.2 Database Connection Issues
**Solution:**
```bash
# Test database connection
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py dbshell"
# Check .env file
cat /var/www/django-app/.env
# Run migrations if needed
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py migrate"
```
#### 2.3 Missing Static Files
**Solution:**
```bash
# Collect static files
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py collectstatic --noinput"
# Check static files directory
ls -la /var/www/django-app/staticfiles/
```
---
### **Issue 3: Static Files Not Loading (CSS/JS Missing)**
**Symptoms:**
- Website loads but no styling
- 404 errors for CSS/JS files
**Diagnosis:**
```bash
# Check nginx config
nginx -t
cat /etc/nginx/sites-enabled/django-app
# Test static file access
curl -I http://YOUR_VPS_IP/static/admin/css/base.css
```
**Solutions:**
```bash
# 1. Collect static files
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py collectstatic --noinput"
# 2. Check nginx static files configuration
grep -A 5 "location /static/" /etc/nginx/sites-enabled/django-app
# 3. Fix permissions
chown -R django:www-data /var/www/django-app/staticfiles/
chmod -R 755 /var/www/django-app/staticfiles/
# 4. Restart nginx
systemctl restart nginx
```
---
### **Issue 4: Permission Denied Errors**
**Symptoms:**
- Various permission denied errors in logs
- Services failing to start
**Solutions:**
```bash
# Fix project ownership
chown -R django:www-data /var/www/django-app
# Fix socket permissions
chown django:www-data /run/gunicorn.sock
# Fix log directory permissions
mkdir -p /var/log/django
chown -R django:www-data /var/log/django
# Restart services
systemctl restart gunicorn.service
```
---
### **Issue 5: Firewall Blocking Connections**
**Symptoms:**
- Connection timeout from external IPs
- Works locally but not from internet
**Diagnosis:**
```bash
# Check firewall status
ufw status
# Test local connection
curl -I http://127.0.0.1
```
**Solutions:**
```bash
# Allow HTTP and HTTPS
ufw allow 'Nginx Full'
ufw allow 80
ufw allow 443
# Reload firewall
ufw reload
# Check status
ufw status
```
---
### **Issue 6: SSL/HTTPS Issues**
**Symptoms:**
- SSL certificate errors
- HTTPS redirects not working
**Solutions:**
```bash
# Check SSL certificate
certbot certificates
# Renew certificate
certbot renew
# Test nginx config
nginx -t
# Check SSL-related settings in .env
grep SECURE_SSL_REDIRECT /var/www/django-app/.env
```
---
## 🔧 **Advanced Debugging**
### **Check System Resources**
```bash
# Check disk space
df -h
# Check memory usage
free -m
htop
# Check CPU usage
top
# Check open files
lsof | grep django
```
### **Network Debugging**
```bash
# Check listening ports
ss -tulpn | grep :80
ss -tulpn | grep :443
ss -tulpn | grep gunicorn
# Check network connections
netstat -tlnp
# Test DNS resolution
nslookup YOUR_DOMAIN
```
### **Log Analysis**
```bash
# Real-time Django logs
journalctl -u gunicorn.service -f
# Real-time Nginx logs
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log
# Search for specific errors
journalctl -u gunicorn.service | grep ERROR
grep "500" /var/log/nginx/access.log
```
## 📊 **Health Check Script**
Create this script to quickly check your deployment health:
```bash
#!/bin/bash
# Save as health-check.sh
echo "🏥 Django Deployment Health Check"
echo "================================"
# Service status
echo "📊 Service Status:"
systemctl is-active gunicorn.socket && echo "✅ Gunicorn Socket: Active" || echo "❌ Gunicorn Socket: Inactive"
systemctl is-active gunicorn.service && echo "✅ Gunicorn Service: Active" || echo "❌ Gunicorn Service: Inactive"
systemctl is-active nginx && echo "✅ Nginx: Active" || echo "❌ Nginx: Inactive"
# HTTP test
echo -e "\n🌐 HTTP Response:"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost)
if [ "$HTTP_CODE" = "200" ]; then
echo "✅ HTTP Response: $HTTP_CODE (OK)"
else
echo "❌ HTTP Response: $HTTP_CODE"
fi
# Disk space
echo -e "\n💾 Disk Usage:"
df -h | grep -E "/$|/var"
# Memory usage
echo -e "\n🧠 Memory Usage:"
free -m | grep Mem
# Recent errors
echo -e "\n🚨 Recent Errors (last 10 lines):"
journalctl -u gunicorn.service -n 10 --no-pager | grep -i error || echo "No recent errors found"
echo -e "\n✅ Health check complete!"
```
## 🆘 **Emergency Recovery**
If everything is broken, try this recovery sequence:
```bash
# 1. Stop all services
systemctl stop gunicorn.service nginx
# 2. Check project files
ls -la /var/www/django-app/
# 3. Recreate virtual environment
sudo -u django bash -c "cd /var/www/django-app && rm -rf venv && python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt"
# 4. Run Django checks
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py check"
# 5. Collect static files
sudo -u django bash -c "cd /var/www/django-app && source venv/bin/activate && python manage.py collectstatic --noinput"
# 6. Fix permissions
chown -R django:www-data /var/www/django-app
# 7. Restart services
systemctl daemon-reload
systemctl start gunicorn.socket nginx
# 8. Test
curl -I http://localhost
```
## 📞 **Getting Help**
If you're still stuck:
1. **Collect information:**
```bash
# System info
uname -a
lsb_release -a
# Service status
systemctl status gunicorn.service nginx
# Recent logs
journalctl -u gunicorn.service -n 50
tail -50 /var/log/nginx/error.log
```
2. **Check Django docs:** https://docs.djangoproject.com/en/stable/howto/deployment/
3. **Check Gunicorn docs:** https://docs.gunicorn.org/
4. **Check Nginx docs:** https://nginx.org/en/docs/
Remember: Most deployment issues are caused by:
- File permissions
- Incorrect paths
- Missing dependencies
- Configuration typos
- Firewall rules
Take it step by step and check each component individually!

300
deploy/deploy-project.sh Executable file
View File

@ -0,0 +1,300 @@
#!/bin/bash
# Multi-Project Django Deployment Script
# Automatically extracts GitHub repo name for project naming
# Usage: sudo bash deploy-project.sh <GITHUB_REPO_URL>
# Example: sudo bash deploy-project.sh https://github.com/thecyberlearn/hostinger-django-demo.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/deploy"
cat > "$PROJECT_PATH/deploy/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/deploy/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

168
deploy/setup-multi-webhook.sh Executable file
View File

@ -0,0 +1,168 @@
#!/bin/bash
"""
Multi-Project Webhook Router Setup Script
Sets up centralized webhook receiver for multiple Django projects
"""
set -e
echo "🔄 Setting up Multi-Project Webhook Router..."
# Configuration
WEBHOOK_SECRET=${1:-$(openssl rand -hex 32)}
SERVICE_USER="django"
WEBHOOK_PATH="/var/www/webhook-manager"
WEBHOOK_ROUTER_PATH="$WEBHOOK_PATH/webhook-router.py"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
# Create webhook manager directory
echo -e "${YELLOW}📦 Setting up webhook manager...${NC}"
mkdir -p "$WEBHOOK_PATH"
# Copy webhook router
cp "$(dirname "$0")/webhook-router.py" "$WEBHOOK_ROUTER_PATH"
chown -R django:www-data "$WEBHOOK_PATH"
chmod +x "$WEBHOOK_ROUTER_PATH"
# Install Flask if not present
echo -e "${YELLOW}📦 Installing Flask...${NC}"
sudo -u django bash -c "cd $WEBHOOK_PATH && python3 -m venv venv && source venv/bin/activate && pip install flask"
# Create webhook secret file
echo -e "${YELLOW}🔐 Setting up webhook secret...${NC}"
echo "WEBHOOK_SECRET=$WEBHOOK_SECRET" > "$WEBHOOK_PATH/.env"
chown django:www-data "$WEBHOOK_PATH/.env"
chmod 600 "$WEBHOOK_PATH/.env"
echo -e "${GREEN}🔑 Webhook Secret: $WEBHOOK_SECRET${NC}"
echo -e "${YELLOW}📝 Save this secret - you'll need it for GitHub webhook configuration!${NC}"
# Create systemd service file
echo -e "${YELLOW}⚙️ Creating systemd service...${NC}"
cat > /etc/systemd/system/django-webhook-router.service << EOF
[Unit]
Description=Django Multi-Project Webhook Router
After=network.target
[Service]
Type=simple
User=$SERVICE_USER
Group=www-data
WorkingDirectory=$WEBHOOK_PATH
Environment=PYTHONPATH=$WEBHOOK_PATH
EnvironmentFile=$WEBHOOK_PATH/.env
ExecStart=$WEBHOOK_PATH/venv/bin/python $WEBHOOK_ROUTER_PATH
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
# Create main nginx configuration with webhook routing
echo -e "${YELLOW}🌐 Configuring Nginx for multi-project...${NC}"
cat > /etc/nginx/sites-available/django-multi-projects << 'EOF'
server {
listen 80 default_server;
server_name _;
# 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;
# Webhook endpoints (centralized)
location /webhook {
proxy_pass http://127.0.0.1:8001/webhook;
proxy_set_header Host $host;
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;
}
# Health check endpoint
location /health {
proxy_pass http://127.0.0.1:8001/health;
proxy_set_header Host $host;
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;
}
# Deployment status endpoint
location /deploy-status {
proxy_pass http://127.0.0.1:8001/status;
proxy_set_header Host $host;
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;
}
# Root endpoint - show project list
location = / {
proxy_pass http://127.0.0.1:8001/health;
proxy_set_header Host $host;
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;
}
# Include project-specific configurations
include /etc/nginx/conf.d/projects/*.conf;
}
EOF
# Create directory for project-specific nginx configs
mkdir -p /etc/nginx/conf.d/projects/
# Disable default nginx site and enable multi-project
rm -f /etc/nginx/sites-enabled/default
ln -sf /etc/nginx/sites-available/django-multi-projects /etc/nginx/sites-enabled/django-multi-projects
# Start and enable services
echo -e "${YELLOW}🚀 Starting services...${NC}"
systemctl daemon-reload
systemctl enable django-webhook-router.service
systemctl start django-webhook-router.service
# Test nginx and restart
nginx -t && systemctl restart nginx
# Check service status
if systemctl is-active --quiet django-webhook-router.service; then
echo -e "${GREEN}✅ Multi-Project Webhook Router is running${NC}"
else
echo -e "${RED}❌ Webhook router failed to start${NC}"
echo "Check logs: journalctl -u django-webhook-router.service -f"
exit 1
fi
echo -e "${GREEN}🎉 Multi-Project Webhook Setup Complete!${NC}"
echo
echo -e "${YELLOW}📋 Configuration:${NC}"
echo -e "1. 🔐 Webhook Secret: ${GREEN}$WEBHOOK_SECRET${NC}"
echo -e "2. 🌐 Webhook URL: ${GREEN}http://YOUR_VPS_IP/webhook${NC}"
echo -e "3. 📊 Status URL: ${GREEN}http://YOUR_VPS_IP/deploy-status${NC}"
echo -e "4. ❤️ Health Check: ${GREEN}http://YOUR_VPS_IP/health${NC}"
echo
echo -e "${YELLOW}📝 GitHub Webhook Setup:${NC}"
echo -e "- Go to each repository → Settings → Webhooks → Add webhook"
echo -e "- Payload URL: http://YOUR_VPS_IP/webhook"
echo -e "- Content type: application/json"
echo -e "- Secret: $WEBHOOK_SECRET"
echo -e "- Events: Just the push event"
echo
echo -e "${YELLOW}🚀 Deploy Projects:${NC}"
echo -e "sudo bash deploy/deploy-project.sh https://github.com/user/repo.git"
echo
echo -e "${YELLOW}🔍 Monitoring:${NC}"
echo -e "- Router logs: ${GREEN}journalctl -u django-webhook-router.service -f${NC}"
echo -e "- All projects: ${GREEN}http://YOUR_VPS_IP/deploy-status${NC}"
echo
echo -e "${GREEN}🎯 Your VPS now supports unlimited Django projects with auto-deploy!${NC}"

248
deploy/webhook-receiver.py Normal file
View File

@ -0,0 +1,248 @@
#!/usr/bin/env python3
"""
GitHub Webhook Receiver for Auto-Deployment
Listens for GitHub push events and triggers automatic deployment
"""
import os
import sys
import json
import hmac
import hashlib
import subprocess
import logging
from datetime import datetime
from flask import Flask, request, jsonify
from threading import Thread
import time
# Configuration
WEBHOOK_SECRET = os.environ.get('WEBHOOK_SECRET', 'your-webhook-secret-here')
REPO_PATH = '/var/www/django-app'
ALLOWED_BRANCHES = ['main', 'master']
LOG_FILE = '/var/log/django/webhook.log'
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(LOG_FILE),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
app = Flask(__name__)
def verify_signature(payload_body, signature_header):
"""Verify GitHub webhook signature"""
if not signature_header:
return False
hash_object = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
payload_body,
hashlib.sha256
)
expected_signature = "sha256=" + hash_object.hexdigest()
return hmac.compare_digest(expected_signature, signature_header)
def run_deployment():
"""Execute deployment in background thread"""
try:
logger.info("🚀 Starting deployment...")
# Change to app directory
os.chdir(REPO_PATH)
# Run deployment script
result = subprocess.run([
'sudo', '-u', 'django', 'bash', '-c',
f'''
cd {REPO_PATH}
# Store current commit for rollback
echo "$(git rev-parse HEAD)" > /tmp/last_working_commit.txt
# Pull latest changes
git fetch origin
git reset --hard origin/main
# Activate virtual environment and update
source venv/bin/activate
# Install/update dependencies
pip install -r requirements.txt
# Run Django management commands
python manage.py migrate
python manage.py collectstatic --noinput
# Test if Django can start (quick check)
python manage.py check --deploy
'''
], capture_output=True, text=True, timeout=300)
if result.returncode == 0:
# Restart services
subprocess.run(['systemctl', 'restart', 'gunicorn.service'], check=True)
# Wait a moment and check if service is running
time.sleep(3)
service_check = subprocess.run(['systemctl', 'is-active', 'gunicorn.service'],
capture_output=True, text=True)
if service_check.stdout.strip() == 'active':
logger.info("✅ Deployment successful!")
# Send success notification (optional)
send_notification("✅ Deployment successful!", "success")
else:
logger.error("❌ Service failed to start after deployment")
rollback()
else:
logger.error(f"❌ Deployment failed: {result.stderr}")
rollback()
except subprocess.TimeoutExpired:
logger.error("❌ Deployment timed out")
rollback()
except Exception as e:
logger.error(f"❌ Deployment error: {str(e)}")
rollback()
def rollback():
"""Rollback to previous working commit"""
try:
logger.info("🔄 Rolling back to previous commit...")
if os.path.exists('/tmp/last_working_commit.txt'):
with open('/tmp/last_working_commit.txt', 'r') as f:
last_commit = f.read().strip()
subprocess.run([
'sudo', '-u', 'django', 'bash', '-c',
f'cd {REPO_PATH} && git reset --hard {last_commit}'
], check=True)
subprocess.run(['systemctl', 'restart', 'gunicorn.service'], check=True)
logger.info("✅ Rollback completed")
send_notification("🔄 Rolled back due to deployment failure", "warning")
else:
logger.error("❌ No previous commit found for rollback")
except Exception as e:
logger.error(f"❌ Rollback failed: {str(e)}")
def send_notification(message, status="info"):
"""Send deployment notification (extend this for Slack/Discord/Email)"""
logger.info(f"📢 Notification: {message}")
# You can extend this to send notifications to:
# - Slack webhook
# - Discord webhook
# - Email
# - SMS
# Example Slack notification (uncomment and configure):
# import requests
# slack_webhook = "YOUR_SLACK_WEBHOOK_URL"
# requests.post(slack_webhook, json={"text": f"🚀 Django App: {message}"})
@app.route('/webhook', methods=['POST'])
def handle_webhook():
"""Handle GitHub webhook"""
# Verify signature
signature = request.headers.get('X-Hub-Signature-256')
if not verify_signature(request.data, signature):
logger.warning("❌ Invalid webhook signature")
return jsonify({"error": "Invalid signature"}), 403
# Parse payload
try:
payload = request.json
except:
logger.warning("❌ Invalid JSON payload")
return jsonify({"error": "Invalid JSON"}), 400
# Check if it's a push event
if request.headers.get('X-GitHub-Event') != 'push':
logger.info(f" Ignoring non-push event: {request.headers.get('X-GitHub-Event')}")
return jsonify({"message": "Not a push event"}), 200
# Extract branch name
ref = payload.get('ref', '')
branch = ref.replace('refs/heads/', '')
# Check if it's a branch we care about
if branch not in ALLOWED_BRANCHES:
logger.info(f" Ignoring push to branch: {branch}")
return jsonify({"message": f"Ignoring branch {branch}"}), 200
# Log the deployment request
commit_hash = payload.get('after', 'unknown')
commit_message = ""
if payload.get('head_commit'):
commit_message = payload['head_commit'].get('message', '')
logger.info(f"🔔 Deployment triggered by push to {branch}")
logger.info(f"📝 Commit: {commit_hash[:8]} - {commit_message[:100]}")
# Start deployment in background thread
deployment_thread = Thread(target=run_deployment)
deployment_thread.start()
return jsonify({
"message": "Deployment started",
"branch": branch,
"commit": commit_hash[:8]
}), 200
@app.route('/health', methods=['GET'])
def health_check():
"""Health check endpoint"""
return jsonify({
"status": "healthy",
"timestamp": datetime.now().isoformat(),
"repo_path": REPO_PATH
})
@app.route('/status', methods=['GET'])
def deployment_status():
"""Get current deployment status"""
try:
# Check if services are running
gunicorn_status = subprocess.run(['systemctl', 'is-active', 'gunicorn.service'],
capture_output=True, text=True)
nginx_status = subprocess.run(['systemctl', 'is-active', 'nginx'],
capture_output=True, text=True)
# Get current commit
os.chdir(REPO_PATH)
commit_result = subprocess.run(['git', 'rev-parse', 'HEAD'],
capture_output=True, text=True)
current_commit = commit_result.stdout.strip()[:8] if commit_result.returncode == 0 else "unknown"
return jsonify({
"gunicorn": gunicorn_status.stdout.strip(),
"nginx": nginx_status.stdout.strip(),
"current_commit": current_commit,
"timestamp": datetime.now().isoformat()
})
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
# Create log directory if it doesn't exist
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
logger.info("🚀 Starting GitHub webhook receiver...")
logger.info(f"📁 Monitoring repository: {REPO_PATH}")
logger.info(f"🌿 Allowed branches: {ALLOWED_BRANCHES}")
# Run Flask app
app.run(host='127.0.0.1', port=8001, debug=False)

350
deploy/webhook-router.py Executable file
View File

@ -0,0 +1,350 @@
#!/usr/bin/env python3
"""
Multi-Project GitHub Webhook Router
Routes webhook requests to appropriate Django projects based on repository name
Supports unlimited Django projects on single VPS
"""
import os
import sys
import json
import hmac
import hashlib
import subprocess
import logging
import glob
from datetime import datetime
from flask import Flask, request, jsonify
from threading import Thread
import time
# Configuration
WEBHOOK_SECRET = os.environ.get('WEBHOOK_SECRET', 'your-webhook-secret-here')
PROJECTS_BASE_PATH = '/var/www'
ALLOWED_BRANCHES = ['main', 'master']
LOG_FILE = '/var/log/django/webhook-router.log'
# Setup logging
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(LOG_FILE),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
app = Flask(__name__)
def discover_projects():
"""Discover all Django projects in /var/www"""
projects = {}
# Look for directories with manage.py (Django projects)
for project_dir in glob.glob(f"{PROJECTS_BASE_PATH}/*/"):
project_name = os.path.basename(project_dir.rstrip('/'))
# Skip hidden directories and system files
if project_name.startswith('.') or project_name == 'html':
continue
manage_py_path = os.path.join(project_dir, 'manage.py')
if os.path.exists(manage_py_path):
projects[project_name] = {
'path': project_dir.rstrip('/'),
'service': f'gunicorn-{project_name}.service'
}
logger.info(f"🔍 Discovered {len(projects)} Django projects: {list(projects.keys())}")
return projects
def extract_repo_name_from_url(repo_url):
"""Extract repository 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
import re
# Remove .git suffix and extract last part
repo_name = re.sub(r'\.git$', '', repo_url)
repo_name = repo_name.split('/')[-1]
return repo_name
def verify_signature(payload_body, signature_header):
"""Verify GitHub webhook signature"""
if not signature_header:
return False
hash_object = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
payload_body,
hashlib.sha256
)
expected_signature = "sha256=" + hash_object.hexdigest()
return hmac.compare_digest(expected_signature, signature_header)
def run_deployment(project_name, project_path, commit_info):
"""Execute deployment for specific project in background thread"""
try:
logger.info(f"🚀 Starting deployment for {project_name}...")
# Change to project directory
os.chdir(project_path)
# Store current commit for rollback
subprocess.run(['bash', '-c', f'echo "$(git rev-parse HEAD)" > /tmp/last_working_commit_{project_name}.txt'])
# Run deployment script
result = subprocess.run([
'sudo', '-u', 'django', 'bash', '-c',
f'''
cd {project_path}
# Pull latest changes
git fetch origin
git reset --hard origin/main
# Activate virtual environment and update
source venv/bin/activate
# Install/update dependencies
pip install -r requirements.txt
# Run Django management commands
python manage.py migrate
python manage.py collectstatic --noinput
# Test if Django can start (quick check)
python manage.py check --deploy
'''
], capture_output=True, text=True, timeout=300)
if result.returncode == 0:
# Restart project-specific service
service_name = f'gunicorn-{project_name}.service'
subprocess.run(['systemctl', 'restart', service_name], check=True)
# Wait and check if service is running
time.sleep(3)
service_check = subprocess.run(['systemctl', 'is-active', service_name],
capture_output=True, text=True)
if service_check.stdout.strip() == 'active':
logger.info(f"✅ Deployment successful for {project_name}!")
send_notification(f"{project_name}: Deployment successful!", "success", commit_info)
else:
logger.error(f"❌ Service failed to start for {project_name}")
rollback(project_name, project_path)
else:
logger.error(f"❌ Deployment failed for {project_name}: {result.stderr}")
rollback(project_name, project_path)
except subprocess.TimeoutExpired:
logger.error(f"❌ Deployment timed out for {project_name}")
rollback(project_name, project_path)
except Exception as e:
logger.error(f"❌ Deployment error for {project_name}: {str(e)}")
rollback(project_name, project_path)
def rollback(project_name, project_path):
"""Rollback to previous working commit for specific project"""
try:
logger.info(f"🔄 Rolling back {project_name} to previous commit...")
rollback_file = f'/tmp/last_working_commit_{project_name}.txt'
if os.path.exists(rollback_file):
with open(rollback_file, 'r') as f:
last_commit = f.read().strip()
subprocess.run([
'sudo', '-u', 'django', 'bash', '-c',
f'cd {project_path} && git reset --hard {last_commit}'
], check=True)
service_name = f'gunicorn-{project_name}.service'
subprocess.run(['systemctl', 'restart', service_name], check=True)
logger.info(f"✅ Rollback completed for {project_name}")
send_notification(f"🔄 {project_name}: Rolled back due to deployment failure", "warning", {})
else:
logger.error(f"❌ No previous commit found for rollback: {project_name}")
except Exception as e:
logger.error(f"❌ Rollback failed for {project_name}: {str(e)}")
def send_notification(message, status="info", commit_info={}):
"""Send deployment notification"""
logger.info(f"📢 Notification: {message}")
# You can extend this to send notifications to:
# - Slack webhook
# - Discord webhook
# - Email
# - SMS
@app.route('/webhook/<project_name>', methods=['POST'])
def handle_project_webhook(project_name):
"""Handle GitHub webhook for specific project"""
# Verify signature
signature = request.headers.get('X-Hub-Signature-256')
if not verify_signature(request.data, signature):
logger.warning(f"❌ Invalid webhook signature for {project_name}")
return jsonify({"error": "Invalid signature"}), 403
# Parse payload
try:
payload = request.json
except:
logger.warning(f"❌ Invalid JSON payload for {project_name}")
return jsonify({"error": "Invalid JSON"}), 400
# Check if it's a push event
if request.headers.get('X-GitHub-Event') != 'push':
logger.info(f" Ignoring non-push event for {project_name}: {request.headers.get('X-GitHub-Event')}")
return jsonify({"message": "Not a push event"}), 200
# Extract branch name
ref = payload.get('ref', '')
branch = ref.replace('refs/heads/', '')
# Check if it's a branch we care about
if branch not in ALLOWED_BRANCHES:
logger.info(f" Ignoring push to branch {branch} for {project_name}")
return jsonify({"message": f"Ignoring branch {branch}"}), 200
# Discover current projects
projects = discover_projects()
# Check if project exists
if project_name not in projects:
logger.warning(f"❌ Project not found: {project_name}")
return jsonify({"error": f"Project {project_name} not found"}), 404
# Get project details
project_path = projects[project_name]['path']
# Extract commit information
commit_hash = payload.get('after', 'unknown')
commit_message = ""
if payload.get('head_commit'):
commit_message = payload['head_commit'].get('message', '')
commit_info = {
'hash': commit_hash[:8],
'message': commit_message[:100],
'branch': branch
}
logger.info(f"🔔 Deployment triggered for {project_name}")
logger.info(f"📝 Branch: {branch}, Commit: {commit_hash[:8]} - {commit_message[:100]}")
# Start deployment in background thread
deployment_thread = Thread(target=run_deployment, args=(project_name, project_path, commit_info))
deployment_thread.start()
return jsonify({
"message": "Deployment started",
"project": project_name,
"branch": branch,
"commit": commit_hash[:8]
}), 200
@app.route('/webhook', methods=['POST'])
def handle_generic_webhook():
"""Handle generic webhook - try to determine project from repository URL"""
# Verify signature
signature = request.headers.get('X-Hub-Signature-256')
if not verify_signature(request.data, signature):
logger.warning("❌ Invalid webhook signature")
return jsonify({"error": "Invalid signature"}), 403
# Parse payload
try:
payload = request.json
except:
logger.warning("❌ Invalid JSON payload")
return jsonify({"error": "Invalid JSON"}), 400
# Extract repository URL
repo_url = payload.get('repository', {}).get('clone_url', '')
if not repo_url:
repo_url = payload.get('repository', {}).get('html_url', '')
if not repo_url:
logger.warning("❌ No repository URL found in payload")
return jsonify({"error": "No repository URL found"}), 400
# Extract project name from repo URL
project_name = extract_repo_name_from_url(repo_url)
logger.info(f"🔍 Extracted project name: {project_name} from URL: {repo_url}")
# Redirect to project-specific webhook handler
return handle_project_webhook(project_name)
@app.route('/health', methods=['GET'])
def health_check():
"""Health check endpoint"""
projects = discover_projects()
return jsonify({
"status": "healthy",
"timestamp": datetime.now().isoformat(),
"projects_count": len(projects),
"projects": list(projects.keys())
})
@app.route('/status', methods=['GET'])
def deployment_status():
"""Get current deployment status for all projects"""
try:
projects = discover_projects()
status_data = {
"timestamp": datetime.now().isoformat(),
"projects": {}
}
for project_name, project_info in projects.items():
# Check service status
service_name = project_info['service']
service_check = subprocess.run(['systemctl', 'is-active', service_name],
capture_output=True, text=True)
# Get current commit
try:
os.chdir(project_info['path'])
commit_result = subprocess.run(['git', 'rev-parse', 'HEAD'],
capture_output=True, text=True)
current_commit = commit_result.stdout.strip()[:8] if commit_result.returncode == 0 else "unknown"
except:
current_commit = "unknown"
status_data["projects"][project_name] = {
"service_status": service_check.stdout.strip(),
"current_commit": current_commit,
"path": project_info['path'],
"service": service_name
}
return jsonify(status_data)
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
# Create log directory if it doesn't exist
os.makedirs(os.path.dirname(LOG_FILE), exist_ok=True)
logger.info("🚀 Starting Multi-Project GitHub Webhook Router...")
# Discover existing projects
projects = discover_projects()
logger.info(f"📁 Managing {len(projects)} Django projects")
for name, info in projects.items():
logger.info(f" - {name}: {info['path']}")
# Run Flask app
app.run(host='127.0.0.1', port=8001, debug=False)

162
deploy/webhook-service.sh Normal file
View File

@ -0,0 +1,162 @@
#!/bin/bash
"""
Auto-Deployment Service Setup Script
Sets up the webhook receiver as a systemd service
"""
set -e
echo "🔄 Setting up Auto-Deployment Service..."
# Configuration
WEBHOOK_SECRET=${1:-$(openssl rand -hex 32)}
SERVICE_USER="django"
APP_PATH="/var/www/django-app"
WEBHOOK_PATH="$APP_PATH/deploy/webhook-receiver.py"
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
# Install Flask if not present
echo -e "${YELLOW}📦 Installing Flask...${NC}"
sudo -u django bash -c "cd $APP_PATH && source venv/bin/activate && pip install flask"
# Create webhook secret file
echo -e "${YELLOW}🔐 Setting up webhook secret...${NC}"
echo "WEBHOOK_SECRET=$WEBHOOK_SECRET" > /var/www/django-app/.env.webhook
chown django:www-data /var/www/django-app/.env.webhook
chmod 600 /var/www/django-app/.env.webhook
echo -e "${GREEN}🔑 Webhook Secret: $WEBHOOK_SECRET${NC}"
echo -e "${YELLOW}📝 Save this secret - you'll need it for GitHub webhook configuration!${NC}"
# Create systemd service file
echo -e "${YELLOW}⚙️ Creating systemd service...${NC}"
cat > /etc/systemd/system/django-webhook.service << EOF
[Unit]
Description=Django Auto-Deployment Webhook Receiver
After=network.target
[Service]
Type=simple
User=$SERVICE_USER
Group=www-data
WorkingDirectory=$APP_PATH
Environment=PYTHONPATH=$APP_PATH
EnvironmentFile=$APP_PATH/.env.webhook
ExecStart=$APP_PATH/venv/bin/python $WEBHOOK_PATH
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
# Create nginx configuration for webhook
echo -e "${YELLOW}🌐 Configuring Nginx proxy...${NC}"
cat > /etc/nginx/sites-available/django-webhook << 'EOF'
server {
listen 80;
server_name webhook.YOUR_DOMAIN.com; # Replace with your subdomain
location /webhook {
proxy_pass http://127.0.0.1:8001/webhook;
proxy_set_header Host $host;
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 /health {
proxy_pass http://127.0.0.1:8001/health;
proxy_set_header Host $host;
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 /status {
proxy_pass http://127.0.0.1:8001/status;
proxy_set_header Host $host;
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;
# Optional: Add basic auth for status endpoint
# auth_basic "Deployment Status";
# auth_basic_user_file /etc/nginx/.htpasswd;
}
}
EOF
# Enable webhook nginx site (optional - you might want to use main domain with /webhook path)
echo -e "${YELLOW} Webhook Nginx config created at /etc/nginx/sites-available/django-webhook${NC}"
echo -e "${YELLOW} You can enable it with: ln -s /etc/nginx/sites-available/django-webhook /etc/nginx/sites-enabled/${NC}"
# Or add webhook endpoint to existing site
echo -e "${YELLOW}🔧 Adding webhook endpoint to main site...${NC}"
MAIN_NGINX_CONFIG="/etc/nginx/sites-available/django-app"
if [ -f "$MAIN_NGINX_CONFIG" ]; then
# Add webhook location block before the last closing brace
sed -i '/^}/i\
# GitHub Webhook endpoint\
location /webhook {\
proxy_pass http://127.0.0.1:8001/webhook;\
proxy_set_header Host $host;\
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;\
}\
\
# Deployment status endpoint\
location /deploy-status {\
proxy_pass http://127.0.0.1:8001/status;\
proxy_set_header Host $host;\
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;\
}' "$MAIN_NGINX_CONFIG"
fi
# Make webhook receiver executable
chmod +x $WEBHOOK_PATH
# Start and enable services
echo -e "${YELLOW}🚀 Starting services...${NC}"
systemctl daemon-reload
systemctl enable django-webhook.service
systemctl start django-webhook.service
# Restart nginx
nginx -t && systemctl restart nginx
# Check service status
if systemctl is-active --quiet django-webhook.service; then
echo -e "${GREEN}✅ Webhook service is running${NC}"
else
echo -e "${RED}❌ Webhook service failed to start${NC}"
echo "Check logs: journalctl -u django-webhook.service -f"
exit 1
fi
echo -e "${GREEN}🎉 Auto-Deployment Setup Complete!${NC}"
echo
echo -e "${YELLOW}📋 Next Steps:${NC}"
echo -e "1. 🔐 Webhook Secret: ${GREEN}$WEBHOOK_SECRET${NC}"
echo -e "2. 🌐 Webhook URL: ${GREEN}http://YOUR_VPS_IP/webhook${NC}"
echo -e "3. 📝 Go to GitHub → Settings → Webhooks → Add webhook"
echo -e "4. 🔧 Configure webhook:"
echo -e " - Payload URL: http://YOUR_VPS_IP/webhook"
echo -e " - Content type: application/json"
echo -e " - Secret: $WEBHOOK_SECRET"
echo -e " - Events: Just the push event"
echo
echo -e "${YELLOW}🔍 Monitoring:${NC}"
echo -e "- Service logs: ${GREEN}journalctl -u django-webhook.service -f${NC}"
echo -e "- Deployment status: ${GREEN}http://YOUR_VPS_IP/deploy-status${NC}"
echo -e "- Health check: ${GREEN}http://YOUR_VPS_IP/health${NC}"
echo
echo -e "${GREEN}🚀 Your VPS now works like Render - just push to GitHub!${NC}"

27
setup-auto-deploy.sh Executable file
View File

@ -0,0 +1,27 @@
#!/bin/bash
# Simple Auto-Deploy Setup Script
# Run this on your VPS to enable GitHub auto-deployment
echo "🚀 Setting up simple auto-deploy webhook..."
echo
# Check if we're on the VPS
if [ ! -d "/var/www/django-app" ]; then
echo "❌ This script should be run on your VPS"
echo "Please run: ssh akvps"
echo "Then: sudo bash setup-auto-deploy.sh"
exit 1
fi
# Run the webhook service setup
echo "📦 Installing webhook service..."
sudo bash /var/www/django-app/deploy/webhook-service.sh
echo
echo "✅ Auto-deploy setup complete!"
echo
echo "Next steps:"
echo "1. Go to: https://github.com/thecyberlearn/hostinger-django-demo/settings/hooks"
echo "2. Click 'Add webhook'"
echo "3. Use the webhook secret shown above"
echo "4. Test by pushing a commit!"

86
setup-django-user.sh Executable file
View File

@ -0,0 +1,86 @@
#!/bin/bash
# Setup django user and SSH access after VPS reset
# Run this FIRST after VPS reset before uploading projects
set -e
# Colors
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
echo -e "${YELLOW}🔧 Setting up django user and SSH access...${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
# Create django user if doesn't exist
if ! id "django" &>/dev/null; then
echo -e "${YELLOW}👤 Creating django user...${NC}"
adduser django --disabled-password --gecos ''
usermod -aG sudo django
echo -e "${GREEN}✅ Django user created${NC}"
else
echo -e "${GREEN}✅ Django user already exists${NC}"
fi
# Setup SSH access for django user
echo -e "${YELLOW}🔑 Setting up SSH access for django user...${NC}"
# Create .ssh directory for django user
mkdir -p /home/django/.ssh
chmod 700 /home/django/.ssh
# Copy SSH keys from root if they exist
if [ -d "/root/.ssh" ] && [ -f "/root/.ssh/authorized_keys" ]; then
cp /root/.ssh/authorized_keys /home/django/.ssh/
echo -e "${GREEN}✅ SSH keys copied from root to django user${NC}"
else
echo -e "${YELLOW}⚠️ No SSH keys found in /root/.ssh/${NC}"
echo -e "${YELLOW}💡 You'll need to copy your public key to /home/django/.ssh/authorized_keys${NC}"
fi
# Set proper ownership and permissions
chown -R django:django /home/django/.ssh
chmod 600 /home/django/.ssh/authorized_keys 2>/dev/null || true
# Update SSH config to allow django user
echo -e "${YELLOW}🔧 Updating SSH configuration...${NC}"
# Ensure django user can sudo without password for specific commands
cat > /etc/sudoers.d/django-deploy << 'EOF'
# Django user deployment permissions
django ALL=(ALL) NOPASSWD: /bin/systemctl restart gunicorn*.service
django ALL=(ALL) NOPASSWD: /bin/systemctl start gunicorn*.service
django ALL=(ALL) NOPASSWD: /bin/systemctl stop gunicorn*.service
django ALL=(ALL) NOPASSWD: /bin/systemctl enable gunicorn*.service
django ALL=(ALL) NOPASSWD: /bin/systemctl status gunicorn*.service
django ALL=(ALL) NOPASSWD: /bin/systemctl daemon-reload
django ALL=(ALL) NOPASSWD: /usr/sbin/nginx -t
django ALL=(ALL) NOPASSWD: /bin/systemctl restart nginx
django ALL=(ALL) NOPASSWD: /bin/systemctl reload nginx
EOF
echo -e "${GREEN}✅ Django user sudo permissions configured${NC}"
# Create project directory in django user home
mkdir -p /home/django
chown django:django /home/django
echo -e "${GREEN}🎉 Django user setup complete!${NC}"
echo
echo -e "${YELLOW}📝 Next steps:${NC}"
echo -e "1. Test SSH access: ${GREEN}ssh akvps 'sudo -u django whoami'${NC}"
echo -e "2. Upload project: ${GREEN}scp -r . akvps:/home/django/project-name${NC}"
echo -e "3. Deploy project: ${GREEN}cd /home/django/project-name && sudo bash deploy/...${NC}"
echo
echo -e "${YELLOW}💡 SSH alias for django user:${NC}"
echo -e "Add to ~/.ssh/config:"
echo -e "${GREEN}Host akvps-django${NC}"
echo -e "${GREEN} HostName $(curl -s ifconfig.me 2>/dev/null || echo 'YOUR_VPS_IP')${NC}"
echo -e "${GREEN} User django${NC}"
echo -e "${GREEN} IdentityFile ~/.ssh/id_rsa${NC}"