Files
malias-web/PROXY_SETUP.md
2026-01-23 13:41:39 +01:00

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

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

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