Standalone Web Applications running behind a reverse proxy

I wanted to know if there was anyone else out there who is struggling with deploying a standalone web application behind a reverse proxy.

It seems that the URLs generated by Xojo are not relative URLs. This seems to be causing a problem:

<https://xojo.com/issue/15367>

Here’s a breakdown of the issue:

For example, lets say I have a stand-alone app running on port 5000, the urls would be something like this:

http://example.com:5000

Now, I would rather the users access the app using something like this:

http://example.com/myapp/

I can use the Apache ProxyPass and ProxyPassReverse to appropriately proxy this request; but since the URLs are coming back like this:

/framework/framework.js

… this presents a problem. Since the URLs in the HTML begin with a slash, they are interpreted to mean this:

http://example.com/framework/framework.js

However, if they were relative URLs (without the preceding slash), then they would be properly interpreted as:

http://example.com/myapp/framework/framework.js

And thus the Apache configuration for proxy would properly forward the request to the application. I verified this by manually entering the URL and was able to access the server via the Apache proxy.

Does anyone else need this to work and either has found a work-around or would like to help prioritize the feedback case?

I’d hunt in the Web target & find everything about “reverse proxy”
@John Joyce has posted a pile and you might try reading his activity to see what else he’s posted
He did a session at XDC about how he uses this with load balancers etc

However I think a lot are using nginx and / or haproxy for this
https://forum.xojo.com/39400-reverse-proxy-server

https://forum.xojo.com/conversations/all?search=apache+reverse+proxy

If deploying to a root of a domain or subdomain, this likely would work fine. The issue is when attempting to deploy to a non-root URL path. Since Xojo Web apps use URLs that start with a slash (/) the browser correctly interprets this to mean that the resource is located at the root of the domain. The simple change Xojo needs is to return relative URLs so that the browser constructs the resource URL.

@Greg O’Lone recommended that this become its own feature request rather than the case I mentioned before, so here’s the new case:

<https://xojo.com/issue/48445>

Using something like mod_proxy_html, it may be possible to work-around this issue, however it seems like this would be poor performance and may have some additional side-effects. I’m looking into it, but haven’t been able to get it working yet.

Your reverse proxy is rewriting the request URL in order to proxy it to http://example.com:5000. You have to rewrite the response as well because Xojo has no idea its running at http://example.com/myapp/.

To your point about performance you are already proxying the request to Xojo so rewriting the response is not much additional effort on the part of the CPU.

@Phillip Zedalis do you happen to have any performance stats regarding the difference in a situation like this? I’m okay with doing this as a work-around, but it seems like it would be better to not have any processing.

Web technologies are not my area of expertise; so perhaps someone with more experience or knowledge can tell me whether my assumption that Xojo should be returning relative paths is correct or not. In the limited HTML development I’ve done, I’ve always used relative URLs for things like style sheets, images, etc. as it allows me to use my site regardless of where I host it. For example, I would be able to have something like:

http://staging.mysite.com

and

http://www.mysite.com

or

http://dev.mysite.com/testing/

This way, I can host a version of my site for testing and final review before pushing to production, and my HTML (because it uses relative URLs for all the resources), I am able to host it in any of these locations without issue.

That’s the basis for my assumption here.

Well the biggest performance penalty of any connection is actually establishing it. Remember your reverse proxy already has to send the data to the backend Xojo app, get its response and then send that response back to the original client. Doing a rewrite in the response is straight forward while it has the response readily available. I don’t have an off hand performance metric but that operation is likely to be quicker than any possible processing you are doing on the Xojo side of things to create the response in the first place. IE: I wouldn’t sweat it.

Remember a Xojo web app is not a drop-in application for conventional web servers. It IS a web server so you have to treat it like you would when you are proxying to any background web server.

Can you expand a bit on the point you made about “so you have to treat it like you would when you are proxying to any background web server”? What is that normal process?

