Friday, April 12, 2019

Supporting Multiple Websites on a Single Webserver


Subtitle: Using NGINX and SNI

When you work with computers the word backup occurs frequently in conversation.  It is not that computers are unreliable, it's just that people expect them to be 100% reliable.


So for years Marcus has operated 2 differently named Websites in different continents.  They are kept uptodate using a single rsync synchronisation command like this


cd /data
rsync -avuzh ./static  username@domain.tld:www/


Saving Money
(Times are Hard)


I've been very happy with the service from Bluehost.com  who represent my US Web Hosting Service.  But today we have full fibre to the Home in England, and though the speed is only the merest fraction of that we had in Switzerland it has been quite reliable.

Plus Marcus has implemented a Multi Internet Load Balancer using Mikrotik hardware, which means that should the Fibre fail there can be an alternated Internet source to select, this even being in an Emergency a USB tethered 4G Smartphone.

The cost of Bluehosting is about 400 USD per year and the cunning plan is now this

a) relocate Both Webservers to our local England bonsai datacentre

b) If funds allow in the future restart dual site hosting, one local, one external


Notes About Bluehost

I'm not an expert, but I did multiple and searches and researched Bluehost in 2017 when I signed up.  So they provide

- Sophisticated Control Panel as shown above.   You can install many facilities, which we did not use

- You have a UNIX command line 

- Ability to synchronise with tools like rsync

- Dedicated IP address

- And the most important point to me: No caps on Bandwidth.  This is important as I investigated building a virtual Amazon or Microsoft host, but when you need huge (well over 300 GB) of disk space and traffic (> 500GB per month) then the cost skyrockets upward.

- Bluehost did provide a solution, it's just not as cheap as free, which is what I'll be describing below


Hosting Multiple Websites

This is the new setup whereby both webservers will be at the end of our home Infrastructure, housed in our least secure and dedicated  DMZ (Demilitarised Zone) . Actually it is a DMG 




00 On Local WebServer

Check nginx is SNI Server Name Indication compatible


# nginx -V
nginx version: nginx/1.15.9
built by gcc 6.3.0 20170516 (Raspbian 6.3.0-18+rpi1+deb9u1)
built with OpenSSL 1.1.0j  20 Nov 2018
TLS SNI support enabled
configure arguments: --add-module=../ngx-fancyindex --with-http_ssl_module
We need our new webserver to be able to look at the domain name of the incoming web URL  and this needs SNI facility.  It was compiled in by me, so good and continue.


01 Moving from Bluehost to Namecheap






The first step was to goto Bluehost and unlock the domain.  After that use the Transfer tab to generate a special code that can be used by the receiving service, which is Namecheap



02 Namecheap Transfer



On the new provider Namecheap enter the special code given by Bluehost and the processing starts

03 Check Back BlueHost

To complete the process (not all Providers require this), go back to the original provider (Bluehost) and it says that a transfer is requested.  You just have to confirm it.

Once this is done  go back to Namecheap

The whole transfer process took less than 2 hours.  I was totally gobsmacked as to the efficiency

By the way I am still smitten with Namecheap and I wrote this earlier.




04 Initial Changes



Namecheap is very clever and on import uses the DNS from Bluehost as their resolution.  In other words at this moment although the domain was transferred it was still running on Bluehost servers.

So change that back to Namecheap local, at which point the website is down.  So hurry up with the next steps


05 Temporarily Add site listening on Port 80

Initially we need to temporarily setup a website on port 80 that responds to the new website request so that the certification program certbot will work


certbot is going to provide us with a free https certificate



pwd
/usr/local/nginx/sites-enabled

# Note the location in /usr/local because this nginx server I compiled myself else
# it would be in /etc/nginx/sites-enabled
# this is the file  yournewdomain.tld

