Deploy SPA application on Google Cloud Storage using Load Balancer and CDN - reactjs

I'm investigating a way of deploying an Angular or React web application on Google Cloud using GCS, Load Balancer, and CDN.
I've set up the LB and the GCS using the urlRewrite, but since the LB does not allow full URL rewrite only pathPrefixRewrite, I cannot redirect all the requests to /index.html
I want to achieve the same functionality as firebase hosting where you can specify the rewrite rules
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
Another option will be to set the 404 page as index.html, but that will result in a 404 status code return by the server, which I don't like.
Is this possible with Load Balancer, because they are not supporting a full rewrite?

Google added rewrite engine in 2020 (see https://serverfault.com/questions/927143/how-to-manage-url-rewrites-with-a-gcp-load-balancer/1045214) and it is only capable pathPrefixRewrite (stripping fixed prefix).
For SPA you need variable suffix rewrite to index.html so you use Nginx or Firebase.
Or mentioned error handler in bucket's HTTP server (with a downside of HTTP code 404 for your virtual URLs):
gsutil web set -m index.html -e index.html gs://web-stage/
Full instructions to set SPA app is here: Google cloud load balancer create backend service for Firebase Hosting to serve microservices & frontend SPA from the same domain via load balancer?
Discussion of LB rewrite engine limitations:
How can I implement a .htaccess configuration in Firebase Hosting?
Google Cloud Load balancer URL Rewrite not working
https://www.reddit.com/r/googlecloud/comments/8zgg20/static_website_url_rewrite/

Related

Serverless Offline <> React - Local Dev Page Load

I have a serverless application that is using the serverless-offline plugin and create-react-app to load a front-end client, but I'm not sure how I can configure my serverless app to load the index.html page and also the proper link format that I can use within my react app to call the serverless-offline generated routes.
I know that serverless applications typically use a static website hosted on S3 and AWS serverless endpoints within the static links to trigger the handlers, but I'm not sure how I can replicate this in the local environment. Can anyone point me in the right direction?
This is my code structure at the moment:
- frontend (create-react-app)
-- create-react-files
- backend
-- controllers
--- login.js
I then have a proxy set up in my create-react-app config file set to serverless-offline port I configured in my serverless.yml file

$http.get returns index.html using Ionic v1 and Firebase hosting

We currently have a Ionic v1 project that calls an API implemented as a Google App Engine application. This Ionic app runs with Ionic serve, PhoneGap, and when deployed to Android/iOS.
We are now trying to deploy to the web using Firebase hosting.
The initial HTML/JS code all runs correctly until we reach an $http.get call to the Google App Engine. What happens then is that the request reaches the GAE server and is processed correctly there with a response being sent back. But in the client code, the response.data property is the contents of the Firebase application’s index.html rather than the response that was supplied from GAE.
We don’t know why this is happening, or how to fix it, but here are some relevant facts:
When we run the app on a device using PhoneGap or via the Google Playstore, the URL by which we access GAE is the same URL if we were accessing GAE from a browser. But, when we run the app via “ionic serve” we must use a proxy to work around a CORS issue. What we do is to specify a simplified URL in the Ionic code, and then provide a mapping of that simplified URL to the GAE’s actual URL in a file called “ionic.project” which looks something like this:
{
"name": "proxy-example",
"app_id": "",
"proxies": [
{
"path": "/api",
"proxyUrl": "http://cors.api.com/api"
}
]
}
When we attempt to deploy the app via either “firebase deploy” or “firebase serve” we must use the proxy version of the URL in our $http.get call. Otherwise the call does not reach the GAE server at all. It is not clear how Firebase knows to use “ionic.project” for the proxy mapping.
We are not using “Angularfire”, only the standard AngularJS library that is packaged with Ionic 1.x
Thanks for any help you can offer.

How to make a ReactJS app active/visible on AWS

I developed a reactJS project (front-end) on AWS which has it RESTFUL API coming from heroku. They are completly separated i.e the frontend and backend.
I have successfully uploaded my files to S3, and have activated my CloudFront Distributions, but I can't really figure out what is wrong because I can't see my react app when I hit the URL generated from the Domain name.
I have checked this SO answer, but it doesn't help.
Please any help will be greatly appreciated.
Firstly, it is perfectly fine to deploy them on different servers/cloud. Can you give the URL ? I feel it is not issue of different clouds but configuration issue. Can you first put a simple html file on same S3 bucket and see if you can access that via your domain name.
Suppose you have your react app example.com hosted in bucket named ant. So, go ahead and put additional test.html in bucket ant. Then try example.com/test.html .. This will make sure your domain setting etc. are proper
I have experienced similar issues trying to run a react.js app through cloudront, here are a few things you should check:
Make sure that your s3 hosting bucket has public read access, or that you have set up your cloudfront origin access policy with the s3 bucket by first creating an origin access identity in cloudfront, then associating the identity with your s3 bucket through the access policy:
{
"Version": "2012-10-17",
"Id": "MyPolicy",
"Statement": [
{
"Sid": "1",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity YOUR_CLOUDFRONT_ORIGIN_ACCESS_ID"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::YOUR_S3_BUCKET/*"
}
]
}
Make sure your s3 bucket has a cors policy allowing requests from any domain similar to:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>Content-Length</AllowedHeader>
</CORSRule>
</CORSConfiguration>
If your package.json file in the react.js app has a homepage, you should remove it as this the application expects to be hosted from that url and not the cloudfront domain. Example package.json with homepage:
{
"name": "your-package-name",
"version": "1.0.0",
"description": "",
"author": "",
"homepage": "https://somepage.com/home",
"repository": {},
"dependencies": {}
}
Make sure that your root object in the cloudfront distribution is index.html
Make sure that after you run "npm run build" in the react app, you are only syncing your build folder with the s3 bucket.
Make sure that if you use the aws cli to move your build files to the s3 bucket, you use the command "aws s3 sync build/ s3://YOUR_DEPLOY_BUCKET/ --acl public-read --delete", this ensures that only the most recent build files are uploaded to s3, and that any old files are deleted.
After pushing files to s3, it is a good idea to run a cloudfront invalidation to ensure that your old files are removed from the cache and any new requests serve up the new files. you can run "aws cloudfront create-invalidation --distribution-id YOUR_CF_DISTRIBUTION_ID --paths '/*'" to accomplish this.
Because react.js uses the virtual dom, and the only html document actually served is the index.html document, you need to add custom error responses to your cloudfront distribution as cloudfront will expect to serve up web pages like about.html or contact.html depending on the route in your react app. I recommend adding custom error responses for http codes 400-404 and mapping the response to status code 200 with a redirect to the "/" route. This ensures that if cloudfront cant find a file such as about.html, it will stay on the index.html file (where your react app is) and react router will virtually route to your /about route. see below for example configuration:
have you tried making setting S3 bucket to “public”?
you can either set a policy for the entire bucket or to to make certain objects available publicly.
here’s an AWS manual
chances are, your react app needs something like that

Nginx call API to production server

I am working on Angular 1 based web application.
I've deployed a web app with nginx , but couldn't deploy production server in my local env.
So, I want call API from the production server. For example,
I am using RestAngular to call API.
Restangular.all('api/user/profile').post(mUser)
This calls
localhost:8080/api/user/profile
because I've deployed a web app in localhost:8080.
I want to redirect requests which starts with "/API" to the production server, by config nginx properly.
So, in this case, it should call API server
http://devprod2api/api/user/profile
Other requests that don't start with "API" should go to:
http://localhost:8080/...
Is it something possible by config nginx properly? If possible, how can I do that?
I am not sure what you have tried, but this just needs a simple proxy_pass as far as I see. Add below to your nginx config and it should point all API to the other server. It assumes that a host entry is present for devprod2api
location /api/ {
proxy_pass http://devprod2api/api/;
}

Redirect all AWS S3 http requests to index.html for AngularJS HTML5Mode

How do I redirect all requests to my static AWS S3 website to index.html so I can use AngularJS' HTML5 Mode?
I recently learned (to my unending delight) that it is possible to use AngularJS without the # in the URL by using HTML5 Mode. However, I know from this answer that this requires some setup on the server, since all requests have to be redirected to the right html file (in this case, index.html) for this to work.
I use AWS S3's static website hosting for my site. I tried adding this to my redirection rules:
<RoutingRules>
<RoutingRule>
<Redirect>
<ReplaceKeyWith>/</ReplaceKeyWith>
</Redirect>
</RoutingRule>
</RoutingRules>
and
<RoutingRules>
<RoutingRule>
<Redirect>
<ReplaceKeyWith>index.html</ReplaceKeyWith>
</Redirect>
</RoutingRule>
</RoutingRules>
but I get issues with too many redirects.
Is there a way to do the kind of redirection necessary in AWS S3 with the static website hosting?
You can use AWS CloudFront for your use case. Setup the S3 bucket behind CloudFront and add index.html as the default route.
Still if the page is refreshed in a angular route (e.g /home), AWS CloudFront will search for a /home.html file in S3 and return 404: Not Found Response. However there is a workaround for this, where you can setup an custom error response for 404: Not Found HTTP error code to points towards the /index.html response page path.
For more details refer the blog post Using AWS CloudFront to serve an SPA hosted on S3.

Resources