How to deploy a web application in aws

Follow step-by-step instructions to deploy a containerized web app using AWS App Runner

In this guide, you will learn how to deploy a containerized application with AWS App Runner.

AWS App Runner is a fully managed service that makes it easy for developers to quickly deploy containerized web applications and APIs, at scale and with no prior infrastructure experience required. Start with your source code or a container image. App Runner automatically builds and deploys the web application and load balances traffic with encryption. App Runner also scales up or down automatically to meet your traffic needs.

In this guide, you will learn how to:

  • Use AWS CDK to create the infrastructure for your application
  • Deploy the application to AWS App Runner

Before Starting this guide, you will need:

  • An AWS account: if you don't already have one follow the  Setup Your Environment getting started guide for a quick overview.
  • Please make sure that you have your AWS CDK properly configured. For more information on how to setup the AWS CDK, please refer to the Getting Started with AWS CDK.

This tutorial is divided into the following short modules. You must complete each module before moving to the next one.

The first step is to create a new directory for our application.

mkdir my_webapp cd my_webapp

Then you can initialize the NodeJS project. This creates the package.json file that will contain all the definitions of your NodeJS application.

We are going to use Express as our web application framework. To use it, we need to install Express as a dependency in our NodeJS project.

After running this command, you will see the dependency appear in the package.json file. Additionally, the node_modules directory and package-lock.json files are created.

Now you can create a new file called app.js. This file will contain the business logic for our NodeJS Express server will reside.

We are now ready to start adding some code. The first thing we need to add is the dependencies for the app - in this case, Express to allow using the module we previously installed, and then add the code to start up the web server. We will specify the web server to use port 8080, as that is what Elastic Beanstalk uses by default.

var express = require('express'); var app = express(); var fs = require('fs'); var port = 8080; app.listen(port, function() { console.log('Server running at http://127.0.0.1:', port); });

We can start up our application now, but it won't do anything yet as we have not defined any code to process requests.

We will now add code to serve a response for a HTTP REST API call. To create our first API call, add the following code between the port definition, and where we start the server.

var express = require('express'); var app = express(); var fs = require('fs'); var port = 8080; // New code app.get('/test', function (req, res) { res.send('the REST endpoint test run!'); }); app.listen(port, function() { console.log('Server running at http://127.0.0.1:%s', port); });

This is just to illustrate how to connect the /test endpoint to our code, you can add in a different response, or code that does something specific, but that is outside the scope of this guide.

Our Express NodeJS application can also serve a static web page. We need to create an HTML page to use as an example, let's create a file called index.html.

Inside this file, add the following HTML with a link to the REST endpoint we created earlier to show how it connects to the backend.

<html> <head> <title>Elastic Beanstalk App</title> </head> <body> <h1>Welcome to the demo for ElasticBeanstalk</h1> <a href="/test">Call the test API</a> </body> </html>

To serve this HTML page from our Express server, we need to add some more code to render the / path when it is called. To do this, add the following code above the /test call:

app.get('/', function (req, res) { html = fs.readFileSync('index.html'); res.writeHead(200); res.write(html); res.end(); });

This code will serve the index.html file whenever a request for the root of the app (/) is made.

We are now ready to run our application and test if it is working locally. To do this, we are going to update package.json with a script to make it easier to run. In the package.json file, replace the scripts section with:

"scripts": { "start": "node app.js" },

Now you can go to your terminal and run:

This will start a local server with the URL http://127.0.0.1:8080 or http://localhost:8080.

When you paste this URL in your browser, you should see the following:

How to deploy a web application in aws

To stop the server, use ctrl + c to stop the process in your terminal where you ran npm start

In this guide, we will take you through deploying a web application with AWS Amplify. Amplify is a framework with a set of tools and services that help you build scalable full stack applications, powered by AWS services.

AWS Amplify is a set of tools and services that can be used together or on their own, to help front-end web and mobile developers build scalable full stack applications, powered by AWS. With Amplify, you can configure app backends and connect your app in minutes, deploy static web apps in a few clicks, and easily manage app content outside the AWS console.

