Files
malias-web/PROXY_SETUP.md

10 KiB

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:

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:

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

Switching Between Modes

To switch from one mode to another:

  1. Edit docker-compose.yml

    # Change this line:
    - ENABLE_PROXY=false  # or true
    
  2. Restart the container

    docker compose down
    docker compose up -d
    
  3. Verify mode in logs

    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:

{
  "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

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:

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

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

# 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:

# 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:

# 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: 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:

# In app.py, change:
SESSION_COOKIE_SECURE=True  # Only send cookie over HTTPS

📊 Testing Your Setup

1. Basic Connectivity

curl -v https://aliases.yourdomain.com/
# Should return 200 OK with HTML

2. Login Test

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

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:

environment:
  - FLASK_DEBUG=True  # Enable debug mode

Restart:

docker compose down
docker compose up -d
docker compose logs -f

Check Application Logs

# 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:

# 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! 🚀