server {
    listen               80;
    server_name          yournewdomain.tld;
  
    root /var/www/root;
 
    # For ACME challenge
    location ~ /.well-known {
        allow all;
    }
#Stop and Start webserver
systemctl stop nginx.service
systemctl start nginx.service
The ACME challenge is going to work this way.  You will run certbot locally. It goes to an Internet based server which asks for a special http URL on your webserver.   Your webserver needs to reply to this hence the highlighted code

06 Temp Comment out existing http reference

So your new webserver will reply to the certbot request on port 80, but  lets just be safe and make sure the other existing webserver does not listen in


# pwd
/usr/local/nginx/sites-enabled

cat existingsite.tld

# server {
  #   listen 80;
  #   server_name  existingsite.tld;
  #   return 301 https://$host$request_uri;

    # root /var/www/root;
    # location / {
    # fancyindex on;
    # fancyindex_exact_size off;        # off: Use GB / MB / KB etc.
    # fancyindex_localtime on;          # on: Use server local time
    # fancyindex_header /header.html;   # Customization Header Code
    # fancyindex_footer /footer.html;   # Customization Footer Code
    # }


     # }
#Stop and Start webserver
systemctl stop nginx.service
systemctl start nginx.service
07 Generate a Certificate

Your new website will serve only https.  Serving http is for losers right?  In fact http requests will be rewritten to https (see above return statement).   Instead of buying a https certificate from a certification authority, now you can generate your own using certbot for free.  How excellent is that?





certbot certonly -a webroot --webroot-path=/var/www/root -d yournewdomain.tld



08 Modify 2nd Website Configuration file


pwd
/usr/local/nginx/sites-enabled

cat yournewdomain.tld

server {
    listen 80;
    server_name  yournewdomain.tld;
    return 301 https://$host$request_uri;

    root /var/www/root;
    location / {
    fancyindex on;
    fancyindex_exact_size off;        # off: Use GB / MB / KB etc.
    fancyindex_localtime on;          # on: Use server local time
    fancyindex_header /header.html;   # Customization Header Code
    fancyindex_footer /footer.html;   # Customization Footer Code
    }


     }


# For ssl
server {
    ssl_certificate /etc/letsencrypt/live/yournewdomain.tld/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yournewdomain.tld/privkey.pem;
    # ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

    default_type  application/octet-stream;

    listen 443 ssl;

    server_name  yournewdomain.tld;

    root /var/www/root;


location / {
    fancyindex on;
    fancyindex_exact_size off;        # off: Use GB / MB / KB etc.
    fancyindex_localtime on;          # on: Use server local time
    fancyindex_header /header.html;   # Customization Header Code
    fancyindex_footer /footer.html;   # Customization Footer Code
    }


} #end of server ssl

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

# :color desert
In this config yournewdomain.tld to be replaced by your secondwebsite domain e.g xibm.com


#Stop and Start webserver
systemctl stop nginx.service
systemctl start nginx.service
09 Put back 1st Website Config File

Need to restore the first webserver config file which essentially means un-commenting the port 80 statements.  So in future the re-write is reinstated.  Obviously for both sites as its in each file


pwd
/usr/local/nginx/sites-enabled


# cat existingsite.tld


server {
    listen 80;
    server_name  existingsite.tld;
    return 301 https://$host$request_uri;

    root /var/www/root;
    location / {
    fancyindex on;
    fancyindex_exact_size off;        # off: Use GB / MB / KB etc.
    fancyindex_localtime on;          # on: Use server local time
    fancyindex_header /header.html;   # Customization Header Code
    fancyindex_footer /footer.html;   # Customization Footer Code
    }


     }


#Stop and Start webserver
systemctl stop nginx.service
systemctl start nginx.service

In this snippet of the configuration since both webservers have exactly the same content we are pointing them to the exact same server root i.e. /var/www/root.  Of course if there were normally 2 webservers that are not a clone of each other they would have their own root statement pointing to different areas.

So the final configuration has 2 config files in the sites-enabled directory called existingsite.tld and yournewdomain.tld.    When nginx starts it passes the inbound URLs to the config appropriate to each file as governed by the server_name parameter in the file.   The normal case would be to have different server_root and different configuration in each file.

In our special case both files are almost identical because they are the same site with different domains.

Using certbot we are able to generate 2 different https certificates free of any charge.  These are referenced in the ssl configuration part of each config file.


And that is it folks
So after the modifications I checked that both websites are now existing together quite wonderfully on the same webserver.  Great!