First, ensure you have CDK installed. if you do not have it installed, please follow the Getting Started with AWS CDK guide:

We will now create the skeleton CDK application using TypeScript as our language of choice:

mkdir ec2-cdk cd ec2-cdk cdk init app --language typescript

This will output the following:

Applying project template app for typescript # Welcome to your CDK TypeScript project! This is a blank project for TypeScript development with CDK. The `cdk.json` file tells the CDK Toolkit how to execute your app. ## Useful commands * `npm run build` compile typescript to js * `npm run watch` watch for changes and compile * `npm run test` perform the jest unit tests * `cdk deploy` deploy this stack to your default AWS account/region * `cdk diff` compare deployed stack with current state * `cdk synth` emits the synthesized CloudFormation template Executing npm install... ✅ All done!

If you see the following message, we recommend you upgrade your CDK version using the supplied command, and then running npm update:

**************************************************** *** Newer version of CDK is available [1.122.0] *** *** Upgrade recommended (npm install -g aws-cdk) *** **************************************************** # npm install -g aws-cdk # npm update

Go to the file /lib/cdk-ecs-infra-stack.ts, this is where you will write the code for the resource stack you are going to create.

A resource stack is a set of cloud infrastructure resources (in your particular case they will be all AWS resources), that will be provisioned into a specific account. The account/region where these resources are provisioned, can be configured in the stack.

In this resource stack, you are going to create the following resources:

  • IAM role: this role will be assigned to the EC2 instance to allow it to call other AWS services.
  • EC2 instance: the virtual machine you will use to host your web application.
  • Security Group: the virtual firewall to allow inbound requests to your web application.
  • EC2 SSH keypair: a set of credentials you can use to SSH to the instance to execute commands to set everything up.

To start creating the EC2 instance, and other resources, you first need to import the correct modules:

npm i @aws-cdk/aws-ec2 @aws-cdk/aws-iam @aws-cdk/aws-s3-assets cdk-ec2-key-pair

You will then edit the lib/cdk-eb-infra-stack.ts file to add the dependency at the top of the file below the existing import for @aws-cdk/core:

import * as ec2 from "@aws-cdk/aws-ec2"; // Allows working with EC2 and VPC resources import * as iam from "@aws-cdk/aws-iam"; // Allows working with IAM resources import * as s3assets from "@aws-cdk/aws-s3-assets"; // Allows managing files with S3 import * as keypair from "cdk-ec2-key-pair"; // Helper to create EC2 SSH keypairs import * as path from "path"; // Helper for working with file paths

These modules provide access to all the components you need for you to deploy the web application. The first step is to find the existing default VPC in your account by adding the following code below the line // The code that defines your stack goes here:

// The code that defines your stack goes here // Look up the default VPC const vpc = ec2.Vpc.fromLookup(this, "VPC", { isDefault: true });

Using the cdk-ec2-key-pair package, you will create an SSH key pair and store that in AWS Secrets Manager.

// Create a key pair to be used with this EC2 Instance const key = new keypair.KeyPair(this, "KeyPair", { name: "cdk-keypair", description: "Key Pair created with CDK Deployment", }); key.grantReadOnPublicKey;

You now need to create a security group, allowing SSH and HTTP access from anywhere by adding 2 rules. Note that SSH access from anywhere is acceptable for a short time in a test environment, but it's unsafe for production environments. You will also create an IAM role for the EC2 instance to allow it to call other AWS services, and attached the pre-built policy to read configurations out of AWS Secrets Manager (where the SSH public key will be stored):

// Security group for the EC2 instance const securityGroup = new ec2.SecurityGroup(this, "SecurityGroup", { vpc, description: "Allow SSH (TCP port 22) and HTTP (TCP port 80) in", allowAllOutbound: true, }); // Allow SSH access on port tcp/22 securityGroup.addIngressRule( ec2.Peer.anyIpv4(), ec2.Port.tcp(22), "Allow SSH Access" ); // Allow HTTP access on port tcp/80 securityGroup.addIngressRule( ec2.Peer.anyIpv4(), ec2.Port.tcp(80), "Allow HTTP Access" ); // IAM role to allow access to other AWS services const role = new iam.Role(this, "ec2Role", { assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"), }); // IAM policy attachment to allow access to role.addManagedPolicy( iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore") );

