How to use vhosts alongside node-http-proxy? - apache

I'm running Nodejs and Apache alongside each other.
node-http-proxy is listening on port 80 and then forwarding requests to either Apache(:9000) or to Express(:8000).
My virtual hosts on Apache look like:
<VirtualHost 127.0.0.1>
DocumentRoot "/localhost/myVhost"
ServerName myVhost
</VirtualHost>
My question is, what is the "correct" way to have vhost like functionality on the Express/Nodejs side? I would prefer to not have to place each Nodejs app on its own port as is suggested here:
https://github.com/nodejitsu/node-http-proxy
(Section titled "Proxy requests using a 'Hostname Only' ProxyTable")
I noticed Connect (which as I understand it, gets bundled in Express) has some vhosts functionality. Should I be using that? If so, what would be the correct way to run it alongside node-http-proxy?
http://www.senchalabs.org/connect/middleware-vhost.html
I also noticed this other module called "Cluster", it seems to be related but I'm not sure how:
http://learnboost.github.com/cluster/
While not wanting to overwhelm, I also came across one called, "Haibu" it seems to be related but I'm not sure if it would just be an all out replacement for using vhosts:
https://github.com/nodejitsu/haibu
Note: I'm a front-end guy, so I'm not very familiar with a lot of server terminology

