500 Internal Server Error error="stream error: stream ID 1455; HTTP_1_1_REQUIRED; received from peer"

Hello,

I am currently setting up Traefik with a few default configurations. Before diving into the details, here are the configuration items:

  • System: Debian 12
  • Updates: Latest
  • Software: Docker-Compose

Configuration deployment:

  • Docker-Compose.yml (Docker Configuration)
  • Traefik.yml (Static Config)
  • Config.yml (Dynamic Config)

We are aiming to expose Microsoft Exchange MAPI to clients using this default configuration. However, during the deployment, we encountered the following error:

500 Internal Server Error error="stream error: stream ID 1455; HTTP_1_1_REQUIRED; received from peer"

We have attempted to configure HTTP/1.1 in various ways based on different sources, but the issue persists.

Could someone assist us in completing the configuration and ensuring it works with Exchange 2019 MAPI?

Thank you!

docker-compose.yml

version: "3.3"

services:

  traefik:
    image: "traefik:v3.3"
    healthcheck:
      test: 
        - CMD
        - traefik
        - healthcheck
      interval: 10s
      timeout: 5s
      retries: 3
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - ./trafeak-host-file:/etc/hosts
      - ./traefik.yaml:/etc/traefik/traefik.yaml
      - ./traefik.log:/traefik.log
      - /dynamic/:/etc/traefik/dynamic
      - /certs/:/certs/
      - /var/run/docker.sock:/var/run/docker.sock

Traefik.yml

## STATIC CONFIG (restart traefik to update)

# shows you a log msg if a newer image tag can be used
global:
  checkNewVersion: true

# log default is ERROR, but WARN is more helpful
log:
  # Log level
  #
  # Optional
  # Default: "ERROR"
  #
  level: DEBUG

  # Sets the filepath for the traefik log. If not specified, stdout will be used.
  # Intermediate directories are created if necessary.
  #
  # Optional
  # Default: os.Stdout
  #
  filePath: /traefik.log

  # Format is either "json" or "common".
  #
  # Optional
  # Default: "common"
  #
  format: common

# enable dashboard on 8080 with auth
api:
  insecure: true
  dashboard: true

# enable ping so the `traefik healthcheck` works
ping: {}


# listen on 80/443, and redirect all 80 to 443 via 301
entryPoints:
  web:
    address: :80
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
          permanent: true
  websecure:
    address: :443

tls:
  certificates:
    - certFile: /certs/cert.crt
      keyFile: /certs/key.crt
  options:
    default:
      sniStrict: false
      alpnProtocols:
        - http/1.1
        - h2
      minVersion: VersionTLS12
      mintls13:
        minVersion: VersionTLS13
  stores:
    default:
      defaultCertificate:
       - certFile: /certs/cert.crt
         keyFile: /certs/key.crt

# auto-proxy containers if they have proper labels
# and also use this file for dynamic config (tls)
providers:
  file:
    fileName: /etc/traefik/dynamic/config.yaml
    watch: true

dynamic.yml

http:
  routers:
    Exchange:
      rule: "Host(`ex01.enviroment.com`)"
      service: Exchange
      priority: 2000
      entryPoints:
        - websecure
      tls:
        domains:
          - main: "ex01.enviroment.com"
        options: "esvdefault"

  services:
    Exchange:
      loadBalancer:
        servers:
          - url: "https://ex01.enviroment.com"

tls:
  certificates:
    - certFile: /certs/cert.crt
      keyFile: /certs/key.crt
  options:
    esvdefault:
      alpnProtocols:
        - "http/1.1"

Use 3 backticks before and after code/config to make it more readable and preserve spacing, which is important in yaml.

You can try to create a serversTransport with disableHTTP2: true and assign it to the Traefik service (doc).

Edit: Adjusted initial post with the 3 backticks to make it readable, thanks for the tip!

I added the configuration without any change in the result.


Dynamic file
http:
  routers:
    Exchange:
      rule: "Host(`ex01.enviroment.com`)"
      service: Exchange
      priority: 2000
      entryPoints:
        - websecure
      tls:
        domains:
          - main: "ex01.enviroment.com"
        options: "esvdefault"
  serversTransports:
    mytransport:
      disableHTTP2: true
  services:
    Exchange:
      loadBalancer:
        servers:
          - url: "https://ex01.enviroment.com"

tls:
  certificates:
    - certFile: /certs/cert.crt
      keyFile: /certs/key.crt
  options:
    esvdefault:
      alpnProtocols:
        - "http/1.1"

You need to assign the serversTransport (reference):

  services:
    Exchange:
      loadBalancer:
        serversTransport: mytransport
        servers:
          - url: "https://ex01.enviroment.com"

Note, you currently create a circular reference with that URL.

Yes, normally this would create circular traffic, but in this case, the hosts file on the traffic server is dynamically updated by our automation, pointing to another address to keep SNI in check with the receiving server.

Your suggestion did make a difference; the connection is now being made. However, Outlook is now asking for passwords. We're one step closer, so thank you for the solution to this part!