You are now ready to create the EC2 instance using a pre-built Amazon Machine Image (AMI) - for this guide, you will be using the Amazon Linux 2 one for X86_64 CPU architecture. You will also pass the IAM role you created, the default VPC, and the instance type to run on, in your case, a t2.micro that has 1 vCPU and 1GB of memory - you view all the different instance types available here.

// Look up the AMI Id for the Amazon Linux 2 Image with CPU Type X86_64 const ami = new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, cpuType: ec2.AmazonLinuxCpuType.X86_64, });

// Create the EC2 instance using the Security Group, AMI, and KeyPair defined. const ec2Instance = new ec2.Instance(this, "Instance", { vpc, instanceType: ec2.InstanceType.of( ec2.InstanceClass.T2, ec2.InstanceSize.MICRO ), machineImage: ami, securityGroup: securityGroup, keyName: key.keyPairName, role: role, });

You have now defined your AWS CDK stack to create an Amazon EC2 instance, a security group with inbound access, and an IAM instance profile. Before deploying the stack, you still need to install the packages on the host OS to run your application, and also copy your application code to the instance. 

Your ec2-cdk-stack.ts file should now look like this:

import * as cdk from '@aws-cdk/core'; import * as ec2 from "@aws-cdk/aws-ec2"; // Allows working with EC2 and VPC resources import * as iam from "@aws-cdk/aws-iam"; // Allows working with IAM resources import * as s3assets from "@aws-cdk/aws-s3-assets"; // Allows managing files with S3 import * as keypair from "cdk-ec2-key-pair"; // Helper to create EC2 SSH keypairs import * as path from "path"; // Helper for working with file paths export class Ec2CdkStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // The code that defines your stack goes here // Look up the default VPC const vpc = ec2.Vpc.fromLookup(this, "VPC", { isDefault: true }); // Create a key pair to be used with this EC2 Instance const key = new keypair.KeyPair(this, "KeyPair", { name: "cdk-keypair", description: "Key Pair created with CDK Deployment", }); key.grantReadOnPublicKey; // Security group for the EC2 instance const securityGroup = new ec2.SecurityGroup(this, "SecurityGroup", { vpc, description: "Allow SSH (TCP port 22) and HTTP (TCP port 80) in", allowAllOutbound: true, }); // Allow SSH access on port tcp/22 securityGroup.addIngressRule( ec2.Peer.anyIpv4(), ec2.Port.tcp(22), "Allow SSH Access" ); // Allow HTTP access on port tcp/80 securityGroup.addIngressRule( ec2.Peer.anyIpv4(), ec2.Port.tcp(80), "Allow HTTP Access" ); // IAM role to allow access to other AWS services const role = new iam.Role(this, "ec2Role", { assumedBy: new iam.ServicePrincipal("ec2.amazonaws.com"), }); // IAM policy attachment to allow access to role.addManagedPolicy( iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore") ); // Look up the AMI Id for the Amazon Linux 2 Image with CPU Type X86_64 const ami = new ec2.AmazonLinuxImage({ generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2, cpuType: ec2.AmazonLinuxCpuType.X86_64, }); // Create the EC2 instance using the Security Group, AMI, and KeyPair defined. const ec2Instance = new ec2.Instance(this, "Instance", { vpc, instanceType: ec2.InstanceType.of( ec2.InstanceClass.T2, ec2.InstanceSize.MICRO ), machineImage: ami, securityGroup: securityGroup, keyName: key.keyPairName, role: role, }); } }


Page 2

Skip to main content

Close Getting Started with AWS AWS Cloud Essentials Hands-on Tutorials

Close Architecture Center Builders' Library

Close Tools Documentation

In this module, you will learn to use  user data to configure an EC2 instance and install software packages on the EC2 instance

