I am running a NestJS application via PM2 on port 3001 in an AWS EC2 instance.
I configured SSL using certbot / Let's Encrypt and nginx. I want the NestJS application to serve as my API server hence the *.api.example.com. I have the client assets (HTML, JavaScript, and CSS) in S3 and a CloudFront distribution.
The issue I am running into is as follows:
- If I navigate to staging.api.example.com in the browser, I receive a 502 Bad Gateway
- If I navigate to staging.api.example.com:3001 in the browser I receive a 404
- If I navigate to staging.api.example.com:3001/users which is a valid API route, everything works fine.
I want requests from staging.api.example.com to hit my NestJS server running at http://127.0.0.1:3001 in the EC2 instance via my nginx reverse proxy configuration.
I also cannot figure out why I have to include the port in the URL in order to reach my backend.
In my EC2 instance I had to add a custom rule to allow TCP traffic on port 3001 which doesn't seem right to me. I'm using a VPC, so I'm not sure if that's part of the problem.
IP Version | Type | Protocol | Port Range |
---|---|---|---|
IPv4 | Custom TCP | TCP | 3001 |
IPv4 | HTTP | TCP | 80 |
IPv4 | HTTPS | TCP | 443 |
Steps I took install certbot and generate a certificate for staging.api.example.com
sudo yum update -y
sudo amazon-linux-extras install nginx1
sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
sudo yum-config-manager --enable epel
sudo yum install certbot python2-certbot-nginx -y
sudo certbot --nginx
How I start the server in my EC2 instance
pm2 start dist/src/main.js --name example
NestJS application configuration
const app = await NestFactory.create(AppModule, {
cors: true,
httpsOptions: {
key: fs.readFileSync('/etc/letsencrypt/live/example.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/example.com/cert.pem')
}
});
await app.listen(3001);
NGINX configuration
server {
listen 443 ssl; # managed by Certbot
listen [::]:443 ssl;
server_name staging.api.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
location / {
proxy_connect_timeout 300;
proxy_read_timeout 300;
proxy_set_header Host $host:$server_port;
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;
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
proxy_redirect http:// https://;
}
}
server {
if ($host = staging.api.example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name staging.api.example.com;
return 404; # managed by Certbot
}
NGINX error log
$ sudo tail -f /var/log/nginx/error.log
2022/11/11 20:17:35 [error] 30033#30033: *1 upstream prematurely closed connection while reading response header from upstream, client: ip, server: staging.api.example.com, request: "GET / HTTP/1.1", upstream: "http://127.0.0.1:3001/", host: "staging.api.example.com"
NGINX access log
sudo tail -f /var/log/nginx/access.log
# navigate to staging.api.example.com in browser
[11/Nov/2022:20:22:16 0000] "GET / HTTP/1.1" 502 559 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" "-"
# navigate to staging.api.example.com/ in browser
[11/Nov/2022:20:22:22 0000] "GET / HTTP/1.1" 502 559 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" "-"
CodePudding user response:
It turns out all I needed to do was change the proxy_pass url in the location block to include https
Original NGINX config - does not work
location / {
...
proxy_pass http://127.0.0.1:3001;
...
}
Updated NGINX config - works
location / {
...
proxy_pass https://127.0.0.1:3001;
...
}