← Back to blog
Series · Part 1May 1, 2025·7 min read

Building Our Own Vercel
Part 1: EC2 + Nginx Setup

Have you ever wondered how Vercel generates a unique subdomain for every deployment and maps it to your project instantly? In this series, we build that exact system ourselves — from scratch. By the end, you'll have your own deployment platform running.

HC

Hari Charan

Full Stack Developer

Series — Building Our Own Vercel
Part 1EC2 + Nginx Setup ← you are here
Part 2Subdomain Mapping with Nginx
Part 3File Upload + S3 Bucket
Part 4Wiring It All Together

What are we actually building?

Have you ever pushed a project to Vercel and noticed you get a URL like my-app-git-main-yourname.vercel.app within seconds? Each deployment gets its own subdomain, its own isolated environment, and it just works.

Have you wondered what's actually happening under the hood? There's no magic — it's a combination of a reverse proxy, subdomain routing, and some smart file serving. And we're going to build exactly that ourselves, step by step, across this series.

Here's the rough plan across the four parts:

  • Part 1 (this one) — spin up an EC2 instance, install Nginx, confirm it's running
  • Part 2 — configure Nginx to route subdomains to different folders
  • Part 3 — handle file uploads and connect an S3 bucket
  • Part 4 — wire it all together into one working deployment flow

By the end of Part 1, your goal is simple: visit your EC2 instance's public IP in a browser and see the Nginx welcome page. That's it. Small win, solid foundation.


Why Nginx?

Nginx (pronounced engine-x) is one of those tools that shows up everywhere once you start looking — and for good reason. It's open source, insanely performant, and used by some of the largest platforms in the world.

For our purposes, Nginx does a few key things:

  • Reverse proxy — receives a request and forwards it to the right place
  • Subdomain routing — checks the Host header and decides where to send traffic
  • Static file serving — can serve HTML/CSS/JS directly without a Node process
  • Load balancing — distribute traffic across multiple servers (we'll get there)

For this series, Nginx is the core piece that makes subdomain mapping possible. When a request comes in for abc123.yourdomain.com, Nginx intercepts it, reads the subdomain, and serves the matching project files. That's the whole trick.


Step 1 — Create an EC2 Instance

You need a server. For this series we'll use AWS EC2, but Google Cloud Compute or any VPS (DigitalOcean, Hetzner) works fine — the setup is identical once you're inside the terminal.

1

Launch the instance

Go to AWS Console → EC2 → Launch Instance. Pick Ubuntu 22.04 LTSas your AMI — it's free tier eligible and has the best community support. For instance type, t2.micro is fine to start.

2

Download your .pem key

When prompted to create a key pair, download the .pemfile and keep it safe. You'll use this to SSH into the instance. You can't download it again.

3

Set up the Security Group

This is the firewall. You need to open two ports in the inbound rules:

TypePortSource
HTTP800.0.0.0/0
SSH220.0.0.0/0

In production you'd restrict SSH to your own IP, but for now this is fine.

4

SSH into the instance

Once the instance is running, grab the public IP from the console and connect:

bash
# Fix the key file permissions first (required)
chmod 400 your-key.pem

# Connect — replace with your actual public IP
ssh -i your-key.pem ubuntu@YOUR_PUBLIC_IP

You should land in the Ubuntu terminal. If you're seeing a connection refused error, the instance is probably still initializing — wait 30 seconds and retry.

💡Your public IP is on the EC2 console next to the instance. It looks like 3.84.xx.xx. Note that it changes every time you stop and restart the instance — we'll deal with that in a later part using an Elastic IP.

Step 2 — Run the Setup Script

Once you're inside the server, here's the setup script. It installs Nginx, Node.js 20, npm, git, and creates the directory structure we'll use to serve project files later.

bash
#!/bin/bash
sudo apt update
sudo apt install -y nginx nodejs npm git

# Install Node.js 20 via the n version manager
sudo npm install -g n && sudo n 20

# Create the directory where project sites will live
sudo mkdir -p /var/www/sites
sudo chown -R ubuntu:ubuntu /var/www/sites

# Set up Nginx config
sudo cp nginx.conf /etc/nginx/sites-available/myplatform
sudo rm -f /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/myplatform /etc/nginx/sites-enabled/

# Apply the new config
sudo systemctl reload nginx

You can either paste this line by line or save it as a setup.sh file and run it:

bash
# Make it executable and run
chmod +x setup.sh
./setup.sh
ℹ️We're referencing a nginx.conffile in this script — we'll write that properly in Part 2 when we set up subdomain routing. For now, Nginx's default config is already enough to confirm everything is working.

Step 3 — Confirm Nginx Is Running

After the script finishes, check that Nginx started correctly:

bash
sudo systemctl status nginx

# You should see something like:
# ● nginx.service - A high performance web server
#    Active: active (running) since ...

If it says active (running)— you're good. Now open your browser and visit your EC2 instance's public IP:

bash
http://YOUR_PUBLIC_IP

✓ What you should see

A plain white page that says "Welcome to nginx!" with some text below it. That's the default Nginx page. If you're seeing it — Nginx is running, your security group is open, and the server is reachable. That's everything we need for Part 1.

⚠️Make sure you're visiting http:// not https://— we haven't set up SSL yet. Your browser might try to redirect you to HTTPS automatically. If the page doesn't load, force http://YOUR_IP in the address bar.

Troubleshooting

SSH: Permission denied

Run chmod 400 your-key.pem first. The key file permissions have to be restricted.

Browser: connection timed out

Check your security group. Port 80 (HTTP) must be open with source 0.0.0.0/0.

Nginx not starting

Run sudo nginx -t to check for config errors. Also check sudo journalctl -u nginx for logs.

Page loads but shows default Apache page

Apache might already be installed. Run sudo systemctl stop apache2 && sudo systemctl start nginx.


Where We Are

That's Part 1 done. You have a live Ubuntu server on EC2, Nginx is installed and running, and you can hit it from a browser. It's not doing anything useful yet — but the foundation is in place.

In Part 2, we get into the actual interesting part: configuring Nginx to read the subdomain from an incoming request and route it to the right folder. That's the core mechanism behind how Vercel (and tools like it) work. See you there.


Part 1 of 4Part 2: Subdomain Mapping →