LF-DevJourney
LF-DevJourney

Reputation: 28529

Config nginx for many client projects

We have about 30+ client projects(some are vue projects and other are static html projects), each projects have seperate root directory.

For now nginx is config like, each project has a location.

 location ^~ /workspaces/ {
     root    /var/www/workspace/;
     index   index.html index.htm;
 }

 location ^~ /offical/ {
     root    /var/www/official/;
     index   index.html index.htm;
 }

...

Each time a new client project released, a new location will add to nginx file. I'm afraid of too many location in the nginx file will affect the efficiency of nginx.

How can I simplify the nginx config file for all the client projects. For example with one location location ^~ /web/, then put all the projects under web path.

Upvotes: 2

Views: 1436

Answers (2)

satanik
satanik

Reputation: 602

I usually use dynamic vhosts for ngninx. Therefore you can create a serving directory e.g. /var/www/ and inside define a directory for e.g. every domain of the client projects you want to deploy.

/var/www/domain.tld
/var/www/subdomain.domain.tld
/var/www/otherproject.tld
/var/www/project.tld/public

and then in nginx you define your server-block as follows

server {                                                                                                                                                                                                                                   
# SSL configuration                                                                                                                                                                                                                      
listen 443 ssl http2 default_server; # managed by Certbot                                                                                                                                                                                
listen [::]:443 ssl http2 default_server;                                                                                                                                                                                                

set $basepath "/var/www";                                                                                                                                                                                                                

server_name ~^(\w+\.)?(?<base>\w+\.\w+)$;                                                                                                                                                                                                

if ( -d $basepath/$host) {                                                                                                                                                                                                               
  set $rootpath $basepath/$host;                                                                                                                                                                                                         
}                                                                                                                                                                                                                                        
if ( -d $basepath/$host/public ) {                                                                                                                                                                                                       
  set $rootpath $basepath/$host/public;                                                                                                                                                                                                  
}                                                                                                                                                                                                                                        
if ( !-d $basepath/$host ) {                                                                                                                                                                                                             
  set $rootpath $basepath/$base;                                                                                                                                                                                                         
  return 301 https://$base$request_uri;                                                                                                                                                                                                  
}                                                                                                                                                                                                                                        

root $rootpath;

access_log "/var/log/nginx/${host}.access.log";                                                                                                                                                                                          
error_log "/var/log/nginx/error.log" debug;                                                                                                                                                                                              

index index.php index.html index.htm index.nginx-debian.html;                                                                                                                                                                            

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

This first sets the basepath to /var/www and then tries in order directories in that basepath. If a directory with the domain from which project is accessed exists and serves them from there, if inside is a public folder this one is preferred. If both are not available it redirects to another defined URL.

Furthermore, for every host a different access.log is generated. Unfortunately for the error.log this does not work, hence all errors are gathered in the common error.log.

for specific files you can then filter for extensions etc. to specify how they are served, in the example above of PHP-files, those are served using the php7.2-fpm.

Upvotes: 1

cnst
cnst

Reputation: 27218

Best Practice

The best practice is to use separate domain names for each app. This is important from the security perspective, to guard against a cross-site scripting vulnerability in one app having any ill effects on all the other apps, and cookie management.

Performance

However, from the performance perspective, nginx is already highly efficient for such common use cases that you shouldn't worry about having a few extra location or server_name directives:

  • location

    I'd imagine that the prefix-based location search would be done on a prefix-based search tree — https://en.wikipedia.org/wiki/Trie — e.g., it would be highly efficient, where, effectively, each input character in the URL would only be examined once, and each level on the tree would only have a certain limited number of branches.

    If you're instead move to use a regex-based approach, then that would be noticeable slower (at least from the performance analysis, you probably won't notice any difference in real use), because then each regular expression would have to be re-evaluated, potentially on the whole input, until a match is found; the complexity being a multiple of the number of regular expressions, times the size of the input URL.

  • server_name

    If you instead move to a server-based definition, based on non-regex server_name specifications, then the matching would be done through a hash-table, which, likewise, is a very efficient operation, where the search would take constant time even on an infinite number of individual server definitions.

Comparison

Which one is more efficient, location or server_name? It is difficult to say for sure without getting into too many details; but I'd imagine that a hash-based search would be more friendly insofar as CPU branch prediction is concerned — https://en.wikipedia.org/wiki/Branch_predictor; but this is getting really into the weeds here, you don't really need to worry about these sorts of things for a webapp. However, I'd still recommend moving to a server-based configuration for security reasons, even if the extra performance benefits are negligible.

tl;dr:

tl;dr: nginx is already highly efficient for your use case as-is, and no further optimisation is required; the best you could do is to make sure that you don't use any regex-based location directives (either at all, or use a ^~ modifier for your prefix-based location directives), because those would be slower than the prefix-based ones; it would also be advisable to switch to server-based configuration for extra security.

References

Upvotes: 4

Related Questions