baptisteArno / typebot.io

💬 Typebot is a powerful chatbot builder that you can self-host.
https://typebot.io
Other
7.17k stars 1.96k forks source link

Port is ignored for viewer URL #1696

Closed kuon closed 1 month ago

kuon commented 1 month ago

I am running the viewer in a staging environment where it runs on a non standard port (not 443).

I have NEXT_PUBLIC_VIEWER_URL and NEXT_PUBLIC_CHAT_API_URL set to the full host with port number.

The preview works in the builder, but when I open the viewer, it tries to do the startChat API call on the URL without the port number.

So, if I have this:

NEXT_PUBLIC_VIEWER_URL=https://dev.xxx.ch:10006
NEXT_PUBLIC_CHAT_API_URL=https://dev.xxx.ch:10006

It will do this call:

https://dev.xxx.ch/api/v1/typebots/my-typebot-bpkjj7k/startChat

Which fails.

It seems that this is due to this line which does not put a port number:

https://github.com/baptisteArno/typebot.io/blob/d49e006df08283a7ada7853e15566e1019fe8026/apps/viewer/src/pages/%5B%5B...publicId%5D%5D.tsx#L81

(also second occurence a few lines below)

If I fix with url: `${protocol}://${forwardedHost ?? host}:10006${pathname}`, it works properly.

baptisteArno commented 1 month ago

Can you share your reverse proxy settings?

kuon commented 1 month ago
     location / {
      proxy_set_header Host $host:$server_port;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-Port $server_port;
      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_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $http_connection;
      proxy_read_timeout 86400;
      proxy_buffering off;
      add_header 'Cross-Origin-Embedder-Policy' 'credentialless';
      add_header 'Cross-Origin-Opener-Policy' 'same-origin';
      proxy_pass http://127.0.0.1:$server_port;
    }

Btw, the proxy_pass port is the same as the external port, but this is normal because the app and nginx does not listen to the same interface.

kuon commented 1 month ago

Digging a bit into it, it seems that the problem is that X-Forwarded-Host does not include the port number, while Host does.

The X-Forwarded-Host header is not standard. And the current usage originates in heroku using separated Host and Port header. Thus, many application and frameworks expect it this way. Amazon also uses it.

After searching behavior of this in different projects, it seems that implementations look at X-Forwarded-Host and if it does not include a port number, then look for X-Forwarded-Port. Which means the port in the host header has precedence over the port in the port header.

kuon commented 1 month ago

Digging some more into it, there is a new Forwarded header which should take precedence over all the other ones.

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Forwarded

In this header, the host does contain the port number.

So if the code is to be as portable as possible, it should do:

Note: if the host field of the Forwarded header does not contain a port number, set it to proto and stop. It should not be considered unset.

baptisteArno commented 1 month ago

Thanks for the info!!