VestaCP Nginx Template

I like VestaCP and I host most of my sites using it on my servers. Recently I started writing more NodeJs applications and found it not trivial to get NodeJS traffic routed via VestaCP Nginx/Apache configs.


I usually make manual changes to the config file for that domain that is running the NodeJs app (which not a good way, since these configs get overwritten if you change the proxy template in the control panel)


Another way, is to make a copy of a template and make the changes there to set the reverse proxy. However, this template only works for one app since the proxy port is hard-coded in the template.

Here is an example of that method:
I first make a copy of default.tpl and default.stpl to my-node-app.tpl and my-node-app.stpl. Once for http and one for https

/usr/local/vesta/data/templates/web/nginx/my-nod-app.tpl

server {
    listen      %ip%:%proxy_port%;
    server_name %domain_idn% %alias_idn%;
    error_log  /var/log/%web_system%/domains/%domain%.error.log error;
    
    root %sdocroot%;
    index index.html;

    location / {
        proxy_pass      http://localhost:3000;
        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;


        try_files $uri $uri/ @rewrites;

        location ~* ^.+\.(%proxy_extentions%)$ {
            access_log     /var/log/%web_system%/domains/%domain%.log combined;
            access_log     /var/log/%web_system%/domains/%domain%.bytes bytes;
            expires        max;
        }
    }

    location @rewrites {
      rewrite ^(.+)$ /index.html last;
    }

    location /error/ {
        alias   %home%/%user%/web/%domain%/document_errors/;
    }


    location ~ /\.ht    {return 404;}
    location ~ /\.svn/  {return 404;}
    location ~ /\.git/  {return 404;}
    location ~ /\.hg/   {return 404;}
    location ~ /\.bzr/  {return 404;}

    include %home%/%user%/conf/web/*nginx.%domain_idn%.conf_letsencrypt;
    include %home%/%user%/conf/web/s%proxy_system%.%domain%.conf*;

/usr/local/vesta/data/templates/web/nginx/my-node-app.stpl

server {
    listen      %ip%:%proxy_ssl_port%;
    server_name %domain_idn% %alias_idn%;
    ssl         on;
    ssl_certificate      %ssl_pem%;
    ssl_certificate_key  %ssl_key%;
    error_log  /var/log/%web_system%/domains/%domain%.error.log error;
    
    # test %port_num%
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

    root %sdocroot%;
    index index.html;

    location / {
        proxy_pass      http://localhost:3000;
        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;


        try_files $uri $uri/ @rewrites;

        location ~* ^.+\.(%proxy_extentions%)$ {
            access_log     /var/log/%web_system%/domains/%domain%.log combined;
            access_log     /var/log/%web_system%/domains/%domain%.bytes bytes;
            expires        max;
        }
    }

    location @rewrites {
      rewrite ^(.+)$ /index.html last;
    }

    location /error/ {
        alias   %home%/%user%/web/%domain%/document_errors/;
    }


    location ~ /\.ht    {return 404;}
    location ~ /\.svn/  {return 404;}
    location ~ /\.git/  {return 404;}
    location ~ /\.hg/   {return 404;}
    location ~ /\.bzr/  {return 404;}

    include %home%/%user%/conf/web/*nginx.%domain_idn%.conf_letsencrypt;
    include %home%/%user%/conf/web/s%proxy_system%.%domain%.conf*;
}

Now, I can chose that template from the control panel domain settings and the traffic would be routed to port 3000.

The problem

The issue with this approach is that for each NodeJs application there needs to be a template created, that can only be used with this app (or this port number)

A better approach would be to be able to set the port and the hostname dynamically and route the requests to any any NodeJs application based on the settings.

But, VestaCP does not have any way of defining an extra field for the template to use. So I thought of creating my own way.

Solution

I could have forked the source code of VestaCP and added a field/way to modify the port number and hostname of the proxy config, but that would be a lot of work for a simple change. I went with a lazy solution that works well.

I first overload the proxy extensions field with the info I need; hostname and port number. Then inject a command to run inside VestaCP’s script that applies the template changes

/usr/local/vesta/bin/v-change-web-domain-proxy-tpl

My command is just a call to a simple bash script that modifies the config file after the changes have been applied by VestaCP replacing a token I have for hostname and default port number defined in the template.

The template

/usr/local/vesta/data/templates/web/nginx/nodejs.tpl

server {
    listen      %ip%:%proxy_port%;
    server_name %domain_idn% %alias_idn%;
    error_log  /var/log/%web_system%/domains/%domain%.error.log error;
    
    root %sdocroot%;
    index index.html;

    location / {
        proxy_pass      http://NODEJS_HOSTNAME:65535;
        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;


        try_files $uri $uri/ @rewrites;

        location ~* ^.+\.(%proxy_extentions%)$ {
            access_log     /var/log/%web_system%/domains/%domain%.log combined;
            access_log     /var/log/%web_system%/domains/%domain%.bytes bytes;
            expires        max;
        }
    }

    location @rewrites {
      rewrite ^(.+)$ /index.html last;
    }

    location /error/ {
        alias   %home%/%user%/web/%domain%/document_errors/;
    }


    location ~ /\.ht    {return 404;}
    location ~ /\.svn/  {return 404;}
    location ~ /\.git/  {return 404;}
    location ~ /\.hg/   {return 404;}
    location ~ /\.bzr/  {return 404;}

    include %home%/%user%/conf/web/*nginx.%domain_idn%.conf_letsencrypt;
    include %home%/%user%/conf/web/s%proxy_system%.%domain%.conf*;
}

/usr/local/vesta/data/templates/web/nginx/nodejs.stpl

server {
    listen      %ip%:%proxy_ssl_port%;
    server_name %domain_idn% %alias_idn%;
    ssl         on;
    ssl_certificate      %ssl_pem%;
    ssl_certificate_key  %ssl_key%;
    error_log  /var/log/%web_system%/domains/%domain%.error.log error;
    
    # test %port_num%
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

    root %sdocroot%;
    index index.html;

    location / {
        proxy_pass      http://NODEJS_HOSTNAME:65535;
        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;


        try_files $uri $uri/ @rewrites;

        location ~* ^.+\.(%proxy_extentions%)$ {
            access_log     /var/log/%web_system%/domains/%domain%.log combined;
            access_log     /var/log/%web_system%/domains/%domain%.bytes bytes;
            expires        max;
        }
    }

    location @rewrites {
      rewrite ^(.+)$ /index.html last;
    }

    location /error/ {
        alias   %home%/%user%/web/%domain%/document_errors/;
    }


    location ~ /\.ht    {return 404;}
    location ~ /\.svn/  {return 404;}
    location ~ /\.git/  {return 404;}
    location ~ /\.hg/   {return 404;}
    location ~ /\.bzr/  {return 404;}

    include %home%/%user%/conf/web/*nginx.%domain_idn%.conf_letsencrypt;
    include %home%/%user%/conf/web/s%proxy_system%.%domain%.conf*;
}

The script

export VESTA=/usr/local/vesta/
user=$1
domain=$2
nodejs_hostname=`/usr/local/vesta/bin/v-list-web-domain $user $domain | grep "PROXY EXT" | sed -r 's/.*nodejs_(.*)_([0-9]+).*/\1/g'`
port_num=`/usr/local/vesta/bin/v-list-web-domain $user $domain | grep "PROXY EXT" | sed -r 's/.*nodejs_(.*)_([0-9]+).*/\2/g'`

sed -i "s/NODEJS_HOSTNAME:65535/$nodejs_hostname:$port_num/g" /home/$user/conf/web/$domain.*

Finally I inserted the script execution at the end of v-change-web-domain-proxy-tpl before the exit command.

/root/nodejs_tpl.sh $1 $2
exit

Leave a Reply