Full Scalable Angular application based on AWS

Angular and AWS

In the last year I have been working on a personal project, based on Angular and PHP. The application https://homezone.al is an advertiser website for renting or selling properties, totally free. It is still working in progress but has the MVP base setup.

As a software engineer in Amazon, I decided to give it a try and build all the infrastructure based on AWS based on what I learned here.

AWS itself has a learning curve but once mastered can lead to build powerful flexible solutions for any kind of application.

The main aim of this article is to illustrate a full application architecture step by step at high level, and how to automate most of the processes.

Tech stack

To develop this application I chose the follow stack:

Angular for the front end:

  • Solid framework all in one, offers solutions for every thing needed to develop a JS based app
  • Strong CLI tool that speeds up component creation, building, dev server …
  • Supports typescript, scss, routing, request interception, great documentation, consistent standards, DI, and more…
  • It is amazing fast, Ivy engine, AOT compiler, lazy loading out of the box…
  • 0 Config, once you type ng new you have a full working web app ready to expand (unlike react you need to create all ecosystem)
  • Incredibly fluid progressive updates (I started with angular 4, and I updated to Angular 12 with no major re-writes)
  • Abstracts a lot the JavaScript fatigue

PHP (7.4) for API based on ZendFramework:

  • Easy and fast to develop, loose typing, great web support
  • Very similar syntax to Javascript

Lot of developers hate PHP but right now I haven’t seen any valid arguments against it. If someone writes bad code is, the problem is the developer not the language. Useless rants generated by ignorance and inability to develop based on SOLID and Design patterns. Lot of successful companies I have worked for, had PHP on backend, generating revenues around 10M, and 800M a year.

Most dev nerds loose focus on the final goal when they develop an application, raging against the language, forgetting that the final goal is to deliver a product to the final customer, that generates health… but this is an a topic for another article…

MySql for data store:

  • Easy to use, flexible and fast enough to hold the right set of data

AWS stack

Here it comes the best part. Before using AWS, typically I would deploy my web application in a single shared host, including domain and server. This would serve the API, JS, Assets, and everything needed and would be an extremely cheap solution (like 20$ including domain). But there are many issues with this, from scalability, to security, CI and so on…

Why AWS? Mainly because is the cheapest and probably on of the best cloud out there.

S3

  • To host any possible static asset, from JS, CSS, images, to the application it self
  • Very cheap, current cost is around 0.50$ per month
  • Fast and reliable

CloudFront

  • Used for having a caching system for the assets
  • S3 does not support HTTPS, but if you put CloudFront in front of it, HTTPS comes for free
  • Straight forward binding to the CNAME of your domain
  • Easy versioning of your application in combination with S3

Route 53

  • You can buy your domain else where and with Route 53 you can easy redirect it to CloudFront
  • This is powerful enough to create an email system based on your domain without the need of an email server
  • Free Amazon SSL certificate under ACM for HTTPS

Elastic BeanStack

  • In a few clicks this will create your Nginx HTTP server, MySQL host, EC2 hosts for the PHP, and a load balancer in the eventually scale is needed
  • Versioning of the API
  • Easy updates of the API, and monitoring
  • Scales automatically on high demand
  • No costs, you pay for EC2 and MySQL instances only (Ok this is the expensive part, a minimal config will cost around 60$ per month)

API Gateway

  • A middleware between the EC2 server and the Client, handles security and allows only HTTPS request to avoid exposing directly the EC2 endpoint
  • Can be configured to add access keys and custom headers for security purpose
  • Free tier, up to 1M request (so free, if your web has more than 1M requests per year, probably you have enough visit to make some money), $1 per 300M after free (ridiculously cheap)

