Comprehensive Guide for Deploying Express, React, and Django Apps on AWS EC2 with SSL (Using Deploy Keys and PM2 for Express)
- Launch an EC2 instance on AWS with an appropriate configuration (Ubuntu, t2.micro, etc.) and ensure it is publicly accessible.
- Configure Security Groups:
- Open ports
22
(SSH),80
(HTTP), and443
(HTTPS) to allow web traffic.
- Open ports
SSH into your EC2 instance:
ssh -i /path/to/your-key.pem ubuntu@<your-ec2-public-ip>
-
Update your system:
sudo apt update && sudo apt upgrade -y
-
Install Nginx:
sudo apt install nginx -y
-
Install Certbot (for SSL certificates):
sudo apt install certbot python3-certbot-nginx -y
-
Install Git (to clone the private repo):
sudo apt install git -y
-
Install Node.js and PM2 (for Express):
sudo apt install nodejs npm -y sudo npm install -g pm2
-
Install Python and other dependencies (for Django):
sudo apt install python3-pip python3-dev libpq-dev nginx -y
Before deploying the app, clone your private Git repository using SSH deploy keys.
-
Generate a new SSH key pair:
ssh-keygen -t rsa -b 4096 -C "deploy-key-for-git-repo" -f ~/.ssh/deploy_key
-
This creates a private key (
deploy_key
) and a public key (deploy_key.pub
) in the~/.ssh
directory.
-
Copy the contents of the public key:
cat ~/.ssh/deploy_key.pub
-
Go to your GitHub repository:
- Navigate to Settings → Deploy Keys → Add deploy key.
- Paste the content of the
deploy_key.pub
file. - Optionally, allow write access if required for your repo.
-
Create or edit the SSH config file:
nano ~/.ssh/config
-
Add the following configuration to ensure SSH uses the deploy key for GitHub:
Host github.com HostName github.com User git IdentityFile ~/.ssh/deploy_key IdentitiesOnly yes
-
Ensure proper permissions on the SSH key:
chmod 600 ~/.ssh/deploy_key
Clone your private repository using SSH:
git clone [email protected]:<your-username>/<your-repo-name>.git
This clones your repository into the current directory.
-
Navigate to your cloned Express app directory:
cd /path/to/your/express-app
-
Install app dependencies:
npm install
-
Start the app with PM2:
pm2 start npm --name "express-app" -- start
-
Save the PM2 process list (so PM2 can restart it automatically on reboot):
pm2 save
-
Configure Nginx to proxy the app (edit
/etc/nginx/sites-available/default
):server { listen 80; server_name <your-ec2-public-dns>; location / { proxy_pass http://localhost:3000; # Assuming your app runs on port 3000 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
-
Restart Nginx to apply changes:
sudo systemctl restart nginx
-
Install Node.js:
sudo apt install nodejs npm -y
-
Navigate to your cloned React app directory:
cd /path/to/your/react-app
-
Build the React app:
npm install npm run build
-
Configure Nginx to serve the build folder:
server { listen 80; server_name <your-ec2-public-dns>; location / { root /path/to/your/react-app/build; try_files $uri /index.html; } }
-
Restart Nginx:
sudo systemctl restart nginx
-
Install Gunicorn:
pip install gunicorn
-
Start the Django app using Gunicorn:
gunicorn --workers 3 --bind unix:/path/to/your/django-app/django.sock your_project_name.wsgi:application
-
Configure Nginx to proxy Gunicorn:
server { listen 80; server_name <your-ec2-public-dns>; location / { proxy_pass http://unix:/path/to/your/django-app/django.sock; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
-
Restart Nginx:
sudo systemctl restart nginx
-
Ensure your EC2 instance is publicly accessible (i.e., your app should be reachable via HTTP on port 80).
-
Obtain an SSL certificate using Certbot:
sudo certbot --nginx -d <your-ec2-public-dns> -d www.<your-ec2-public-dns>
Certbot will automatically:
- Verify domain ownership.
- Install the SSL certificate.
- Configure Nginx to serve HTTPS traffic.
-
Test SSL Configuration: After running Certbot, you can visit
https://<your-ec2-public-dns>
to verify that your site is secured with HTTPS. -
Renewal: Certbot automatically handles renewals. You can test the renewal process with:
sudo certbot renew --dry-run
Certbot automatically configures Nginx for HTTPS, but if needed, you can manually adjust your Nginx configuration file (/etc/nginx/sites-available/default
) to ensure it's set up correctly for SSL:
server {
listen 443 ssl;
server_name <your-ec2-public-dns>;
ssl_certificate /etc/letsencrypt/live/<your-ec2-public-dns>/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/<your-ec2-public-dns>/privkey.pem;
# Other SSL configurations (e.g., security headers)
location / {
proxy_pass http://localhost:3000; # For Express, or update based on app type
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 80;
server_name <your-ec2-public-dns>;
return 301 https://$host$request_uri;
}
This configuration redirects all HTTP traffic to HTTPS.
For Django apps, it’s good practice to set up systemd for automatic management of Gunicorn:
-
Create a systemd service file for Gunicorn:
sudo nano /etc/systemd/system/gunicorn.service
-
Add the following configuration:
[Unit] Description=gunicorn daemon for Django project After=network.target [Service] User=ubuntu Group=www-data WorkingDirectory=/path/to/your/django-app ExecStart=/path/to/your/virtualenv/bin/gunicorn --workers 3 --bind unix:/path/to/your/django-app/django.sock your_project_name.wsgi:application [Install] WantedBy=multi-user.target
-
Start and enable the Gunicorn service:
sudo systemctl daemon-reload sudo systemctl start gunicorn sudo systemctl enable gunicorn
After completing these steps, test your application by visiting https://<your-ec2-public-dns>
in your browser. You should see your app running securely with an SSL certificate.
This guide covers the entire process of deploying a single app (Express with PM2, React, or Django) on an AWS EC2 instance. It includes steps for:
- Cloning the app from a private Git repository using deploy keys.
- Setting up PM2 to manage the Express app.
- Setting up Nginx to serve the app.
- Obtaining and configuring SSL certificates using Certbot.
- Optionally setting up systemd for Django apps.
The process is designed to be clear, efficient, and secure for production deployments.
Let me know if you need more assistance!