﻿{"id":392,"date":"2022-03-04T16:34:46","date_gmt":"2022-03-04T11:04:46","guid":{"rendered":"https:\/\/blogs.infosys.com\/digital-experience\/?p=392"},"modified":"2022-03-04T16:34:46","modified_gmt":"2022-03-04T11:04:46","slug":"hosting-static-single-page-web-application-on-aws-s3","status":"publish","type":"post","link":"https:\/\/blogs.infosys.com\/digital-experience\/web-ui-ux\/hosting-static-single-page-web-application-on-aws-s3.html","title":{"rendered":"Hosting Static\/Single Page Web Application on AWS S3"},"content":{"rendered":"<p>One of the key design decisions for any web application development\/deployment is \u2013 the selection of a web hosting option. A few of the key parameters impacting the decision are \u2013 cost, supported behaviors, scalability, availability, maintainability.<\/p>\n<p>AWS supports hosting static web applications in S3. This document discusses various aspects of hosting a static web application on S3.<\/p>\n<h3>Key Requirements<\/h3>\n<p>Any web application hosting options on AWS cloud must cater to the following key requirements<\/p>\n<ul>\n<li>Cost-optimized<\/li>\n<li>Easily manageable, maintainable, performant<\/li>\n<li>Scalable and high availability<\/li>\n<li>Support for HTTPS, custom domain<\/li>\n<\/ul>\n<h3>Web Application Types<\/h3>\n<p>Before we go into further details, Web applications could be categorized into the following two types \u2013<\/p>\n<ul>\n<li>Static web application &#8211; Web application that can be delivered to a browser without requiring any server-side processing to generate\/manipulate HTML\/CSS. This includes Single Page applications (example web application developed using UI frameworks such as Angular, ReactJs, VueJs)<\/li>\n<li>Web application requiring server-side processing\u00a0\u2013 web application which requires processing at a server (example ASP.NET, PHP, Java-based web application) to generate a page which will be then rendered on the user browser. This includes Single page applications requiring Server-side rendering<\/li>\n<\/ul>\n<h3>AWS S3 for Static Web Application Deployment<\/h3>\n<p>AWS S3 provides a feature to host static web applications. Though only S3 is sufficient to host any static web application. In real-life production scenarios, a few other AWS components need to be included to complete the setup. The below section provides further details.<\/p>\n<h3>Architecture Diagram<\/h3>\n<p>The following diagram provides the recommended architecture:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium\" src=\"https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/themes\/infosys-blog\/images\/Sample-Image.jpg\" width=\"936\" height=\"203\" \/><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #000080\"><strong>Simple Storage Service (S3)<\/strong><\/span><\/p>\n<p>S3 Bucket is used to host the static web application content. Key features of S3 include low latency, high throughput, and high durability. S3 auto-scales for storage needs.<\/p>\n<p>An important consideration to be made \u2013 is S3 hosted endpoints do not support HTTPS. To use HTTPS, S3 deployed web application needs to be served by Cloud Front (CDN).<\/p>\n<p><span style=\"color: #000080\"><strong>Cloud Front<\/strong><\/span><\/p>\n<p>The cloud front is the Content Delivery Network (CDN) service provided by AWS. Cloud front is required for the following \u2013<\/p>\n<ul>\n<li>Define custom domain for deployed web application<\/li>\n<li>Make web applications available over HTTPS<\/li>\n<li>Provide abstraction over S3 i.e., the S3 endpoint can be made private, enhancing security<\/li>\n<li>Add response headers (security\/CORS\/Custom etc.) using Response Header policy<\/li>\n<li>Handle HTTP Error codes to redirect to a specific location. For example, in the case of a single-page application, when the user tries to access an application-specific URL (ex. <a href=\"https:\/\/example.com\/SPA\/route\/will\/fail\">https:\/\/example.com\/SPA\/route\/will\/fail<\/a>). By default, the request fails as no file exists in the S3 bucket matching the supplied path. To handle such a scenario cloud front could be configured to redirect the flow to the SPA entry point i.e. index.html. Once SPA is loaded in the browser it SPA framework takes over and handles application behavior based on browser URL<\/li>\n<\/ul>\n<p><span style=\"color: #000080\"><strong>Lamba<\/strong><\/span><\/p>\n<p>Lambda @ edge could be used to perform various tasks such as \u2013<\/p>\n<ul>\n<li>Response header manipulation<\/li>\n<li>S3 with multiple subdirectories. Conditional redirection to subdirectories<\/li>\n<\/ul>\n<p><span style=\"color: #000080\"><strong>Route 53<\/strong><\/span><\/p>\n<p>The CloudFront URL is not very user friendly. Using Route 53 custom domain name can be mapped to CloudFront.<\/p>\n<h3>Cost Considerations<\/h3>\n<p>This section describes the cost associated with services mentioned in the above architecture diagram. It\u2019s a key driving factor to determine, the suitability of S3 static web hosting for the given scenario.<\/p>\n<p><span style=\"color: #000080\"><strong>Simple Storage Service (S3)<\/strong><\/span><\/p>\n<p>Though S3 pricing is determined by types of usage i.e. type of storage used, location of storage, number of requests, amount of stored data. When S3 is used for web hosting content is delivered via CloudFront, the cost will be based on the amount of data stored in the S3 bucket.<\/p>\n<p><span style=\"color: #000080\"><strong>Cloud Front<\/strong><\/span> &#8211; \u00a0The CloudFront pricing is driven by \u2013<\/p>\n<ul>\n<li>Amount of data transferred to end user<\/li>\n<li>Number of http(s) requests<\/li>\n<li>Cloud front location<\/li>\n<\/ul>\n<p>No cost involved \u2013<\/p>\n<ul>\n<li>Data fetch from origin (S3) to edge location<\/li>\n<li>Cloud front to Origin- Not applicable<\/li>\n<\/ul>\n<p><strong><span style=\"color: #000080\">Lambda@Edge<\/span><\/strong> &#8211; Lambda@Edge pricing is driven by<\/p>\n<ul>\n<li>Number of function invocations<\/li>\n<li>Required compute capacity<\/li>\n<li>Compute duration<\/li>\n<\/ul>\n<p><span style=\"color: #000080\"><strong>Route 53<\/strong><\/span> \u2013 Route 53 pricing is driven by \u2013 the number of domain names managed, the number of the hosted zone, and user queries.<\/p>\n<p>For static web hosting queries to the cloud, the front does not incur any cost. So the pricing is based on one registered domain and hosted zone.<\/p>\n<h3>Decision considerations to be made while opting for S3 based hosting &#8211;<\/h3>\n<p><span style=\"color: #000080\"><strong>Web Application Type<\/strong><\/span><\/p>\n<p>S3 is an object-based storage service and not a web server. It only supports hosting a static web application. An application requiring server-side processing can\u2019t be hosted in S3. For Single Page applications requiring server-side rendering, S3 hosting is not a feasible option.<\/p>\n<p><strong><span style=\"color: #000080\">Data Storage<\/span> <\/strong><\/p>\n<p>Data storage impacts the S3 cost. Application assets storage requirement needs to be analyzed carefully.<\/p>\n<p><strong><span style=\"color: #000080\">Number of\u00a0 \u00a0visitors<\/span><\/strong><\/p>\n<p>The number of visitors impacts the number of HTTP (s) requests and the amount of data transferred to end-users (cloud front cost factors).<\/p>\n<h3>Advantages of S3 based static web hosting<\/h3>\n<p><strong>Serverless<\/strong>\u00a0\u2013 Content is hosted in S3. This eliminates the need of purchasing a web server\/virtual machine, which needs to be kept up 24&#215;7 in the order for the web application to be available always<\/p>\n<p><strong>Availability<\/strong>\u00a0\u2013 High availability is driven by high availability used AWS services i.e., CloudFront, S3, Edge@Lambda<\/p>\n<p><strong>Auto Scale\u00a0<\/strong>\u2013 S3 auto scales as needed<\/p>\n<p><strong>CDN Advantages<\/strong>\u00a0\u2013 Contents are served via cloud front (AWS CDN Services), entailing all benefits associated with CDN<\/p>\n<p><strong>Cost\u00a0<\/strong>\u2013 Relatively cheaper compared to other hosting options (considerations to be made are described in the previous section). Also, S3 is charged based on what is being used this is cheaper compared to hosting the application on a dedicated server as we have to pay based on servers uptime (irrespective of server application being used or not)<\/p>\n<h3>Few common scenarios to consider \u2013<\/h3>\n<p><span style=\"color: #000080\"><strong>Scenario<\/strong><\/span> &#8211;<\/p>\n<p>While navigating a single page application (for example angular\/react-based application), though URL changes in the browser address bar, no corresponding HTML page exists on the server. UI frameworks such as Angular, ReactJs handle such behavior on the client-side (i.e., browser). If a single page application is hosted in S3, S3 returns 404 (page not found) if the user tries to access the inner URL (by typing the URL directly in the browser or reloads the page by refreshing the browser (F5)).<\/p>\n<p>One of the approaches, to handle the above scenario could be &#8211; to create a CloudFront distribution with your S3 bucket as the origin, index.html as the default root object. Also, configure the Error page to point to Index.html. This way S3 404 page will load the index.html. As soon as index.html loads the UI framework (ex. angular\/react), client-side routing will kick in, showing the correct view to the user.<\/p>\n<p><span style=\"color: #000080\"><strong>Scenario<\/strong><\/span> \u2013<\/p>\n<p>I have an angular-based application supporting multiple languages (ex. English &amp; Hindi). I have a different deployable for each of the languages. Let us assume, as per the current deployable strategy two deployable are deployed in the language subfolder inside the given S3 bucket i.e.<\/p>\n<p>MyS3Bucket (S3 bucket)<\/p>\n<p>|<\/p>\n<p>|&#8212;&#8212;&#8212;- English (subfolder)<\/p>\n<p>|<\/p>\n<p>|&#8212;&#8212;&#8212;- Hindi (subfolder)<\/p>\n<p>&nbsp;<\/p>\n<p>With the above deployment strategy, the application should support behaviors such as &#8211; browser refresh, accessing the inner URL.<\/p>\n<p>The solution approach mentioned in the above scenario poses a challenge as \u2013 only one index.html could be defined as the root object. In the above-mentioned folder structure, each of the subfolders will have its own index.html<\/p>\n<p>One of the approaches, to handle the above scenario could be \u2013<\/p>\n<ul>\n<li>Create a Lambda function<\/li>\n<li>Based on the incoming URL, update the request URL to point to the correct subdirectory index.html<\/li>\n<\/ul>\n<p><strong>References<\/strong><\/p>\n<ul>\n<li>https:\/\/aws.amazon.com\/getting-started\/projects\/host-static-website\/services-costs\/<\/li>\n<li>https:\/\/aws.amazon.com\/premiumsupport\/knowledge-center\/cloudfront-serve-static-website\/<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>One of the key design decisions for any web application development\/deployment is \u2013 the [&hellip;]<\/p>\n","protected":false},"author":210,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[2],"tags":[],"coauthors":[66],"class_list":["post-392","post","type-post","status-publish","format-standard","hentry","category-web-ui-ux"],"acf":[],"_links":{"self":[{"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/posts\/392","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/users\/210"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/comments?post=392"}],"version-history":[{"count":21,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/posts\/392\/revisions"}],"predecessor-version":[{"id":488,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/posts\/392\/revisions\/488"}],"wp:attachment":[{"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/media?parent=392"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/categories?post=392"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/tags?post=392"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/coauthors?post=392"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}