Any documents or tutorials you can point me to? In my case, I’m running a VPS at a cloud provider. I already have a site set up, email, database, etc. Its running cPanel/WHM on CentOS 6.x. The process of installing the app and getting it up and running was not terrible, but I am just wanting to pretty-up the URLs a bit and avoid extra processing. I may try the subdomain route, but I really didn’t want to do that because I imagine that will cause me to incur a different certificate for SSL. Also, I really wanted the URLs to appear just like the rest of my site URLs.

So, if my site is:

http://mysite.com

I wanted the app to sit at:

http://mysite.com/myapp

This way, my normal pages, such as:

http://mysite.com/somepage.html

Would still work.

(of course, that isn’t really my site, it is just an example URL)

Then, all my links would look the same, even if they’re actually routing to a Xojo-based app. I’m sure you get the idea.

How would someone set that up to work?

To clarify, the app is technically not writing the urls as root urls. They are written as:

App.url + "/framework/framework.js"

The problem being that the app thinks its running at the root, and so App.url is an empty string.

Thanks for the clarification. It seems like if it were written like this:

App.url + “framework/framework.js”

…and by default, App.url was either “” (empty string) or “/” then it would be relatively simple for me to get the functionality I am wanting by ensuring that App.url was empty string.

Correct me if I’m wrong, but if it was written like I suggest above, where App.url was empty string, and perhaps the documentation said that it was important to use a trailing slash if specifying an App.url, then it would have solved my issue.

From what I can tell, WebApplication.URL is read-only, so three isn’t a way I can set it. Also, it says “For standalone web applications this always returns the empty string.” So it doesn’t look like trying to set that would be possible. I’m not sure how that can help me yet. I don’t see a way to set this was a command-line parameter either.

So, given the state of things, I don’t see how I could achieve the deployment that I would like to have, with exception to possibly performing the mod_proxy_html on each request. That will be my next attempt.

If there are any other ideas, or if this can be updated in a future build, that would be great. In the meantime, I’m a bit stuck.

This would be a silent breaking change for any existing user projects that use App.URL, so its behavior will not be changed.

There is another possibility though. You could serve your HTML files through the app by interrupting the incoming request in app.HandleUrl.

I personally would just recommend setting up the standalone at http://myapp.mysite.com

Ryan,

I think I side with @Phillip Zedalis on this one. You are going through a lot in order just to keep a specific URL structure.

That said, you might be able to get where you want by using mod_rewrite along with mod_proxy_html. You could potentially set up your app on a subdomain as suggested, then use mod_rewrite to change references from the subdirectory to the subdomain. You may run into complications, I have never actually tried this, but seems doable :wink:

Since I can’t write a post without referencing HAproxy, you could also set that up as your front end and use its routing and rewriting rules to pass requests along to either apache or xojo, as you see fit.

Either way you are looking forward to some tinkering.

@Greg O’Lone yep, I would never encourage a silent breaking change, as I wouldn’t appreciate that myself if the situation were reversed. It would be better to find a way to introduce the feature I want, without breaking other users.

So, for example, there could be an option such as “Use relative URLs for Standalone” which would be “off by default” and therefore not break any existing user. But a user like myself could simply turn that new flag on. Then, in the methods inside Xojo where the URLs are constructed, it would just be a simple branch, checking that flag and either constructing the URL with or without the leading slash.

To my mind, this seems relatively simple and harmless, and would allow for Xojo web apps to be easily placed behind a proxy without imposing additional processing or URL conventions.

If I’m building an app for my own product/service, or doing work for a client, I dislike the idea of needing to tell them how their URLs need to be structure simply because I choose a tool that either imposes unnecessary URL implications, or requires some of the CPU to be used up in post-processing.

There are several reasons why mod_proxy_html is not an ideal solution:

  1. Unnecessary CPU and memory overhead
  2. Time delays
  3. “weak link” that could go wrong

