Changed app for proxy and https++
This commit is contained in:
322
PROXY_SETUP.md
Normal file
322
PROXY_SETUP.md
Normal file
@@ -0,0 +1,322 @@
|
|||||||
|
# Reverse Proxy Setup Guide
|
||||||
|
|
||||||
|
This guide helps you configure reverse proxies (Nginx, Traefik, Zoraxy, Authelia, Caddy, etc.) to work with Mailcow Alias Manager.
|
||||||
|
|
||||||
|
## ✅ Built-in Proxy Support
|
||||||
|
|
||||||
|
The application includes **ProxyFix middleware** that automatically handles:
|
||||||
|
- ✅ HTTPS detection via `X-Forwarded-Proto`
|
||||||
|
- ✅ Host header forwarding via `X-Forwarded-Host`
|
||||||
|
- ✅ Client IP forwarding via `X-Forwarded-For`
|
||||||
|
- ✅ Path prefix support via `X-Forwarded-Prefix`
|
||||||
|
|
||||||
|
**No configuration changes needed in most cases!**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Common Proxy Configurations
|
||||||
|
|
||||||
|
### **Zoraxy** (Your Current Setup)
|
||||||
|
|
||||||
|
Zoraxy automatically sets the required headers. Just configure:
|
||||||
|
|
||||||
|
1. **Upstream Target**: `http://localhost:5172` (or your Docker IP)
|
||||||
|
2. **Enable WebSocket**: Yes (optional, recommended)
|
||||||
|
3. **Enable Proxy Headers**: Yes (should be default)
|
||||||
|
|
||||||
|
**Example Zoraxy Config:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "mailcow-alias-manager",
|
||||||
|
"upstream": "http://localhost:5172",
|
||||||
|
"domain": "aliases.yourdomain.com"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Authelia** (Authentication Proxy)
|
||||||
|
|
||||||
|
If using Authelia in front of the app:
|
||||||
|
|
||||||
|
1. **Authelia forwards the user after login** - this should work automatically
|
||||||
|
2. **Make sure Authelia passes these headers**:
|
||||||
|
- `X-Forwarded-Proto`
|
||||||
|
- `X-Forwarded-Host`
|
||||||
|
- `X-Forwarded-For`
|
||||||
|
|
||||||
|
**Common Issue**: Authelia redirects → App login page
|
||||||
|
**Solution**: The app has its own authentication. You have two options:
|
||||||
|
- **Option A**: Disable app login (requires code modification)
|
||||||
|
- **Option B**: Use Authelia for network access, app login for API access
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Nginx**
|
||||||
|
|
||||||
|
```nginx
|
||||||
|
server {
|
||||||
|
listen 443 ssl http2;
|
||||||
|
server_name aliases.yourdomain.com;
|
||||||
|
|
||||||
|
ssl_certificate /path/to/cert.pem;
|
||||||
|
ssl_certificate_key /path/to/key.pem;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
proxy_pass http://localhost:5172;
|
||||||
|
|
||||||
|
# Required headers for ProxyFix
|
||||||
|
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;
|
||||||
|
proxy_set_header X-Forwarded-Host $host;
|
||||||
|
|
||||||
|
# Optional: WebSocket support
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Traefik**
|
||||||
|
|
||||||
|
**docker-compose.yml:**
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
mailcow-alias-manager:
|
||||||
|
image: gitlab.pm/rune/malias-web:latest
|
||||||
|
container_name: mailcow-alias-manager
|
||||||
|
volumes:
|
||||||
|
- ./data:/app/data
|
||||||
|
restart: unless-stopped
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.malias.rule=Host(`aliases.yourdomain.com`)"
|
||||||
|
- "traefik.http.routers.malias.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.malias.tls=true"
|
||||||
|
- "traefik.http.routers.malias.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.services.malias.loadbalancer.server.port=5172"
|
||||||
|
networks:
|
||||||
|
- traefik
|
||||||
|
|
||||||
|
networks:
|
||||||
|
traefik:
|
||||||
|
external: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Traefik automatically sets `X-Forwarded-*` headers by default.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Caddy**
|
||||||
|
|
||||||
|
```caddy
|
||||||
|
aliases.yourdomain.com {
|
||||||
|
reverse_proxy localhost:5172
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Caddy automatically handles all proxy headers - no configuration needed!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 Troubleshooting
|
||||||
|
|
||||||
|
### **Issue: "NetworkError when attempting to fetch resource"**
|
||||||
|
|
||||||
|
**Causes:**
|
||||||
|
1. Mixed HTTP/HTTPS content
|
||||||
|
2. CORS blocking requests
|
||||||
|
3. Session cookie not being set
|
||||||
|
4. Proxy not forwarding headers
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
|
||||||
|
#### **1. Check Proxy Headers**
|
||||||
|
Your proxy MUST forward these headers:
|
||||||
|
```
|
||||||
|
X-Forwarded-Proto: https
|
||||||
|
X-Forwarded-Host: aliases.yourdomain.com
|
||||||
|
X-Forwarded-For: <client-ip>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **2. Check Browser Console**
|
||||||
|
Open browser DevTools (F12) → Console tab → Look for errors:
|
||||||
|
- **CORS errors**: Proxy misconfiguration
|
||||||
|
- **Mixed content**: HTTP resources on HTTPS page
|
||||||
|
- **401 Unauthorized**: Session/cookie issue
|
||||||
|
|
||||||
|
#### **3. Test Direct Access**
|
||||||
|
```bash
|
||||||
|
# Test without proxy
|
||||||
|
curl http://localhost:5172/
|
||||||
|
|
||||||
|
# Should return HTML (login page)
|
||||||
|
```
|
||||||
|
|
||||||
|
If this works but proxy doesn't, it's a proxy configuration issue.
|
||||||
|
|
||||||
|
#### **4. Check Session Cookies**
|
||||||
|
In browser DevTools → Application tab → Cookies:
|
||||||
|
- **Domain**: Should match your proxy domain
|
||||||
|
- **Path**: `/`
|
||||||
|
- **HttpOnly**: Should be `true`
|
||||||
|
- **Secure**: Depends on your setup
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Issue: Login works but redirects to HTTP instead of HTTPS**
|
||||||
|
|
||||||
|
**Solution**: Already fixed in latest version via `PREFERRED_URL_SCHEME='https'` in app config.
|
||||||
|
|
||||||
|
If still happening:
|
||||||
|
1. Verify proxy sends `X-Forwarded-Proto: https`
|
||||||
|
2. Check `docker compose logs -f mailcow-alias-manager`
|
||||||
|
3. Rebuild image: `docker compose up -d --build`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Issue: "Invalid password" but password is correct**
|
||||||
|
|
||||||
|
This is NOT a proxy issue - this is an authentication issue:
|
||||||
|
```bash
|
||||||
|
# Reset password
|
||||||
|
docker exec -it mailcow-alias-manager python3 reset_password.py "newpass"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **Issue: 502 Bad Gateway**
|
||||||
|
|
||||||
|
**Causes:**
|
||||||
|
1. App not running
|
||||||
|
2. Wrong upstream port
|
||||||
|
3. Container network issue
|
||||||
|
|
||||||
|
**Check:**
|
||||||
|
```bash
|
||||||
|
# Is container running?
|
||||||
|
docker ps | grep mailcow-alias-manager
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
docker compose logs -f mailcow-alias-manager
|
||||||
|
|
||||||
|
# Test internal connectivity
|
||||||
|
docker exec mailcow-alias-manager curl http://localhost:5172
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔒 Security Best Practices
|
||||||
|
|
||||||
|
### **1. HTTPS Only**
|
||||||
|
Always use HTTPS in production. HTTP is only for local testing.
|
||||||
|
|
||||||
|
### **2. Restrict Access**
|
||||||
|
Use firewall or proxy rules to restrict access:
|
||||||
|
```nginx
|
||||||
|
# Nginx: Restrict to internal network only
|
||||||
|
allow 192.168.1.0/24;
|
||||||
|
deny all;
|
||||||
|
```
|
||||||
|
|
||||||
|
### **3. Use Authelia/Authentik**
|
||||||
|
Add SSO layer for additional security:
|
||||||
|
- Users authenticate via Authelia
|
||||||
|
- Then app login provides API access
|
||||||
|
- Two-factor authentication recommended
|
||||||
|
|
||||||
|
### **4. Keep Session Cookies Secure**
|
||||||
|
The app sets:
|
||||||
|
- `HttpOnly=True` - Prevents JavaScript access
|
||||||
|
- `SameSite=Lax` - CSRF protection
|
||||||
|
|
||||||
|
For HTTPS-only deployments, you can enforce secure cookies:
|
||||||
|
```python
|
||||||
|
# In app.py, change:
|
||||||
|
SESSION_COOKIE_SECURE=True # Only send cookie over HTTPS
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Testing Your Setup
|
||||||
|
|
||||||
|
### **1. Basic Connectivity**
|
||||||
|
```bash
|
||||||
|
curl -v https://aliases.yourdomain.com/
|
||||||
|
# Should return 200 OK with HTML
|
||||||
|
```
|
||||||
|
|
||||||
|
### **2. Login Test**
|
||||||
|
```bash
|
||||||
|
curl -v -X POST https://aliases.yourdomain.com/login \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"password":"yourpassword"}' \
|
||||||
|
-c cookies.txt
|
||||||
|
|
||||||
|
# Check response - should be JSON with status: success
|
||||||
|
```
|
||||||
|
|
||||||
|
### **3. Session Test**
|
||||||
|
```bash
|
||||||
|
curl -v https://aliases.yourdomain.com/ \
|
||||||
|
-b cookies.txt
|
||||||
|
|
||||||
|
# Should return main page HTML (not login redirect)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🆘 Still Having Issues?
|
||||||
|
|
||||||
|
### **Enable Debug Logging**
|
||||||
|
|
||||||
|
**docker-compose.yml:**
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
- FLASK_DEBUG=True # Enable debug mode
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart:
|
||||||
|
```bash
|
||||||
|
docker compose down
|
||||||
|
docker compose up -d
|
||||||
|
docker compose logs -f
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Check Application Logs**
|
||||||
|
```bash
|
||||||
|
# View logs
|
||||||
|
docker compose logs -f mailcow-alias-manager
|
||||||
|
|
||||||
|
# Check for errors
|
||||||
|
docker compose logs mailcow-alias-manager | grep -i error
|
||||||
|
```
|
||||||
|
|
||||||
|
### **Test Without Proxy**
|
||||||
|
Temporarily bypass proxy to isolate the issue:
|
||||||
|
```bash
|
||||||
|
# Direct access test
|
||||||
|
curl http://localhost:5172/
|
||||||
|
```
|
||||||
|
|
||||||
|
If this works, the issue is with proxy configuration, not the app.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Summary
|
||||||
|
|
||||||
|
**The app is already configured for reverse proxies!**
|
||||||
|
|
||||||
|
Key points:
|
||||||
|
- ✅ ProxyFix middleware is enabled
|
||||||
|
- ✅ Handles X-Forwarded-* headers automatically
|
||||||
|
- ✅ HTTPS redirect support built-in
|
||||||
|
- ✅ Session cookies work behind proxies
|
||||||
|
- ✅ No code changes needed
|
||||||
|
|
||||||
|
Just make sure your proxy forwards the standard headers and you're good to go! 🚀
|
||||||
20
app.py
20
app.py
@@ -1,5 +1,6 @@
|
|||||||
from flask import Flask, render_template, request, jsonify, redirect, url_for, session
|
from flask import Flask, render_template, request, jsonify, redirect, url_for, session
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||||
import malias_wrapper as malias_w
|
import malias_wrapper as malias_w
|
||||||
import os
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
@@ -8,9 +9,28 @@ import sys
|
|||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.secret_key = os.urandom(24) # Secret key for session management
|
app.secret_key = os.urandom(24) # Secret key for session management
|
||||||
|
|
||||||
|
# Configure for reverse proxy (Authelia, Zoraxy, Nginx, etc.)
|
||||||
|
# This fixes HTTPS detection and redirects when behind a proxy
|
||||||
|
app.wsgi_app = ProxyFix(
|
||||||
|
app.wsgi_app,
|
||||||
|
x_for=1, # Trust X-Forwarded-For with 1 proxy
|
||||||
|
x_proto=1, # Trust X-Forwarded-Proto (http/https)
|
||||||
|
x_host=1, # Trust X-Forwarded-Host
|
||||||
|
x_prefix=1 # Trust X-Forwarded-Prefix
|
||||||
|
)
|
||||||
|
|
||||||
# Initialize database on startup
|
# Initialize database on startup
|
||||||
malias_w.init_database()
|
malias_w.init_database()
|
||||||
|
|
||||||
|
# Session configuration for reverse proxy
|
||||||
|
# Allow session cookies to work properly behind HTTPS proxy
|
||||||
|
app.config.update(
|
||||||
|
SESSION_COOKIE_SECURE=False, # Set to True if using HTTPS only
|
||||||
|
SESSION_COOKIE_HTTPONLY=True, # Prevent JavaScript access to session cookie
|
||||||
|
SESSION_COOKIE_SAMESITE='Lax', # CSRF protection
|
||||||
|
PREFERRED_URL_SCHEME='https' # Generate HTTPS URLs when behind proxy
|
||||||
|
)
|
||||||
|
|
||||||
def login_required(f):
|
def login_required(f):
|
||||||
"""Decorator to require login for routes"""
|
"""Decorator to require login for routes"""
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
|
|||||||
@@ -8,6 +8,12 @@
|
|||||||
# Recommended Settings:
|
# Recommended Settings:
|
||||||
# - Production: FLASK_ENV=production, FLASK_DEBUG=False (default)
|
# - Production: FLASK_ENV=production, FLASK_DEBUG=False (default)
|
||||||
# - Development: FLASK_ENV=development, FLASK_DEBUG=True
|
# - Development: FLASK_ENV=development, FLASK_DEBUG=True
|
||||||
|
#
|
||||||
|
# Reverse Proxy Support:
|
||||||
|
# ----------------------
|
||||||
|
# This application is configured to work behind reverse proxies (Nginx, Traefik, Zoraxy, Authelia, etc.)
|
||||||
|
# The ProxyFix middleware automatically handles X-Forwarded-* headers for HTTPS detection
|
||||||
|
# No additional configuration needed for most standard proxy setups
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mailcow-alias-manager:
|
mailcow-alias-manager:
|
||||||
|
|||||||
Reference in New Issue
Block a user