This guide walks through all steps to deploy a full-stack MERN app (MongoDB, Express, React, Node.js) on an EC2 instance using Docker, GitLab CI/CD, and SSH keys.
EC2-Tutorial.pem
)
chmod 400 EC2-Tutorial.pem
ssh -i /path/to/EC2-Tutorial.pem ubuntu@<Public_IP>
sudo apt update && sudo apt install docker.io docker-compose -y
sudo usermod -aG docker $USER
newgrp docker
git clone git@gitlab.com:your-username/networth-Tracker.git
On your local machine:
ssh-keygen -t rsa -b 4096 -C "gitlab-deploy"
# Save as ~/.ssh/gitlab-deploy
Add to GitLab
SSH_PRIVATE_KEY
with contents of
~/.ssh/gitlab-deploy
Add to EC2
cat ~/.ssh/gitlab-deploy.pub # Copy this
ssh -i EC2-Tutorial.pem ubuntu@<EC2_IP>
echo "<paste_here>" >> ~/.ssh/authorized_keys
Ensure structure:
networth-Tracker/
├── backend/
│ ├── Dockerfile
│ ├── .env
│ └── ...
├── frontend/
│ └── Dockerfile
├── docker-compose.yml
└── .gitlab-ci.yml
docker-compose.yml
services:
frontend:
build: ./frontend
ports:
- "3000:80"
depends_on:
- backend
backend:
build: ./backend
ports:
- "5000:5000"
env_file:
- ./backend/.env
depends_on:
- mongo
mongo:
image: mongo
ports:
- "27017:27017"
.gitlab-ci.yml
stages:
- deploy
deploy_to_ec2:
stage: deploy
before_script:
- "which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )"
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan -H <Elastic_IP> >> ~/.ssh/known_hosts
script:
- ssh ubuntu@<Elastic_IP> "cd ~/networth-Tracker && git pull && docker-compose down && docker-compose up -d --build"
only:
- main
<Elastic_IP>
in GitLab and local SSH
commands
git add .
git commit -m "Initial commit"
git push origin main
http://<Elastic_IP>:3000
docker system prune -af
on the EC2 instance to free
up space.
~/.ssh/authorized_keys
and GitLab’s
private key is valid.
.gitlab-ci.yml
has been committed and pushed with the
new IP. Trigger a fresh pipeline, not just a retry.
docker rm <container-id>
or
docker-compose down
.
git pull
fails due to ref mismatch, run
git fetch --all && git reset --hard origin/main
on
the EC2.
docker-compose up -d
or
set up a systemd service or cron job to restart Docker on reboot.
http://localhost
with your actual Elastic IP when
deployed.