If you are new to AWS, the confusing part is usually not launching EC2 itself. The real friction starts right after that: which ports should you open, when do you need an Elastic IP, and how do you expose an app to the internet without opening too much? This guide follows that exact flow.
When should you use EC2?
EC2 is a good fit when you need a Linux machine that keeps running for:
- deploying a backend
- running an internal database or Redis
- building a test environment
- hosting a web app, API, or worker
If you only need to run a small app and do not want to manage a server, ECS Fargate, App Runner, or Lightsail may be simpler. But if you want to understand AWS infrastructure from the ground up, EC2 is still the easiest starting point.
4 concepts to understand before clicking Launch
What is EC2 in this context?
Think of EC2 as a virtual machine running inside AWS. You choose:
- an operating system such as Ubuntu
- an instance type such as
t3.microort3.small - EBS storage
- network rules that define who can reach the machine
What is a Security Group?
A Security Group is the instance-level firewall. It decides:
- which ports are open
- which IPs are allowed in
- what traffic can go out
Examples:
- open
22for SSH - open
80for HTTP - open
443for HTTPS - do not expose
3306,5432, or6379publicly unless you really need to
What is an Elastic IP?
The default public IPv4 on EC2 can change after you stop and start the instance. An Elastic IP is a static public IP that helps when you need:
- stable DNS records
- a public IP that does not change after stop/start
- a long-running server
What does exposing an app publicly mean?
It means users on the internet can reach your app through:
- a public IP
- an Elastic IP
- or a domain pointing to that IP
To make this work, all 4 layers must be correct:
- the EC2 instance must have internet routing
- the Security Group must allow the right ports
- the OS firewall must not block them
- the app must listen on the correct address such as
0.0.0.0
Step 1: Launch your first EC2 instance
Open AWS Console -> EC2 -> Instances -> Launch instance.
Minimum setup:
Name: for examplemy-first-ec2AMI:Ubuntu Server 24.04 LTSInstance type:t3.microort3.smallKey pair: create one if you do not have one yetNetwork settings: allow SSH from your IP onlyStorage: 20 GB is enough for a small test box or web app
For a first machine, start with:
- only
SSHopen - source set to
My IP
Do not pre-open many ports unless you already know what the app needs.
Step 2: SSH into the instance
Once the instance is running, copy the public IP and connect:
chmod 400 my-key.pem
ssh -i my-key.pem ubuntu@YOUR_EC2_PUBLIC_IP
If SSH fails, check these first:
- the key file is correct
- port
22is open in the Security Group - the source for port
22matches your current IP - the subnet and route table have internet gateway access
Step 3: Understand Security Group rules the easy way
A common setup for a web app looks like this:
| Purpose | Port | Recommended source |
|---|---|---|
| SSH | 22 |
your IP |
| HTTP | 80 |
0.0.0.0/0 |
| HTTPS | 443 |
0.0.0.0/0 |
For an app running on 3000, 8000, or 8080:
- for quick testing, you can expose that port directly
- for production, it is better to keep the app internal and put Nginx in front on
80/443
Ports you usually should not expose directly:
- MySQL
3306 - PostgreSQL
5432 - Redis
6379 - MongoDB
27017
If those services must be reachable, prefer:
- allowing only private IP ranges
- allowing another Security Group
- or using SSH tunnels, a bastion host, or a VPN
Step 4: When do you need an Elastic IP?
If this machine will stay online for a while, serve a domain, or needs a stable public IP, attach an Elastic IP.
Go to:
EC2 -> Elastic IPs -> Allocate Elastic IP -> Associate Elastic IP
Attach it to the correct instance.
Good reasons to use an Elastic IP:
- production server
- domain-based access
- whitelisting your IP in third-party services
Cases where you may not need it yet:
- short-lived test machines
- temporary labs
Note: an allocated Elastic IP that is not attached can still incur charges. Release it if you no longer need it.
Step 5: Expose your app publicly with fewer mistakes
Quick way for testing
Assume your Node.js app runs on port 3000:
ss -tulpn | grep 3000
If the app is only bound to 127.0.0.1:3000, outside traffic cannot reach it. The app must listen on 0.0.0.0.
Example with Express:
app.listen(3000, "0.0.0.0");
Then add an inbound rule:
TCP 3000- source
0.0.0.0/0for temporary testing
At that point you can test:
http://YOUR_ELASTIC_IP:3000
Better approach for production
Do not leave port 3000 publicly exposed long term. Put Nginx in front:
sudo apt update
sudo apt install nginx -y
Example config:
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Enable it and reload:
sudo nginx -t
sudo systemctl reload nginx
At this point the Security Group only needs:
80443
Your backend stays internal on:
127.0.0.1:3000
This is cleaner because:
- fewer public ports
- SSL is easier
- swapping apps behind the proxy is easier
- logs and rate limiting are easier at the reverse proxy layer
How to make a domain point to it
Once you have an Elastic IP:
- go to your DNS provider
- create an
Arecord - point the domain or subdomain to the Elastic IP
Example:
api.example.com -> 3.25.xx.xx
If you use Nginx, you can then add HTTPS with Let's Encrypt or put the domain behind Cloudflare.
Common mistakes when exposing EC2
The Security Group is open but it still does not work
Usually one of these is wrong:
- the app is listening on
127.0.0.1instead of0.0.0.0 - Ubuntu
ufwis enabled and blocking the port - Nginx was not reloaded or the config is invalid
- you edited the wrong Security Group
Quick checks:
sudo ufw status
ss -tulpn
curl http://127.0.0.1:3000
curl http://YOUR_ELASTIC_IP
SSH works but HTTP does not
That usually means:
- port
22is configured correctly - but
80or443is not open in the Security Group - or the web server is not running
The IP changed after stop/start
That is the point where you need an Elastic IP. The default public IP is not meant to stay fixed long term.
Quick conclusion
If you only want the short version:
- launch Ubuntu on EC2
- open
22only for your IP - SSH into the machine
- run the app and make sure it listens on
0.0.0.0 - in production, expose it through Nginx on
80/443 - attach an Elastic IP if you need a stable IP or a domain
If you follow this flow, most “EC2 is running but I still cannot access it from outside” problems become much easier to debug.