Reverse proxying http frame

I'm trying to fix an issue with my Grafana Powerwall Dashboard, where a iframe seems to not be upgrading to https.

For example with HTTP (where everything is working):

And then when I enable HTTPS (frame doesn't load):

Using curl with http, I get a response:

curl -vvv http://grafana.bsmt-srv1.home.arpa:8675/
* Connected to grafana.bsmt-srv1.home.arpa (192.168.50.252) port 8675
> GET / HTTP/1.1
> Host: grafana.bsmt-srv1.home.arpa:8675
> User-Agent: curl/8.4.0
> Accept: */*
>   * HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: BaseHTTP/0.6 Python/3.10.13
< Date: Tue, 07 Nov 2023 09:01:49 GMT

As opposed to HTTPS where:

curl -vvv https://grafana.bsmt-srv1.home.arpa:8675/
*   Trying 192.168.50.252:8675...
* Connected to grafana.bsmt-srv1.home.arpa (192.168.50.252) port 8675
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
* OpenSSL/3.1.4: error:0A00010B:SSL routines::wrong version number
* Closing connection
curl: (35) OpenSSL/3.1.4: error:0A00010B:SSL routines::wrong version number

I think what is happening is when I visit https://grafana.bsmt-srv1.home.arpa it's trying to connect to the pypowerwall container on https://grafana.bsmt-srv1.home.arpa:8675 which is serving the frame only on http. Due to some cross-origin issue it doesn't appear (but the rest of grafana works).

These are the two container definitions that I have:

pypowerwall:
    image: jasonacox/pypowerwall:latest
    container_name: pypowerwall
    hostname: pypowerwall
    restart: always
    ports:
        - target: 8675
          published: 8675
          # host_ip: 127.0.0.1
          mode: host
    env_file:
      - pypowerwall.env
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.pypowerwall.tls=true"
      - "traefik.http.routers.pypowerwall.tls.certresolver=stepca"
      - "traefik.http.routers.pypowerwall.rule=Host(`pypowerwall.$MY_DOMAIN`)"
      - "traefik.http.routers.pypowerwall.entrypoints=websecure"
      - "traefik.http.services.pypowerwall.loadbalancer.server.port=8675"
grafana:
    image: grafana/grafana:9.1.2-ubuntu
    container_name: grafana
    hostname: grafana
    restart: always
    user: "1003:1003"
    volumes:
        - type: bind
          source: /mnt/container_data/grafana
          target: /var/lib/grafana
    ports:
        - target: 9000
          published: 9000
          host_ip: 127.0.0.1
          mode: host
    env_file:
        - grafana.env
    depends_on:
        - influxdb
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.grafana.tls=true"
      - "traefik.http.routers.grafana.tls.certresolver=stepca"
      - "traefik.http.routers.grafana.rule=Host(`grafana.$MY_DOMAIN`)"
      - "traefik.http.routers.grafana-websocket.rule=Host(`grafana.$MY_DOMAIN`) && Path(`/api/live/ws`)"
      - "traefik.http.routers.grafana.entrypoints=websecure"
      - "traefik.http.services.grafana.loadbalancer.server.port=9000"
      - "traefik.http.middlewares.cors.headers.customResponseHeaders.Access-Control-Allow-Origin=*"
      - "traefik.http.routers.grafana.middlewares=cors"

I tried with the traefik.http.middlewares.cors.headers.customResponseHeaders and traefik.http.routers.grafana.middlewares options to see if that would fix things but it didn't.

Anyone know what I need to do to make the iframe also https?

There was this thread SSL / HTTPS proxy · jasonacox/Powerwall-Dashboard · Discussion #215 · GitHub but nobody seemed to know what to do with Traefik.

Are you sure the Grafana thing is not just configured for that element to show an iFrame with http URL instead of https URL?

No it's not https://github.com/jasonacox/Powerwall-Dashboard/blob/main/dashboards/powerflow-animation.html#L46. Can also see from the debugger in the second screenshot that it's trying to load https (but nothing there).

Can see from the debugger that it's definitely https, when that is enabled. The issue is there is no https being served by Traefik for pypowerwall.

I would have thought I could have just had my own entry point pypowerwall and just had a cross request to that.

I'm pretty sure the problem is with my pypowerwall labels.

I think the problem is there's two services, there's grafana (which is on port 9000) and pypowerwall which is on 8675, but for some reason it wants to use the grafana.example.com domain instead of pypowerwall.example.com, as a result the pypowerwall container is not getting proxied.

It sounds exactly like the problem described here SSL / HTTPS proxy · jasonacox/Powerwall-Dashboard · Discussion #215 · GitHub

When trying to embedd the pyPowerwall current flow graphic into a webpage of my own I ran into the problem that browsers will block attempts to embed a insecure (http) iframe within a secure (https) webpage. I thought I would document how I solved this.

So now in my webpage, instead of pointing the iFrame at the pyPowerwall host, port 8675, I point it at my lighttpd host (as https), same port number, which is then proxy'd over to the non-secure pyPowerwall host. Works like a charm.

That seems to be the issue, it's trying to load the iframe from the pyPowerwall container which is not http.

I'm thinking that this should look like https://pypowerwall.bsmt-srv1.home.arpa:443 not showing on port 8675.

Seems to be this line exactly:

  powerFrame.src = window.location.protocol + "//" + window.location.hostname + ":8675/";

Is where the https url comes from. I wonder what I can do to make Traefik reverse proxy that.

That’s the same or a different port than the original request to the page?

Different port. Grafana is on port 9000 and is at http://grafana.bsmt-srv1.home.arpa:9000
PyPowerwall is on port http://grafana.bsmt-srv1.home.arpa:8675

What appears to be working is traefik appears to be proxying http://grafana.bsmt-srv1.home.arpa:9000 to https://grafana.bsmt-srv1.home.arpa:443 correctly.

The problem appears to be that the frame is still at http://grafana.bsmt-srv1.home.arpa:8675 and is not being proxied. Even though I have those labels set it wants to look at https://grafana.bsmt-srv1.home.arpa:8675 for it, which does not exist hence the error.

Everything only works when I disable TLS on the grafana docker container and serve the whole page over http, something I want to avoid doing.

Thanks in advance :heart: for helping me worth through this, I have been pulling my hair out over this for some time and was never able to solve it myself.

So the iFrame uses the same protocol (http/s) as the parent page, so no issues with that.

But the iFrame uses the same port for http and https. I am not sure Traefik can handle that.

Furthermore it’s strange to see http is working for the iFrame target, even though TLS is enabled on the router.

Share your full Traefik static and dynamic config.

It does appear to yes, but shouldn't it be possible to simply offer https and not http?

Traefik service:

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    hostname: traefik
    networks:
      - traefik-proxy
    ports:
      - 80:80
      - 443:443
      - 8080:8080
    environment:
      LEGO_CA_CERTIFICATES: "/etc/traefik/certs/root.crt"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefik.yml:/traefik.yml:ro"
      - "/mnt/container_data/traefik/certs:/etc/traefik/certs:ro"
      - "acme:/etc/acme"
volumes:
  acme:

networks:
  traefik-proxy:
    external: true

Dynamic config. Note I commented out the http/https redirect because I couldn't get this working. If I get this working I don't plan on offering http at all.

log:
  level: INFO

api:
  insecure: true
  dashboard: true

entryPoints:
  web:
   address: ":80"
#   http:
#     redirections:
#      entrypoint:
#        to: "websecure"
#        scheme: "https"
  websecure:
    address: ":443"

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false

certificatesResolvers:
  stepca:
    acme:
      caServer: "https://tinyca.bsmt-rpi1.home.arpa/acme/acme/directory"
      email: "admin@home.arpa"
      storage: "/etc/acme/acme.json"
      httpChallenge:
        entryPoint: web

I have a Raspberry Pi on the inside of my network which hands out certificates like this, that works well.

Of course you can use https only.

Currently you expose the port of the target container. Instead Traefik needs to expose the port and you need to create an entrypoint for the port.

(Assuming both run on the same server/node)

So that should mean my traefik config should look like this:

services:
  traefik:
    image: traefik:latest
    container_name: traefik
    hostname: traefik
    networks:
      - traefik-proxy
    ports:
      - 80:80
      - 443:443
      - 8080:8080
      - "${PYPOWERWALL_PORTS:-8675:8675}"
    environment:
      LEGO_CA_CERTIFICATES: "/etc/traefik/certs/root.crt"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefik.yml:/traefik.yml:ro"
      - "/mnt/container_data/traefik/certs:/etc/traefik/certs:ro"
      - "acme:/etc/acme"
volumes:
  acme:

networks:
  traefik-proxy:
    external: true

I changed the way the ports were exposed in line with what upstream did in their example.

services:
  pypowerwall:
    image: jasonacox/pypowerwall:0.6.2t28
    container_name: pypowerwall
    hostname: pypowerwall
    restart: unless-stopped
    user: "${PWD_USER:-1000:1000}"
    # ports:
    # - "${PYPOWERWALL_PORTS:-8675:8675}"
    env_file:
      - pypowerwall.env
    labels:
      - "traefik.enable=true"
      ## Are the below three rules even needed?
      - "traefik.http.routers.pypowerwall.tls=true"
      - "traefik.http.routers.pypowerwall.tls.certresolver=stepca"
      - "traefik.http.routers.pypowerwall.rule=Host(`pypowerwall.$MY_DOMAIN`)" 

      - "traefik.http.routers.pypowerwall.entrypoints=pypw_secure"
      - "traefik.http.services.pypowerwall.loadbalancer.server.port=8675"

I'm not quite sure if these labels are correct. for example because the page uses window.location.hostname, that woud always mean the domain would be grafana.**

So that sound look like this:

entryPoints:
  web:
   address: ":80"
#   http:
#     redirections:
#      entrypoint:
#        to: "websecure"
#        scheme: "https"
  websecure:
    address: ":443"
  pypw_secure:
    address: ":8675"

Yes I am.

Other question I am confused about:

ports:
- "${PYPOWERWALL_PORTS:-8675:8675}"

Should this be on the Traefik container, or the pypowerwall container?

I think I need it on the traefik container because that is what will appear in the browser:

  window.location.protocol + "//" + window.location.hostname + ":8675/";

at the same time that is the port exposed by pypowerwall. I can't use the same port on both containers.

Correct, port 8675 needs to be on Traefik for TLS to work.

You don’t need ports on target service, you should not expose those externally, going around Traefik.

Use Docker network, see simple Traefik example.

Success, got this working! Thanks, @bluepuma77

For the powerwall config:

 pypowerwall:
    image: jasonacox/pypowerwall:0.6.2t28
    container_name: pypowerwall
    hostname: pypowerwall
    restart: unless-stopped
    user: "${PWD_USER:-1000:1000}"
    env_file:
      - pypowerwall.env
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.pypowerwall.tls=true"
      - "traefik.http.routers.pypowerwall.rule=Host(`grafana.$MY_DOMAIN`)"
      - "traefik.http.routers.pypowerwall.entrypoints=pypw_secure"
      - "traefik.http.services.pypowerwall.loadbalancer.server.port=8675"

Keypoint there is to use the grafana host, because that is hardcoded.

Then for the traefik config:

traefik:
    image: traefik:latest
    container_name: traefik
    hostname: traefik
    networks:
      - traefik-proxy
    ports:
      - 80:80
      - 443:443
      - 8080:8080
      - "${PYPOWERWALL_PORTS:-8675:8675}" ## add the port here
    environment:
      LEGO_CA_CERTIFICATES: "/etc/traefik/certs/root.crt"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefik.yml:/traefik.yml:ro"
      - "/mnt/container_data/traefik/certs:/etc/traefik/certs:ro"
      - "acme:/etc/acme"
volumes:
  acme:

networks:
  traefik-proxy:
    external: true

and finally add entry point!

entryPoints:
  web:
   address: ":80"
   http:
     redirections:
      entrypoint:
        to: "websecure"
        scheme: "https"
  websecure:
    address: ":443"
  pypw_secure:
    address: ":8675"
1 Like

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.