I never figured out Haibu or Cluster. But I did find a good solution that addressed my issue. To my surprise, it was actually quite simple. However, I don't know much about servers, so while this works, it may not be optimal.
I set up virtual hosts like normal on Apache
(http://httpd.apache.org/docs/2.0/vhosts/examples.html)
I installed the following on Node
Express (http://expressjs.com/)
node-http-proxy (https://github.com/nodejitsu/node-http-proxy)
Then, as a matter of personal style, I placed all my virtual hosts in a common directory (/localhost)
I then switched Apache to listen on a port other than port 80. I just happened to choose port 9000 because I had seen that used somewhere. (In httpd.conf, changed "Listen 80" to "Listen 9000"). I also had to make sure that all my virtual hosts, as defined in extra/httpd-vhosts.conf were set to an IP based nameVirtualHost (127.0.0.1) instead of using a port (*:80).
On the Node side, I created my app/server (aka node virtual host) that listened on port 8000 (somewhat arbitrarily choice of port number) See this link on creating a server with express: http://expressjs.com/guide.html
In my /localhost directory I then created a file called "nodeHttpProxy.js"
Using node-http-proxy, in nodeHttpProxy.js I then created a proxy server that listens on port 80. Using express, which wraps connect (http://www.senchalabs.org/connect/) I created my virtual hosts.
The nodeHttpProxy.js file looks like this:
// Module dependancies
var httpProxy = require('/usr/local/lib/node_modules/http-proxy/lib/node-http-proxy')
, express = require('/usr/local/lib/node_modules/express/lib/express');
// Http proxy-server
httpProxy.createServer(function (req, res, proxy) {
// Array of node host names
var nodeVhosts = [
'vhost1'
, 'vhost2'
]
, host = req.header('host')
, port = nodeVhosts.indexOf(host) > -1
? 8000
: 9000;
// Now proxy the request
proxy.proxyRequest(req, res, {
host: host
, port: port
});
})
.listen(80);
// Vhosts server
express.createServer()
.use(express.vhost('vhost1', require('./vhost1/app')))
.use(express.vhost('vhost2', require('./vhost2/app')))
.app.listen(8000);
As you can see, I will have to do two things each time I create a new Node virtual host:
add the virtual host name to my "nodeVhosts" array
define a new express virtual host using the .set method
Of course, I will also have to create the actual host path/files in my /localhost directory.
Once all this is done I just need to run nodeHttpProxy.js:
node nodeHttpProxy.js
You might get some weird "EACCESS" error, in which case, just run as sudo.
It will listen on port 80, and if the host matches one of the names in the nodeVhosts array it will forward the request to that host on port 8000, otherwise it will forward the the request onto that host on port 9000.

I've been giving this some thought lately as I'm tackling the same problems on my personal test environment. You are not going to be able to get around having each node application running on it's own port, but you can abstract away the pain of that process. Here is what I am using now, but I hope to build an npm package around this to simplify things in the future.
Each of my node.js applications has a map file that contains the port that the application is listening on as well as a map that indicates the expected path which the application is being served on. The contents of the file look like this:
{"path": "domain.com/path", "port": 3001}
When I start my application, it will read the port from the map.json file and listen on the specified port.
var map = fs.readFileSync('map.json', 'ascii');
app.listen(map.port);
Then in my proxy setup, I iterate over each of my node.js application directories, and check for a map.json file which indicates port 80 traffic should be proxied to this application.
I use almost the exact same method to setup the proxy for our apache hosted applications as well. We use a folder based convention on the PHP websites that we are serving and it uses the following configuration:
VirtualDocumentRoot /var/www/%-2.0.%-1/%-3+/
VirtualScriptAlias /var/www/%-2.0.%-1/%-3+/cgi-bin/
This essentially allows us to map domains to folders using the following structure.
http://sub.domain.com/ = /var/www/domain.com/sub/
There is no additional configuration needed to add or remove sites. This is very close to what I am currently using to proxy both apache and node sites. I am able to add new node and new apache sites without modifying this proxy application.
proxy.js
var fs = require('fs');
var httpProxy = require('http-proxy');
var proxyTable = [];
// Map apache proxies
fs.readdirSync('/var/www/').forEach(function(domain) {
fs.readdirSync('/var/www/' + domain).forEach(function(path) {
var fqd = domain + '/' + path;
var port = fs.readFileSync('port', 'ascii');
proxyTable[fqd] = fqd + ':' + 8080;
});
});
// Map node proxies
fs.readdirSync('/var/www-node/').forEach(function(domain) {
var map = fs.readFileSync('map.json', 'ascii');
proxyTable.[map.path] = '127.0.0.1:' + map.port;
});
var options = {
router: proxyTable
};
var proxyServer = httpProxy.createServer(options);
proxyServer.listen(80);
In the future, I will probably decouple the path from the port that the application is listening on, but this configuration allows me to build the proxy map automatically with very little work. Hopefully this helps.

I took some inspiration from #uglymunky and wrote a chef script to do this on Ubuntu.
With this script you can install express and apache with vhost support on a single server using 1 line after you pull down my chef project from github
https://github.com/toranb/ubuntu-web-server
If you have git installed and you pull it down you can kick it off like so ...
sudo ./install.sh configuration.json
This does require Ubuntu 12.04 or greater as I took advantage of an upstart script to start node when you reboot the machine
When the script is finished you will have a working ubuntu web server with express to run any node apps you configured, along side apache to run any wsgi apps you configured

I'm working on an extremely minimal and to the point library that can be totally segregated from your projects. Basically the idea would be run this independently on your servers and don't ever worry about having to bundle this in your projects how you would with connect.
Take a look at the config.json file to see how simple it actually is to setup.
I was looking for this and I did find a few things but they didn't support everything I needed which specifically is HTTPS, WS and WSS!
Right now the library I wrote only works for HTTP. But in the next few days I hope to have it finished and working for HTTPS, WS and WSS as well.

Related

Setting firewall rules to enabling running Apache2HttpServer and ApacheTomcat 9 on the same machine with two different hostname/ip:port

I have a Virtual Machine Linux Debian 10, with two Host-Only Network interfaces actived respectvely 192.168.56.10 and 192.168.56.15 with static ip address.
Apache Tomcat 9 is installed and Apache2 Http Server is installed too.
My purpose is that Apache Tomcat 9 must run on 192.168.56.15:8080,
while Apache2 Http Server must run on 192.168.56.10:80.
The /etc/hosts file in my Linux is:
#
192.168.56.10 www.example.com
192.168.56.15 openam.example.com
#
The C:\Windows\System32\drivers\etc\hosts is the same.
In short I'm trying to setup a small development enviroment for Identity and Access Managment using the Forgerock's AM solution. That software has to be deployed as a .war file (openam.war) in Tomcat /webapps and it will be mapped as openam.example.com, and I want this service run on
192.168.56.15:8080/openam;
So my problem is that I want two different services responding two different interfaces but running on the same Virtual machine.
I want that only if i type 192.168.56.15:8080 or openam.example.com:8080 I recive a respond from Tomcat, but if I type 192.168.56.15:80 or openam.example.com:80 Apache Http Server doesn't have to respond. Apache Http Server have to respond only on 192.168.56.10:80 or www.example.com.
In this way I can have like two different machines one with the web server and one with the application server, responding on two different IP addresses and hostname, but running on the same machine.
Thanks for help!
You could have 2 IPs but what's the point in doing so?
I find it rather pointless to have 2 separate IPs for 2 different services on the same machine (e.g tomcat on 1 / HTTP server on the other) for a development environment inside a VM. Port handling will be handled by the operating system itself and route the request to the open port.
Keep in mind that browsers will try to connect http:// calls on port 80 by default - so unless you type 8080 into the URL the browser it is just going to use port 80.
If you do not want calls to openam.example.com to come in on port 80, the simplest way round it is to use a htaccess rule that implements a rewrite for any request that contains openam.example.com (or just anything in a subdomain portion) on port 80 to be rewritten to the appropriate URL.

uWSGI and nginx configuration for multiple flask apps running on different ports on the same server

I have multiple small flask apps. I would want to run each of the flask apps on different ports on the same server(single domain).
For example say i have 3 flask apps
tasks.py --> has API endpoints with /task only
users.py --> has API endpoints with /user only
analysis.py --> has API endpoints with /analysis only
domain name : api.test.com
I want to run tasks.py on port 8080 , users.py on port 5000 and analysis.py on say port 4500.
I want to configure my uWSGI and nginx so that when i hit the api.test.com/task/xxxx i want the request to be directed to port 8080 (where tasks.py is running),
similarly api.test.com/user/xxxx should be directed to port 5000 and api.test.com/analysis/xxxx to 4500
It seems to me that you could have one single uWSGI isntance for that with one port, but if you like this way of thinking, then you can follow the next way.
Suppose, you already have several uWSGI instances running on different ports: 8080, 5000 and 4500.
Then you need to create an Nginx config with approximately the following content (read the comments, please):
# webserver configuration
server {
# port to be listened by the web-server
listen 80;
# domain name with its aliases or the ip
server_name api.test.com;
# SETUP THREE LOCATION SECTIONS FOR EACH ACTION
location /task {
# AND SPECIFY THE NEEDED ADDRESS:PORT HERE
uwsgi_pass YOUR_SERVER_IP:8080;
# ONE MAY ALSO USE UNIX-SOCKET (IF ON THE SAME SERVER), INSTEAD OF A PORT
# uwsgi_pass unix:/path/to/the/socket.sock
include /etc/nginx/uwsgi_params; # stadard parms with environment variables required by a uwsgi app
}
location /user {
uwsgi_pass YOUR_SERVER_IP:5000;
include /etc/nginx/uwsgi_params;
}
location /analysis {
uwsgi_pass YOUR_SERVER_IP:4500;
include /etc/nginx/uwsgi_params;
}
}
I hope, you know, how to run three uWSGI instances for each of the ports.
In my opinion, this is extremely ugly, as in order to add any new action you will have to edit Nginx config again. So I don't recommend this solution and only suggest this answer as demonstration of Nginx's capabilities in connection with other web servers.

Cannot install Wordpress Multisite (Network) on a custom port

I'm running a website at http://localhost:8080/sitename. However, when I'm trying to create a network of sites with wordpress, I'm getting the following error under Tools-> Network:
ERROR: You cannot install a network of sites with your server address.
You cannot use port numbers such as :8080.
I tried to create a virtual host and a fake domain but I can't make it work.
How can I solve that?
At this moment, Wordpress only seem to support 80 and 443 ports. A temporary possible workaround to use any custom (i.e. http 8080) port:
Open wp-admin/includes/network.php and find the section of code where it mentions array( ':80', ':443' ) and add :8080 too in that array.
After completing setup of network, you might need in wp-config to adjust to such:
define( 'DOMAIN_CURRENT_SITE', 'example.com'. (stristr($_SERVER['PHP_SELF'],'wp-login.php') ? '':':8080') );
As noted in comments (thanks) after creating first sub-site, it might have port number embedded in domain name, so try to enter Mysql Database (i.e. try hosting's phpMyAdmin, or even installed plugin before starting procedure) and in _blogs & _site& _options tables, to adjust homepage urls of subsites(i.e. separate port number from domain).
That's all. Login again to your project.
From my experience, WP is not designed to use custom ports for multi-sites so the blogs (sub-sites) hosts get messed up in the DB.
My solution: After you switch to multi-site or create a new site, you need to go to your db admin page (e.g. phpMyAdmin) and fix the blogs domain in the wp_blogs table. Basically WP failed to add a colon between the host and port; just have to add it-> localhost8080 becomes localhost:8080.
So, on the site's settings add the missing colon to the siteurl and home urls.
I found temporary solution:
running "netstat -o -n -a | findstr 0.0.80" in CMD will show you wich service is using the port 80. If PID is 4 it means that port 80 is used by the system (propably IIS or web matrix if it is installed - this was my case). i changed the port IIS was using from IIS Manager and i also deactivated MsDepSvc service (Web Matrix) which was also using port 80. After that i reconfigured apache to work in port 80 and everything worked OK!

Will running node.js with Apache causes too much performance degradation?

I am trying to run Apache and node.js on the same Amazon EC2 instance. After research online, I came up with the following solution:
run Apache on port 9000
run node.js apps on port 8001, 8002 and so on.
create a reverse proxy in node.js, running on port 80. It routes requests to different ports based on the hostname.
This solution works. (Although I haven't found a way to start node.js automatically)
My question is, will running multiple node instance causes performance degradation? Or will the reverse proxy be a problem?
Thanks,
Performance Degradation
On the contrary. If all you do with node is proxying, the overload is insignificant (as compared to apache's). I do have a quite similar setup as yours (small virtual machine, 3 legacy apache websites, node.js proxying and enhancement). So far, apache is the resource eater, not my node apps, which nonetheless proxy/filter/intercept every incoming http request
Here's my setup :
main proxy
which handles all incoming requests (for as many domains as you like) : I personally use nodejitsu's http-proxy which is very robust and simple to configure
var http = require('http');
var httpProxy = require('http-proxy');
var options = {
hostnameOnly: true,
router: {
'domain1.com': '127.0.0.1:8081',
'www.domain1.com': '127.0.0.1:8081',
'subdomain1.domain1.com': '127.0.0.1:8082',
(...)
'domain2.com': '127.0.0.1:8090',
(...)
}
}
var mainProxy = httpProxy.createServer(options);
mainProxy.listen(8080);
You can redirect to apache directly from the option object, or do some more url parsing in another (middleware) node app on a different port.
WARN: if you don't wish to install/run node as 'root' (which I'd strongly advise in a production environement) : redirect port 80 to some other port with an IPTABLE directive (let's say 8080) where this proxy runs (see here for detailed example of Iptable directives). Mine, on a debian squeeze, reads :
#REDIRECT port 80 to 8080
$IPTABLES -t nat -I PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
node apps
which do some URL parsing with regexes, or whatever you need. Ex: redirect to a few (legacy) apache servers which (in my case) only serve legacy content not yet served by the 'in developement' node apps.
Daemonisation
There are several solutions to make node run as a daemon. My favorite two are :
nodemon will monitor all files in your node app folder and subfolder for change and restart the node app on file change. It's perfect for a development environment
forever (yet again by Nodejitsu) will restart your node app if ever it stops. It's very customisable.
Also :
init.d script : I've written this debian init.d script for my own servers (should work on ubuntu)
Node is really really fast and it's build for handling thousands of connections in the same time, so using a proxy built with it won't be a problem at all in my opinion.

Ports Apache and ExpressJS

I am using Apache, which listens on port 80, expressjs and socket.io. Mainly, my question is in which port should I make expressjs to listen to so that I do not need to write the port on the url.
Let's say I want to get the id of this url:
localhost/web/:id
The problem is that if I have Apache running on port 80, then expressjs won't recognize that url, so I should write it like this [if I have app.listen(81)]:
localhost:81/web/:id
Which is actually unreal because I can't make the user to write :81
I've read something about http-node-proxy, but don't understand pretty well
Thanks!
Why do you need to run both Apache and Node?
If its a requirement, you're going to need to come up with a way to forward a particular route/path on to the particular server you're hosting resources on. This is called a reverse http proxy.
You can:
Run Apache on port 80 and forward a subset of urls onto node, which will run on a non-80 port - http://www.apachetutor.org/admin/reverseproxies
Run node on port 80 and use something like node-http-proxy to set up route forwarding - http://blog.nodejitsu.com/http-proxy-intro
Run something like ngnix as the reverse proxy, and have both apache and node on non-80 ports - http://www.ubuntugeek.com/using-nginx-as-a-reverse-proxy-to-get-the-most-out-of-your-vps.html
Or... collapse your servers and just use node. Node can do static file hosting (not super well, but that's all relative)