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

web.context-root is needed if the URL can not be rewritten. #88

Open
chi-bd opened this issue Feb 21, 2021 · 13 comments
Open

web.context-root is needed if the URL can not be rewritten. #88

chi-bd opened this issue Feb 21, 2021 · 13 comments
Labels
area/ui Related to the user interface

Comments

@chi-bd
Copy link

chi-bd commented Feb 21, 2021

At a1679dd, web.context-root is deleted.
But this option is needed in the environment which the URL can not be rewritten, for example Amazon ALB ingress controller.
Would you please revive it?

@TwiN
Copy link
Owner

TwiN commented Feb 21, 2021

As mentioned in v2.0.0's release notes:

Removed web.context-root (Vue.js' router doesn't easily support context roots. May be re-implemented in the future if enough people ask for it)

The main reason for removing it is due to my inability to make a dynamic context root work with Vue.js' router (without ugly hacks) despite several attempts.

If you want to have a go at it, feel free, but unless a few more people request this, I won't personally try to re-implement it.

That being said, for your specific issue, most people create a separate CNAME (e.g. status.example.com) for their status page.
Is there something preventing you from doing this?

@KarlMW
Copy link

KarlMW commented Mar 1, 2021

What about this? https://stackoverflow.com/questions/43879418/deploy-vuejs-app-in-a-subdirectory
It seems that it can be done with an edit of web/app/vue.config.js like this:

module.exports = {
  ...
  publicPath: "./"
  ...
};

(bear in mind that I know nothing of what I write - I just googled the problem - hopefully not wasting your time here)

In terms of the usefulness of being able to host content in a sub-directory - it's one of the first things I look for in a service I want to privately self-host (ie. purely for my own use). Being in a subdirectory means that its existence is not visible, whereas the existence of subdomains is publicly displayed in DNS.

@KarlMW
Copy link

KarlMW commented Mar 1, 2021

I hope that's not one of the "ugly" hacks you refer to :-)

@TwiN
Copy link
Owner

TwiN commented Mar 1, 2021

@KarlMW Hahaha no, if it was just that, it couldn't even be called a hack.

In fact, this would work fine if we weren't using Vue's router for the service detail page.

