Initial
This commit is contained in:
@@ -0,0 +1,334 @@
|
||||
# /product-finder Deployment Fix Guide
|
||||
|
||||
## 🔴 Problem
|
||||
|
||||
The application works locally at `http://localhost:8080/` but fails on the server at `https://columbiawindows.com/product-finder/`.
|
||||
|
||||
The redirect from `/product-finder` → `/product-finder/login` works, but then the login page or subsequent routes fail.
|
||||
|
||||
## ✅ Solution Applied
|
||||
|
||||
Three critical changes were made to fix subdirectory deployment:
|
||||
|
||||
### 1. **Added PrefixMiddleware to app.py**
|
||||
|
||||
This middleware tells Flask about the `/product-finder` prefix by setting `SCRIPT_NAME` in the WSGI environment:
|
||||
|
||||
```python
|
||||
class PrefixMiddleware:
|
||||
"""Middleware to handle subdirectory deployments"""
|
||||
def __init__(self, app, prefix=''):
|
||||
self.app = app
|
||||
self.prefix = prefix.rstrip('/')
|
||||
|
||||
def __call__(self, environ, start_response):
|
||||
if self.prefix and self.prefix != '/':
|
||||
path = environ.get('PATH_INFO', '')
|
||||
script_name = environ.get('SCRIPT_NAME', '')
|
||||
|
||||
if not script_name.startswith(self.prefix):
|
||||
environ['SCRIPT_NAME'] = self.prefix + script_name
|
||||
if path.startswith(self.prefix):
|
||||
environ['PATH_INFO'] = path[len(self.prefix):]
|
||||
|
||||
return self.app(environ, start_response)
|
||||
```
|
||||
|
||||
This is automatically applied when `APPLICATION_ROOT` is set.
|
||||
|
||||
### 2. **Updated passenger_wsgi.py**
|
||||
|
||||
Sets the `APPLICATION_ROOT` environment variable before importing the app:
|
||||
|
||||
```python
|
||||
if 'APPLICATION_ROOT' not in os.environ:
|
||||
os.environ['APPLICATION_ROOT'] = '/product-finder'
|
||||
```
|
||||
|
||||
### 3. **Updated config.py**
|
||||
|
||||
Production configuration now defaults to `/product-finder`:
|
||||
|
||||
```python
|
||||
class ProductionConfig(Config):
|
||||
APPLICATION_ROOT = os.environ.get('APPLICATION_ROOT', '/product-finder')
|
||||
```
|
||||
|
||||
Development still uses `/` for local testing.
|
||||
|
||||
## 📤 Files to Upload
|
||||
|
||||
Upload these updated files to your server:
|
||||
|
||||
1. **`app/app.py`** - Contains PrefixMiddleware
|
||||
2. **`app/passenger_wsgi.py`** - Sets APPLICATION_ROOT env var
|
||||
3. **`app/config.py`** - Production defaults to /product-finder
|
||||
4. **`app/.htaccess`** - Apache configuration (new file)
|
||||
5. **All template files** - Already updated with url_for() and BASE_URL
|
||||
|
||||
## 🔧 Server Configuration
|
||||
|
||||
### Option A: Using .htaccess (Recommended)
|
||||
|
||||
The `.htaccess` file is already configured for `/product-finder`. Upload it to your `app/` folder on the server.
|
||||
|
||||
**Important:** Update these lines in `.htaccess`:
|
||||
```apache
|
||||
PassengerAppRoot /home/USERNAME/public_html/product-finder
|
||||
PassengerPython /usr/bin/python3 # Update to your Python path
|
||||
```
|
||||
|
||||
### Option B: Apache Virtual Host Configuration
|
||||
|
||||
If you have access to Apache config, add this to your virtual host:
|
||||
|
||||
```apache
|
||||
<Directory "/home/USERNAME/public_html/product-finder">
|
||||
SetEnv APPLICATION_ROOT /product-finder
|
||||
PassengerEnabled on
|
||||
PassengerAppRoot /home/USERNAME/public_html/product-finder
|
||||
PassengerPython /usr/bin/python3
|
||||
Allow from all
|
||||
Options -MultiViews
|
||||
</Directory>
|
||||
```
|
||||
|
||||
## 🚀 Deployment Steps
|
||||
|
||||
1. **Backup Current Installation**
|
||||
```bash
|
||||
mv product-finder product-finder.backup
|
||||
```
|
||||
|
||||
2. **Upload Updated Files**
|
||||
- Upload entire `app/` folder to server
|
||||
- Or just upload the 5 changed files listed above
|
||||
|
||||
3. **Restart Passenger**
|
||||
```bash
|
||||
# In product-finder folder
|
||||
mkdir -p tmp
|
||||
touch tmp/restart.txt
|
||||
```
|
||||
|
||||
4. **Test the Application**
|
||||
- Go to: `https://columbiawindows.com/product-finder/`
|
||||
- Should redirect to: `https://columbiawindows.com/product-finder/login`
|
||||
- Login page should load with all CSS/JS
|
||||
- Login should work and redirect properly
|
||||
- All routes should work: `/product-finder/users`, etc.
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Issue: Still getting 404 on login page
|
||||
|
||||
**Check server error logs:**
|
||||
```bash
|
||||
tail -f ~/logs/error_log # or wherever your error logs are
|
||||
```
|
||||
|
||||
**Verify APPLICATION_ROOT is set:**
|
||||
Add this test route to app.py temporarily:
|
||||
```python
|
||||
@app.route('/debug-config')
|
||||
def debug_config():
|
||||
return jsonify({
|
||||
'APPLICATION_ROOT': app.config.get('APPLICATION_ROOT'),
|
||||
'script_root': request.script_root,
|
||||
'url_root': request.url_root,
|
||||
'base_url': request.base_url
|
||||
})
|
||||
```
|
||||
|
||||
Then visit: `https://columbiawindows.com/product-finder/debug-config`
|
||||
|
||||
**Expected response:**
|
||||
```json
|
||||
{
|
||||
"APPLICATION_ROOT": "/product-finder",
|
||||
"script_root": "/product-finder",
|
||||
"url_root": "https://columbiawindows.com/product-finder/",
|
||||
"base_url": "https://columbiawindows.com/product-finder/debug-config"
|
||||
}
|
||||
```
|
||||
|
||||
### Issue: CSS/JS files not loading
|
||||
|
||||
**Check that routes are working:**
|
||||
- Visit: `https://columbiawindows.com/product-finder/css/styles.css`
|
||||
- Should return CSS file, not 404
|
||||
|
||||
**Check .htaccess MIME types:**
|
||||
Ensure these lines are in `.htaccess`:
|
||||
```apache
|
||||
AddType text/css .css
|
||||
AddType application/javascript .js
|
||||
AddType application/json .json
|
||||
```
|
||||
|
||||
### Issue: Login works but redirects are wrong
|
||||
|
||||
**Check redirect code in templates:**
|
||||
All JavaScript should use `BASE_URL`:
|
||||
```javascript
|
||||
const BASE_URL = '{{ base_url }}';
|
||||
window.location.href = BASE_URL + '/login';
|
||||
```
|
||||
|
||||
All Python redirects should use `url_for()`:
|
||||
```python
|
||||
return redirect(url_for('login_page'))
|
||||
```
|
||||
|
||||
### Issue: Works locally, fails on server
|
||||
|
||||
**Verify environment:**
|
||||
```bash
|
||||
# SSH to server
|
||||
cd ~/public_html/product-finder
|
||||
python3 -c "import os; print(os.environ.get('APPLICATION_ROOT', 'NOT SET'))"
|
||||
```
|
||||
|
||||
Should print: `/product-finder`
|
||||
|
||||
**Check Passenger is using correct Python:**
|
||||
```bash
|
||||
which python3
|
||||
# Use this path in PassengerPython directive
|
||||
```
|
||||
|
||||
### Issue: Sessions not persisting
|
||||
|
||||
**Check SECRET_KEY:**
|
||||
```python
|
||||
# In config.py, production should have a fixed SECRET_KEY
|
||||
SECRET_KEY = 'your-fixed-secret-key-here' # Don't use secrets.token_hex() in production
|
||||
```
|
||||
|
||||
**Check cookie settings:**
|
||||
Session cookies need to work with the subdirectory path.
|
||||
|
||||
### Issue: API calls return 404
|
||||
|
||||
**Check browser console:**
|
||||
Press F12, go to Network tab, and check the actual URLs being called.
|
||||
|
||||
**Should see:**
|
||||
```
|
||||
https://columbiawindows.com/product-finder/api/login
|
||||
https://columbiawindows.com/product-finder/api/session
|
||||
```
|
||||
|
||||
**If you see:**
|
||||
```
|
||||
https://columbiawindows.com/api/login ❌ Missing prefix
|
||||
```
|
||||
|
||||
Then `BASE_URL` is not set correctly in template.
|
||||
|
||||
## ✅ Verification Checklist
|
||||
|
||||
After deployment, test these in order:
|
||||
|
||||
- [ ] Visit `https://columbiawindows.com/product-finder/`
|
||||
- Should redirect to `/product-finder/login` ✓
|
||||
|
||||
- [ ] Login page loads
|
||||
- CSS styled correctly ✓
|
||||
- No 404s in browser console ✓
|
||||
|
||||
- [ ] Login with Master/Master
|
||||
- Should redirect to `/product-finder/select-location` ✓
|
||||
|
||||
- [ ] Select a location
|
||||
- Should redirect to `/product-finder/` ✓
|
||||
|
||||
- [ ] User info shows in header ✓
|
||||
|
||||
- [ ] Click "User Management" (if Master user)
|
||||
- Should go to `/product-finder/users` ✓
|
||||
|
||||
- [ ] Logout
|
||||
- Should return to `/product-finder/login` ✓
|
||||
|
||||
## 📝 Key Points
|
||||
|
||||
1. **The middleware is critical** - It tells Flask about the `/product-finder` prefix
|
||||
2. **passenger_wsgi.py sets the env var** - Before importing the app
|
||||
3. **All templates use BASE_URL** - For JavaScript fetch calls
|
||||
4. **All routes use url_for()** - For Python redirects
|
||||
5. **Production config defaults to /product-finder** - Development stays at /
|
||||
|
||||
## 🔄 Rolling Back
|
||||
|
||||
If something goes wrong:
|
||||
|
||||
```bash
|
||||
# Remove new files
|
||||
rm -rf product-finder
|
||||
|
||||
# Restore backup
|
||||
mv product-finder.backup product-finder
|
||||
|
||||
# Restart Passenger
|
||||
touch product-finder/tmp/restart.txt
|
||||
```
|
||||
|
||||
## 📞 Still Having Issues?
|
||||
|
||||
Run this diagnostic script on the server:
|
||||
|
||||
```python
|
||||
# Save as test_deployment.py in product-finder folder
|
||||
import os
|
||||
import sys
|
||||
|
||||
print("=" * 60)
|
||||
print("DEPLOYMENT DIAGNOSTIC")
|
||||
print("=" * 60)
|
||||
print(f"Python Version: {sys.version}")
|
||||
print(f"Current Directory: {os.getcwd()}")
|
||||
print(f"APPLICATION_ROOT env: {os.environ.get('APPLICATION_ROOT', 'NOT SET')}")
|
||||
print()
|
||||
|
||||
try:
|
||||
os.environ['APPLICATION_ROOT'] = '/product-finder'
|
||||
from app import app
|
||||
print("✓ App imported successfully")
|
||||
print(f"APPLICATION_ROOT config: {app.config.get('APPLICATION_ROOT')}")
|
||||
print(f"Middleware applied: {'PrefixMiddleware' in str(type(app.wsgi_app))}")
|
||||
except Exception as e:
|
||||
print(f"✗ Error importing app: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
```
|
||||
|
||||
Run with: `python3 test_deployment.py`
|
||||
|
||||
## 🎯 Expected Behavior
|
||||
|
||||
**Before these changes:**
|
||||
- Redirect works: `/product-finder` → `/product-finder/login` ✓
|
||||
- Login page loads BUT Flask doesn't know about `/product-finder` prefix
|
||||
- All `url_for()` calls generate `/login` instead of `/product-finder/login` ❌
|
||||
- Result: 404 errors on subpages
|
||||
|
||||
**After these changes:**
|
||||
- Flask knows it's at `/product-finder` via middleware ✓
|
||||
- All `url_for()` generates `/product-finder/login` ✓
|
||||
- All templates use `BASE_URL = '/product-finder'` ✓
|
||||
- Result: Everything works ✓
|
||||
|
||||
## 🆘 Quick Fix Checklist
|
||||
|
||||
If deployed and not working:
|
||||
|
||||
1. [ ] Uploaded `app/app.py` with PrefixMiddleware?
|
||||
2. [ ] Uploaded `app/passenger_wsgi.py` with env var setting?
|
||||
3. [ ] Uploaded `app/.htaccess` with SetEnv directive?
|
||||
4. [ ] Ran `touch tmp/restart.txt` to restart Passenger?
|
||||
5. [ ] Checked error logs for Python errors?
|
||||
6. [ ] Tested `/product-finder/debug-config` route?
|
||||
7. [ ] Verified cookies are being set (F12 > Application > Cookies)?
|
||||
|
||||
If all checked and still failing, check server error logs for the actual Python error.
|
||||
Reference in New Issue
Block a user