Simple Web App

In this part we will be deploying a simple full-stack web app to an EC2 instance. The app will connect to a MySQL database and use a caddy reverse proxy to serve traffic. This will all be setup on a single EC2 instance.

Here's an example of exactly what we'll be doing:

The app you will be deploying is a basic bun server, not a node server, but the process is the same. It is a simple QR code generator that stores the data in a MySQL database.

Setup Instance

step 1:

Setup a new EC2 instance with the following settings:

Then login to the instance using SSH.

  • Instance type: t2.micro
  • OS: Ubuntu Server 24.04 LTS
  • Security group:
    • SSH: Port 22
    • HTTP: Port 80
    • HTTPS: Port 443

Once the instance is created, login to the instance using ssh. We're now going to install MySQL on the instance and setup a new database.

MySQL

step 2:

Install MySQL on the EC2 instance

sudo apt install mysql-server -y
sudo mysql_secure_installation
step 3:

Create a new database and user for the web app

sudo mysql
CREATE DATABASE my_app;
CREATE USER 'my_app_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'StrongPassword123!';
GRANT ALL PRIVILEGES ON my_app.* TO 'my_app_user'@'localhost';
FLUSH PRIVILEGES;

That's all we need to do to setup the database for the web app. It will need to connect to the database using the following MySQL connection string environment variable:

