Victor is a full stack software engineer who loves travelling and building things. Most recently created Ewolo, a cross-platform workout logger.
Setting up multiple websites with Nginx, Node.js and MySQL

Here's a little tutorial on how to setup multiple Node.js applications running on different ports and serving different domains on one machine. I'll assume that you're doing this on some cloud hosted machine running ubuntu (>= 12.04) and on which you have root access. I'll also assume that you've gotten as far as being able to run your Node.js apps and being able to get data via :

http://<ip_address_of_the_machine>:<port1>
http://<ip_address_of_the_machine>:<port2>

So what we are now going to do is setup Nginx as a reverse proxy and let it map requests for a particular domain to the correct Node.js app. We thus begin by installing Nginx:

sudo apt-get install nginx
sudo service nginx start

Heading to http://<ip_address_of_the_machine> should now show the default welcome page. By default Nginx sets you up with a basic website configuration found under /etc/nginx/sites-available. There's another folder /etc/nginx/sites-enabled, which contains symlinks to the site configurations that are actually going to be loaded. For now, let's create a new configuration (replace port1 with your desired port).

cd /etc/nginx/sites-available
sudo vim domain1.com
server {

        listen 80 default_server;
        server_name domain1.com www.domain1.com;
        access_log /var/log/nginx/domain1.log;

        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-NginX-Proxy true;

                proxy_pass http://127.0.0.1:port1;
                proxy_redirect off;

                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}
cd /etc/nginx/sites-enabled
sudo rm default
sudo ln -s ../sites-available/domain1.com domain1.com
sudo service nginx restart

What we did here is tell Nginx to listen on port 80 for requests to domain1.com and www.domain1.com and then pass them along to the Node.js application listening on <port1>. We then removed the link to the default configuration and added a link to our new configuration and restarted nginx for the changes to take effet.

Heading to domain1.com in the browser should serve up your website! This is assuming that domain1's DNS entry has been correctly setup to point to the IP address of our machine in question. We will do something very similar for our second website (replace port2 again):

cd /etc/nginx/sites-available
sudo vim domain2.com
server {

        listen 80;
        server_name domain2.com www.domain2.com;
        access_log /var/log/nginx/domain2.com.log;

        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-NginX-Proxy true;

                proxy_pass http://127.0.0.1:port2;
                proxy_redirect off;

                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}
cd /etc/nginx/sites-enabled
sudo ln -s ../sites-available/domain2.com domain2.com
sudo service nginx restart

Heading to http://domain2.com should now serve you domain2's content!

A lesser person would probably pack it up and call it a day at this point but we're better than this. Let's assume that we have MySQL installed on the machine and that we'd like to install phpmyadmin for easy database management. We first need to enable PHP support for Nginx.

Update April 7, 2017
I recently upgraded ubuntu to the latest LTS which came with php7. The changes required are as follows:
sudo apt-get install php7-fpm php7-mysql
Skip fixing the security hole in php.ini and use the following sock file location in the server configuration
fastcgi_pass unix:/run/php/php7.0-fpm.sock;

sudo apt-get install php5-fpm php5-mysql

There's a small security hole in the default configuration of this module. Let's close it by opening up the php.ini file and uncommenting cgi.fix_pathinfo=1 and changing it to cgi.fix_pathinfo=0. You can google what this variable does and why we're doing this.

sudo vim /etc/php5/fpm/php.ini
; fix security hole
cgi.fix_pathinfo=0
sudo service php5-fpm restart

Nginx should now have php support setup, lets modify domain2's configuration to pass php requests via the php module.

sudo vim /etc/nginx/sites-enabled/domain2.com
server {

        listen 80;
        server_name domain2.com www.domain2.com;
        access_log /var/log/nginx/domain2.com.log;

        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-NginX-Proxy true;

                proxy_pass http://127.0.0.1:port2;
                proxy_redirect off;

                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
}

server {

  listen 8000;
  server_name domain2.com www.domain2.com;
    access_log /var/log/nginx/domain2.com.log;

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


  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
  }
}

Notice how we now forward requests to http://domain2.com:8000 over to /usr/share/nginx/html, thus heading to this url should fire up the default Nginx welcome page again. We can make a quick php info page to test that php is working fine.

sudo nano /usr/share/nginx/html/info.php
<?php
  phpinfo();
?>

Head to http://domain2.com:8000/info.php and revel in the glory that is php! We're not done yet, we'll install phpmyadmin to allow us to manage MySQL. Here we skip configuring phpmyadmin with the provided webserver choices and instead set it up via dbconfig-common.

sudo apt-get install phpmyadmin

# password: 
# bypass configuration
# setup dbconfig-common

Heading to http://domain2.com:8000/phpmyadmin now shows us our phpmyadmin interface!

Here we setup Nginx as a reverse proxy to serve Node.js applications but depending on your use case it is possible to use some Node.js modules such as vhost and simply route to separate applications depending on the hostname.

Feel free to email me regarding this tutorial. Cheers!