Own your Setup for Side Projects
Roll your VM with all your side project running on custom domains with SSL (includes setting up nginx & certbot setup)
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
pem
file and store it safely.- To connect to your VM using SSH, you now need to run a command like
That almost wraps part of the things we will do in the browser. ๐๐ปโโ๏ธssh -i "my.pem" ubuntu@<public-dns-of-ec2-instance>
[BONUS] โจ Connect from VS Code
- Add an entry in your
~/.ssh/config
as 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
machineName
and 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
- Node 14.x
โ 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
gunicorn
orpm2
as 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.