# Reverse Proxy Setup Guide This guide helps you configure reverse proxies (Nginx, Traefik, Zoraxy, Authelia, Caddy, etc.) to work with Mailcow Alias Manager. --- ## 🔧 ENABLE_PROXY Configuration The application supports **two access modes** controlled by the `ENABLE_PROXY` environment variable in `docker-compose.yml`: ### **Mode 1: Direct Access (ENABLE_PROXY=false)** - DEFAULT Use this when accessing the application directly via IP:port **without a reverse proxy**. **docker-compose.yml:** ```yaml environment: - ENABLE_PROXY=false # Default setting ``` **Access:** `http://192.168.1.100:5172` (replace with your server IP) **Features:** - ✅ Works over HTTP (no HTTPS required) - ✅ Standard cookie behavior (SameSite=Lax) - ✅ No proxy configuration needed - ✅ Simple login flow - ✅ Perfect for internal/LAN access **When to use:** - Accessing from internal network only - No reverse proxy in place - Testing or development - Simple single-server setup --- ### **Mode 2: Proxy Access (ENABLE_PROXY=true)** Use this when running **behind a reverse proxy** (Authelia, Zoraxy, Nginx, Traefik, Caddy). **docker-compose.yml:** ```yaml environment: - ENABLE_PROXY=true ``` **Access:** `https://alias.yourdomain.com` (through your reverse proxy) **Features:** - ✅ ProxyFix middleware handles X-Forwarded-* headers - ✅ HTTPS redirect support - ✅ Secure cookies (HTTPS only) - ✅ Works with authentication proxies (Authelia) - ✅ Multi-proxy chain support **When to use:** - Accessing from internet via domain name - Behind Nginx, Traefik, Caddy, HAProxy - Behind authentication proxy (Authelia, Authentik) - SSL/TLS termination at proxy - Production deployments with HTTPS **Special Feature - Authelia Auto-Login:** When `ENABLE_PROXY=true` and you're using Authelia, the app automatically logs you in using Authelia's authentication headers. **No app password needed!** Simply authenticate through Authelia, and you'll be logged into the Mailcow Alias Manager automatically. --- ### **Switching Between Modes** To switch from one mode to another: 1. **Edit `docker-compose.yml`** ```yaml # Change this line: - ENABLE_PROXY=false # or true ``` 2. **Restart the container** ```bash docker compose down docker compose up -d ``` 3. **Verify mode in logs** ```bash docker compose logs mailcow-alias-manager | grep "ACCESS MODE" ``` You should see either: - `ACCESS MODE: Direct IP:Port (ENABLE_PROXY=false)` - `ACCESS MODE: Reverse Proxy (ENABLE_PROXY=true)` 4. **Clear browser cookies** (IMPORTANT!) - Press F12 → Application → Cookies - Delete all cookies for your domain - Close and reopen browser 5. **Login again** --- ### **Quick Reference Table** | Access Method | ENABLE_PROXY | Access URL | Cookie Mode | |--------------|--------------|------------|-------------| | Direct IP:port | `false` (default) | `http://192.168.1.100:5172` | HTTP, SameSite=Lax | | Nginx/Traefik | `true` | `https://alias.example.com` | HTTPS, SameSite=None | | Authelia + Zoraxy | `true` | `https://alias.example.com` | HTTPS, SameSite=None | | Caddy | `true` | `https://alias.example.com` | HTTPS, SameSite=None | | Local dev (`python3 app.py`) | N/A (not set) | `http://localhost:5172` | HTTP, SameSite=Lax | --- ## ✅ Built-in Proxy Support (When ENABLE_PROXY=true) 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` **Works with 2 proxies in chain** (e.g., Zoraxy → Authelia → App) --- ## 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: ``` #### **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! 🚀