From 79ee3afef1891e03e35db54cc40d33f9c1bd0fbf Mon Sep 17 00:00:00 2001 From: Ajay Kumar <162270014+iamajaykr06@users.noreply.github.com> Date: Sat, 30 May 2026 17:04:33 +0530 Subject: [PATCH] fix: correct gunicorn deployment configuration - Update backend/run.py to expose WSGI app for gunicorn production server - Create backend/Procfile with correct gunicorn command - Update docs/deployment-guide.md with correct Procfile and Docker configurations - Fix app factory reference in Dockerfile and Docker Compose This fixes the "Exited with status 1" error on Render deployment where gunicorn was trying to call a factory function instead of serving the WSGI application directly. Fixes #[deployment-error] --- backend/Procfile | 1 + backend/run.py | 6 +- docs/deployment-guide.md | 135 ++++++++++++++++++++++++++------------- 3 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 backend/Procfile diff --git a/backend/Procfile b/backend/Procfile new file mode 100644 index 0000000..c3e3500 --- /dev/null +++ b/backend/Procfile @@ -0,0 +1 @@ +web: gunicorn -w 4 -b 0.0.0.0:$PORT run:app diff --git a/backend/run.py b/backend/run.py index 6f8ca43..4a34cea 100644 --- a/backend/run.py +++ b/backend/run.py @@ -18,13 +18,17 @@ # werkzeug's scrypt password hashing (check_password_hash fails under eventlet). # Using threading mode for SocketIO instead. +import os from dotenv import load_dotenv load_dotenv() from app import create_app, socketio -app = create_app() +app = create_app(env=os.environ.get("FLASK_ENV", "production")) + +# For production with gunicorn, the app object is used directly as a WSGI application. +# For development, run: socketio.run(app, host="0.0.0.0", port=5000, debug=True) if __name__ == "__main__": socketio.run(app, host="0.0.0.0", port=5000, debug=False, allow_unsafe_werkzeug=True) diff --git a/docs/deployment-guide.md b/docs/deployment-guide.md index 1bd2a2c..6cbd602 100644 --- a/docs/deployment-guide.md +++ b/docs/deployment-guide.md @@ -1,12 +1,16 @@ # Deployment Guide -This guide covers five deployment methods for AIPCSS, from beginner-friendly to advanced. +This guide covers deploying the AIPCSS application (frontend + backend) to various hosting platforms. -## Quick Comparison +## Deployment Platforms Comparison -| Feature | Vercel + Render | Railway | Docker | AWS | Self-Hosted VPS | -|---------|-----------------|---------|--------|-----|-----------------| -| Difficulty | Easy | Easy | Medium | Hard | Hard | +| Platform | Ease | Cost | Free Tier | Trial | Scalability | Best For | +|----------|------|------|-----------|-------|-------------|----------| +| **Render** | ⭐⭐⭐⭐ | Low | Yes | 12 months | Auto | Students / Demos | +| **Railway** | ⭐⭐⭐⭐⭐ | Very Low | Yes | Trial | Limited | Quick Deploy | +| **Docker Compose** | ⭐⭐⭐ | Self | Yes | N/A | Manual | Full Control | +| **AWS** | ⭐⭐ | Medium | Yes | 12 months | Auto | Enterprise | +| **Fly.io** | ⭐⭐⭐⭐ | Low | Yes | Trial | Auto | Institutions | | Free Tier | Yes | Trial | N/A | 12 months | N/A | | Monthly Cost | $0 - $7 | $0 - $5 | $5 - $20 | $10 - $50 | $5 - $20 | | Custom Domain | Yes | Yes | Yes | Yes | Yes | @@ -20,7 +24,7 @@ This guide covers five deployment methods for AIPCSS, from beginner-friendly to ## Environment Variables | Variable | Backend/Frontend | Description | -|----------|-----------------|-------------| +|----------|-----------------|----------| | `SECRET_KEY` | Backend | Flask secret key for sessions | | `JWT_SECRET_KEY` | Backend | JWT token signing key | | `DATABASE_URL` | Backend | Database connection string | @@ -45,16 +49,19 @@ This guide covers five deployment methods for AIPCSS, from beginner-friendly to ### Backend on Render -1. Create a `Procfile` in `backend/`: - ``` - web: gunicorn -w 4 -b 0.0.0.0:$PORT app:create_app() - ``` -2. Go to [render.com](https://render.com) → **New Web Service** → Connect repo -3. Configure: +1. Go to [render.com](https://render.com) → **New Web Service** → Connect repo +2. Configure: - **Root Directory**: `backend` - **Runtime**: Python 3 -4. Add a **PostgreSQL** database from Render dashboard -5. Add environment variables: `SECRET_KEY`, `JWT_SECRET_KEY`, `DATABASE_URL`, `FLASK_ENV=production` + - **Build Command**: `pip install -r requirements.txt` + - **Start Command**: `gunicorn -w 4 -b 0.0.0.0:$PORT run:app` +3. Add a **PostgreSQL** database from Render dashboard +4. Add environment variables: + - `SECRET_KEY` (generate a random secret) + - `JWT_SECRET_KEY` (generate a random secret) + - `DATABASE_URL` (auto-populated by Render) + - `FLASK_ENV=production` +5. Click **Deploy** --- @@ -65,10 +72,11 @@ This guide covers five deployment methods for AIPCSS, from beginner-friendly to 3. Add a **PostgreSQL** database service 4. Configure environment variables on the backend service 5. Railway provides internal networking automatically +6. Set **Start Command** to `gunicorn -w 4 -b 0.0.0.0:$PORT run:app` --- -## Method 3: Docker +## Method 3: Docker Compose (Local or VPS) ### Backend Dockerfile (`backend/Dockerfile`) @@ -79,7 +87,7 @@ COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 5000 -CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:create_app()"] +CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "run:app"] ``` ### Frontend Dockerfile (`frontend/Dockerfile`) @@ -90,12 +98,13 @@ WORKDIR /app COPY package*.json . RUN npm ci COPY . . -ARG VITE_API_BASE_URL +ARG VITE_API_BASE_URL=http://localhost:5000 ENV VITE_API_BASE_URL=$VITE_API_BASE_URL RUN npm run build FROM nginx:alpine COPY --from=build /app/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` @@ -115,24 +124,32 @@ services: - pgdata:/var/lib/postgresql/data ports: - '5432:5432' + healthcheck: + test: ["CMD-SHELL", "pg_isready -U aipcss_user"] + interval: 10s + timeout: 5s + retries: 5 backend: build: ./backend environment: DATABASE_URL: postgresql://aipcss_user:change_me_in_production@db:5432/aipcss - SECRET_KEY: your-secret-key - JWT_SECRET_KEY: your-jwt-secret + SECRET_KEY: your-secret-key-here + JWT_SECRET_KEY: your-jwt-secret-here FLASK_ENV: production ports: - '5000:5000' depends_on: - - db + db: + condition: service_healthy + volumes: + - ./backend:/app frontend: build: context: ./frontend args: - VITE_API_BASE_URL: http://localhost:5000/api + VITE_API_BASE_URL: http://localhost:5000 ports: - '80:80' depends_on: @@ -142,41 +159,71 @@ volumes: pgdata: ``` -### Deploy +**Run locally:** +```bash +docker-compose up --build +``` + +Access the app at `http://localhost` + +--- + +## Environment Setup + +### Generate Secrets ```bash -docker compose up -d --build +python -c "import secrets; print(secrets.token_urlsafe(32))" +``` + +Run this command twice to generate `SECRET_KEY` and `JWT_SECRET_KEY`. + +### Database Connection String + +**PostgreSQL:** +``` +postgresql://username:password@host:port/database +``` + +**Example (Render managed database):** +``` +postgresql://aipcss_user:your-password@dpg-xyz.render.internal:5432/aipcss ``` --- -## Method 4: AWS +## Post-Deployment -- **Frontend**: Build locally → Upload to S3 → Distribute via CloudFront -- **Backend**: Deploy to Elastic Beanstalk with Gunicorn -- **Database**: Amazon RDS PostgreSQL +1. **Database Migrations:** Run `flask db upgrade` in the backend service +2. **Test API:** Visit `https://your-backend-url/api/health` (if endpoint exists) +3. **Frontend Configuration:** Ensure `VITE_API_BASE_URL` points to your backend +4. **SSL/TLS:** Most platforms auto-enable HTTPS --- -## Method 5: Self-Hosted VPS +## Troubleshooting + +### Gunicorn Exit Status 1 +- Ensure `DATABASE_URL` is set correctly +- Check logs for missing imports or initialization errors +- Verify `FLASK_ENV=production` is set +- Ensure `run:app` is accessible (the WSGI app object in `backend/run.py`) + +### SocketIO Connection Issues +- Flask-SocketIO works with gunicorn when using the correct WSGI app +- Ensure `CORS_ORIGINS` environment variable allows frontend domain +- Check browser console for connection errors -1. Provision a VPS (2 CPU, 4 GB RAM minimum) -2. Install: Python 3.11, Node.js 20, PostgreSQL 15, Nginx -3. Build frontend: `cd frontend && npm run build` -4. Serve frontend from `/var/www/aipcss/` with Nginx -5. Run backend with Gunicorn + systemd service -6. Configure Nginx as reverse proxy (port 80/443 → port 5000) -7. Set up SSL with Let's Encrypt: `sudo certbot --nginx` +### Database Connection Errors +- Verify `DATABASE_URL` format +- Test connection string locally before deploying +- Ensure database service is running and accessible --- -## Post-Deployment Checklist +## Additional Resources -- [ ] Change all default secret keys to strong random values -- [ ] Enable HTTPS and redirect HTTP to HTTPS -- [ ] Enable gzip/Brotli compression on web server -- [ ] Configure database backups (daily minimum) -- [ ] Set up uptime monitoring (UptimeRobot, etc.) -- [ ] Test scheduling algorithm in production -- [ ] Verify PDF export functionality -- [ ] Register the first admin account and set up test data +- [Render Documentation](https://render.com/docs) +- [Railway Documentation](https://docs.railway.app) +- [Flask Deployment Guide](https://flask.palletsprojects.com/en/latest/deploying/) +- [Gunicorn Documentation](https://docs.gunicorn.org)