Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a customized base URL in the configuration through an environment variable #516

Open
dodo920306 opened this issue Sep 9, 2024 · 10 comments · Fixed by #528 or #530
Open

Add a customized base URL in the configuration through an environment variable #516

dodo920306 opened this issue Sep 9, 2024 · 10 comments · Fixed by #528 or #530
Assignees
Labels
enhancement New feature or request

Comments

@dodo920306
Copy link
Contributor

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

@dodo920306 dodo920306 added the enhancement New feature or request label Sep 9, 2024
@anselvo
Copy link
Contributor

anselvo commented Sep 9, 2024

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
Copy link
Contributor Author

dodo920306 commented Sep 9, 2024

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
Copy link
Contributor

anselvo commented Sep 11, 2024

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
Copy link
Contributor Author

dodo920306 commented Sep 12, 2024

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
Copy link
Contributor

anselvo commented Sep 13, 2024

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

@anselvo anselvo linked a pull request Sep 18, 2024 that will close this issue
@anselvo anselvo self-assigned this Sep 18, 2024
@anselvo anselvo reopened this Sep 18, 2024
@dodo920306
Copy link
Contributor Author

dodo920306 commented Sep 19, 2024

I think I fully solved this.

Please check #529 🙏.

@dodo920306 dodo920306 changed the title Add a customized base URL in vite.config through an environment variable Add a customized base URL in the configuration through an environment variable Sep 19, 2024
This was linked to pull requests Sep 20, 2024
@anselvo
Copy link
Contributor

anselvo commented Sep 20, 2024

Please, test version v1.3.4 and let me know if it works for you, env variable is IVORY_URL_PATH

@dodo920306
Copy link
Contributor Author

dodo920306 commented Sep 20, 2024

OK, I get it. You decided to use the server directly to serve these files. It's a brilliant idea!
I'm currently using Ivory at work but on weekend leave. It even works fine with the version of Ivory on my original feature branch, so I don't see any reason it won't do it with the latest version.
But still, I will test it and update you with the latest status after I’m back on Monday in my time zone, and I will close this issue then if nothing wrong happens. Thanks!

@anselvo
Copy link
Contributor

anselvo commented Sep 20, 2024

Am I right, that your solution works only with additional / in the path?

With current implement it should work with and without it.

P.S. I've created task for TLS #531 (comment)

@dodo920306
Copy link
Contributor Author

dodo920306 commented Sep 21, 2024

I guess it depends on what / you're asking about? The original solution only works when BASE_URL is in the form of /xyz because I thought it should be users' responsibility to assign the value in the right way, and then the entrypoint just

  1. replaces location / with location /xyz
  2. replaces location /api with location /xyz/api
  3. replaces rewrite ${BASE_URL}(.*) $1 break; with rewrite /xyz(.*) $1 break;

If nothing is given, the solution will skip the first two steps and replace rewrite ${BASE_URL}(.*) $1 break; with rewrite (.*) $1 break;, which rewrites nothing, and since the paths of locations aren't changed, the original path / can work.

If no slash is given, the solution will

  1. replaces location / with location \xyz
  2. replaces location /api with location \xyz/api
  3. replaces rewrite ${BASE_URL}(.*) $1 break; with rewrite \xyz(.*) $1 break;

A leading backslash is there since it was originally added to make / escape for the command sed and crashes Nginx.

If a trailing slash is given, the solution will

  1. replaces location / with location /xyz/
  2. replaces location /api with location /xyz//api
  3. replaces rewrite ${BASE_URL}(.*) $1 break; with rewrite /xyz/(.*) $1 break;

The first step will make the redirection break, so the request path of the website must be /xyz/ with the trailing slash. Requesting /xyz will be responded with 404.
The second step will also cause Nginx to fail.

So, I guess yeah, I'm glad that there is a more flexible solution.

Thus, if the slash you meant is the leading slash, the answer is yes. If the slash it the trailing slash, the answer is no. There must not be a trailing slash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
2 participants