GCP Load Balancer - Host and path rules not working - google-cloud-platform

I have a VM that has 3 applications hosted on it. All the apps are working fine with the VM's public IP and port (e.g. 34.44.55.66:{port})
React JS website 1 (port 3001)
React JS website 2 (port 3002)
Express JS API 1 (port 3003)
I now want to have all these behind a Cloud Load Balancer. I've done the following for it.
Created three backend services (one for each application)
Created Host and Path rules as below
The load balancer is created without any issues. However, only the default path works fine. Refer to the details below (consider the LB IP as 55.66.77.88).
55.66.77.88: Website-1 opens without any issue (default path)
55.66.77.88/website-1: Website-1 shows error messages in the browser console
55.66.77.88/website-2: Website-2 shows error messages in the browser console
55.66.77.88/api-1: API-1 shows an error message in the browser console
GET http://55.66.77.88/api-1 404 (Not Found)
Whenever I map any of the above backend services with the default path, they work fine. However, they do not work as expected when the path is entered in the browser.
Any advice will be appreciated.

Keep in mind that, in your configuration, there isn't URL rewrite action. That means your request
55.66.77.88/website-1/index.html
will reach the backend on this path
# Backend bucket example
gs://my-bucket/website-1/index.html
# Instance group backend
<backend>/website-1/index.html
# Network Endpoint Group backend
<NEG>/website-1/index.html
The base path provided to the load balancer is forwarded. When you haven't additional path in the forward, it works (case of the root path 55.66.77.88/)
You can override the behavior in the advanced mode, and you can define URL rewrite for each of your rules.
You can define rewrite rule like this in the console
Click on advanced configuration
Set up your default configuration (any domain, any path)
Then click on add host and path rule
Put * in the host as you did
Then click on the pencil of the path rule section to define the rule by default. Here again, select your backend by default. no special rewrite, it's the default path.
Now click on add path rule.
Add your matching paths. And only / in the rewrite URL part (you can rewrite your host if the backend rely on the host name, but it doesn't seem your case)
Do this for all your backend and test it (let 3 - 5 minutes to propagate your update to the edge node)

Related

Redirect to url from load balancer without CORS error

I was wondering if any of you know how to achieve that a GCP load balancer redirect to an url with "CORS enabled". What do I mean by that?, well I have the following scenario:
One load balancer that has to redirect to other load balancers depending on the path of the URL (LB A)
"Simple" load balancer that has many backends attached (LB B, LB C, etc)
So my flow is as follow:
LB A (/pathB) -- redirect -> LB B
LB A (/pathC) -- redirect -> LB C
This works as expected if requested by a simple HTTP Request (like cURL or Postman) but fails if its requested on a website. Why?, because the preflight OPTIONS request is redirected and that brings a CORS error Redirect is not allowed for a preflight request, and even if the OPTIONS request is skipped, a simple GET request will also have a redirected response without the CORS headers (which will fail).
Is this possible?, if so how can I achieve it?, I tried to add a cors policy on LB A but a LB can't have a routeAction with a urlRedirect.
Practically I just want to inject the CORS headers on the 301 Response to avoid the error.
After a long time searching for a solution I finally got to a "working" conclusion.
If you want that a google's load balancer inject some headers (specially cors headers) on a request thats redirected to another domain, then you are out of luck (also mentioned here). Even with the new LB version it seems that is not possible (at the moment, am sure this feature will release in some time). Maybe there is a way of doing it, but neither the docs nor the api seems to tell you how.
Then you just "can't" do this?. Well, no, the classic load balancer has something call an Internet NEG which is like having "external backends" you can point to, so I just create various NEGs to meet my needs and attach them in the LB as backends. So I accomplish my example as follow:
If LB B has the domain lb-b.com and LB C has lb-c.com
Create 2 Global NEGs (Internet NEGs) with the full domain name as lb-b.com and lb-c.com respectibly
Then create 2 backend services on LB A with each one associated with each NEG.
Finally select Advanced host and path rule and create one Path rule for each LB, for example for LB B:
Create a path rule of /pathB/*
Select the option Route traffic to a single backend
Use path prefix as / (if you want to "remove" the pathB prefix on the forward)
Select the backend service you previously create corresponding to lb-b.com
Sharing this information with documentation and guidance as a workaround for handling and enabling CORS.
Another thing that I can think of for this scenario is by using cloud function for redirects and CORS headers. You can use this link as a guidance for this scenario. Let me also share another link where you can see different code sample.
To use a reverse proxy in front of the load balancer that can handle the CORS header and the redirecting request we can use Apache or Nginx. For this scenario we can follow this link as a guidance.

GCP: load balancer rewrite path

I'm setting up traffic management for a global external HTTP(S) load balancers. I have two backend Cloud Run services, serverless-lb-www-service and serverless-lb-api-service, that I want to serve from the same IP/domain.
I want to configure them like this:
example.com -> serverless-lb-www-service
example.com/api -> serverless-lb-api-service
I can use the simple routing rules to serve traffic semi-expected:
path
backend
/*
serverless-lb-www-service
/api
serverless-lb-api-service
/api/*
serverless-lb-api-service
However, I'm running into an issue where I try to access an endpoint that is not the root API end, like example.com/api/test. I'm always seeing the response I would expect from example.com/api.
I believe it has something to do with my API (running express.js) receiving the path /api when it is instead expecting to serve that route from there just /test. I think I might need to set up a rewrite to remove /api when it hits the API
Any help would be much appreciated. Thanks
update
I can confirm that the requests as logged in the API are all prefixed with /api. I can solve my issue by changing all API route handlers to expect the /api prefix in production environment. However I would still rather do this via a path rewrite so application code is the same in all environments
You can customize the host and path rules. You can follow the steps through this link. It is also using Cloud Run services and might help you with the rewrite path issues.
Note: Just scroll all the way down if the link will not redirect and show the "Customize the host and path rules" steps.

GCP Load Balancer redirect while keeping query parameters

In my GCP project am a doing a Host and path rules redirect on one of my load balancers. I am trying to get the redirect to pass the query parameters, but it is not.
Essentially trying to do:
subdomain.domain.com?foo=bar -> www.domain.com/path?foo=bar.
The redirect works to the path, but it does not keep the query params. From what I can see here, it should work.
https://cloud.google.com/load-balancing/docs/https/traffic-management#redirects
Redirect to a different URL formed by modifying the host, path, or both the host and path portion of the URL, and either stripping out or retaining any query parameters.
In Google Cloud, the stripQuery field can also be used with a Load Balancer, specifically the GCP HTTP(S) Load Balancer. This feature allows you to configure whether the query string present in the incoming request's URL will be included or removed when the request is forwarded to a backend service.
When stripQuery is set to false, the query string will be included in
the path when forwarding traffic to the backend service.
i.e: if a request is made to "example.com/path?key=value", and stripQuery is set to false, the request will be forwarded to the backend service as if it were made to "example.com/path?key=value".
By disabling the stripQuery feature in Google Cloud Load balancer we can forward the query params to the new host we have redirected to.
Here is a configuration YAML we can use to redirect the site to another site preserving the query parameters.
defaultService: projects/example/global/backendServices/example-test
name: example-matcher1
routeRules:
- urlRedirect:
stripQuery: false
hostRedirect: ie.example.com
redirectResponseCode: MOVED_PERMANENTLY_DEFAULT
If you are using DefaultRedirect in Advanced host and path rule:
You should uncheck the Strip query in Google Cloud Load Balancer Edit Page for Advanced Route Rules Routing Rules .
Reference:
enter image description here

Google cloud, how to rewrite load balancer host & path for bucket service so I don't have to nest my files under, example: /files/public?

I know there are a few threads on this issue out there but all of them have answers from 2019 where other behaviours and features were available, for example, at the time you couldn't even add a bucket as a backend service on a load balancer.
I'm trying to serve files from bucket A from mydomain.com/storage/public and bucket B from mydomain.com/storage/private which isn't an issue.
What I haven't successfully done is to rewrite the path so that I don't have to add all my files in bucket A nested in the folder /storage/public and for bucket B in /storage/private -- but rather just serve them from the root of the bucket.
I have added the following path & host rewrite rule that doesn't work:
host:
path: /*
I'm assuming this tells it to rewrite mydomain.com/storage/public/myfile.png to mydomain.com/myfile.png, but again this doesn't seem to work.
As I understand that you might have one file eg xyz, .png in public folder so your URL looks like
mydomain.com/storage/public/xyz.png
And would like to serve the file(s) from the root folder ie., mydomain.com/storage/xyz.png. You have also attempted to rewrite the paths and were not able to do so. Let me know if I captured your information correctly.
I would recommend you to modify your configuration with below steps:
Click edit on your Load balancer
Change the host and path rules :
In the left column of the screen, click Host and path rules.
Select Advanced host and path rule (URL redirect, URL rewrite).
Click the row that contains the non-default path rule,
Click the pencil icon edit for the /storage/* Route traffic to a single backend:backend name
Under Paths, delete /storage/* and add /*.
Under Action, select Route traffic to a single backend.
Click Add-on action (URL rewrite).
Leave Host rewrite blank.
Under Path prefix rewrite, enter /storage/.
Under Backend, select backend name and Click Save and Click Done.
If everything looks correct, click Update to update your HTTP load balancer.
Refer the documentation for more information.

DNS hosting public and web application on different hosts

Here is my setup.
Public site hosted by squarespace.com (www.example-domain.com)
Web application (AWS EC2/ELB), i would like to be available via the same domain. (my.example-domain.com)
Custom profile pages available as www.example-domain.com/username
My question is how can i setup the DNS to achieve this? If can't do it just through DNS, any suggestions? The problem i am facing is that if squarespace.com is handling the www.example-domain.com traffic how can i have it only partially handle it for certain urls. Maybe i am going about this in the wrong was all together though.
The two first are ok. As you mention, (1) is not compatible with (3) for a pure DNS config as www of example-domain.com has to be configured to a single end-point.
Some ideas of non-DNS workaround:
Having the squarespace.com domain on sqsp.example-domain.com and configure your www domain to a custom web server on which you configure the root (/) to redirect (HTTP 300) to sqsp.example-domain.com. It will be quite transparent for the user, except in his browser address.
The same but setting on / a full page HTML iframe containing sqsp.example-domain.com.
The iframe approach is a "less clean", Google the solutions to build your opinion.
EDIT:
As #mike-ryan mentioned, there is the proxy solution as well where you configure you web server to request another server to get the content to return to your user. If you are already using AWS, a smart way to do this is to use CloudFront: you can setup CloudFront to proxy one server on one URL and proxy another server on other URL. Actually, this is maybe the faster to way to implement you need. Of course, a proxy is one more "hop", so it may add more delay.
If you really want to have content served from different servers while only using a single domain name, you'll need to set up a proxy server to handle the request routing for you. I am assuming your custom profile pages must be served from your EC2 instance.
Nginx will receive all requests, and will then decide whether they should be sent to Square Space or your web app. Requests will be reverse proxied to Square Space or to your app, depending on the URL.
This is similar to #smad's answer, except it will all be invisible to the users which IMHO is better than redirecting the user to a new domain name.
Example steps:
Set up an Nginx server, create two virtual hosts - one for my.example.com, and one for www.example.com
Create two upstreams in your Nginx config - one for Square Space, and one for your app
Configure the www.example.com virtual host to reverse proxy connections to the Square Space upstream, if the URL is "/". Otherwise, traffic should be proxied to your app upstream [0]
Configure the my.example.com virtual host to proxy all traffic to your app upstream
[0] how to reverse proxy via nginx a specific url?