Amazon pinpoint

  • Mostly used to send emails for registration and property updates to registered users
  • Super cheap ($1 per 10'000 email)
  • Supports email, SMS, push notifications

AWS Lambda

Let’s glue all together part 1: The Front End

1. Build the Angular application

I start building my angular app, adding components, testing locally, and finally run ng build this will create a production ready angular application in the dist folder of your project:

ng build --configuration production --build-optimizer --output-path=dist/prod/v1.0

Note 1: Do not use the --base-href and --deploy-url options of Angular cli. This will mess up your routing and your assets path used in components and CSS. We will manage this using CloudFront and S3

Note 2: Inside your components and CSS use absolute paths to relative to your index.html file. index.html and assets folder are at the same level, and will be at the same at deploy time. Example:

<img src="/assets/images/icons/home-gray.svg" alt="Home" />

2. Upload on S3

I need to upload the compiled application on S3, in a new folder in order to version it (let’s say I introduce a bug and I want easily to rollback to the previous version). I can do it manually every time I build a new version or I can automate this part. So I decided to build a NodeJS script. This script will upload every file and sub-folder into the bucket:

Note: Do not use the above script because it is missing some dependencies, find the full script at the end of part 1.

All I have to do is run:

await deployVersionOnS3('dist/prod/v1.0', 'prod/v1.0', 'MY_S3_BUCKET');

Note: You need to create an S3 bucket, configure it as S3 website and create a IAM user with accessKeyId, secretAccessKey and with S3 access in order for the JS AWS SDK to work.

3. Update/Create CloudFront distribution

The main reason we use CloudFront is caching, versioning and redirect to our domain.

Note: This step requires that you have created a hosted zone in Route53 and have updated the NameServers of your domain provider to point at Route53 NameServers

Example of Domain custom NS to point to AWS NS

First we need to create a new CF distribution with the following config (leave the rest to default value):

  • Origin Domain Name: Your S3 bucket endpoint
  • Origin Path: Your angular app version folder in S3, ex. /prod/v1.0
  • Viewer Protocol Policy: Redirect HTTP to HTTPS
  • Alternate Domain Names (CNAMEs) : www.yourdomain.com, yourdomain.com
  • SSL Certificate: Custom SSL Certificate, and create one for free by clicking on Request or Import a Certificate with ACM
  • Default Root Object: index.html (the index file of our application)

Now we have a CF distribution ready to serve our static files from the S3 bucket.

Every time we create a new version of the Angular application, example /prod/v1.1 we will need to update the distribution to point to the new version by changing the Origin Path and the invalidate it’s cache. Let’s automate this using a script:

What is happening here:

  • getCFDistribution: This function retrieves the CF distribution config created above, we need just to pass as parameter the distribution ID
  • updateOriginPathCF: This function takes the CF distribution config, updates the OriginPath to point at the new location (prod/v1.1), and saves the changes on AWS CF distribution
  • invalidateCloudFrontCache: This simply tells to CloudFront to invalidate the cache and start loading from the new application

Note: The CF distribution config is a JSON format object, which is huge, but all we need is the DistributionConfig, the ETag and the ID. After we get this data from the API, in the DistributionConfig all we need to update is the OriginPath of the first item, and give it back to the CF update function.

4. Final Script

And this is my final script, that updates and uploads the new version of the Angular application online:

All done, now by just running node deploy.js the Angular APP will be build and automatically uploaded online.

Let’s glue all together part 2: The Back End, API

1. The evil PHP

First thing we need for our API is a server to run the infamous PHP rest api, a database, and a secure way to access it, with some protection around. We can go do all manually, by creating an EC2 instance, a MySQL server, some security groups, load balancer … but wait AWS ElasticBenstalk can do all in some simple clicks.

2. Elastic Beanstalk

Open Elastic Beanstalk on AWS, Click Create Environment, select Web server environment, click next and configure:

  • Environment name: A name of your choice, mySuperApi
  • Domain: This will be in practices your endpoint API to the EC2 webserver public directory, where sits your index.php
  • Platform: PHP (and version)
  • Upload your code: Select your PHP application zipped

Click Create Environment and wait 5 minutes…

Note: You can click Configure More option, but I would suggest to leave EB decide the configuration, you can edit after if needed

Once the environment is created, navigate to the Configuration and add the MySQL database by clicking on edit.

Now we can decide to upload the API code manually by zipping it, but let’s automate it as well to facilitate future updates:

What is happening here:

  1. createApiZip: We zip all our PHP code, eventually we change configurations (example API endpoints inside PHP config files)
  2. In case we have or we want to change NGINX configurations (or apache) we just create a folder.platform/nginx/conf.d/elasticbeanstalk/ourcustom.conf and we put any custom server configuration file here
location / {    try_files $uri $uri/ /index.php$is_args$args;}

This folder should be included in the zip, and when we upload it on EB it will apply those changes to the server. For full documentation here.

Note: Every time we do an upload, EB will reset the server settings, so in order to preserve the configuration those must be stored inside the .platform folder and uploaded every time along with your code.

3. uploadFileOnS3: Once we zip, se upload the application on the S3 bucket provided by EB, so EB can pick it up

4. createAppVersionOnElastichBeanstalk: At this point we need to create a new Application version on EB, with a label the S3 location

5. updateEbEnvironment: Here we ask EB to switch the API to the new version

And we are done, every time we need to update our API we just run from command line node deploy_api.js

3. API Gateway

The main purpose of the API Gateway is to avoid exposing the EC2 endpoint directly and to add HTTPS on the API calls. This is once-off configuration and rarely will need to change.

To be honest, API Gateway user interface is a bit messy, not one of the best of AWS.

  1. Go in API Gateway console and click Create API, and chose REST API
  2. In the next screen chose REST, New Api, and set a name and Click create
  3. In the next Screen in the Left Nav Menu, click Resources
  4. Here API Gateway will link automatically to your EB Endpoint,
  5. In the Actions dropdown click Deploy API, and create a new stage
  6. After that will generate the API Endpoint which you will need to use in your Angular application to make the calls.

Note: you might need some extra configuration here to redirect the API Gateway properly, I am not going into details otherwise this article will be very long.

With this final steps we are done. Now we have a full set up AWS infrastructure to server our Web Application, and all automated.

All you need now is just work on code, once it is ready and tested, you just need 2 command to deploy online.

Let’s secure

Last but not least security is important. We need to secure these steps:

  1. S3 bucket Policy can be configured to be accessible only by CloudFront and your domain by using the Policy. In the CF distribution add a Referer customer header and then configure the S3 bucket policy as the following:

2. Configure your code CORS to accept calls only from your domain.

3. Add a key to your API to your API and rotate from time to time, also configure the API to be accessible only from your domain, to avoid API scraping.

4. I got some fake registration, calling the register API like a sort of DoS attack, to avoid this I had to add some protection in place like throttling, and delays on UI.

5. Monitor your application using the amazing AWS CloudWatch, which will automatically create for you dashboards with Metrics, like number if API calls, number of errors, 500, 400, logs diving in amazing simple way with few clicks. Also you can configure alerts and alarms, and schedule processes…

Conclusion

In conclusion we build up a full scalable automated Web Application based on AWS.

I tried to be more expressive as possible and to contain the article length as this topic can be huge if we go in detail.

All I need is now is just develop the code, and deploy, not more overhead in server configurations.

AWS offers a powerful easy to configure system, easy to be done with few clicks and enough flexible to be automated via cli.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store