Just a {code} blog

Hosting multiple sites with a single nginx config file

This is the only solution that worked for me when it comes hosting multiple websites with multiple domains on a single nginx server and one IP.

The traditional way of doing this is to separate every server block in the sites-enabled folder with the accompanying config file. For example the sites-enabled folder structure would look like this:


/sites-enabled
  |-- example.com
  |-- mywebsite.com
The server block for example.com would look like this:

server {
	Listen 80;
	Server_name example.com
	Root /var/www/example.com/html
	Index index.php index.html

 location / {
            try_files $uri $uri/ =404;
  }

          location ~ \.php$ {
            	include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/run/php/php7.0-fpm.sock;
          }

}
The server block for mywebsite.com:

server {
	Listen 80;
	Server_name mywebsite.com
	Root /var/www/mywebsite.com/html
	Index index.php index.html

 location / {
            try_files $uri $uri/ =404;
  }

          location ~ \.php$ {
            	include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/run/php/php7.0-fpm.sock;
          }
}

For some strange reason, this didn’t work for me, even with Ubuntu 16.04 and nginx 1.10. With the above configuration, example.com becomes the default server, even thought default_server is not declared inside the listen directive.

When I point my browser to mywebsite.com , the example.com website would show up.

The solution

The solution I came up with is having a single configuration file that store the domain in a variable and then use it for the root directory:


   server {
          listen 80;
          server_name ~^(www\.)?(?.+)$;
          root /var/www/$domain/html;
          index index.php index.html;

          location / {
            try_files $uri $uri/ =404;
          }

          location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/run/php/php7.0-fpm.sock;
          }

        }

Now you can make multiple folders inside

/var/www/
for example:
/var/www/onesite.com/html
and place index.html or index.php inside that folder and point onesite.com to your IP and voila.

There is one more thing though..

The above configuration works great for non-https but if you need https(who doesn’t?) then it doesn’t work. The reason? Variables are evaluated in the run-time during the processing of each request (Link)

That means that if we want to add ssl configuration to the above script:


ssl_certificate /etc/letsencrypt/live/$server_name/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$server_name/privkey.pem;
it will not work.

In future post I will share with you my bash script for overcoming this problem. Until then, keep coding!