When you launch an instance in Amazon EC2, you have the option of passing user data to it that can be used to perform common automated configuration tasks and even run scripts after the instance starts. You will use this feature to simplify your application deployment by specifying what software to install and configure on first launch, and copy the sample application to the instance. This module will cover how to create the user data and add it to the EC2 instance created in the previous module.

  • How user data is added to the EC2 instance
  • Create the user data to install and configure all required packages on the OS
  • Deploy your web application by copying it to the instance

The sample web application hosted in the SampleApp folder, is a Python application that you will be deploying. It requires Nginx and uWSGI to run. To install these components, there are a number of steps to follow. First, you need to install all the OS packages, configure nginx and uwsgi, ensure they are are running, and copy the sample application to the instance. A script file that configures all of these setup steps is provided in SampleApp/configure_amz_linux_sample_app.sh - please have a look at the steps in it if you want to know more about how the instance is configured.

To deploy the web application, you need to add code to CDK that will copy the configuration files and scripts, and the sample app to S3. You will configure the configuration scripts. To do so, add the following code in ec2-cdk-stack.ts below the previous code:

// Use an asset to allow uploading files to S3, and then download it to the EC2 instance as part of the user data // --- Sample App --- // Upload the sample app to S3 const sampleAppAsset = new s3assets.Asset(this, "SampleAppAsset", { path: path.join(__dirname, "../../SampleApp"), }); // Allow EC2 instance to read the file sampleAppAsset.grantRead(role); // Download the file from S3, and store the full location and filename as a variable const sampleAppFilePath = ec2Instance.userData.addS3DownloadCommand({ bucket: sampleAppAsset.bucket, bucketKey: sampleAppAsset.s3ObjectKey, }); // --- Sample App --- // --- Configuration Script --- // Upload the configuration file to S3 const configScriptAsset = new s3assets.Asset(this, "ConfigScriptAsset", { path: path.join(__dirname, "../../SampleApp/configure_amz_linux_sample_app.sh"), }); // Allow EC2 instance to read the file configScriptAsset.grantRead(ec2Instance.role); // Download the file from S3, and store the full location and filename as a variable const configScriptFilePath = ec2Instance.userData.addS3DownloadCommand({ bucket: configScriptAsset.bucket, bucketKey: configScriptAsset.s3ObjectKey, }); // Add a line to the user data to execute the downloaded file ec2Instance.userData.addExecuteFileCommand({ filePath: configScriptFilePath, arguments: sampleAppFilePath, }); // --- Configuration Script ---

All the steps will be added to the user data script of your instance, and execute when it first boots up. There is one more step before you can deploy everything: adding output to the CDK stack to make it easier to SSH to the instance. In the infrastructure above, you created an SSH key, which is stored in AWS Secret Manager. To download it to your workstation, you need to retrieve it. You will also need the public IP of the instance, and the SSH command to execute. 

Add the following code to the stack at the bottom:

// Create outputs for connecting // Output the public IP address of the EC2 instance new cdk.CfnOutput(this, "IP Address", { value: ec2Instance.instancePublicIp, }); // Command to download the SSH key new cdk.CfnOutput(this, "Download Key Command", { value: "aws secretsmanager get-secret-value --secret-id ec2-ssh-key/cdk-keypair/private --query SecretString --output text > cdk-key.pem && chmod 400 cdk-key.pem", }); // Command to access the EC2 instance using SSH new cdk.CfnOutput(this, "ssh command", { value: "ssh -i cdk-key.pem -o IdentitiesOnly=yes ec2-user@" + ec2Instance.instancePublicIp, });

These three outputs will show you the following:

  • How to download the SSH key to access the instance
  • The public IP of the instance
  • An SSH command to access the instance.

You are now ready to deploy the stack.

In this module, you learned how to add user data to an EC2 instance to allow configuring it when it starts up for the first time. You used this to install all the dependencies, configure nginx and uwsgi, and deploy the sample application. In the next module, you will deploy the stack and the sample application.

Up Next: Deploy CDK Stack