在Nginx位置规则中使用变量

tom*_*mka 49 variables webserver nginx

在Nginx中,我正在尝试定义一个变量,它允许我为所有位置块配置子文件夹.我这样做了:

set $folder '/test';

location $folder/ {
   [...]
}

location $folder/something {
   [...]
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这似乎不起作用.虽然Nginx没有抱怨语法,但在请求时返回404 /test/.如果我明确地写了文件夹,它就可以了.那么如何在位置块中使用变量呢?

Dan*_*ack 68

你不能.Nginx并不真正支持配置文件中的变量,它的开发人员模拟了要求添加此功能的所有人:

"与静态配置相比,[变量]相当昂贵.[A]宏扩展和"包含"指令应该与[例如] sed + make或任何其他常用模板机制一起使用." http://nginx.org/en/docs/faq/variables_in_config.html

您应该编写或下载一个允许您从占位符配置文件生成配置文件的小工具.

更新下面的代码仍然可以工作,但我已经将它全部包装到一个名为Configurator的小型PHP程序/库中,也可以在Packagist上,它允许从模板和各种形式的配置数据中轻松生成nginx/php-fpm等配置文件.

例如,我的nginx源配置文件如下所示:

location  / {
    try_files $uri /routing.php?$args;
    fastcgi_pass   unix:%phpfpm.socket%/php-fpm-www.sock;
    include       %mysite.root.directory%/conf/fastcgi.conf;
}
Run Code Online (Sandbox Code Playgroud)

然后我有一个定义了变量的配置文件:

phpfpm.socket=/var/run/php-fpm.socket
mysite.root.directory=/home/mysite
Run Code Online (Sandbox Code Playgroud)

然后我使用它生成实际的配置文件.看起来你是一个Python人,所以基于PHP的例子可能对你没有帮助,但对于其他使用PHP的人来说:

<?php

require_once('path.php');

$filesToGenerate = array(
    'conf/nginx.conf' => 'autogen/nginx.conf',
    'conf/mysite.nginx.conf' => 'autogen/mysite.nginx.conf',
    'conf/mysite.php-fpm.conf' => 'autogen/mysite.php-fpm.conf',
    'conf/my.cnf' => 'autogen/my.cnf',
);

$environment = 'amazonec2';

if ($argc >= 2){
    $environmentRequired = $argv[1];

    $allowedVars = array(
        'amazonec2',
        'macports',
    );

    if (in_array($environmentRequired, $allowedVars) == true){
        $environment = $environmentRequired;
    }
}
else{
    echo "Defaulting to [".$environment."] environment";
}

$config = getConfigForEnvironment($environment);

foreach($filesToGenerate as $inputFilename => $outputFilename){
    generateConfigFile(PATH_TO_ROOT.$inputFilename, PATH_TO_ROOT.$outputFilename, $config);
}


function    getConfigForEnvironment($environment){
    $config = parse_ini_file(PATH_TO_ROOT."conf/deployConfig.ini", TRUE);
    $configWithMarkers = array();
    foreach($config[$environment] as $key => $value){
        $configWithMarkers['%'.$key.'%'] = $value;
    }

    return  $configWithMarkers;
}


function    generateConfigFile($inputFilename, $outputFilename, $config){

    $lines = file($inputFilename);

    if($lines === FALSE){
        echo "Failed to read [".$inputFilename."] for reading.";
        exit(-1);
    }

    $fileHandle = fopen($outputFilename, "w");

    if($fileHandle === FALSE){
        echo "Failed to read [".$outputFilename."] for writing.";
        exit(-1);
    }

    $search = array_keys($config);
    $replace = array_values($config);

    foreach($lines as $line){
        $line = str_replace($search, $replace, $line);
        fwrite($fileHandle, $line);
    }

    fclose($fileHandle);
}

?>
Run Code Online (Sandbox Code Playgroud)

然后deployConfig.ini看起来像:

[global]

;global variables go here.

[amazonec2]
nginx.log.directory = /var/log/nginx
nginx.root.directory = /usr/share/nginx
nginx.conf.directory = /etc/nginx
nginx.run.directory  = /var/run
nginx.user           = nginx

[macports]
nginx.log.directory = /opt/local/var/log/nginx
nginx.root.directory = /opt/local/share/nginx
nginx.conf.directory = /opt/local/etc/nginx
nginx.run.directory  = /opt/local/var/run
nginx.user           = _www
Run Code Online (Sandbox Code Playgroud)

  • 与@RickyB 的想法相同。为什么不具有带有变量的宏功能(如在 Apache 中),这些变量在启动、重新启动或重新加载期间被替换并在内存中保留为静态配置?因此不需要额外的工具和解决方法。 (3认同)
  • 我确定nginx在启动时编译静态变量并不困难,就像它们如何处理包含(逻辑推测)一样 (2认同)

Var*_*ahl 14

这已经晚了很多年,但自从我找到解决方案后,我会在这里发布。通过使用地图,可以执行要求的操作:

map $http_host $variable_name {
    hostnames;

    default       /ap/;
    example.com   /api/;
    *.example.org /whatever/;
}

server {
    location $variable_name/test {
        proxy_pass $auth_proxy;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您需要在多个服务器之间共享同一个端点,您还可以通过简单地默认值来降低成本:

map "" $variable_name {
    default       /test/;
}
Run Code Online (Sandbox Code Playgroud)

Map 可用于根据字符串的内容初始化变量,并可在http范围内使用,允许变量是全局的并可跨服务器共享。


rst*_*use 7

你可以做与你提议的相反的事情。

location (/test)/ {
   set $folder $1;
}

location (/test_/something {
   set $folder $1;
}
Run Code Online (Sandbox Code Playgroud)

  • 因为给其他人+1 很有趣。 (2认同)