Adding SSL with Let's Encrypt on EC2 Free HTTPS for Your Node.js App
Learn how to add free SSL certificates with Let's Encrypt and Certbot on AWS EC2, enabling HTTPS for your Node.js application with automatic renewal.
Adding SSL with Let's Encrypt on EC2
SSL (HTTPS) is essential for production web apps. It encrypts traffic, protects user data, and is required for features like HTTP-only cookies with secure: true. Let's Encrypt provides free SSL certificates.
Prerequisites
- An EC2 instance with Nginx configured
- A domain name pointing to your EC2 public IP (via A record in DNS)
- Ports 80 and 443 open in your security group
- Nginx running and responding on port 80
Step 1: Install Certbot
sudo apt update sudo apt install -y certbot python3-certbot-nginx
Certbot is the tool that automatically obtains and installs Let's Encrypt certificates.
Step 2: Verify Your Domain
Before getting an SSL certificate, Let's Encrypt verifies that you control the domain. Ensure:
- Your domain (e.g., api.yourdomain.com) has an A record pointing to your EC2 public IP
- Nginx is running and responding on port 80
- Your Nginx server_name matches the domain
Test by visiting http://api.yourdomain.com in a browser you should see your API response.
Step 3: Obtain the SSL Certificate
sudo certbot --nginx -d api.yourdomain.com
Certbot will:
- Verify domain ownership
- Obtain the SSL certificate
- Automatically modify the Nginx configuration to use HTTPS
- Set up HTTP to HTTPS redirect
Follow the prompts:
- Email: Enter your email for expiry notifications
- Terms of service: Agree
- Share email: N (optional)
- Redirect: Choose option 2 (redirect all HTTP to HTTPS)
Step 4: Verify HTTPS
Visit https://api.yourdomain.com in your browser. You should see the padlock icon indicating a secure connection.
Test with curl:
curl -I https://api.yourdomain.com/api/health # HTTP/2 200 # server: nginx # ...
Step 5: Auto-Renewal
Let's Encrypt certificates expire after 90 days. Certbot sets up automatic renewal by default.
Test the renewal process:
sudo certbot renew --dry-run
This simulates the renewal without actually renewing. If it succeeds, auto-renewal is working.
The renewal cron job is at /etc/cron.d/certbot and runs twice daily.
Step 6: Update Your App for HTTPS
Now that you have HTTPS, update your backend:
# .env NODE_ENV=production CLIENT_URL=https://yourdomain.com
Update cookie settings for cross-site HTTPS:
res.cookie("token", token, { httpOnly: true, secure: true, // HTTPS only sameSite: "none", // Allow cross-site cookies (if frontend is on a different domain) maxAge: 7 * 24 * 60 * 60 * 1000 });
Note: sameSite: "none" requires secure: true. If frontend and backend are on the same domain, use sameSite: "lax".
Step 7: Update Frontend Environment
Update the frontend to use HTTPS:
VITE_API_URL=https://api.yourdomain.com/api VITE_SOCKET_URL=https://api.yourdomain.com
The Nginx Configuration After Certbot
Certbot automatically adds these lines to your Nginx config:
server { server_name api.yourdomain.com; # SSL configuration added by Certbot listen 443 ssl; ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; location / { proxy_pass http://localhost:3000; # ... proxy headers ... } } # HTTP to HTTPS redirect server { if ($host = api.yourdomain.com) { return 301 https://$host$request_uri; } listen 80; server_name api.yourdomain.com; return 404; }
Troubleshooting
"Connection refused" on HTTPS:
- Check that port 443 is open in your EC2 security group
- Verify Nginx is running:
sudo systemctl status nginx
Certbot fails to verify domain:
- Ensure DNS A record points to the correct EC2 IP
- Wait for DNS propagation (can take up to 24 hours)
- Check that Nginx server_name matches the domain
Certificate renewal fails:
- Run
sudo certbot renew --dry-runto test - Check that port 80 is accessible (Let's Encrypt uses HTTP-01 challenge)
- Check Certbot logs:
sudo cat /var/log/letsencrypt/letsencrypt.log
The Takeaway
Adding SSL with Let's Encrypt is free and automated with Certbot. Install certbot, run sudo certbot --nginx -d yourdomain.com, and Certbot handles certificate issuance, Nginx configuration, and auto-renewal. After SSL, update your app to use secure cookies and HTTPS URLs. Always verify with certbot renew --dry-run that auto-renewal is working.
Install certbot (sudo apt install certbot python3-certbot-nginx), ensure your domain points to your EC2 IP, then run sudo certbot --nginx -d yourdomain.com. Certbot obtains the certificate and configures Nginx automatically.
Certificates expire after 90 days. Certbot sets up automatic renewal by default (runs twice daily via cron). Test renewal with sudo certbot renew --dry-run to ensure it will work when needed.
Set secure: true (HTTPS only), httpOnly: true (no JS access), and sameSite: 'none' if frontend and backend are on different domains (requires secure: true). Use sameSite: 'lax' if they're on the same domain.
Check that your DNS A record points to the correct EC2 public IP, wait for DNS propagation (up to 24 hours), ensure Nginx is running and the server_name matches the domain, and verify port 80 is open in your security group.
Yes, Certbot modifies the Nginx configuration to add SSL certificate paths, listen on port 443, and redirect all HTTP traffic to HTTPS. You don't need to manually edit the Nginx config for SSL.
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

