Ctrl K
ComunidadGuías…

docs/REVERSE_PROXY.md

Rama dev · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Running BillionMail Behind a Reverse Proxy

BillionMail can be placed behind a reverse proxy (nginx, Caddy, Traefik, etc.) to add SSL termination, custom domains, or integrate with existing infrastructure.

## The `reverse_proxy_domain` Setting

BillionMail stores a `reverse_proxy_domain` value in the `bm_options` table. When set, tracking URLs (open/click tracking) and public-facing links use this domain instead of the internal container address.

**Set via UI:** Settings > General > Reverse Proxy Domain

The domain must include the scheme, e.g. `https://mail.example.com`. BillionMail tests connectivity by calling `GET {domain}/api/languages/get` before saving.

## Required Headers

All proxy configs must forward these headers:

| Header | Purpose |
|--------|---------|
| `Host` | Original host header for correct URL generation |
| `X-Real-IP` | Client's real IP for analytics and rate limiting |
| `X-Forwarded-For` | Full proxy chain for logging |
| `X-Forwarded-Proto` | `https` — ensures BillionMail generates HTTPS tracking URLs |

## Nginx

```nginx
server {
    listen 443 ssl http2;
    server_name mail.example.com;

    ssl_certificate     /etc/ssl/certs/mail.example.com.pem;
    ssl_certificate_key /etc/ssl/private/mail.example.com.key;

    client_max_body_size 50m;

    location / {
        proxy_pass http://127.0.0.1:8080;

        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;

        # WebSocket support (live updates)
        proxy_http_version 1.1;
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection "upgrade";

        # SPA fallback — let BillionMail handle routing
        proxy_intercept_errors off;
    }
}

# HTTP -> HTTPS redirect
server {
    listen 80;
    server_name mail.example.com;
    return 301 https://$host$request_uri;
}
```

## Caddy

```caddyfile
mail.example.com {
    reverse_proxy 127.0.0.1:8080 {
        header_up Host {host}
        header_up X-Real-IP {remote}
        header_up X-Forwarded-Proto {scheme}
    }
}
```

Caddy handles SSL certificates automatically via Let's Encrypt.

## Traefik (Docker labels)

```yaml
labels:
  - "traefik.enable=true"
  - "traefik.http.routers.billionmail.rule=Host(`mail.example.com`)"
  - "traefik.http.routers.billionmail.tls.certresolver=letsencrypt"
  - "traefik.http.services.billionmail.loadbalancer.server.port=8080"
```

## After Setup

1. Set the reverse proxy domain in BillionMail: Settings > General > Reverse Proxy Domain
2. Enter your full URL with scheme: `https://mail.example.com`
3. BillionMail will test the connection before saving

## Troubleshooting

### SPA 404 errors on page refresh

The frontend is a Vue SPA — all routes must resolve to the BillionMail backend, not return static 404s. Ensure your proxy passes all paths to the upstream (no `try_files` that serve a local 404 page).

### Tracking URLs showing internal port (e.g. `:5679`)

The `reverse_proxy_domain` is not set, or `X-Forwarded-Proto` / `Host` headers are not forwarded. BillionMail falls back to the internal address. Set the reverse proxy domain in Settings after confirming headers are passed.

### SSL certificate mismatch

Ensure the certificate matches the domain used in `reverse_proxy_domain`. If using Caddy, certificates are automatic. For nginx, verify `ssl_certificate` matches `server_name`.

### WebSocket connection failures

If live dashboard updates stop working behind the proxy, ensure you forward `Upgrade` and `Connection` headers (see nginx config above). Caddy handles this automatically.