9.5 KiB
/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:
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:
if 'APPLICATION_ROOT' not in os.environ:
os.environ['APPLICATION_ROOT'] = '/product-finder'
3. Updated config.py
Production configuration now defaults to /product-finder:
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:
app/app.py- Contains PrefixMiddlewareapp/passenger_wsgi.py- Sets APPLICATION_ROOT env varapp/config.py- Production defaults to /product-finderapp/.htaccess- Apache configuration (new file)- 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:
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:
<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
-
Backup Current Installation
mv product-finder product-finder.backup -
Upload Updated Files
- Upload entire
app/folder to server - Or just upload the 5 changed files listed above
- Upload entire
-
Restart Passenger
# In product-finder folder mkdir -p tmp touch tmp/restart.txt -
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.
- Go to:
🐛 Troubleshooting
Issue: Still getting 404 on login page
Check server error logs:
tail -f ~/logs/error_log # or wherever your error logs are
Verify APPLICATION_ROOT is set: Add this test route to app.py temporarily:
@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:
{
"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:
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:
const BASE_URL = '{{ base_url }}';
window.location.href = BASE_URL + '/login';
All Python redirects should use url_for():
return redirect(url_for('login_page'))
Issue: Works locally, fails on server
Verify environment:
# 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:
which python3
# Use this path in PassengerPython directive
Issue: Sessions not persisting
Check SECRET_KEY:
# 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✓
- Should redirect to
-
Login page loads
- CSS styled correctly ✓
- No 404s in browser console ✓
-
Login with Master/Master
- Should redirect to
/product-finder/select-location✓
- Should redirect to
-
Select a location
- Should redirect to
/product-finder/✓
- Should redirect to
-
User info shows in header ✓
-
Click "User Management" (if Master user)
- Should go to
/product-finder/users✓
- Should go to
-
Logout
- Should return to
/product-finder/login✓
- Should return to
📝 Key Points
- The middleware is critical - It tells Flask about the
/product-finderprefix - passenger_wsgi.py sets the env var - Before importing the app
- All templates use BASE_URL - For JavaScript fetch calls
- All routes use url_for() - For Python redirects
- Production config defaults to /product-finder - Development stays at /
🔄 Rolling Back
If something goes wrong:
# 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:
# 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-finderprefix - All
url_for()calls generate/logininstead of/product-finder/login❌ - Result: 404 errors on subpages
After these changes:
- Flask knows it's at
/product-findervia 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:
- Uploaded
app/app.pywith PrefixMiddleware? - Uploaded
app/passenger_wsgi.pywith env var setting? - Uploaded
app/.htaccesswith SetEnv directive? - Ran
touch tmp/restart.txtto restart Passenger? - Checked error logs for Python errors?
- Tested
/product-finder/debug-configroute? - Verified cookies are being set (F12 > Application > Cookies)?
If all checked and still failing, check server error logs for the actual Python error.