Automatically creating new virtual hosts with Nginx (Bash script)

NOTE: This script has been superseded by this one: Bash Script to Create new virtual hosts on Nginx each under a different user

Setting up virtual hosts on any sort of web server normally takes at least a few minutes and several commands (if you’re not running a control panel of some variety, and even then it normally takes a good number of clicks and checking boxes to get what you want). All of this can be quite annoying when you have to set up several of these a day.

So I put together a simple bash script to quickly provision the hosting for a new static site running on Nginx. The script was originally build for use on the Amazon AMI running on AWS. The script uses the sudo command as the password is not required for the default user on the AWS AMI, however if you are running as a non root user with access to the sudo command then you should be prompted for your password when running the script.

What does the script do:

  • Creates a new vhosts entry for nginx using a basic template
  • Creates a new directory for the new vhost and sets nginx as the owner
  • Adds a simple index.html file to the new directory to show the site is working.
  • Reloads Nginx to allow the new vhost to be picked up

How it works:

It uses the debian style set up for apache as its basis for handling vhosts with Nginx. This means under your Nginx config directory (/etc/nginx) you need to have two extra directories:

  • sites-available
  • sites-enabled

In the sites available dir goes the the individual config files for each vhost, each new vhost using a new file. Under the sites enabled directory goes a symlink to the config file in the sites available directory, this gives you the ability to disable sites without removing tis files or config. This all works by adding the following line to the end of the /etc/nginx/nginx.conf file (within the http section)

# Load all vhosts !
include /etc/nginx/sites-enabled/*.conf;

The hosting directory for the new site can be set by modifying the WEB_DIR value at the top of the script which defaults to /var/www

So the new hosting directory for your domain example.com ends up as:

/var/www/example_com

Whilst the original version of the script created a new user for each site and made that user the owner of the hosting directory I have removed this functionality to make the script less taylored to my needs (if needed this user creation bit could easily be re-added) . For the moment then the script grants the nginx user owner rights to the new vhost directory (which from a security perspective is not great), so you may want to modify this.

How to use it:

Simply download the tar file at the end of the this article and extract it. If your not sure how to extract a tar file either read the man pages or use the command below:

tar -xzf create_nginx_vhost.tar.gz

Once you have extracted the archive just run the create_nginx_site.sh script passing to it the domain name as the only parameter (you will need execute permissions), e.g.

./create_nginx_site.sh example.com

And you should see an output similar to the following:

Creating hosting for: example.com
Reloading nginx:                                             [  OK  ]
Site Created for example.com

The script:

# Script by: Seb Dangerfield - sebdangerfield.me.uk
NGINX_CONFIG='/etc/nginx/sites-available'
NGINX_SITES_ENABLED='/etc/nginx/sites-enabled'
WEB_DIR='/var/www'
SED=`which sed`
CURRENT_DIR=`dirname $0`
 
if [ -z $1 ]; then
	echo "No domain name given"
	exit 1
fi
DOMAIN=$1
 
# check the domain is roughly valid!
PATTERN="^([[:alnum:]]([[:alnum:]\-]{0,61}[[:alnum:]])?\.)+[[:alpha:]]{2,6}$"
if [[ "$DOMAIN" =~ $PATTERN ]]; then
	DOMAIN=`echo $DOMAIN | tr '[A-Z]' '[a-z]'`
	echo "Creating hosting for:" $DOMAIN
else
	echo "invalid domain name"
	exit 1
fi
 
#Replace dots with underscores
SITE_DIR=`echo $DOMAIN | $SED 's/\./_/g'`
 
# Now we need to copy the virtual host template
CONFIG=$NGINX_CONFIG/$DOMAIN.conf
sudo cp $CURRENT_DIR/virtual_host.template $CONFIG
sudo $SED -i "s/DOMAIN/$DOMAIN/g" $CONFIG
sudo $SED -i "s!ROOT!$WEB_DIR/$SITE_DIR!g" $CONFIG
 
# set up web root
sudo mkdir $WEB_DIR/$SITE_DIR
sudo chown nginx:nginx -R $WEB_DIR/$SITE_DIR
sudo chmod 600 $CONFIG
 
# create symlink to enable site
sudo ln -s $CONFIG $NGINX_SITES_ENABLED/$DOMAIN.conf
 
# reload Nginx to pull in new config
sudo /etc/init.d/nginx reload
 
# put the template index.html file into the new domains web dir
sudo cp $CURRENT_DIR/index.html.template $WEB_DIR/$SITE_DIR/index.html
sudo $SED -i "s/SITE/$DOMAIN/g" $WEB_DIR/$SITE_DIR/index.html
sudo chown nginx:nginx $WEB_DIR/$SITE_DIR/index.html
 
echo "Site Created for $DOMAIN"

Download:

Please note both downloads contain exactly the same files

download (tar.gz)
download (zip)

Comments or Questions:

If you have any comments or questions please use the comments section below.

  • Artem

    Hey, can you please check your tar archive is right? I’m getting an error.

    • Seb Dangerfield

      The download appears to work fine. However just to make sure I have re-created the compressed tar archive and also uploaded a zip file of the files, both archives contain the same files just different formats depending on what people fancy.

  • Thank you Seb! This script is just what I was looking for 🙂

  • How would you add another argument for the IP address and have it add to listen in the .conf file?

    • Seb Dangerfield

      If we pass the IP as the second argument to the script then the simplest way todo this is to add a new line into the virtual_host.template file to tell nginx which IP address to listen on as follows:

      server {
         listen IP:80;
        server_name www.DOMAIN DOMAIN;

      Then modify the create_site_simple.sh and add a new line in the script after line 30 (i.e. in the section “Now we need to copy the virtual host template”):

      sudo $SED -i "s/IP/$2/g" $CONFIG
  • Fantastic script, Seb, and also great website you have here. One thing I perhaps would suggest, is when setting ownership of the web root, it would be wise to set the owner to the user but the group nginx:
    chown -R george:nginx /var/www/example.com

    I found this as a great way to ensure that the user’s own account can still publish sites under /var/www either through SFTP/HG/GIT or however without having to sudo or anything.

    Cheers

  • er0r

    nice article!

    but how can i add extra structure like

    vhost.vhots.tld and inside extra 3 dir HTDOCS, LOG, TMP