Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: gunicorn -w 4 -b 0.0.0.0:$PORT run:app
6 changes: 5 additions & 1 deletion backend/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
135 changes: 91 additions & 44 deletions docs/deployment-guide.md
Original file line number Diff line number Diff line change
@@ -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 |
Expand All @@ -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 |
Expand All @@ -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**

---

Expand All @@ -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`)

Expand All @@ -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`)
Expand All @@ -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;"]
```
Expand All @@ -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:
Expand All @@ -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)
Loading