Generate server block (v-hosts) for nginx dynamically
Hey pals, I will show you how to create a basic shell script so you can dynamically generate nginx virtual hosts or "subdomains" for every site you want to put online. There are two examples, one for your node or whatever app that runs locally, the second is for static websites.
Reversed proxy subdomain example
If you are running a node app on a specific port this basic example will help you to create and connect your site. The following is the stub file we will use subdomain.stub
:
server {
listen 80;
listen [::]:80;
index index.html index.htm;
server_name {{DOMAIN}}.yoursite.com;
location / {
proxy_pass http://localhost:{{PORT}};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Now let's create the generator.sh
shell script:
#!/bin/bash
SED=$(which sed)
CURRENT_DIR=$(dirname $0)
# check the domain is valid!
PATTERN="^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$"
if [[ "$1" =~ $PATTERN ]]; then
DOMAIN=$(echo $1 | tr '[A-Z]' '[a-z]')
echo "Creating hosting for:" $DOMAIN
else
echo "invalid domain name"
exit 1
fi
CONFIG="$CURRENT_DIR/$DOMAIN.yoursite.com"
cp $CURRENT_DIR/subdomain.stub $CONFIG
$SED -i "s/{{DOMAIN}}/$DOMAIN/g" $CONFIG
$SED -i "s/{{PORT}}/$2/g" $CONFIG
echo "The subdomain has been successfully generated"
cp $CONFIG "/etc/nginx/sites-available"
ln -s "/etc/nginx/sites-available/$DOMAIN.yoursite.com" "/etc/nginx/sites-enabled"
echo "The subdomain has been moved to nginx to sites-available and symlinked to sites-enabled"
In your terminal you run the command as follows: ./
generator.sh
<DOMAIN> <PORT>
In order to run this script you have to make it executable with this command: chmod u+x
generator.sh
otherwise you won't be able to execute it.
Now it's ready to run, let me explain what it does:
Stores the current location
Creates a domain pattern and then compares it with the 1st parameter (DOMAIN)
Defines CONFIG location, then clones the subdomain.stub file into the previous definition
Replaces the
{{DOMAIN}}
value inside the cloned configurationReplaces the
{{PORT}}
value inside the cloned configuration
At this point our virtual host is ready to be published
Copies the new virtual host file into "/etc/nginx/sites-available" which is the folder for every available site with nginx
Then creates a symlink from the previous location to
/etc/nginx/sites-enabled
which is the folder for every enabled site with nginx
Once this is done you need to ensure virtual hosts definitions are valid. You can do this by running nginx -t
in your terminal. If everything went well now you only need to reload/restart nginx so changes can be applied. nginx service reload/restart
.
Static site subdomain example
This example is for static websites (not SSR)
subdmain.stub
:
server {
listen 80;
listen [::]:80;
root /var/www/{{DOMAIN}};
index index.html index.htm index.nginx-debian.html;
server_name {{DOMAIN}}.yoursite.com;
location / {
try_files $uri $uri/ /index.html = 404; #This line redirects to index for correct react router usage
}
}
Then we use basically the same generator.sh
script than before:
#!/bin/bash
SED=$(which sed)
CURRENT_DIR=$(dirname $0)
# check the domain is valid!
PATTERN="^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])$"
if [[ "$1" =~ $PATTERN ]]; then
DOMAIN=$(echo $1 | tr '[A-Z]' '[a-z]')
echo "Creating hosting for:" $DOMAIN
else
echo "invalid domain name"
exit 1
fi
CONFIG="$CURRENT_DIR/$DOMAIN.yoursite.com"
cp $CURRENT_DIR/subdomain.stub $CONFIG
$SED -i "s/{{DOMAIN}}/$DOMAIN/g" $CONFIG
echo "The subdomain has been successfully generated"
cp $CONFIG "/etc/nginx/sites-available"
ln -s "/etc/nginx/sites-available/$DOMAIN.yoursite.com" "/etc/nginx/sites-enabled"
echo "The subdomain has been moved to nginx to sites-available and symlinked to sites-enabled"
The only difference is that we no longer require a PORT, so you will run the command like this: ./
generator.sh
${DOMAIN}
(Do not forget to make the script executable)
From here the sky is the limit my friend, you could easily create your own stubs/snippets with many variables as needed. Also they only contain the minimum requirements to be served by nginx, have fun adding more specifications.
BONUS!! 🤯
If you read my previous post Easy node apps deployment with PM2 let me show you how you could integrate this virtual host generator to a pm2 deployment set up file ecosystem.config.js
:
module.exports = {
deploy: {
production: {
user: USER,
host: HOST,
ref: BRANCH,
repo: REPO,
path: PATH,
'post-setup': `npm install && cd setup/ && chmod u+x generator.sh && ./generator.sh ${DOMAIN}`
}
}
};
Now you only have to create a /setup
folder inside your project with the subdomain stub as well as the generator script and that's it. Ready to be executed after setup.
This post was originally published in my dev.to blog: https://dev.to/eichgi/generate-server-block-virtual-hosts-for-nginx-dynamically-1fpp
Subscribe to my newsletter
Read articles from Hiram directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Hiram
Hiram
senior software engineer | cloud engineer