Nginx cannot run JavaScript files!

Hello,
The Dockerfile is as follows:

FROM node:latest

RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

COPY ./www/package.json /usr/src/app/package.json
RUN npm install
RUN npm update

COPY ./www /usr/src/app

EXPOSE 3000

The YAML file is as follows:

version: '3.9'
services:
    nodejs:
      container_name: Node
      build:
         context: .
         dockerfile: Dockerfile
      command: npm start
      volumes:
        - ./www:/usr/src/app
      expose:
        - "3000"
    nginx:
      image: nginx:latest
      container_name: Nginx-NodeJS
      ports:
        - '80:80'
      volumes:
        - ./default.conf:/etc/nginx/conf.d/default.conf
        - ./www:/usr/share/nginx/html
      depends_on:
        - nodejs
      links:
        - nodejs

The default.conf file is as follows:

server {
   listen 80;
   server_name default_server;
   error_log  /var/log/nginx/error.system-default.log;
   access_log /var/log/nginx/access.system-default.log;
   charset utf-8;

   root /usr/share/nginx/html;
   index index.html index.php index.js;

location ~ \.js$ {
    proxy_pass http://nodejs:3000;          
    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;
  }

    location / {
     autoindex on;
     try_files $uri $uri/ $uri.html =404;
    }
}

The index.js file is as follows:

const http = require('http')
const server = http.createServer((req, res) => {
	res.writeHead(200, { 'content-type': 'text/html' })

	if (req.url === '/') {
		res.write('<h1>Node and Nginx on Docker is Working</h1>')
		res.end()
	} else {
		res.write('<h1>404 Nout Found</h1>')
		res.end()
	}
})

server.listen(process.env.PORT || 3000, () => console.log(`server running on ${server.address().port}`))

the Node.js container is running:

Node  |
Node  | > docker-nodejs@1.0.0 start
Node  | > node index.js
Node  |
Node  | server running on 3000

But Nginx can’t see Node.js:

# curl http://localhost/index.js
<h1>404 Nout Found</h1>

When I move the proxy_pass line http://nodejs:3000; to location / , then:

# curl http://localhost
<h1>Node and Nginx on Docker is Working</h1>
#
# curl http://localhost/index.js
const http = require('http')
const server = http.createServer((req, res) => {
	res.writeHead(200, { 'content-type': 'text/html' })

	if (req.url === '/') {
		res.write('<h1>Node and Nginx on Docker is Working</h1>')
		res.end()
	} else {
		res.write('<h1>404 Nout Found</h1>')
		res.end()
	}
})

server.listen(process.env.PORT || 3000, () => console.log('server running on ${server.address().port}'))

Apparently, the problem is solved, but the JavaScript file does not run.

What is wrong?

Thank you.

Your index.js defines and runs a server, it is not a file to be accessed by itself.

Can you please try the following?

server {
   listen 80;
   server_name default_server;
   error_log  /var/log/nginx/error.system-default.log;
   access_log /var/log/nginx/access.system-default.log;
   charset utf-8;

   root /usr/share/nginx/html;

    location / {
     autoindex on;
     try_files $uri $uri/ $uri.html @nodejs;
    }

    location @nodejs {
      proxy_pass http://nodejs:3000;          
      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;
  }
}

It seems like there’s a misunderstanding regarding how Nginx is configured to proxy requests to the Node.js server. Let’s go through the configuration and see where the issue might be.

In your Nginx configuration, you have the following:

location ~ \.js$ {
    proxy_pass http://nodejs:3000;          
    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;
}

This configuration is set up to proxy requests ending with “.js” to the Node.js server running on port 3000.

However, your index.js file is not meant to be accessed directly via HTTP. It’s a Node.js application itself that listens for requests. Therefore, when you try to access http://localhost/index.js, Nginx passes the request to Node.js, but Node.js doesn’t know how to handle it because it’s expecting requests to / or /index.html.

To fix this issue:

  1. Remove the location ~ \.js$ { ... } block from your Nginx configuration, as it’s not necessary for this setup.

  2. Update your Nginx configuration to proxy all requests to Node.js, and let Node.js handle routing internally:

location / {
    proxy_pass http://nodejs:3000;
    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;
}

With this configuration, Nginx will pass all requests to Node.js, and your Node.js application can handle routing internally based on the requested URL.

After making these changes, restart your Nginx container and try accessing your application again. It should work as expected.

Be aware that with the config of @digital49 all URLs are passed to nodejs, including CSS and JS files and the like. You probably want those to be served by nginx instead.

Hello,
Thank you so much for your reply.
I did and the results are as follows:

# curl http://localhost
<html>
<head><title>Index of /</title></head>
<body>
<h1>Index of /</h1><hr><pre><a href="../">../</a>
<a href="node_modules/">node_modules/</a>                                      03-Apr-2024 10:05                   -
<a href="index.js">index.js</a>                                           03-Apr-2024 12:08                 409
<a href="index.js.new">index.js.new</a>                                       03-Apr-2024 07:17                 265
<a href="package-lock.json">package-lock.json</a>                                  03-Apr-2024 10:05               43384
<a href="package.json">package.json</a>                                       03-Apr-2024 10:05                 172
<a href="package.json.org">package.json.org</a>                                   02-Apr-2024 17:37                 718
</pre><hr></body>
</html>

And:

# curl http://localhost/index.js
const http = require('http')
const server = http.createServer((req, res) => {
	res.writeHead(200, { 'content-type': 'text/html' })

	if (req.url === '/index.js') {
		res.write('<h1>Node and Nginx on Docker is Working</h1>')
		res.end()
	} else {
		res.write('<h1>404 Nout Found</h1>')
		res.end()
	}
})

server.listen(process.env.PORT || 3000, () => console.log('server running on ${server.address().port}'))

Why did you delete the index index.html index.php index.js; line?

Hello,
Thank you so much for your reply.
As I said I had moved proxy_pass http://nodejs:3000; to location/, but I can’t do this because the Nginx server must also handle other files like PHP. For example:

    location ~ \.php$ {
       fastcgi_pass    php-fpm:9000;
       fastcgi_index   index.php;
       fastcgi_param   SCRIPT_FILENAME $document_root$fastcgi_script_name;
       add_header      script-filename $document_root$fastcgi_script_name always;
       include         fastcgi_params;
    }

Hello,
The problem was solved by using the following solution:

upstream nodejs {
    server nodejs:3000;
}

server {
   listen 80;
...

location ~ \.js$ {
    proxy_pass http://nodejs;
...

1- Can this method cause problems?

2- Can I do the same for PHP files?