veegres / ivory

Ivory is designed to simplify and visualise work with Postgres clusters. It provides patroni management ui and postgres query builder.
GNU General Public License v3.0
33 stars 6 forks source link

Add a customized base URL in `vite.config` through an environment variable #516

Open dodo920306 opened 1 week ago

dodo920306 commented 1 week ago

Is your feature request related to a problem? Please describe. Ivory now uses / as its base URL as default. Allowing users to change this when building Ivory with docker run -e can let Ivory become more flexible when being deployed alongside other services and accessed through a reverse proxy.

Describe the solution you'd like I think adding the base option in vite.config with process.env can achieve this, but still an integration test should be conducted in case that this isn't compatible with the current Ivory program. A default value should also be assigned in case that users didn't provide a value.

Describe alternatives you've considered Adding the --base option to vite build should also be able to achieve the same goal.

Additional context ref

anselvo commented 1 week ago

Hi, so vite is responsible only for dev run, as I understand you talk about providing this base url inside the docker and then Ivory to work under this url. The problem is that under the hood it builds files and then locate them inside the docker then this is nginx who is responsible for directing you to these files or backend API https://github.com/veegres/ivory/blob/master/docker/production/nginx.conf.

Tbh I'm not sure that this is really a good idea, and use case is not really clear for me, probably you need to configure your DNS or your proxy. For example at my work we have haproxy that routes ivory.company.com to Ivory and it works well and all other things can be solved by running the docker on the desired port that can be handled by your proxy.

dodo920306 commented 1 week ago

In which case, both Nginx and the website frontend itself should apply this base URL configuration.

It's actually a good idea to provide such a feature though. I mean, ones can possibly want to make all their HA monitoring stuff, including dashboards like Ivory, under the same domain name, like dashboard.example.com.

In this way, their coworkers can access different services by http://dashboard.example.com/prometheus, http://dashboard.example.com/grafana, http://dashboard.example.com/haproxy for the status page of HAProxy, and http://dashboard.example.com/ivory for Ivory, and so on. While these services can be running on separate different machines, a single machine with the host name dashboard.example.com and a proper proxy running on it like Nginx or HAProxy is able to handle the traffic.

However, if a base URL, /ivory in this case, isn't provided, the front-end service will ask for the static and media files under the default / path for rendering the page. Since the service now is running on http://dashboard.example.com/ivory, such requests won't work. In fact, Ivory can only work on the / path, but the / path isn't always available, since ones can have home pages or other stuff. This limits the usage of a host name since if its meaning has nothing to do with Ivory, unlike ivory.company.com, supporting such a service on the / path can be weird.

Thus, although it's not necessary, it's helpful to allow a customized base URL.

Btw, since you have mentioned Nginx, I think another feature allowing https traffic with TLS certificates can also be helpful. Should I open another issue about it?

anselvo commented 5 days ago

Since the service now is running on http://dashboard.example.com/ivory, such requests won't work. In fact, Ivory can only work on the / path, but the / path isn't always available, since ones can have home pages or other stuff. This limits the usage of a host name since if its meaning has nothing to do with Ivory

I'm not really good at reverse proxies, but I though that in your proxy (HAProxy, Nginx, etc) you can configure desired url like http://dashboard.example.com/ivory and specify domain and port to the Ivory, like localhost:8181 and it should work. So you need to make this port available outside and extract it in your docker, then your proxy will direct all request from your url to this server. Isn't it a solution?

I think another feature allowing https traffic with TLS certificates can also be helpful. Should I open another issue about it?

yeah, I thought about adding tls for Ivory, you can create a task of course, but for now solution is to hide your proxy under TLS and direct this proxy to Ivory. You don't have safety between proxy and Ivory, but at least you will have safety between client and proxy (this is how I use it right now, but of course some day it should be added). If you good at configuring Nginx and it certs feel free to contribute :) It shouldn't be hard, but require some knowledge that I need to investigate, that is why it is not supported yet.

dodo920306 commented 5 days ago

I'm not a frontend guy, so my explanation could be faulty, but I'll try my best to explain the problem.

... I though that in your proxy (HAProxy, Nginx, etc) you can configure desired url like http://dashboard.example.com/ivory and specify domain and port to the Ivory, like localhost:8181 and it should work.

Like I said, that's not gonna work. At lease not how the frontend framework works.

However, if a base URL, /ivory in this case, isn't provided, the front-end service will ask for the static and media files under the default / path for rendering the page.

Take a look at web/index.html, and you can see why.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8"/>
        <link rel="icon" href="/ivory-fav.png"/>
        <meta name="viewport" content="width=device-width, initial-scale=1"/>
        <!--
          manifest.json provides metadata used when your web app is installed on a
          user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
        -->
        <link rel="manifest" href="/manifest.json"/>
        <title>Ivory</title>
    </head>
    <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <div id="root"></div>
        <!--
          This HTML file is a template.
          If you open it directly in the browser, you will see an empty page.

          You can add webfonts, meta tags, or analytics to this file.
          The build step will place the bundled scripts into the <body> tag.

          To begin the development, run `npm start` or `yarn start`.
          To create a production bundle, use `npm run build` or `yarn build`.
        -->
        <script type="module" src="/src/app/main/index.tsx"></script>
    </body>
</html>

As you can see, all static files are repuested under the / path. By that, I mean, all hrefs and srcs like href="/ivory-fav.png", href="/manifest.json", and src="/src/app/main/index.tsx". These paths are actually where the web browsers will ask these elements from under the host, so for a host name as dashboard.example.com, the web browsers will try to ask for these things directly under http://dashboard.example.com/ivory-fav.png or else. Since the correct path should be http://dashboard.example.com/ivory/ivory-fav.png because that's where Ivory is running at, the browsers will be responsed a 404 error for that there is no /ivory-fav.png, and so does for any other element.

What's worse, if there are only some of these pictures or files missing, the website can still work, but no, the real html in the production environment the browsers get from your frontend will include something like

<head>
    ...
    <script type="module" crossorigin src="/assets/index-Cv0uEsfF.js"></script>
    <link rel="stylesheet" crossorigin href="/assets/index-CFMAGa7F.css">
    ...
</head>

to introduce all you have done in the rest of the frontend programs (The suffices of them here may change). Still, since Ivory is running under /ivory, the correct paths that can be accessed Ivory at are /ivory/assets/index-Cv0uEsfF.js and /ivory/assets/index-CFMAGa7F.css. So again, the browsers will get more 404 errors, and all of your frontend work can't be accessed by the browsers. Thus, the users will get an empty webpage. That's why it says "You need to enable JavaScript to run this app." because the web browsers have to run JS programs to access your work, but the current situation is the browsers can't even get the JS programs.

In conclusion, even though your users know they should get Ivory under /ivory with proxies properly configured, their browsers don't know, so they ask your programs, and your programs don't know either, so the website is broken.

P.S. You can see all of what browsers asking in the Network tab of the developer tools by pressing F12 when connecting to the webpage.

anselvo commented 3 days ago

ok, probably I should recheck this, after you mentioned these static files, maybe you're right, so I will do it and share what I will get