Deploying your applications on AWS EC2 with Caddy reverse proxy
Tags: aws, webdev, cloud, devops
Published: 2022-08-18 17:46:34

---
title: Deploying your applications on AWS EC2 with Caddy reverse proxy
published: true
date: 2022-08-17 18:11:26 UTC
tags: aws,webdevelopment,cloud,devops
canonical_url: 
---

![Header Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/93jyij2629z63lw61o0p.jpg)

#### Serving your applications through HTTPS reverse proxy

In this tutorial, I am going to discuss how to deploy your containerized applications on an AWS EC2 (Elastic Compute Cloud) instance with a reverse proxy, so you can use your domain to access multiple apps running in the same instance.

Let’s begin with setting up our infrastructure on AWS. Login to your AWS console and navigate to the EC2 page.

![search ec2 on aws dashboard](https://cdn-images-1.medium.com/max/1024/1*O6ZAUYhT2YEA-sDVFCHYkA.png)

Next, click on the Launch Instance button and follow the steps to set up a server.

Remember to select the “Ubuntu” image for OS and instance type as “t2.micro” which is eligible for the always free tier.

![](https://cdn-images-1.medium.com/max/1024/1*LgAy8HL0WYCvyEMeFXHnyA.png)

Create a key pair for SSHing into your server later on. Use the .ppk format for your keys as shown below. Download and safely store this key file to access your server in the future. Leaving other settings to default, click on “Launch Instance”.

![](https://cdn-images-1.medium.com/max/802/1*kVVSSJYIshIABEYroa1jGw.png)

Since you will be using a domain name for your server, you need to get the IP address of the server. Still, every time you stop/start your server, it gets a new IP address, so for this problem, AWS has a feature for an Elastic IP that remains constant, you can link this IP to any of your EC2 instances. In the side panel, under “Network & Security” open the Elastic IP page and click on “Allocate Elastic IP address” and a new permanent IP address will be added to your dashboard.

![](https://cdn-images-1.medium.com/max/1024/1*7kaCI90VFI0CY-eDM7xsag.png)

Now click on the new IP address and click on “Associate Elastic IP address” and then in the instance dropdown, select your instance name and allocate this permanent address.

Now, let’s set up our environment to login into our server. I prefer using [Termius](https://termius.com/) for logging into my servers. If you are a student, you can get this for free using the [github student pack](https://termius.com/education?utm_source=github+termius). You can also use PuTTy or just the ssh command in your terminal for logging in, there are various tutorials for that. I going with Termius for this one. Once you downloaded and installed the client, let’s add our server to the client.

![Termius client](https://cdn-images-1.medium.com/max/1024/1*RvpvoIokOj51kO8UAs6qlw.png)

Click on Add > New Host, then in the side panel, add the label, the Elastic IP address which we created, then in the ssh panel, click the keys, and add in your .ppk key which you created and saved earlier. In the username, add “ubuntu”, you can also customize the terminal theme by scrolling down, and that's it, you created a profile for SSHing into your server. Now just double-click on your host and you will be connected to your server. Easyy!

Now that you have your infra set-up, let’s prepare our machine by installing some tools like Docker and Caddy to prepare it for hosting.

Enter the commands in order to install the Docker engine on your instance

```
sudo apt-get update

sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release

sudo mkdir -p /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
```

This should install docker in your instance, to verify, enter docker version . If there exists any problem refer to [original docs](https://docs.docker.com/engine/install/ubuntu/).

Next, let us install the Caddy server :

```
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https 

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg 

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list 

sudo apt update 

sudo apt install caddy
```

Run caddy to verify. With this, you will have the necessary software to deploy your application.

Next, let’s clone our project from GitHub in our server using git clone and also create a configuration file for Caddy. To create the configuration file or Caddyfile , run touch Caddyfile , it will create the file in your pwd (present working directory)

![](https://cdn-images-1.medium.com/max/375/1*zRUeZk3xPz13CbyYBiy-bQ.png)

Now, to run your application with docker, you must either have a Dockerfile in your project directory or a docker image in the docker hub. Here, I am building my own image from a Dockerfile , you can pull it from docker hub too using docker pull command.

To build from the Dockerfile , cd into your project folder, for me it is cd portfolio , and run the command :

```
docker build . -t <your app name>:latest
```

> If you want to learn more about containers and using docker, you can check out my other blog [here](https://medium.com/developer-student-clubs-tiet/containerization-and-using-docker-e75b9e67d3fd).

If you don't have a Dockerfile in your project, you can search for configurations specific to your project. I have created a sample for a react-app.

```
FROM node:18-alpine3.14
WORKDIR /app
COPY package.json .
COPY package-lock.json .
RUN npm ci
COPY . .
CMD ["npm","run","start"]
```

> Put this into the root of your folder, and also create a .dockerignore to ignore any file you don't want to copy into the container like node\_modules as it will create its own node modules. Commit these files and push it to github, and pull the changes to the server.

Now run the docker build command given above, then run docker images , it will show the images available to docker.

Now to run the container for your app, run the following command to start a running service for your image

```
docker run -p 3000:3000 -d <image id>
```

The -p flag is to bind a port from the host to the container (3000:3000 means 3000 port of our host to 3000 in the container since the react app works on this port by default) and -d is to run the container in the background in the detached mode.

![](https://cdn-images-1.medium.com/max/921/1*6FYxts5JFzNL2K27sgQSjA.png)

This should start and expose your app on your public Elastic IP address. To view the app using your IP address, you will first need to create a security rule to allow incoming traffic on port 3000. In your AWS console, on the EC2 dashboard, go to the security groups and click on the id, to open and edit it.

![](https://cdn-images-1.medium.com/max/1024/1*AaQHvOP8EDYymRW4v5or6w.png)

In the security rules, add an inbound rule of type “Custom TCP” with a port range of 3000 and source as anywhere, save the rules and you are ready to go. Now enter the URL http://{Elastic IP address}:3000 and you should be able to see the react app.

> Notice that you are currently using HTTP protocol and your connection is not secure, we will be using the Caddy server for reverse proxy which automatically provisions a TLS/SSL certificate and renews it giving your domain HTTPS capabilities.

Now, for the last part, let’s set up the reverse proxy with the Caddy server. You should have a domain name with you, if not, you can get one for free on name.com, Namecheap or a .tech domain using the Github Student pack. Now go to your domain name provider, and edit the DNS records for your domain to point at the server.

> Add two (one for @ and other for www) A records in the DNS setting with the value of Elastic IP. An A record id used to point to an IP address.

![](https://cdn-images-1.medium.com/max/1024/1*8nVhcS5XTsg6wZLqmSIaiw.png)
_Adding record on Cloudflare_

@ root stands for the base domain like example.com, abcd.tech etc., similarly for using your domain like www.example.com, replace @ with www, pointing to the same IP. In this way, you can add multiple subdomains in the name field pointing to various servers.

> Remember to turn off any proxy from the DNS provider as we will create our own proxy server.

> Reverse proxy is a service which sits in front of our applications and listens on port 80 (HTTP) and port 443 (HTTPS) ports and directs our request to specific ports hosting various services. Using this, we can host multiple applications in a single server with our reverse proxy redirecting according to specified subdomains or paths. You can read more about it [here](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/).

Now let's create our reverse proxy, and edit the Caddyfile which we previously created using vim by executing the following command to open the vim editor (vim Caddyfile) .

> To edit the file, press i, then press escape key when you are done with changes. To save and exit, type :wq

![](https://cdn-images-1.medium.com/max/1024/1*shO9YXuLTSW54u0CSi2Q5w.png)

Caddyfile serves as the configuration file for the caddy server. It has a highly human readable and straight-forward syntax. To create a reverse proxy server, we just have to write the following code, and it will spin up a highly robust and production grade reverse proxy server.

```
yourdomain.com {
   reverse_proxy localhost:<port number of your service>
} 

# you can repeat this setup for multiple domains since we are using the www subdomain to, lets add it (the spaces are important in syntax)

http://www.yourdomain.com {
   reverse_proxy localhost:3000
}
```

> You can read more about Caddy and its syntax in the documentation [here](https://caddyserver.com/docs/getting-started).

Now you are all set, just run caddy run to start the servers and see the logs or caddy start to start the server in the background. This will spin up the server and it will provision the TLS/SSL certificates for your domain which will take some time, after which you can see your application running on your domain.

> Here, the server is listening on port 443 for HTTPS and forwarding the requests to internal ports as specified in Caddyfile, 3000 in our case.

In a similar fashion, you can create images of your application, run them on different ports, add subdomain in your DNS records pointing to your Elastic IP and lastly add block for your subdomain in Caddyfile and run caddy reload and voila, you can run multiple services in a single server with various subdomains served through a HTTPS reverse proxy.

### Conclusion

In this way, you can containerize multiple applications and deploy them on AWS EC2 instance and provide subdomains for access. If you have any doubts or errors on any do comment or ping me on discord at utkarsh#9378. Do share and give a like if this article helped you.

> See you again reader !! 😊👋

-Utkarsh Tripathi
Microsoft Learn Student Chapter, Thapar University, Patiala