为许多客户端项目配置 nginx

Posted

技术标签:

【中文标题】为许多客户端项目配置 nginx【英文标题】:Config nginx for many client projects 【发布时间】:2020-02-12 04:07:18 【问题描述】:

我们有大约 30+ 个客户端项目(一些是 vue 项目,另一些是静态 html 项目),每个项目都有单独的根目录。

目前 nginx 的配置类似,每个项目都有一个location

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

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

...

每次发布​​一个新的客户端项目,一个新的location 都会添加到 nginx 文件中。怕nginx文件里的location太多会影响nginx的效率。

如何简化所有客户端项目的 nginx 配置文件。比如有一个位置location ^~ /web/,然后把所有的项目放在web路径下。

【问题讨论】:

如果index 相同,您可以删除它。如果您有 100 个位置,我不知道有任何“性能”问题。尤其是因为这是开发服务器,所以他们每天收到的请求并不多。你有什么顾虑?而且也很难提出任何建议,因为我们不知道这些项目是什么样的后端。如果 2 是 python,2 是 go,2 是 ruby​​,2 php,2 nodejs.... 如果它们只是静态的,为什么不使用 root /var/www 和 1 个位置:location / try_files $uri $uri/ =404 【参考方案1】:

最佳实践

最佳做法是为每个应用使用单独的域名。从安全角度来看,这对于防止一个应用程序中的跨站点脚本漏洞对所有其他应用程序和 cookie 管理产生任何不良影响非常重要。

性能

但是,从性能的角度来看,nginx 对于此类常见用例已经非常高效,您不必担心有一些额外的 locationserver_name 指令:

location

我想基于前缀的 location 搜索将在基于前缀的搜索树上完成 - https://en.wikipedia.org/wiki/Trie - 例如,它会非常高效,其中,有效地, URL 中的每个输入字符只会被检查一次,并且树上的每个级别只会有一定数量的分支。

如果您转而使用基于正则表达式的方法,那么速度会明显变慢(至少从性能分析来看,您可能不会注意到实际使用中的任何差异),因为这样每个正则表达式都会必须重新评估,可能在整个输入上,直到找到匹配;复杂度是正则表达式数量的倍数,乘以输入 URL 的大小。

server_name

如果您改为使用基于非正则表达式 server_name 规范的基于 server 的定义,则匹配将通过哈希表完成,同样,一个非常有效的操作,即使在无限数量的单个 server 定义上,搜索也将花费恒定的时间。

比较

locationserver_name 哪个效率更高?如果不涉及太多细节,就很难确定;但我想就 CPU 分支预测而言,基于哈希的搜索会更友好——https://en.wikipedia.org/wiki/Branch_predictor;但这在这里真的很麻烦,你真的不需要为 webapp 担心这些事情。但是,出于安全原因,我仍然建议迁移到基于服务器的配置,即使额外的性能优势可以忽略不计。

tl;博士:

tl;dr:对于您的用例,nginx 已经非常高效,无需进一步优化;您能做的最好的事情是确保您不使用任何基于正则表达式的location 指令(或者根本不使用^~ 修饰符作为基于前缀的location 指令),因为那些将是比基于前缀的慢;还建议切换到基于服务器的配置以获得额外的安全性。

参考文献

http://nginx.org/r/location http://nginx.org/r/server_name http://nginx.org/docs/hash.html http://nginx.org/docs/http/server_names.html http://nginx.org/docs/http/request_processing.html

【讨论】:

这是位置搜索的代码 - ngx.su/src/http/…;这是树的结构,具有排序的左、右和包含子树(例如,具有 3 个分支选项的树)-ngx.su/src/http/…;另外,这是正在创建的树 - ngx.su/src/http/ngx_http.c#ngx_http_create_locations_tree. 我决定编写一个单独的 QA,详细介绍位置搜索的实现; ***.com/q/58445434/1122270.【参考方案2】:

我通常为 ngninx 使用动态虚拟主机。因此,您可以创建一个服务目录,例如/var/www/ 并在里面定义一个目录,例如您要部署的客户端项目的每个域。

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

然后在 nginx 中你定义你的服务器块如下

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;                                                                                                                                                                                            

这首先将基本路径设置为/var/www,然后按该基本路径中的目录顺序尝试。如果存在访问项目所在域的目录并从那里为它们提供服务,如果里面是公用文件夹,则首选此目录。如果两者都不可用,它会重定向到另一个定义的 URL。

此外,每个主机都会生成一个不同的access.log。不幸的是,error.log 这不起作用,因此所有错误都集中在公共 error.log 中。

对于特定文件,您可以过滤扩展名等,以指定如何提供它们,在上面的PHP-files 示例中,这些文件使用php7.2-fpm 提供。 p>

【讨论】:

以上是关于为许多客户端项目配置 nginx的主要内容,如果未能解决你的问题,请参考以下文章

nginx服务器配置多域名

Nginx 设置项目配置文件不可 URL 访问

Nginx 设置项目配置文件不可 URL 访问

Web项目之Nginx配置文件优化篇

通过Nginx为网站配置二级域名并访问指定项目

不能使用多个项目