Website hosting with AWS EC2, API Gateway and Vercel
This is a personal-use post for hosting a full-stack website for public access. Everytime I wanted to deploy a new website, I had to go through several tutorials and stuck in the same problems over and over again. Therefore, I decide to record the whole process in this post based on my previous experience, so that I can deploy my website smoother in the future.
(P.S. Screenshots will be uploaded in the near future)
Backend
The backend will be hosted on AWS EC2. First, check if your AWS account still has enough free tier usage (i.e., it’s in the first 12 month). If you can afford, never mind. Otherwise, create a new account.
Security Group
Two SG should be created: one for ssh connection, one for internet access
ssh-sg:
- inbound: SSH-TCP-22-Custom-0.0.0.0/0
- outbound: All traffic-All-All-Custom-0.0.0.0/0
internet-sg:
- inbound: Custom TCP-TCP-4000-Custom-0.0.0.0/0, HTTP-TCP-80-Custom-0.0.0.0/0, HTTPS-TCP-443-Custom-0.0.0.0/0
- outbound: All traffic-All-All-Custom-0.0.0.0/0
EC2 instance
Linux, t2.micro, select a key pair, put 2 SGs in, launch.
After the instance is successfully launched, connect it via SSH. (in aws/local terminal)
Initialize machine
Run the following code to update the environment:
sudo apt update
sudo apt install nodejs -y
sudo apt install npm -y
sudo npm install --global yarn
sudo npm i ts-node --g
sudo snap install docker
sudo docker version # check if success
Repository download
Generate an SSH Key for GitHub access:
ssh-keygen
Then paste the public key into GitHub Settings.
Select a location to clone the GitHub repository. Remember to check some configuration such as the base url and port.
Direct to that folder.
Add a .env file if your app uses environment variables. Then go into the file and paste in your environment variables.
touch .env
sudo nano .env
First Test
Run the application. The terminal should show success message. We cannot access through the ip yet, since the port isn’t accessible right now.
npm install
node server.js
If you encounter this problem:
session: options?.session,
^
SyntaxError: Unexpected token '.'
Just update your Node.js:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
nvm ls-remote
nvm install <version>
nvm use <version>
Add NGINX with Docker
NGINX: a highly popular open-source web server, reverse proxy server, load balancer, and HTTP cache.
Go to root directory, install NGINX, and go to that directory.
cd ~
git clone https://github.com/coderaidershaun/nginx-with-docker.git
cd nginx-with-docker
sudo nano nginx.conf # modify the config file
Modify the conf file following the comment, change all the “frontend” part to “backend”. Then build the docker image(might take some time):
tips for nano: save&exit is Ctrl+O, Enter, Ctrl+X
sudo docker build -t nginx-with-docker . --no-cache
Permanently running service
We need to keep the NGINX and backend running all the time even after system reboot.
For NGINX:
cd ~
sudo nano /etc/systemd/system/reverseproxy.service
Paste this in the service file:
[Unit]
Description=Reverseproxy Service
After=network.target
Wants=network.target
[Service]
Type=simple
Restart=always
RestartSec=5
ExecStart=sudo docker run -p 80:80 nginx-with-docker
[Install]
WantedBy=default.target
Then start the service:
sudo systemctl enable reverseproxy
sudo systemctl start reverseproxy
sudo systemctl status reverseproxy
The status should show “active (running)” in green.
Other useful code for debug:
sudo systemctl daemon-reload
sudo systemctl stop reverseproxy
sudo journalctl -fu reverseproxy.service
For Backend:
cd ~
sudo nano /etc/systemd/system/backend.service
You should find the path of your new version of node.js using “whereis node”. Then remember to change the path in below.
Paste this in the service file:
[Unit]
Description=Backend Service
After=network.target
Wants=network.target
[Service]
Type=simple
Restart=always
RestartSec=5
ExecStart=/home/ubuntu/.nvm/versions/node/v20.11.1/bin/node /home/ubuntu/movipendent/backend/server.js
[Install]
WantedBy=default.target
Then start the service:
sudo systemctl enable backend
sudo systemctl start backend
sudo systemctl status backend
Second test
Now access your endpoint through HTTP, you should see your server working.
Frontend
Somehow my EC2 t2.micro always fails when I try to run frontend and backend simultaneously, so I turn to Vercel to host my frontend.
The steps on Vercel are quite straight-forward, just connect to your gitHub repository and modify the backend url in config file. The most critical issue is to establish a connection between Vercel as HTTPS to EC2 instance as HTTP.
API Gateway
AWS API Gateway can expose an HTTPS endpoint that communicates with your backend over HTTP. This way, your frontend can make secure HTTPS requests to the API Gateway, and the API Gateway handles communication with your backend over HTTP.
First, create API in AWS API Gateway. If the backend follows a RESTful pattern, select REST API
Now build your API branches in “Resources”: you can add resources under a path, and create a method for this resource. For the endpoint, enter the actual endpoint that is running on your EC2 instance. Also, enable CORS for each endpoint (both 4XX, 5XX, GET method) In my case, I need to click “enable CORS” and configure for twice until the CORS is actually enabled.
-
GET method with a query: besides assigning the query when creating this method, you also make other configurations. In Integrations request - URL query string parameters, add the mapping relation (see its info for detailed format)
-
POST or DELETE method with a request body: in the method request, find the “Request body” at the last row. Add a model with content type of “application/json” and Model of “empty”.
After all the configuration, deploy the APIs as one stage, and it’s all done, CONGRATULATIONS!
Enjoy Reading This Article?
Here are some more articles you might like to read next: