394

I want to use Node because it's swift, uses the same language I am using on the client side, and it's non-blocking by definition. But the guy who I hired to write the program for file handling (saving, editing, renaming, downloading, uploading files, etc.), he wants to use apache. So, I must:

  1. Convince him to use Node (he's giving up little ground on that)

  2. Figure out how to upload, download, rename, save, etc. files in node or

  3. I must install apache and node on the same server.

Which is the most favorable situation, and how do I implement that?

Michael Irigoyen
  • 22,513
  • 17
  • 89
  • 131
Matt
  • 5,553
  • 5
  • 24
  • 32

10 Answers10

768

Great question!

There are many websites and free web apps implemented in PHP that run on Apache, lots of people use it so you can mash up something pretty easy and besides, its a no-brainer way of serving static content. Node is fast, powerful, elegant, and a sexy tool with the raw power of V8 and a flat stack with no in-built dependencies.

I also want the ease/flexibility of Apache and yet the grunt and elegance of Node.JS, why can't I have both?

Fortunately with the ProxyPass directive in the Apache httpd.conf its not too hard to pipe all requests on a particular URL to your Node.JS application.

ProxyPass /node http://localhost:8000

Also, make sure the following lines are NOT commented out so you get the right proxy and submodule to reroute http requests:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Then run your Node app on port 8000!

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Apache!\n');
}).listen(8000, '127.0.0.1');

Then you can access all Node.JS logic using the /node/ path on your url, the rest of the website can be left to Apache to host your existing PHP pages:

enter image description here

Now the only thing left is convincing your hosting company let your run with this configuration!!!

YakovL
  • 7,557
  • 12
  • 62
  • 102
Steven de Salas
  • 20,944
  • 9
  • 74
  • 82
  • 6
    This was a great answer, just wanted to add a link with a little more info on proxy pass that I used to make this work. Check the comments as well.http://boriskuzmanovic.wordpress.com/2006/10/20/apaches-proxypass-on-ubuntu/ – Alex Muro Oct 15 '13 at 22:08
  • 1
    @Steven I never thought that we could use the Proxy module the provide such an elegant solution! – Birla Feb 14 '14 at 08:06
  • 12
    I tested putting "ProxyPass / http://127.0.0.1:8000/" inside a virtual host container and was able to successfully redirect an entire domain group to a node instance. I also tested with "time wget..." to compare speed of accessing node directly to accessing it over Apache. In 30 pairs of trials, the average difference was about 0.56ms. The lowest load time was 120ms for both direct and via Apache. The highest load time was 154ms for direct and 164 via Apache. Not a significant difference. If I had the luxury of two IPs I would not route through Apache, but for now I will stick with Proxypass – kaan_a Mar 19 '14 at 15:59
  • 1
    I'd like to point those using Apache2 to this link, note that httpd.conf is a different file for apache2 http://stackoverflow.com/questions/11687125/my-httpd-conf-is-empty – t3dodson Jul 26 '14 at 06:59
  • 5
    Doesn't this proxy requests from Apache to Node, while it takes away the benefits of Node's non-blocking nature? – html_programmer Sep 16 '14 at 20:52
  • 1
    Hi @Kim, you are adding an extra filtering layer but the delays are minimal (<1 ms according to Sazzads test). This would be similar to using a reverse-proxy for internal routing like most enterprise firewalls use. Not sure how this would take away non-blocking nature of Node. – Steven de Salas Sep 18 '14 at 23:48
  • Thanks for this very helpful answer @StevendeSalas. Any idea about how to do it when some WebSocket is involved ? http://stackoverflow.com/questions/27526281/websockets-and-apache-proxy – Basj Dec 17 '14 at 13:10
  • 2
    Hi @Basj, I dont have experience installing support for websockets myself. Having said that, Apache 2.4.6 appears to have support for proxying websockets traffic with using `mod_proxy_wstunnel`. I see you have now found your answer, for others with same problem please refer to: http://serverfault.com/questions/616370/configuring-apache-2-4-mod-proxy-wstunnel-for-socket-io-1-0/623027#623027 – Steven de Salas Dec 18 '14 at 01:48
  • This used localhost on port 8000 for node.js. I have a remote web server setup so I can access it from outside of my lan. If I have www.url.com that resolves to the ip address on my webserver will www.url.com/node using your example still load this node js page? – steviesama May 31 '15 at 05:10
  • Hi @steviesama - yep should be fine, just remember that the `localhost` reference is being resolved by the remote server so you are really just pointing from the remote server to itself. You only need a fully qualified reference (ie `http://app.myotherdomain.com:8000/`) if you are using 2 different servers for apache and node. – Steven de Salas Jun 01 '15 at 00:44
  • @StevendeSalas I didn't even think about that. I should know that. I was thinking to hard on how node.js worked. I've never used it before and the simple stuff escaped me. – steviesama Jun 04 '15 at 12:28
  • I don't seem to have a strictly named proxy pass. I have proxy_fdpass.load which is the closest match. Also a while back I updated apache, and it doesn't seem to use loadmodule in apache2.conf, it has a mods-available directory and I think it uses a2enmod now if I recall. It's been a while though. Would proxy_fdpass.load be similar to this proxypass mentioned here? – steviesama Jun 04 '15 at 12:37
  • 4
    Where do I add this on debian based distributions? There's no httpd.conf file. – santi Jul 27 '15 at 12:11
  • BTW it should be ProxyPass /node http://localhost:8000 since according to documentation: If the first argument ends with a trailing /, the second argument should also end with a trailing /, and vice versa – jony89 Jun 29 '16 at 14:25
  • I have the same question as @santi How would I impliment this on Ubuntu Sever? using apache2.conf? – Native Coder Nov 16 '16 at 21:08
  • 1
    Hi @NativeCoder @santi, I havent tried these myself but a quick search for `ProxyPass apache2 conf` yields some good examples. Here is [one from boris](https://boriskuzmanovic.wordpress.com/2006/10/20/apaches-proxypass-on-ubuntu/), [digital ocean](https://www.digitalocean.com/community/tutorials/how-to-use-apache-http-server-as-reverse-proxy-using-mod_proxy-extension), [another by lease web](https://www.leaseweb.com/labs/2014/12/tutorial-apache-2-4-transparent-reverse-proxy/). They all seem much of a muchness. – Steven de Salas Nov 18 '16 at 03:28
  • How subject are you to proxy abuse with your setup, have you checked? https://wiki.apache.org/httpd/ProxyAbuse – Jacksonkr Mar 27 '17 at 11:08
  • @Jacksonkr none I would imagine. You are just proxying incoming requests to localhost (on the same server). I got a few other things on my plate but you are welcome to give it a try. – Steven de Salas Mar 27 '17 at 11:35
  • this does not load source files. how do i get the source files to append `/node/` to all the source includes instead or `/` – shorif2000 Sep 20 '17 at 15:19
  • Hi @rudminda the question is not about hosting your `node_modules` as static assets within apache, but about nodejs and apache sharing access to HTTP calls. – Steven de Salas Oct 19 '17 at 02:08
  • I'm doing this in a digital ocean droplet running apache2, works like a dream – Felipe Alarcon Oct 26 '17 at 20:02
  • 1
    please remove the extra / at the end of the ProxyPass line or express routes will not work https://stackoverflow.com/questions/33152648/how-to-set-up-apache-proxypass-to-preserve-express-routes – Delcasda Jan 10 '18 at 18:43
  • Great answer how would one do this over https? @Steven de Salas – FabricioG Nov 08 '18 at 21:05
  • 1
    Hi @FabricioG, should be possible if you have some experience of setting up SSL certificates: listen on port 8443 with node using [`https` module](https://nodejs.org/api/https.html#https_https_createserver_options_requestlistener) and your own self-signed certificates, then [route https traffic from Apache](https://serverfault.com/questions/84821/apache-proxypass-with-ssl), making sure you have `mod_ssl` installed. You should install proper SSL certs on Apache, as this will be facing incoming traffic, then some [extra config from this post](https://ubuntuforums.org/showthread.php?t=2064909). – Steven de Salas Nov 09 '18 at 13:31
  • What about iis server? – Mendi Sterenfeld Jul 16 '20 at 15:57
  • I had to run the following commands too: sudo a2enmod proxy sudo a2enmod proxy_http – Tanzeel Aug 14 '20 at 14:06
  • I am doing ProxyPass / http://127.0.0.1:8082 but its crashing. :| – Raul Chiarella Nov 29 '21 at 17:14
  • I don;t have to convince my hosting provider as I use MY OWN SERVER... Ahahahaha !!! – Thanasis Oct 28 '22 at 13:51
  • Not working for me. Instead of loading my React app, which is running in a Docker container, it loads a static `index.html` page (the one created by running `create-react-app`) which displays nothing. I also tried pointing to another Tomcat server on the same box and it displayed the main page but with no graphics, only text. Using `ProxyPass /node http://www.google.com` did work though. Not sure what the issue is. – Mike Lowery May 06 '23 at 21:08
85

This question belongs more on Server Fault but FWIW I'd say running Apache in front of Node.js is not a good approach in most cases.

Apache's ProxyPass is awesome for lots of things (like exposing Tomcat based services as part of a site) and if your Node.js app is just doing a specific, small role or is an internal tool that's only likely to have a limited number of users then it might be easier just to use it so you can get it working and move on, but that doesn't sound like the case here.

If you want to take advantage of the performance and scale you'll get from using Node.js - and especially if you want to use something that involves maintaining a persistent connection like web sockets - you are better off running both Apache and your Node.js on other ports (e.g. Apache on localhost:8080, Node.js on localhost:3000) and then running something like nginx, Varnish or HA proxy in front - and routing traffic that way.

With something like varnish or nginx you can route traffic based on path and/or host. They both use much less system resources and is much more scalable that using Apache to do the same thing.

Iain Collins
  • 6,774
  • 3
  • 43
  • 43
  • Ya but it is resource intensive – The Oracle May 21 '18 at 00:01
  • 1
    Do you have some numbers to back up your statement that nginx would be less resource intensive than httpd? – RedShift Oct 03 '18 at 18:30
  • I don't though it's quite dramatic. While I try not to link out in replies as links are fragile but you can find some discussion and examples via Google – e.g. https://help.dreamhost.com/hc/en-us/articles/215945987-Web-server-performance-comparison … Apache is great software but typically it's not a great approach in a context like this. – Iain Collins Oct 04 '18 at 23:35
  • This answer sounds good, but then how to access to Node.js through httpS as it is already taken by Apache ? – Pierre Apr 29 '19 at 15:38
  • 2
    Nginx is faster I agree, but then you have the overhead of an extra service to configure and manage. Since the question asks for Apache and Node on the same server, it seems like Nginx is a bit of a third wheel. – Steven de Salas Jun 03 '20 at 10:42
  • some people still think apache is slow but its latest version 2.4 can do anything that nginx does and as fast. adding an extra layer without any reason is a bad idea – wlf Oct 05 '20 at 17:54
  • @wlf It's about scalability; on the same hardware you generally won't be able to handle as many requests at the same time with Apache as you can with Nginx and the difference in performance can be dramatic. If you are dealing with a relatively low volume of requests (e.g. that can be handled by a single server) then the extra flexibility of Apache may be a good trade off as the difference in performance won't be as big a factor. – Iain Collins Oct 08 '20 at 12:18
42


Instructions to run node server along apache2(v2.4.xx) server:

In order to pipe all requests on a particular URL to your Node.JS application create CUSTOM.conf file inside /etc/apache2/conf-available directory, and add following line to the created file:

ProxyPass /node http://localhost:8000/

Change 8000 to the prefered port number for node server.
Enable custom configurations with following command:

$> sudo a2enconf CUSTOM

CUSTOM is your newly created filename without extension, then enable proxy_http with the command:

$> sudo a2enmod proxy_http

it should enable both proxy and proxy_http modules. You can check whether module is enabled or not with:

$> sudo a2query -m MODULE_NAME

After configuration and modules enabled, you will need to restart apache server:

$> sudo service apache2 restart

Now you can execute node server. All requests to the URL/node will be handled by node server.

krmld
  • 1,248
  • 14
  • 9
  • Works like a charm! :) – Kees Koenen Jun 12 '19 at 21:44
  • I get internal server error (500) with no indication whatsoever what goes wrong. Any idea what may cause it or where I can see some logs? I'm new to vps and linux/ubuntu in general. – DFSFOT Jun 04 '21 at 17:53
  • If the first argument ends with a trailing /, the second argument should also end with a trailing /, and vice versa. Otherwise, the resulting requests to the backend may miss some needed slashes and do not deliver the expected results. – Mike Lowery May 06 '23 at 20:56
17

Running Node and Apache on one server is trivial as they don't conflict. NodeJS is just a way to execute JavaScript server side. The real dilemma comes from accessing both Node and Apache from outside. As I see it you have two choices:

  1. Set up Apache to proxy all matching requests to NodeJS, which will do the file uploading and whatever else in node.

  2. Have Apache and Node on different IP:port combinations (if your server has two IPs, then one can be bound to your node listener, the other to Apache).

I'm also beginning to suspect that this might not be what you are actually looking for. If your end goal is for you to write your application logic in Nodejs and some "file handling" part that you off-load to a contractor, then its really a choice of language, not a web server.

LJones
  • 35
  • 1
  • 8
Yarek T
  • 9,715
  • 2
  • 28
  • 38
11

You can use a different approach such as writing a reverse proxy server with nodejs to proxy both apache and all other nodejs apps.

First you need to make apache run on a different port other than port 80. ex: port 8080

Then you can write a reverse proxy script with nodejs as:

var proxy = require('redbird')({port: 80, xfwd: false);

proxy.register("mydomain.me/blog", "http://mydomain.me:8080/blog");
proxy.register("mydomain.me", "http://mydomain.me:3000");

Following article describes the whole process of making this.

RUN APACHE WITH NODE JS REVERSE PROXY – USING REDBIRD

wathmal
  • 371
  • 4
  • 9
9

I combined the answer above with certbot SSL cert and CORS access-control-allow-headers and got it working so I thought I would share the results.

Apache httpd.conf added to the bottom of the file:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Apache VirtualHost settings (doc root for PHP is under Apache and SSL with Certbot, while node.js/socket.io site runs on port 3000 - and uses SSL cert from Apache) Also notice the node.js site uses the proxy for the folder /nodejs, socket.io, and ws (websockets):

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName www.example.com
    ServerAlias www.example.com
    DocumentRoot /var/html/www.example.com
    ErrorLog /var/html/log/error.log
    CustomLog /var/html/log/requests.log combined
    SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^socket.io          [NC]
    RewriteCond %{QUERY_STRING} transport=websocket [NC]
    RewriteRule /{.*}       ws://localhost:3000/$1  [P,L]

    RewriteCond %{HTTP:Connection} Upgrade [NC]
    RewriteRule /(.*) ws://localhost:3000/$1 [P,L]

    ProxyPass /nodejs http://localhost:3000/
    ProxyPassReverse /nodejs http://localhost:3000/

    ProxyPass /socket.io http://localhost:3000/socket.io
    ProxyPassReverse /socket.io http://localhost:3000/socket.io

    ProxyPass /socket.io ws://localhost:3000/socket.io
    ProxyPassReverse /socket.io ws://localhost:3000/socket.io

</VirtualHost>
</IfModule>

Then my node.js app (app.js):

var express = require('express');
var app = express();
    app.use(function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Headers", "X-Requested-With");
        res.header("Access-Control-Allow-Headers", "Content-Type");
        res.header("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
        next();
    });
var http = require('http').Server(app);
var io = require('socket.io')(http);

http.listen({host:'0.0.0.0',port:3000});

I force a ip4 listener, but that is optional - you can substitute:

http.listen(3000);

node.js app (app.js) code continues with:

io.of('/nodejs').on('connection', function(socket) {
    //optional settings:
    io.set('heartbeat timeout', 3000); 
    io.set('heartbeat interval', 1000);

    //listener for when a user is added
    socket.on('add user', function(data) {
         socket.join('AnyRoomName');
         socket.broadcast.emit('user joined', data);
    });

    //listener for when a user leaves
    socket.on('remove user', function(data) {
         socket.leave('AnyRoomName');
         socket.broadcast.emit('user left', data);
    });

    //sample listener for any other function
    socket.on('named-event', function(data) {
         //code....
         socket.broadcast.emit('named-event-broadcast', data);
    });

    // add more listeners as needed... use different named-events...
});

finally, on the client side (created as nodejs.js):

//notice the /nodejs path
var socket = io.connect('https://www.example.com/nodejs');

//listener for user joined
socket.on('user joined', function(data) {
    // code... data shows who joined...
});

//listener for user left
socket.on('user left', function(data) {
    // code... data shows who left...
});

// sample listener for any function:
socket.on('named-event-broadcast', function(data) {
    // this receives the broadcast data (I use json then parse and execute code)
    console.log('data1=' + data.data1);
    console.log('data2=' + data.data2);
});

// sample send broadcast json data for user joined:
socket.emit('user joined', {
    'userid': 'userid-value',
    'username':'username-value'
});

// sample send broadcast json data for user left 
//(I added the following with an event listener for 'beforeunload'):
// socket.emit('user joined', {
//     'userid': 'userid-value',
//     'username':'username-value'
// });

// sample send broadcast json data for any named-event:
socket.emit('named-event', {
    'data1': 'value1',
    'data2':'value2'
});

In this example when the JS loads, it will emit to the socket a "named-event" sending the data in JSON to the node.js/socket.io server.

Using the io and socket on the server under path /nodejs (connected by client), receives the data an then resends it as a broadcast. Any other users in the socket would receive the data with their listener "named-event-broadcast". Note that the sender does not receive their own broadcast.

Dr. Aaron Dishno
  • 1,859
  • 1
  • 29
  • 24
3
ProxyPass /node http://localhost:8000/     
  • this worked for me when I made above entry in httpd-vhosts.conf instead of httpd.conf
  • I have XAMPP installed over my environment & was looking to hit all the traffic at apache on port 80 with NodeJS applicatin running on 8080 port i.e. http://localhost/[name_of_the_node_application]
rahul shukla
  • 233
  • 3
  • 11
0

I recently ran into this kinda issue, where I need to communicate between client and server using websocket in a PHP based codeigniter project.

I resolved this issue by adding my port(node app running on) into Allow incoming TCP ports & Allow outgoing TCP ports lists.

You can find these configurations in Firewall Configurations in your server's WHM panel.

-1

I was looking for the same information. Finally found the answer from the link on the answer above by @Straseus

http://arguments.callee.info/2010/04/20/running-apache-and-node-js-together/

Here is the final solution to run apache website on port 80, node js service on port 8080 and use .htaccess RewriteRule

In the DocumentRoot of the apache website, add the following:

Options +FollowSymLinks -MultiViews

<IfModule mod_rewrite.c>

RewriteEngine on

# Simple URL redirect:
RewriteRule ^test.html$ http://arguments.callee.info:8000/test/ [P]

# More complicated (the user sees only "benchmark.html" in their address bar)
RewriteRule ^benchmark.html$ http://arguments.callee.info:8000/node?action=benchmark [P]

# Redirect a whole subdirectory:
RewriteRule ^node/(.*) http://arguments.callee.info:8000/$1 [P]

For the directory level redirect, the link above suggested (.+) rule, which requires one or more character after the 'node/'. I had to convert it to (.*) which is zero or more for my stuff to work.

Thanks a lot for the link @Straseus

pd1980
  • 103
  • 1
  • 8
-5

I am assuming that you are making a web app because you refer to Apache and Node. Quick answer - Is it possible - YES. Is it recommended - NO. Node bundles it's own webserver and most websites run on port 80. I am also assuming that there is currently no Apache plugin which is supported by Nodejs and I am not sure if creating a virtual host is the best way to implement this. These are the questions that should be answered by developers who maintain Nodejs like the good folks at Joyent.

Instead of ports, it would be better to evaluate Node's tech stack which is completely different from most others and which is why I love it but it also involves a few compromises that you should be aware of in advance.

Your example looks similar to a CMS or a sharing web app and there are hundreds of out of the box apps available that will run just fine on Apache. Even if you do not like any readymade solution, you could write a webapp in PHP / Java / Python or mix n match it with a couple of ready made apps and they are all designed and supported to run behind a single instance of Apache.

It's time to pause and think about what I just said.

Now you are ready to decide on which techstack you are going to use. If your website will never use any out of the thousands of ready made apps that require Apache, then go for Node otherwise you must first eliminate the assumptions that I have stated earlier.

In the end, your choice of techstack is way more important than any individual component.

I completely agree with @Straseus that it is relatively trivial to use node.js file system api for handling uploads and downloads but think more about what you want from your website in the long run and then choose your techstack.

Learning Node's framework is easier than learning other frameworks but it is not a panacea. With a slightly more effort (which may be a worthwhile endeavor in itself), you can learn any other framework too. We all learn from each other and you will be more productive if you are working as a small team than if you are working alone and your backend technical skills will also develop faster. Therefore, do not discount the skills of other members of your team so cheaply.

This post is about a year old and chances are that you have already decided but I hope that my rant will help the next person who is going through a similar decision.

Thanks for reading.

RHT
  • 4,974
  • 3
  • 26
  • 32