Nginx With Node.js As Backend Server Always Returns Status Code 200 Instead Of 404

- 1 answer

I am using Nginx as a reverse proxy, with a Node.js Express server as the backend.

When trying to load a custom-made 404 page on Express, Nginx always returns a 200 status code, even though Express correctly sends back to Nginx a 404 status code.

What is the problem with the configuration?

I'm also using EJS as the template engine, however, I don't think it contributes to the problem. I am using PM2 as the process manager to run the server. I have tested without using Nginx as a reverse proxy, and everything in Express seems to work fine, i.e. Express correctly returns a 404 status code.

Here's my Express code:

const path = require('path')

const express = require('express')

const app = express()

const port = process.argv[2] || 3000

// Define paths for Express config
const publicDirPath = path.join(__dirname, '../public')
const viewsPath = path.join(__dirname, '../templates/views')

// Set EJS engine and views location
app.set('view engine', 'ejs')
app.set('views', viewsPath)

// Set static files location

app.get('/testing404', (req, res) => {
    res.status(404).render('404', {
        title: '404 error',
        content: 'This is a 404 error page.'

app.listen(port, () => {
    console.log('Server started at port ' + port + '!')

Here's my relevant Nginx configuration:

upstream nthreads {
    server localhost:3000;

server {

        root /var/www/[XXXXX]/html;
        index index.html index.htm index.nginx-debian.html;

        server_name [XXXXX] www.[XXXXX];

        location / {
                proxy_pass http://nthreads;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;


As explained, I expected a 404 status code to be returned from Nginx through the Node.js Express backend server, but I'm getting a 200 status code instead, what's the problem then?



Turns out everything was working correctly. I have forgotten to reload the server process, and it was running an old code without the 404 status code. Nginx does indeed correctly forward the 404 status code returned by the backend Node.js Express server.