I'm setting up my MERN project on my production server and whilst
making sure you can manually type in URL (such as myproject.com/dashboard) I added the following line to the server section of my Nginx configuration file try_files $uri /index.html; to allow this(as stated by the react-router training page). This has now caused the following response when trying to login Cannot POST /index.html.
If I remove the line all calls to the api work(i can login again) but I cannot enter url manually.
I've tried moving the try_files line to the top of the server section incase the server section is sensitive to this.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name myproject.com;
root /home/forge/myproject.com/client/build;
...
location / {
try_files $uri /index.html;
proxy_pass http://127.0.0.1:8080;
}
...
}
const express = require('express');
const app = express();
app.use( express.static( `${__dirname}/client/build` ) );
app.use('/api/users', usersRouter);
app.use('/api/playlists', playlistRouter);
app.get('*', (req, res) => {
res.sendFile(`${__dirname}/client/build/index.html`);
});
I expect to be able to login(make calls to my api) and enter URLs manually to my project.
I think your configuration is not valid. In your config if requested file does not exists you are sending the file index.html no matter what. Will never call proxy.
Since your server has /api prefix configure that on your nginx server like this. So request starts with /api will be proxy to your backend server.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name myproject.com;
root /home/forge/myproject.com/client/build;
location /api/ {
proxy_pass http://127.0.0.1:8080;
}
location / {
try_files $uri /index.html;
}
}
I am running XAMPP on Windows to host an Apache server on port 80. Now I'm trying to have a NodeJS script running in the background but the problem is that it can only listen on port 80. If it does, everything works as it should but I can't have Apache running at the same time, because Apache takes priority and just serves my website. The NodeJS script doesn't even get to listen.
My question is: how do I switch the listening port of the NodeJS script (the specific port really doesn't matter) so that Apache can still run on port 80 and I can reach the NodeJS script from all around the world.
Part of the NodeJS code:
const http = require('http');
const port = 8080;
const host = '0.0.0.0';
server = http.createServer( function(req, res) {
if (req.method == 'POST') {
var body = '';
req.on('data', function (data) {
body += data;
doStuff(body);
});
res.writeHead(200, {'Content-Type': 'text'});
res.end('received request successfully');
}
else {
res.writeHead(405, {'Content-Type': 'text'});
res.end('not allowed method ' + req.method + ', try again with GET or POST');
}
})
server.listen(port, null, function(error){
if(!!error){
console.log("\x1b[41m%s\x1b[0m", "error while initializing listener on port " + port + ": " + error);
}
else{
console.log("\x1b[32m%s\x1b[0m", "started listener at 'http://" + host + ':' + port + "'");}
});
Additional information is in my other question which got flagged as duplicate.
Looking at your other question, which was marked as duplicate of this one, you've got some additional information there that will probably help to elucidate what you're needing. Specifically, you mention the following:
I want to host multiple http servers with NodeJS, that all get and send http requests. At the same time I want to have Apache running, which occupies port 80. If I disable Apache and let NodeJS run on port 80, it will work but I can't have them running at the same time.
This script will run and receive requests locally at port 8081, but I can't seem to send an AJAX request to it through the Internet, even after forwarding the port with my router:
I think #ankit-agarwal is probably right in that you need a reverse proxy setup to forward traffic to your different backends. Assuming you've got an externally facing IP address, you should be able to access each of your backends using the ports they are listening on. For example, if the exposed public IP address of your machine is 100.120.110.43:
+---------+------+-------------------------------------+
| Backend | Port | Web Address |
+=========+======+=====================================+
| Apache | 80 | 100.120.110.43 or 100.120.110.43:80 |
| Node1 | 8080 | 100.120.110.43:8080 |
| Node2 | 8081 | 100.120.110.43:8081 |
+---------+------+-------------------------------------+
If you want to access each of the backends without specifying the port, you have to have some way to tell your internal network which backend to serve based on the request. One way of doing this is to use path based routing, where you setup your reverse proxy to route the traffic to the different backends based on the path in the url. You didn't post your Apache configuration, but you can use your current Apache server to handle this using the ProxyPass and ProxyPassReverse directives similar to below:
ProxyPass "/node1" "http://100.120.110.43:8080/"
ProxyPassReverse "/node1" "http://100.120.110.43:8080/"
ProxyPass "/node2" "http://100.120.110.43:8081/"
ProxyPassReverse "/node2" "http://100.120.110.43:8081/"
The cool thing about using a reverse proxy is that you don't have to expose your node backends to the public. Let's assume you haven't, and they are only accessible from the internal network at 0.0.0.0:port.
Listen 80
<VirtualHost *:80>
DocumentRoot /www/apache
ServerName www.apachefrontend.com
ProxyRequests off
ProxyPass /node1 http://0.0.0.0:8080/
ProxyPassReverse /node1 http://0.0.0.0:8080/
ProxyPass /node2 http://0.0.0.0:8081/
ProxyPassReverse /node2 http://0.0.0.0:8081/
</VirtualHost>
You could also point to different hosts/ips that only you have access to.
Finally, you can also use VirtualHost and ServerName if you have different DNS records to point to the different backends.
Listen 80
<VirtualHost *:80>
DocumentRoot /www/apache
ServerName www.apachefrontend.com
</VirtualHost>
<VirtualHost *:80>
ServerName www.nodebackend1.com
ProxyRequests off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
<Location />
ProxyPass / http://0.0.0.0:8080/
ProxyPassReverse / http://0.0.0.0:8080/
</Location>
</VirtualHost>
<VirtualHost *:80>
ServerName www.nodebackend2.com
ProxyRequests off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
<Location />
ProxyPass / http://0.0.0.0:8081/
ProxyPassReverse / http://0.0.0.0:8081/
</Location>
</VirtualHost>
For any of the above to work, you need to have mod_proxy and mod_proxy_http enabled in apache.
These probably aren't the most robust examples and I haven't tested them, but they should demonstrate the idea. You can learn more here.
Just change your node.js server port something like:
var server = app.listen(8080, function() {
console.log('Ready on port %d', server.address().port);
});
where 8080 is node.js server' new port.
I haven't really understood what you meant by you're not getting any response, because I ran the same code and it works fine for me.
I only noticed something here (I kept a note for you in the comment)
server = http.createServer( function(req, res) {
if (req.method == 'POST') {
var body = '';
req.on('data', function (data) {
body += data;
doStuff(body); //you haven't defined doStuff so you will end up with a error message on this line, but you sever will still run fine
});
res.writeHead(200, {'Content-Type': 'text'});
res.end('received request successfully');
}
else {
res.writeHead(405, {'Content-Type': 'text'});
res.end('not allowed method ' + req.method + ', try again with GET or POST');
}
})
When running your post request, don't forget to add "" in your body area, select raw then choose JSON(application/json). That should run fine for you, except you might get a reference error as shown below, but you should still get your response of received request successfully.
error
doStuff(body);
^
ReferenceError: doStuff is not defined
Ensure that you're doing the same thing and let us know if your issue it resolved.
Seem something already running on your 8080 port. Simply change to another port. For example 7000
And make sure that all request you call to nodejs app like this
localhost:7000 // Normal we run at port 80 url simply localhost without port
If I want use Apache and Nodejs in same port:
npm http-proxy-middleware
1. Set Apache Port = 81
[apache dir]/conf/httpd.conf
~59: Listen 81
2. Set nodejs APP port = 3050
server.listen(3050);
// on linux ports<1000 require root privilegue
3. Use third proxy APP (http-proxy-middleware)
// https://www.npmjs.com/package/http-proxy-middleware
var express = require('express');
var proxy = require('http-proxy-middleware');
// proxy middleware options
var options = {
target: 'http://localhost:81', // target host ROOT
changeOrigin: true, // needed for virtual hosted sites
ws: true, // proxy websockets
pathRewrite: {
// '^/api/old-path' : '/api/new-path', // rewrite path
// '^/api/remove/path' : '/path' // remove base path
},
router: {
// Examples:
// when request.headers.host == 'dev.localhost:3000',
// override target 'http://www.example.org' to 'http://localhost:8000'
// 'dev.localhost:3000' : 'http://localhost:8000',
// 'localhost:9000': 'localhost:9002/sub',
// '/sub': 'http://localhost:9002',
'localhost': 'http://localhost:81', //Root to Apache
'sub.localhost': 'http://localhost:3050', // internal
'sub.mydomain.com': 'http://localhost:3050', //external
},
};
// create the proxy (without context)
// var proxy_wp = proxy(options_wp);
var proxy_node = proxy(options);
// mount `exampleProxy` in web server
var app = express();
app.use(proxy_node);
app.listen(80);
Then:
localhost:80 - is apache site
sub.localhost:80 - node
localhost:80/sub - node, if you set
for task runner i use npm PM2
This is same scenario as using NodeJs in a Shared Hosting. I have written a blogpost about it here
Let me give an excerpt.
Just run the NodeJS server at let's say 8080 port.
Now, let's say your Apache serves at http://example.com, create a folder in your public_html or www. let's say the name is server. So, your new folder path is http://example.com/server
create a .htaccess file in the server folder
add the following lines,
RewriteEngine On
RewriteRule ^$ http://127.0.0.1:8080/ [P,L] #which is your node server ip:port
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ http://127.0.0.1:8080/$1 [P,L] #same ip:port
This will redirect all the requests from http://example.com/server to your Node server.
I have a working websocket which can be reached from my clientside code like this: (Not using Socket.io or any library, just plain html5 websockets)
ws://localhost:9000/socket/connect
The Websocket is implemented in Java Play Framework
public WebSocket connect() {
return WebSocket.Text.accept(request -> ActorFlow.actorRef(out -> SocketActor.props(out, jsonWebToken),
actorSystem, materializer
)
);
}
Anyway this is working fine, however I now want to set up https for the website and am doing this on nginx. Switching to https I also need to use the wss protocol instead of ws, therefore I want to proxy wss calls as well through nginx and hereby I am facing issues.
I have configured my nginx for the websocket proxy as stated here https://www.nginx.com/blog/websocket-nginx/ My complete config looks like this
upstream backend {
server backend:9000;
}
server {
listen 80;
server_name _;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name legato;
ssl_certificate /etc/nginx/ssl/legato.crt;
ssl_certificate_key /etc/nginx/ssl/legato.key;
location /api {
return 302 /api/;
}
location /api/ {
proxy_pass http://backend/;
}
location /statics {
root /var/www;
}
location /socket/connect {
proxy_pass http://backend/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
location / {
root /var/www/frontend;
index index.html;
try_files $uri /index.html;
}
}
so the /socket/connect route is forwarded to the websocket backend route.
From my clientside javascript code I am opening the websocket now like this
socket = new WebSocket(wss://192.168.155.177/socket/connect);
which gives me the error
WebSocket connection to 'wss://192.168.155.177/socket/connect' failed: Error during WebSocket handshake: Unexpected response code: 200
Can somebody explain to me what is wrong in this case?
I found a little workaround for this issue, gonna leave it here for anybody in the future.
So I was trying:
Implement SSL encryption for the Websockets on NGINX. This didn't work because NGINX would connect to the websocket via http again. Since I am not using any socket.io this didn't work as the backend does not support it
Implement SSL on backend side. This was rather tricky to me. Switching to https on java involves using keystores, furthermore How to use TLS in Play!Framework WebSockets ("wss://") suggest that even if I could get https working it might be that wss still won't work. So after a few failed attempts I ditched this.
The solution was using stunnel which allowed me to open up a port, encrypt any incoming traffic and forward it to another port. So I am now ssl encrpyting traffic on port 9433 and forwarding it to the backends unecrypted ws Endpoint which made it work.
If you wan't to use it in an actual production environment you should do some research on the scaleability of this method, especially stunnel.
I have a node express app running in a Docker container and through the app i'm trying to log the IP address of the incoming request. Since i'm running everything behind a firewall i used something like this "req.headers['x-forwarded-for'] || req.connection.remoteAddress" but it logs the same IP address each time irrespective of the request origin. i.e. i always see the same IP even when it is made from different IP's.
Is there an elegant way to log the IP address of the node app running in a docker container. Will using this package help https://www.npmjs.com/package/ip
If not please suggest a way to capture the IP address.
I know this is old, but this might still help.
What worked for me was a combination of my Express container and NGINX running as a reverse proxy on the host machine.
For the NGINX, I added the following settings:
proxy_pass http://localhost:9461; # <-- put the exposed port of the Docker Express container
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
With the above, once I access my Express container (via my specified NGINX server_name), the IP of the request will be stored in req.headers['x-forwarded-for'] :
console.log("IP of this request is:", req.headers['x-forwarded-for']);
const {exec} = require('child_process');
let hostname = 'localhost';
exec("ip route | awk '/default/ {print $3}'", (error, stdout) => {
if (error) {
console.error('cannot get outer ip address for wrapper service', error);
} else {
hostname = stdout.replace(/\n/, '');
}
});
After that, in hostname variable contains the host ip.
I've installed node.js on my server(it is a virtual windows server). I am also having the domain. I want to run my node.js application on a port 8001 so that when I open, say http://example.com:8001/ it will open my application.
Actually, I am also having a PHP site running on Apache server on port 80(XAMPP). It is perfectly working fine when I open say, http://example.com.
Thanks
In apache, create a new vhost. You have to proxy all requests through apache to your node app as apache is listening to port 80.
<VirtualHost *:80>
ServerName example.com
ProxyRequests off
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
<Location />
ProxyPass http://localhost:8001/
ProxyPassReverse http://localhost:8001/
</Location>
</VirtualHost>
If you are not on a name-based virtual host environment you can just start your Node.js server and it will be available to the world from the defined port. But if the server IP address runs many services using different domain names and you want your Node.js server to reply only from http://example.com:8001 you can use e.g. the vhost module on your node server to listen to specific domain only:
var express = require('express'),
host = require('vhost');
var app = express();
app.get('/', function(req, res) {
res.send("Hello from vhost");
});
var main = express();
main.use(vhost('example.com', app));
if (!module.parent) {
main.listen(8001);
}
You can also proxy the requests through a web server like Apache or nginx, but to have the service responding from port 8001 you would need to bind the web server to port 8001 in addition to 80 you are already using, and run your Node.js server on some other port.
Generally people prefer using the standard HTTP port and use a web server to reverse proxy traffic to the Node.js server running on a non-privileged port. As you already have the PHP application on your domain name you would then follow advice by #SamT and run your Node.js application from e.g. http://mynodeapp.example.com