Own your Setup for Side Projects
May 01, 2024
Let's start by talking about side projects, we all start them and some of us finish a few too 😛. But most of the side projects are for fun/PoC and end up getting deployed on free services like Heroku/Glitch for backend or Vercel/Netlify for frontend.
And those are a great set of services to start with, in fact, tools that host static sites rarely ask for money for features like 100% uptime (duh!) and SSL for custom domains, but for services that hosts your servers for you, sooner or later will find a way to ask for money.
Context switching closer to the post title, recently one of my Node Servers which was hosted on Heroku (surviving on GitHub Student Pack Credits ❤ on Hobby Plan) lost the ability to use SSL with a custom domain 😟, as Heroku doesn't allow you to use a custom domain with SSL on free plans.
This was a trigger and I decided to take an EC2 instance (you can take a similar machine on GCP, Azure, DigitalOcean, etc.) and set up all my servers there themselves with custom domains (yes! with SSL).
Let's begin!
☁ Setup your EC2 Instance (or similar instances)
-
Make an AWS account and get a free tier VM, I have suggested some options below:
- AMI -> Ubuntu Server 20.04 LTS (HVM), SSD Volume Type (64-bit (x86))
- Instance Type -> Choose
t2.micro - Rest is almost default which is 8GB storage & 1GB RAM
- Also, you can whitelist Traffic Type, Port and IPs in Security Group Step and Launch the Instance.
-
Generate a key pair and download the
pemfile and store it safely. -
To connect to your VM using SSH, you now need to run a command like
ssh -i "my.pem" ubuntu@`<public-dns-of-ec2-instance>`
That almost wraps part of the things we will do in the browser. 🙆🏻♂️
[BONUS] ✨ Connect from VS Code
- Add an entry in your
~/.ssh/configas below:
Host machineName
User ubuntu
HostName `<public-dns-of-ec2-instance>`
IdentityFile `<path-to-my.pem-file>`
- Install Remote-SSH
- Press Ctrl/Cmd + Shift + P and write
Connect to Host - Select
machineNameand it's done! 🤝🏻
📦 Configure your machine
- First things first, the machine comes with Ubuntu 20, but we might need more stuff, so lets update the package lists
sudo apt-get update
- Next is I'll recommend creating a separate folder and then clone the repos you want to host.
- For ease generate SSH Key and add it to GitHub, for generation use these commands and output is your public SSH Key.
ssh-keygen -t ed25519 -C "your-github-email"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub
- Now install all the dependencies that you'll need (unless using docker images), I'll show a few below
- Node 14.x
curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
sudo bash nodesource_setup.sh
sudo apt install -y nodejs
node -v
- pm2 (process manager for keeping your servers running)
sudo npm i -g pm2
⚒ Install nginx & certbot
- nginx or NginX, is a web server that can also be used as a reverse proxy, load balancer, mail proxy, and HTTP cache. We'll quickly install and enable it.
sudo apt install nginx
sudo systemctl enable nginx
sudo systemctl start nginx
- certbot 🤖 is a tool which generates free & legit SSL Certs 🔐 using LetsEncrypt, it also has features auto-renew. We'll install certbot service and nginx plugin for the same
sudo apt-get install certbot # for certbot
sudo apt-get install python3-certbot-nginx # for python plugin
We are all ready with dependencies, now we'll move to the final steps.
👨🏻💻 Starting your applications and Adding Domains
- Now you need to start your servers either on
gunicornorpm2as per your need. To start with pm2, say your program starts withnpm run start, then use
pm2 start "npm run start" --name "your-api"
At this stage if your API runs on say port 1337, you can access the API at http://<public-ip-of-instance>:1337
Now let's add the domain to it. For that first, you need to make a DNS Record Entry.
Type: A
Name: `@`(if you want to use domain) else `subdomain`
Value: `<public-ip-of-ec2-instance>`
TTL: as per your requirement
Once this entry is created, now we need to generate SSL Cert and Private key on our side.
Generate a certificate for your domain/subdomain using the command below and answer the prompts as needed
sudo certbot certonly --nginx
This command finished by creating two files at
/etc/letsencrypt/live/<your-domain>/fullchain.pem
/etc/letsencrypt/live/<your-domain>/privkey.pem
Now let's set up Nginx for your server Suppose you want to run your server running on 1337 port on your-domain, then
cd /etc/nginx/sites-available
nano your-domain.conf
Now few things, we first create the file in sites-available so that we don't mess up directly with nginx, once we test the config, then we create a soft link to the same in sites-enabled which is where nginx looks up while mapping requests.
In your-domain.conf, add the following content and replace <your-domain>
server {
listen 80;
listen 443 ssl;
server_name `<your-domain>`;
ssl_certificate /etc/letsencrypt/live/`<your-domain>`/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/`<your-domain>`/privkey.pem;
location / {
proxy_pass http://localhost:1337;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Now let's make a soft link as promised
cd /etc/nginx/sites-enabled
sudo ln -s ../sites-available/your-domain.conf .
After you are done with this, let's test our conf file ✅
sudo nginx -t
if all is well, you can signal nginx to reload configs
sudo nginx -s reload
Now your API can be accessed at your-domain 🎉
So, you have completed a one-time setup of your EC2 instance and deployed one of your APIs on a custom domain.
In the same way, you can add as many side projects as you want to the same machine and redirect internally to another port.