Long story short, one of publicPath's limitations is that a relative path cannot be used in conjunction with history.pushState, which is unfortunately used by Vue.js' router. I could fix this by using hash history (e.g. http://localhost:8080/#/services/core_twinnation-sitemap), but I just can't bring myself to like that style of routing.

reference:

Limitations of relative publicPath

Relative publicPath has some limitations and should be avoided when:

  • You are using HTML5 history.pushState routing;
  • You are using the pages option to build a multi-paged app.

I tried several different methods, but none worked in a clean way.

I didn't want to specify what I meant by "ugly" hacks, because they're really ugly, but the one way I found that works would be to read the generated static script (https://github.com/TwinProduction/gatus/blob/master/web/static/js/app.js) on application start, replace the value of a constant by the defined context root and overwrite the default script with the new script that has the appropriate context root. Coupling that with the base parameter of VueRouter (https://router.vuejs.org/api/#base) would be sufficient, but well, it's hacky.


By the way, it is not possible to do a reverse lookup to retrieve the CNAMEs of a domain (unless you have access to the zone files).

For instance, if I create the CNAME potato.twinnation.org, it's basically impossible for anybody to know unless I tell them, or unless they bruteforce every single strings and find it (or they just happen to try it - but don't bother, I don't have that cname 🤣).

This is known as denial of existence.

Even if a malicious user had access to the zone files, you could still hide it from them by using a wildcard CNAME domain record, and by pointing that to a reverse proxy which would have the necessary configuration telling it to route requests with a given host to the appropriate application, you'd be the only person privy to the existence of that application.

That being said, this is still security by obscurity, which is IMO not enough if you don't want prying eyes to have access to your application, which is why you can also configure basic authentication on top of that: https://github.com/TwinProduction/gatus#basic-authentication

@KarlMW
Copy link

KarlMW commented Mar 2, 2021

Thanks for the detailed reply. You've made gatus very easy for people to build in docker themselves - thanks for that, too :-)
I tried setting publicPath: '/gatus/' in web/app/vue.config.js and then rebuilt it, hoping that a static root would work. Sadly it failed - it was still looking for its assets under /

w.r.t. CNAME reverse lookups, I'm not sure how it's done, but my never-used-publicly CNAMEs are findable on the web, eg. via https://www.nmmapper.com/sys/tools/subdomainfinder/

Whether it's some sort of active probing, or whether they just monitor certificate transparency logs, I don't know. I generally use client certificates (handled by traefik) for my private domains (as well as passwords), so I'm reasonably confident that no-one can get in, but I like a bit of obscurity as well :-)

@MiddleMan5
Copy link

MiddleMan5 commented Jun 7, 2022

A lot of our deployments use path routing to separate out environments, so we really do need this feature.
Allowing us to configure the full external path would also be acceptable. You may still need to modify a constant on the client side (our backends usually write the configured value to <base href=PATH /> which our frontend's read into a variable in our path building utils on load)

IE:
external-root: https://health.my-domain.com/region-1/

All relative links accessed by the client would be replaced by the full external root path, although I'm not sure how this plays with pushState.

Edit:

Another thing I noticed is that the html resource uris are all full path, these might be better specified as relative imports unless the html renderer is doing something fancy with them. Ideally we don't have to do path rewriting and the app just supports being mounted on a subdirectory
image

Obviously changing uris from ie /js/app.js to js/app,js has other implications, but it's an option that allows the browser to request resources relative to the current path

@TwiN
Copy link
Owner

TwiN commented Jul 19, 2022

@MiddleMan5 If you or anybody else can get it to work with the front-end, feel free to do so. I'm completely fine with using a different approach for routing -- if pushState has to go, then so be it.

I do want to rewrite a good part of the UI at some point and make it a little less minimalist, but I don't know when that will happen.

@michaelkrieger
Copy link

w.r.t. CNAME reverse lookups, I'm not sure how it's done, but my never-used-publicly CNAMEs are findable on the web, eg. via https://www.nmmapper.com/sys/tools/subdomainfinder/

They get this data from SSL Transparency. Looking at it from a number of domains I control, it includes only those that exist in SSL Transparency records (even a typo that existed for 1 minute) that show up there. Unless you have an misconfigured (or old pre RFC8482 server that still answers ANY queries, this is the only place to get the values.

I'm sure the big names (8.8.8.8 and 1.1.1.1 or major ISPs) could probably assemble it from DNS query logging though. It should be assumed that it's out there (and hence have basic auth or something like authelia in front of it). I agree that subdomains are a better place for a lot of services, but this same problem exists with many VUE apps.

@ansilh
Copy link
Contributor

ansilh commented Jun 15, 2023

Got stuck in this issue when I configured Gatus behind a Google's LB backed by IAP authentication.
we use a common FQDN and uses route based redicretion via URL map rewrite, but the Gatus web app always respond with default root ("/") instead of the called base URL ("https://common.ingress.dom/<custom_dir>/")
Now the only option for left is to create an Ingress rule to route the traffic via a new DNS entry and I've to duplicate the GCP ingress configuration only for Gatus :(

Would be great if we can call this out in the README to avoid surprise at the end.

@TwiN
Copy link
Owner

TwiN commented Jun 20, 2023

@ansilh Could you make a PR for this?
A section in the FAQ should suffice

@akozlins
Copy link

after some tries, here is what worked for me:

  • rebuild gatus fronend (npm --prefix web/app run build) with following changes
# set publicPath in vue.config.js
ARG VUE_PUBLIC_PATH
RUN sed -i \
    -e "s|publicPath: .*|publicPath: '${VUE_PUBLIC_PATH}'|" \
    web/app/vue.config.js

# use relative path '.' for SERVER_URL in main.js
RUN sed -i \
    -e "s|export const SERVER_URL = .*|export const SERVER_URL = '.'|" \
    web/app/src/main.js

# use relative path '.' for resources in index.html
RUN sed -i \
    -e 's|="/|="./|g' \
    web/app/public/index.html
  • and reverse proxy (only relevant lines from docker-compose)
build: { dockerfile: "Dockerfile", args: [ "VUE_PUBLIC_PATH=/gatus", ] }
labels:
- "traefik.http.middlewares.gatus.stripprefix.prefixes=/gatus"
- "traefik.http.routers.gatus.middlewares=gatus"
- "traefik.http.routers.gatus.rule=PathPrefix(`/gatus/`)"

@rokiden
Copy link

rokiden commented Aug 28, 2023

I'm homelab enthusiast with free domain from DDNS provider, subdomain option unavailable for me. Subpath would be very useful, otherwise I can use Gatus only through SSH tunnel :( (but its very uncomfortable from mobile device)

@TwiN TwiN added the area/ui Related to the user interface label Nov 5, 2023
@lpil
Copy link

lpil commented Nov 5, 2023

I'm in the same situation as @rokiden here! Adding new domains to the infra in question is not possible.

If the paths for the CSS and JS and badges had the preceding / removed from the start of the paths then Gatus would work so long as folks navigated to homepage first. This is not ideal, but it takes Gatus from broken to usable for in this situation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/ui Related to the user interface
Projects
None yet
Development

No branches or pull requests

9 participants