The more configuration points there are, the more fragile the deployment is, so eliminating any weak links in the process is a great idea. The less work-arounds that are added, the less error-prone the solution.

@Phillip Zedalis, I may have to go through the subdomain route if I want to avoid the processing overhead of mod_proxy_html. There are several reasons why the subdomain approach is not ideal:

  1. Imposes URL requirements for deployment that may be undesirable
  2. Requires additional security certificate for new domain
  3. Requires new subdomain for each app deployment

@John Joyce, yes, I suppose I am making an effort to be able to ensure that I can deliver the solutions that I am desiring. Whether I’m doing work for myself or for a client, I like to be able to do what they ask and what I think the customer will want. When the technology we use imposes upon our ability to deliver the desired solution, I take the time to try to deliver the best I can. In this case, I think there are some deployment restrictions which impose upon “business requirements.” For example, I do not want to tell a client that I can’t do what they want just because of a technology selection that I have recommended. Especially when the solution to fix it is as simple as removing a leading slash character from system-generated URLs so that the typical proxy configuration can cleanly pass-through the requests to the standalone server.

If there is a desire to have three apps on a server, which I would like to deliver like this:

https://domain.com/app1
https://domain.com/app2
https://domain.com/app3

Because of this leading slash, I would need to now “force” a deployment that either imposes additional processing on all requests (i.e. mod_proxy_html) or requires URLs to look more like this:

https://app1.domain.com
https://app2.domain.com
https://app3.domain.com

Whenever possible, I do not like to have to make “business requirement” decisions because of technology selection, or have “business requirements” unnecessarily changed because of technology selection. There is one exception to this, and that is when the “business requirement” was unreasonable and existing technology available does not operate this way. However, in this case, this is an “unreasonable” imposition by the technology because the alternatives do not impose this.

For example, if a client said to me, “can we reverse the URL so that the domain is the last element?” I would have to reply, “No, I’m sorry that is not how URLs work.” In that case, all browsers require that the domain/host is the first element after the scheme (if no user is specified, etc.); that is not something I can change; so the request to put the domain at the end of the URL is not reasonable from a business requirement. But a business requirement that says that the URL should use the standard organization URL appended with the app name (as in the first set of examples) is a perfectly reasonable business requirement which now has to change because of a single slash character; or I have to let them know that there will need to be additional processing (which costs money and time, and adds a fragile link to the app deployment) because of a technology selection that I recommended. I have been in plenty of meetings where these kinds of discussions take place, and then someone says, “well maybe we shouldn’t choose technology XX in the first place.” I do not like Xojo to receive that kind of response from potential clients or projects.

1 Like

Famous last words…

But people already put web apps behind reverse proxies with great success. In fact, over the years we’ve added specific support for some of the headers necessary to do this.

Have you thought about showing your web apps within an iframe on an HTML page instead?

@Greg O’Lone I am not interested in an argument. I wanted to accomplish something, it isn’t possible in the current version of Xojo, so I’ve filled out a feature request. I would be delighted if it could be implemented; and I know that the Xojo developers would be able to figure out a way to do it without breaking everyone else. In the meanwhile, I’ll look for a workaround.

Has it been solved?

[quote=337583:@Ryan Dary]
https://app1.domain.com
https://app2.domain.com
https://app3.domain.com [/quote]

I ran into the same issue with several apps sitting behind a NetScaler and ended up doing what you said and changing the sub-domain for each app rather than trying to rewrite the response and it worked out nicely. I have a wildcard cert which covers all of the app(x).domain.com transactions.

In my mind, this makes more sense than doing https://domain.com/app(x) for a couple of reasons. First. it means you never have to worry about having to rewrite the path to fix redirects and second I’ve always felt that the path should specify “related” pages of a single app or site such as “domain.com/home, domain.com/documents, domain.com/images. etc.” whereas the subdomain breaks out the applications themselves. Of course, this is a preference but it really does flow better than having a separate path for each app.