One of the key design decisions for any web application development/deployment is – the selection of a web hosting option. A few of the key parameters impacting the decision are – cost, supported behaviors, scalability, availability, maintainability.
AWS supports hosting static web applications in S3. This document discusses various aspects of hosting a static web application on S3.
Any web application hosting options on AWS cloud must cater to the following key requirements
- Easily manageable, maintainable, performant
- Scalable and high availability
- Support for HTTPS, custom domain
Web Application Types
Before we go into further details, Web applications could be categorized into the following two types –
- Static web application – 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)
- Web application requiring server-side processing – 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
AWS S3 for Static Web Application Deployment
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.
The following diagram provides the recommended architecture:
Simple Storage Service (S3)
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.
An important consideration to be made – is S3 hosted endpoints do not support HTTPS. To use HTTPS, S3 deployed web application needs to be served by Cloud Front (CDN).
The cloud front is the Content Delivery Network (CDN) service provided by AWS. Cloud front is required for the following –
- Define custom domain for deployed web application
- Make web applications available over HTTPS
- Provide abstraction over S3 i.e., the S3 endpoint can be made private, enhancing security
- Add response headers (security/CORS/Custom etc.) using Response Header policy
- 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. https://example.com/SPA/route/will/fail). 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
Lambda @ edge could be used to perform various tasks such as –
- Response header manipulation
- S3 with multiple subdirectories. Conditional redirection to subdirectories
The CloudFront URL is not very user friendly. Using Route 53 custom domain name can be mapped to CloudFront.
This section describes the cost associated with services mentioned in the above architecture diagram. It’s a key driving factor to determine, the suitability of S3 static web hosting for the given scenario.
Simple Storage Service (S3)
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.
Cloud Front – The CloudFront pricing is driven by –
- Amount of data transferred to end user
- Number of http(s) requests
- Cloud front location
No cost involved –
- Data fetch from origin (S3) to edge location
- Cloud front to Origin- Not applicable
Lambda@Edge – Lambda@Edge pricing is driven by
- Number of function invocations
- Required compute capacity
- Compute duration
Route 53 – Route 53 pricing is driven by – the number of domain names managed, the number of the hosted zone, and user queries.
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.
Decision considerations to be made while opting for S3 based hosting –
Web Application Type
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’t be hosted in S3. For Single Page applications requiring server-side rendering, S3 hosting is not a feasible option.
Data storage impacts the S3 cost. Application assets storage requirement needs to be analyzed carefully.
Number of visitors
The number of visitors impacts the number of HTTP (s) requests and the amount of data transferred to end-users (cloud front cost factors).
Advantages of S3 based static web hosting
Serverless – Content is hosted in S3. This eliminates the need of purchasing a web server/virtual machine, which needs to be kept up 24×7 in the order for the web application to be available always
Availability – High availability is driven by high availability used AWS services i.e., CloudFront, S3, Edge@Lambda
Auto Scale – S3 auto scales as needed
CDN Advantages – Contents are served via cloud front (AWS CDN Services), entailing all benefits associated with CDN
Cost – 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)
Few common scenarios to consider –
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)).
One of the approaches, to handle the above scenario could be – 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.
I have an angular-based application supporting multiple languages (ex. English & 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.
MyS3Bucket (S3 bucket)
|———- English (subfolder)
|———- Hindi (subfolder)
With the above deployment strategy, the application should support behaviors such as – browser refresh, accessing the inner URL.
The solution approach mentioned in the above scenario poses a challenge as – 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
One of the approaches, to handle the above scenario could be –
- Create a Lambda function
- Based on the incoming URL, update the request URL to point to the correct subdirectory index.html