MYSQL_URL='mysql://my_app_user:StrongPassword123!@localhost:3306/my_app'
Show timestamps
00:00
Now we're gonna set up the full stack web application
00:02
on a single EC2 instance.
00:04
And for this, I have provided the source code
00:07
for a full stack app.
00:09
It's a bun backend with a React front end,
00:11
and you can download the code from this section
00:14
using that button there.
00:16
And if we open this up, it's a zip folder,
00:18
but I'm just gonna open this directory in cursor
00:22
just so we can see what's going on.
00:23
So we have the front end code,
00:25
which has already been compiled.
00:26
It's a React front end.
00:27
We have the server code, which is bun,
00:29
so it's all TypeScript.
00:30
And we need to put this on an EC2 instance
00:32
and run it with a database and with a reverse proxy.
00:34
And although this is a bun TypeScript server
00:38
with a React front end,
00:39
these concepts are gonna be pretty much the same,
00:42
no matter what kind of server you are deploying
00:44
to an EC2 instance.
00:46
It's just that the environment would be different.
00:47
So on this EC2 instance,
00:49
I'm gonna install bun to run my bun server.
00:52
On a .NET instance, I'm gonna install .NET
00:55
and compile my application to run in the .NET runtime.
00:58
If it was something like a C++ or Go app,
01:00
I would compile that
01:01
and then just run the compiled code on the server.
01:04
But the concepts are still gonna be the same
01:06
as what we're doing here.
01:07
So I am going to start by setting up a new EC2 instance.
01:11
So I'm gonna go into my Playground account again.
01:13
I'm still in Oregon for this,
01:14
and I'm gonna go to the EC2 dashboard,
01:17
go to instances.
01:19
I actually left my instance from the last one running,
01:21
which you gotta be careful about.
01:22
So I am gonna terminate that before I do anything.
01:25
Make sure you're terminating your instances.
01:26
You really don't wanna get an AWS bill.
01:28
at the end of the month.
01:29
So that's terminating.
01:30
I'm gonna launch a brand new instance,
01:32
and I'm gonna call this, I don't know, simple web app.
01:36
It's gonna be the same as before.
01:37
We're gonna use Ubuntu 24.04.
01:40
We're gonna use the T2 Micro, which is in the free tier.
01:43
I'm gonna use my key pair to be able to log in.
01:46
And then I'm gonna edit this
01:48
and create my own security group.
01:50
So I'm gonna allow SSH just from my IP address,
01:54
and we are gonna allow HTTP, HTTP right there,
01:58
port 80 from anywhere.
02:01
And actually I'm gonna go custom for this one
02:02
because this defaults to IPV4 and IPV6.
02:05
And I only wanna allow on IPV4 addresses.
02:09
So any IPV4 address can access this,
02:11
which does mean that I'm canceling out anyone
02:13
with an IPV6 address.
02:14
And I wouldn't necessarily wanna do that.
02:16
But for this example, I am just gonna stick to IPV4
02:19
and I'm only gonna set up an A record in route 53,
02:22
which is an IPV4 record.
02:24
And then I'm gonna add another rule here.
02:26
This is gonna be for HTTPS.
02:28
'Cause this is a web server.
02:30
We want anyone on the public internet
02:31
to be able to access this over HTTP and HTTPS.
02:35
And since we're using caddy,
02:36
that's going to forward anything that is an HTTP request
02:40
to be an HTTPS request.
02:41
So that looks good.
02:42
For storage, I'm gonna leave that as eight gigabytes.
02:45
That's more than enough for this test instance.
02:47
And we are gonna launch this instance.
02:50
Then I'm gonna select the instance.
02:53
And if this is set up yet it's running,
02:54
I'm gonna select connect again, SSH client,
02:57
click on the SSH commands, copy it,
03:00
and then paste that into terminal on my local machine,
03:03
but change the path to be my home.ssh directory.
03:08
So that should allow me to log in.
03:10
Yes.
03:11
And now there we go.
03:11
I am on my new Ubuntu instance.
03:14
And again, the first thing I'm gonna do
03:16
is update and upgrade this, take a couple of minutes,
03:18
but I do wanna make sure that we're on the latest version
03:21
of Ubuntu and everything's up to date.
03:23
Then after this, we're gonna set up the MySQL database.
03:26
But for this web app that we're gonna deploy,
03:28
then we'll deploy the app
03:29
and we'll deploy a caddy reverse proxy.
03:32
And the application itself is a QR code generator app
03:36
where you can upload images.
03:38
So it might store images in the file system.
03:40
It will then store the data about that in a MySQL database.
03:43
And then every time someone scans the QR code,
03:45
it will redirect them to whichever site
03:47
you wanted to set the QR code up for.
03:49
So some of this stuff we've already done,
03:50
we already set up the database
03:51
and the reverse proxy in a different part.
03:54
So we're just basically gonna be copying what we've already done.
03:56
And then we'll focus really on how to deploy
04:00
a custom application to an EC2 instance.
04:03
So now that that's done,
04:04
I am gonna do what I did before
04:07
and install the MySQL server.
04:10
And I did that with the secure installation.
04:12
So it's gonna go through the steps with me again,
04:14
where I'm gonna make sure everything is set up
04:17
in a more secure way.
04:19
And now I have MySQL set up
04:22
so I can pseudo MySQL to go into the database.
04:24
And this one's gonna be a little different
04:26
from before 'cause we're only gonna access
04:27
this database privately.
04:28
We don't need to open up port 3306.
04:30
We don't need to allow public users.
04:32
We just need a private local user
04:34
to be able to access the database.
04:36
Like I said, this is for a QR code app.
04:38
So I'm gonna start by setting up the database here.
04:41
And actually we create the database.
04:42
I call this MyApp.
04:44
We're gonna create a user called MyAppUser
04:46
that can access the database over local host.
04:48
That's all we need, a private local host user.
04:51
And we have the same password as before.
04:53
And we're granting all privileges on this database.
04:55
We're gonna create a database to MyAppUser.
04:58
So I don't need to use the root user.
04:59
I'm just gonna use the MyAppUser
05:01
from my QR code bun application to access this database.
05:05
And the way we'll do that
05:06
is we'll use an environment variable.
05:07
So here is the entire MySQL string
05:10
to access this database from local host.
05:13
So here is the MyAppUser that's been created.
05:15
Here is the password at local host.
05:18
And the database is called MyApp.
05:20
So as long as we have this environment variable
05:22
set up on the EC2 instance,
05:25
we're gonna be able to access the database.
05:27
So the next thing I wanna do is install bun
05:30
because this is the runtime that is needed
05:33
to run a bun application, obviously.
05:36
So again, like I said, if it's a different application,
05:38
you would need a different runtime
05:39
or a different interpreter.
05:40
If this was a Python application, I'd install Python.
05:42
If it was Ruby, I'd install Ruby.
05:43
If it was a compiled application,
05:45
I would install the system packages I need
05:46
and then just run that binary.
05:48
So it really depends on what you're doing here.
05:50
This just happens to be specific to installing Ruby.
05:53
So I'm gonna go ahead and install Ruby.
05:55
And I'm gonna run it in bun because it's a bun application.
05:57
But these steps apply to any sort of software
05:59
that you're gonna deploy here.
06:01
So I'm just gonna copy this to install bun.
06:03
So I'll exit MySQL and I will install bun on this server.
06:08
And now that that has been installed,
06:10
I should be able to run bun.
06:12
Yep, so I can see that I am running bun version 1.2.17.
06:16
Okay, so that's pretty good.
06:18
So now I need to get my source code
06:21
or my compiled application, whatever it is onto the server.
06:24
And there's a bunch of different ways of doing this.
06:25
I'm just gonna go with a really simple way that will work
06:29
no matter what application you have
06:30
or what operating system you're using.
06:32
So I have my code locally right here.
06:35
I'm getting a bunch of red
06:36
'cause I haven't installed the dependencies locally.
06:37
We will install the dependencies on the server though.
06:40
So what I can do is if I go to the path of this application,
06:44
so I'm just gonna copy my working directory here.
06:48
I'm gonna open a terminal window on my local machine
06:51
and I'm just gonna go to my application.
06:54
So if I list the contents of this,
06:55
I can see this is my application code in the server directory.
07:00
I have a bunch of TypeScript, I have an index.ts,
07:02
which is the entry point to my application.
07:04
And then in my front end,
07:06
I have all of the React app stuff
07:10
and I've already compiled this into the disk directory
07:14
because I don't necessarily wanna compile my code
07:15
on my production EC2 instance.
07:18
If there's a compilation step,
07:19
I'm gonna do that beforehand.
07:21
This could be done through like a GitHub action
07:23
or some sort of CI/CD pipeline.
07:25
But for a small application,
07:27
it just makes sense to run your code locally,
07:29
build it locally,
07:30
and then send the production assets to the server
07:32
and just run the app there.
07:34
So I have my application locally.
07:37
Let's say I've been developing it.
07:38
I've been committing and pushing to GitHub, whatever,
07:40
and I've built it.
07:41
It's ready to go on the EC2 instance.
07:42
Now, all I wanna do is copy my local code
07:45
onto my EC2 instance.
07:47
And there's a few ways of doing this,
07:49
but if I scroll down a bit,
07:50
you can see that I can just use scp,
07:53
which is a copy command that uses the SSH protocol.
07:55
It's a protocol to copy something
07:56
from one machine to another.
07:57
So it's a very simple way of copying the code
08:00
up to the EC2 instance.
08:02
Or if your computer supports it,
08:03
you can use rsync.
08:04
So I'm on a Mac.
08:05
This will just work if I use rsync.
08:06
Any Linux machine, rsync should work as well.
08:08
And this synchronizes your code to the EC2 instance
08:12
or to the remote instance.
08:13
So if you make a small change to a file locally,
08:16
you just run rsync and it will only update that file
08:18
on the remote server, which is super handy.
08:20
So if you don't have rsync, you can just use scp,
08:22
but I'm gonna use rsync for this.
08:24
So I'm gonna copy
08:25
this and I am in my application locally
08:28
on my local machine.
08:30
I'm gonna run this command.
08:32
So I have rsync.
08:34
We're gonna exclude the node modules
08:35
'cause we're gonna install those on the server.
08:37
Since I'm running this locally on a Mac right now,
08:39
and I'm gonna run it on a Ubuntu Linux machine,
08:42
I wanna make sure that I install any
08:43
of the dependencies fresh on that EC2 instance.
08:46
I'm gonna exclude git 'cause that's just a lot
08:48
of files to copy.
08:49
I'm gonna exclude the .env because that's
08:51
for my local environment variables,
08:53
not for the remote server environment variables.
08:54
And then here, I need to specify the SSH stuff
08:58
that we used before.
08:59
So if I go back to my EC2 instance,
09:01
I can see that the SSH key is this one that I'm using.
09:06
So I'm gonna copy that in here in my .ssh directory,
09:10
then that's the name of the key I'm using
09:11
for this specific instance.
09:13
And it is ubuntu@ and here is the host name
09:16
of my current instance.
09:17
I'm gonna input that where it says IP address.
09:22
Okay, so this dot here is saying,
09:24
I'm gonna sync up the current directory.
09:25
So that's the directory I'm in, qr full stack,
09:28
and then we're gonna save that,
09:30
or we're gonna copy it to the Ubuntu instance.
09:32
And on the remote server,
09:34
I'm gonna make sure that goes into an app directory
09:36
on the home directory on my server.
09:38
So right now, if I'm on my Ubuntu instance and I ls,
09:41
there's nothing in my home directory.
09:43
There are no folders there, no code.
09:45
But if I run this, I'm expecting it to copy everything
09:47
from the current directory dot to an application directory
09:51
on that remote server.
09:52
So if I hit enter now,
09:53
it should be able to see every single file.
09:54
That it copies.
09:56
And if I run this again,
09:57
because rsync just synchronizes,
09:58
it should copy nothing
09:59
'cause it knows that there's no diffs there.
10:01
But if I go back to my EC2 instance and I ls again,
10:03
I can see there's now an app directory.
10:05
So if I ls the app directory,
10:07
I can see this is all of the code
10:09
that I need to run on the server.
10:10
So a really simple way of just getting the code
10:11
from one machine to another to be able to run it.
10:13
And again, this is how I do it for most of the servers
10:16
when I'm just creating apps that I'm working on alone
10:19
and I just need to get code somewhere
10:20
or an application somewhere to run it.
10:22
It's just so easy to use rsync to get it on the server.
10:24
So I now have the code from my local machine
10:26
on the EC2 instance.
10:28
And now I should see if I can run it.
10:29
So since this is a bun application,
10:32
I'm gonna cd into the app and I'm gonna bun install.
10:35
And again, if this was Python, you'd pip install.
10:38
If it was Ruby, you'd gem install or whatever it is.
10:40
If it were a C++ app,
10:41
I'd have to install all the dynamic libraries
10:43
that weren't compiled with that code.
10:45
Whatever it is, you need to make sure
10:46
that you have set up the system
10:48
to be able to run your application.
10:50
So now I should be able to bun start.
10:52
It shouldn't actually work that well because
10:54
I don't have my environment variable set up.
10:56
Let's see, yeah, it needs MySQL URL.
10:59
This application needs that environment variable
11:01
on the system, but I am able to run it with bun
11:03
and get that error message at least.
11:05
So now I can just copy this code here.
11:08
So I know that environment variable is gonna be this value
11:12
because we already set up the database
11:13
to be my app with my app user.
11:15
That's already all set up.
11:17
So if I copy this just to test it out,
11:19
we can see that this is gonna be the environment variable
11:21
we're passing in MySQL URL and then, oh, right.
11:24
We have to migrate the database.
11:26
So because this web server has the database schema
11:30
as TypeScript code, we're gonna run a migration
11:32
to actually set up the tables on the database.
11:34
So before I do this, if we MySQL dash U my app user dash P
11:39
and I enter that strong password.
11:48
If I show databases, the my app database is already set up.
11:52
So if I use my app and then show
11:54
tables, there are no tables in this database yet.
11:57
So I need to set up those tables.
11:58
It's gonna happen from the application.
12:00
The application itself is going to perform that migration
12:03
and set up those tables.
12:04
So I'm gonna exit this and I'm gonna run that code.
12:07
So using this environment variable point to the database,
12:11
I'm gonna run the migration for this specific application.
12:13
Hopefully this works.
12:15
So that said it was applied successfully
12:16
and we can test this out by again, logging into the database.
12:20
And now if I use my app, then show,
12:24
show tables, I can see that I have the migrations table
12:27
plus all the QR code app tables that I need
12:30
for this application.
12:31
And we could even go in and I guess like describe some
12:34
of these tables if we really wanted to see in depth
12:37
what was going on here.
12:38
So here's the QR codes table, here's the schema for it.
12:40
If I exit this, I can actually show you that
12:43
in the drizzle directory, there is a file for the migration.
12:48
So if you wanted to cat this file, you could see
12:51
this is the actual code that was run to set up
12:53
those tables, but that's not super important.
12:56
Just make sure that you run any things that you need to run.
12:58
You install the dependencies, you run migrations,
13:00
if that's part of the process.
13:01
And now the application should be ready to run.
13:03
So the next thing I wanna do is run bun start
13:08
with that MySQL URL environment variable.
13:12
So we're gonna make sure we have that environment variable
13:13
in front of it.
13:14
And then I'm gonna run bun run start
13:17
and that should start the server.
13:19
And this server I think is running on port 3000.
13:23
So if I were to log into this instance in a different window,
13:27
I think I should be able to curl local host 3000.
13:32
And there is the homepage.
13:33
That's the homepage of a react app, obviously.
13:36
So that does seem to be working.
13:38
If this is running, I'm able to make a call request
13:41
on local host to see that application.
13:43
We won't be able to visit this over the public internet
13:45
'cause we haven't opened up port 3000.
13:46
We don't wanna do that.
13:48
But this does just test that everything is working.
13:50
And if I were to stop running it in this window
13:52
and try and make that curl request,
13:53
it won't work because we are depending on this command
13:58
on the EC2 instance currently running to run the web server.
14:02
And we'll solve some of these problems as we go.
14:04
We'll set up a HTTP and HTTPS.
14:06
We'll make sure that this runs in the background
14:07
no matter what.
14:08
But this first step does show us
14:10
that our custom application is working.
14:12
So the next thing we're gonna do is install caddy
14:15
because I wanna be able to visit this
14:16
over the public internet.
14:18
So I'm gonna stop running this app
14:19
and I'm gonna run the same commands from before
14:22
to install caddy.
14:23
I'm gonna use this as a reverse proxy
14:24
so that we can visit the application
14:26
over port 443 with an SSL certificate.
14:28
So caddy is installed.
14:29
Now I can sudo vim/etc/caddy/caddy file.
14:34
And we're just gonna start by setting this up
14:38
so that if we access it over port 80,
14:41
it is a reverse proxy to our server running on port 3000.
14:46
So for this, all I need to do is say any connection
14:49
that comes in on port 80, caddy is gonna be a reverse proxy
14:53
to local host 3000.
14:56
That's where the bun application is running.
14:58
It's literally just forwarding requests onto our application.
15:00
The great thing about this is that the application,
15:04
the software that's running,
15:04
whether it's a bun app or a Python app or whatever,
15:07
just focuses on the application logic.
15:09
And by having a reverse proxy,
15:11
that can handle everything that is front facing.
15:13
It can handle the SSL certificates and HTTPS.
15:15
It can handle caching.
15:16
And we can even set this up to be a load balancer
15:18
to balance the load between multiple applications.
15:20
So this is a really handy thing to put in front of your web app.
15:23
So you can see here, I have applications.
15:24
So I'm gonna save that and then sudo systemctl reload caddy.
15:29
And now if I make a curl request to local host,
15:33
nothing will happen because the application isn't running.
15:36
But if I run the app again with bun run start
15:39
and the environment variable, this should now be working.
15:42
So if I check in the other terminal window,
15:44
I'm still on the EC2 instance,
15:46
I should be able to curl local host, just port 80.
15:50
And I can see that my application is running.
15:53
If I go back to my EC2 instance,
15:56
I'm gonna go to the ID and copy that public IPv4 address.
16:00
If I open up a new tab and go to that and continue to site,
16:02
even though it's unsecure, this is the QR code application.
16:06
So this does appear to be working.
16:08
It appears to be running.
16:09
Take off dark mode so we can actually see everything.
16:11
But this is the QR code application.
16:14
So if I close this terminal window over here
16:17
that's running the app or I stop it for any reason,
16:19
the app isn't gonna run.
16:20
That's one problem we need to solve.
16:21
And the other one is we don't have a domain name
16:23
or a cell certificate.
16:24
So we do need to solve both of those problems right now.
16:28
And the first thing we're gonna do
16:29
is make sure that this application runs.
16:31
So I don't wanna have to be always logged into my server
16:33
and running bun run start to make sure
16:35
that my server is up and running.
16:37
So we're gonna have this run in the background
16:39
using systemd because that is the standard way
16:43
to run things.
16:44
And that is what we've been using
16:45
to run all the other things.
16:46
We've been using systemctl to run MySQL, to run caddy.
16:50
Now we're gonna set up our own service and run it
16:53
the same way that we run everything else
16:54
on the Linux machines.
16:56
So I am going to sudo vim/etc/app.emv first
17:01
because we're gonna set up a environment variables file.
17:04
And this is super handy
17:06
because if we put our environment variables
17:08
into its separate file,
17:10
then we can manage those separately.
17:11
And we can also modify those on instances later on
17:14
using user data.
17:15
But we'll get to that in a much later section.
17:17
For now, I just need that MySQL environment variable.
17:21
So I'm gonna paste that in here.
17:22
This is the string that the application needs.
17:25
I could also add other environment variables
17:27
that my application might use.
17:29
So it uses port, for example.
17:30
I wanna make sure that that's always 3000.
17:32
So I can add that in here.
17:33
So any environment variables that I need for my application,
17:36
I can just put into this file.
17:37
And it won't be a system-wide environment variable.
17:39
No other applications need to know about these things.
17:41
It's just gonna be the environment
17:43
for my running application through systemd.
17:46
So I'm gonna exit this and save it.
17:49
Then I'm gonna make sure that the Ubuntu,
17:52
user, is able, or is the owner of this.
17:55
'Cause my application is gonna be running
17:57
under the Ubuntu user.
17:59
And I need to make sure, pseudo chown,
18:01
that my app can access the environment variable file
18:03
without needing root permission to run my application.
18:06
I shouldn't trust the application code.
18:08
With root permissions, I just need to make sure
18:10
that anything it accesses has the correct permission.
18:12
So it's now owned by Ubuntu.
18:14
And I'm also gonna chmod it so that it can only be read.
18:18
It doesn't need to be written, /etc/app.emv.
18:21
So now it's,
18:22
it's a little bit more secure to access this file
18:24
from the application.
18:25
And that's just the environment variables.
18:28
We now need to set up the systemd file.
18:30
And for that, we're going to use vim again
18:32
to set up a myapp.service.
18:35
You can call this whatever you want.
18:36
I'm just calling it myapp for now.
18:38
At the location, /etc/systemd/system/whatever.service.
18:43
So we're gonna create a brand new file here
18:45
and I'm gonna copy the code that we need.
18:47
So I'm gonna copy all of this right here.
18:50
And I'm gonna paste that in
18:52
over here.
18:53
So we have the description of the application.
18:55
This is whatever your app would be.
18:57
It's a QR code app in this case.
18:58
We're gonna make sure that the network
19:01
and user are set up before we actually run this system.
19:05
The user we're gonna run this as is Ubuntu.
19:07
The working directory of this specific application
19:09
is in the app directory.
19:11
We're gonna start it using bun
19:12
and I'm giving it the full path to bun
19:13
just in case the path variable hasn't been set up yet.
19:16
So we're gonna run start.
19:17
That's how we run this application.
19:18
Again, this is dependent on what kind of application
19:21
you're running on the EC2.
19:22
Instance, we always want it to restart.
19:24
If there's any issues, it crashes for whatever reason,
19:27
make sure this app restarts itself
19:28
and that it's always trying to run.
19:30
I'm gonna set up another environment variable here
19:33
just to make sure that it's in production mode
19:35
for bun node applications.
19:37
I usually just add that in here to make sure it's there.
19:39
The environment, I'm also gonna make sure that bun
19:42
is included in the path environment variable
19:44
just in case anything goes wrong there.
19:46
And then the environment file
19:47
where I'm gonna set up all the other environment variables
19:49
are gonna be in app.env.
19:51
So I'm giving it that.
19:52
And then we have this syslog identifier.
19:54
And this is important because this is how we're gonna identify
19:57
this specific application in the logs.
20:00
So later on when we go to view the system logs,
20:03
we can actually identify this application
20:04
over other applications.
20:06
So I am gonna save this file.
20:08
And now we should be able to run
20:11
sudo systemctl start myapp.service.
20:16
Just like we did for caddy and for mysql,
20:19
we should be able to start this thing.
20:21
And once it starts,
20:22
it should be running.
20:23
So we should be able to run curl localhost.
20:26
Locally, I should be able to run curl localhost 3000.
20:29
But now this application is running behind the scenes.
20:32
It doesn't matter if I close this terminal window or anything.
20:35
It is gonna still be running.
20:36
And if I wanna make sure that this app is still running,
20:38
even if the server reboots itself or something else,
20:41
I need to sudo systemctl enable myapp.service.
20:46
And now I can turn my Ubuntu instance off and on again.
20:50
And this application will start up.
20:52
It will always try to be running.
20:54
Even if it crashes, it will still try and run itself again.
20:57
And this is exactly what we want
20:58
with any of the applications we're running
20:59
on the EC2 instance.
21:00
We wanna make sure they're always running.
21:02
And we could double check that everything is good
21:04
with sudo systemctl status myapp.service.
21:09
And really what I'm looking for here
21:11
is that it's active and running.
21:13
And then if I wanted to view logs for my application,
21:15
I could run sudo journalctl fu
21:19
just to get the last logs to tail them.
21:21
And myapp.service.
21:24
And here are the logs coming out of my application right now.
21:28
If I were to go and test this out,
21:31
I don't know, let's say I save this QR code.
21:33
I think that should cause, yeah, some logs here.
21:35
So it saved that QR code now to the database.
21:37
And I can see the logs coming out here.
21:39
I could inspect those if I need to for whatever reason.
21:42
But I'm just gonna get out of this
21:43
because everything seems to be running pretty well.
21:46
But I am still using the IP address.
21:48
So the app's running, it's connected to the database.
21:51
It's working great, but I don't have a domain name.
21:54
So I really wanna set up a domain name right now.
21:56
And then we can use that in caddy
21:59
to have it generate a TLS certificate for us.
22:02
So I'm gonna head back over to Route 53
22:04
and go to the hosted zone.
22:07
And I'm gonna create, no, in my host zone, there we go,
22:10
play.cloudcoursexyz, I'm gonna create a new record.
22:14
And for this subdomain, I think I'll go qrec2 1,
22:18
the first version of this.
22:20
It's good to use a unique subdomain
22:21
for every single thing that you do
22:23
because these domains do get cached.
22:27
It's just simpler and quicker to just use a brand new domain
22:30
every single time you do something,
22:31
especially when we're just playing around here
22:33
in the Playground account.
22:34
So that's gonna be my domain name.
22:36
The value is gonna be the IP address of that EC2 instance.
22:39
So let's go back.
22:41
I got my simple web app.
22:42
I'm gonna copy that and paste that in.
22:45
And we're just setting up an A record for this.
22:46
So if I create that record, I should now,
22:50
let's see, let's make sure it's here,
22:51
qrec2 1.play.cloudcoursexyz,
22:54
I should be able to access my site through that domain name,
22:58
even though it's not using HTTPS,
22:59
but it is still, I'm able to access it through that.
23:02
So it's set up with HTTPS.
23:04
We already did this before.
23:05
I can go back to sudo vim/etc/cadi/cadi file.
23:10
And instead of having it be port 80 here,
23:16
I'm gonna paste in that entire domain name.
23:18
And then when I reload caddy,
23:19
it's gonna set up the TLS certificates for us.
23:21
So now if I just save this file
23:23
and sudo systemctl reload caddy,
23:26
this should now be working in such a way.
23:29
So before it was not secure,
23:30
if I refresh this, it should be trying to go to HTTPS.
23:35
I don't know why there's an issue there, HTTPS.
23:37
No, something went wrong.
23:39
Let's see, sudo journalctl caddy.
23:44
It looks mostly good.
23:46
I am gonna try maybe just restarting sudo systemctl reload.
23:51
Restart caddy.
23:53
Let's see if I can boot this thing.
23:54
Okay, so I think that just took a little bit of time.
23:56
It seems to be working now.
23:57
We are using this over HTTPS.
24:00
And now, yeah, this is a full stack application
24:03
that is working on an EC2 instance.
24:05
We can test this out and monitor it.
24:07
So I'm gonna run HTOP on my EC2 instance.
24:11
And this is just gonna show us metrics
24:13
about how much CPU and memory we're using.
24:16
So right now we don't have much CPU usage.
24:19
In fact, it's sometimes going
24:21
all the way down to 0%.
24:22
And that's because the application isn't being used.
24:24
And this is a great use case for a T-Series instance.
24:28
But we can see this being used.
24:30
So if I put these side by side, here is the CPU usage.
24:34
It's nothing right now.
24:35
But if I drag an image into this,
24:37
I designed this to not be the most efficient.
24:40
So if I put an image into my QR generator,
24:43
it's gonna convert this image to a QR code.
24:46
And we should see the CPU usage go up
24:48
just a little bit there.
24:49
And if I start playing,
24:51
playing around with these different settings,
24:53
you can monitor that CPU usage up there.
24:55
And you can see that processing these images
24:58
is taking more of a toll on the CPU.
25:00
And if I create, I don't know, let's go sammichward.com,
25:05
that is gonna use up the CPU a little bit.
25:07
But if I save this QR code now,
25:09
it's gonna go through all of these
25:11
and generate the QR code
25:13
for each of those individual types of image.
25:16
And we're gonna see it's still only hovering around 35%.
25:18
If I was doing this a few times, a few different QR codes,
25:20
it might peak to a hundred percent.
25:22
But this can just simulate how you,
25:24
a bunch of users or a bunch of user interactivity
25:27
on your server could increase the CPU usage.
25:30
That one doesn't even look,
25:31
yeah, this black and white doesn't work great.
25:32
Oh, that one's kind of cool.
25:33
Yeah, okay, so you can scan that
25:35
and it'll take you to sammichward.com.
25:36
And it's also storing all of this data in the database.
25:39
So on the EC2 instance still,
25:41
I could in the server directory, I think.
25:46
Yeah, there is the uploads directory.
25:50
It's storing all these images directly on the server.
25:53
Then if I were to go sudo mysql,
25:57
let's use the my app database.
26:00
And I can't remember the name of the tables, QR codes.
26:05
So I can select star from QR codes
26:09
and I can see those are my different QR codes.
26:11
And then if I would scan and use it,
26:13
I would see different uses in this database.
26:14
So this is just checking that everything is working.
26:18
Again, if I needed to check the logs
26:20
for my application, I could sudo journalctl myapp.service.
26:25
And I can see everything that's going on there.
26:30
So all of this, yeah, seems to be working.
26:31
I can monitor this all from the EC2 instance.
26:34
And you can monitor some of this stuff
26:37
from the web dashboard too.
26:38
So if I go to the instance details here
26:41
and we go down to monitoring,
26:44
we're not gonna be able to see the logs.
26:45
Right now, we'll have to set that up with CloudWatch
26:47
in a later part, but right now we can monitor things.
26:50
Like how much network is going in and out
26:53
of the EC2 instance, the CPU utilization
26:55
over a certain timeframe.
26:57
So right now this is one hour,
26:59
but pretty cool that we can monitor that here.
27:02
We can see the CPU credit balance for the T-Series instance.
27:06
So there's some amount of monitoring that you can do here.
27:09
You can also go over to CloudWatch
27:11
to monitor all of this in more detail.
27:13
And again, we're gonna get to a section on CloudWatch
27:15
where we can monitor one EC2 instance
27:17
or thousands of EC2 instances all in one place
27:19
without having to log in.
27:20
So I'm not gonna go into them,
27:21
but this is just kind of a basic setup,
27:22
a basic web app with basic monitoring for an EC2 instance.
27:26
And then just make sure that you go
27:28
and terminate this instance
27:30
and remove the Route 53 record when you're done with this.
27:33
So I'm gonna go instant state, terminate this
27:36
'cause I'm completely done with it now.
27:37
Then in Route 53, I'm gonna go select my record
27:42
and delete this record just to clean up after this part.
Cloud Course
Cloud Course
$89.70
$299.00 Lifetime
  • 81+ learning resources
  • 57 lessons and tutorials
  • 15 hands-on deployments
  • 9 quizzes
  • 29 videos (4h 17m 38s)
  • More content coming soon
  • Unlimited lifetime access to all course content
  • Deployment assessment CLI tool
  • Exclusive Discord access
Original Price:$299.00
Discount:-$209.30
Total:$89.70