web-dev-qa-db-fra.com

Utilisation de variables dans les règles de localisation Nginx

Dans Nginx, j'essaie de définir une variable qui me permet de configurer un sous-dossier pour tous mes blocs de localisation. J'ai fait ça:

set $folder '/test';

location $folder/ {
   [...]
}

location $folder/something {
   [...]
}

Malheureusement, cela ne semble pas fonctionner. Bien que Nginx ne se plaint pas de la syntaxe, il renvoie 404 en demandant /test/. Si j'écris explicitement le dossier, cela fonctionne. Alors, comment puis-je utiliser des variables dans des blocs de localisation?

47
tomka

Tu ne peux pas. Nginx ne supporte pas vraiment les variables dans les fichiers de configuration, et ses développeurs se moquent de tous ceux qui demandent l'ajout de cette fonctionnalité:

"Les [variables] sont plutôt coûteuses comparées à la configuration statique ordinaire. Les directives d'expansion de macro et d'inclusion" doivent être utilisées [avec] par exemple sed + make ou tout autre mécanisme de modèle commun. " http://nginx.org/en/docs/faq/variables_in_config.html

Vous devriez écrire ou télécharger un petit outil qui vous permettra de générer des fichiers de configuration à partir de fichiers de configuration réservés.

Mise à jour Le code ci-dessous fonctionne toujours, mais j'ai tout résumé dans un petit PHP programme/bibliothèque appelé Configurateur également sur Packagist , ce qui permet de générer facilement des fichiers de configuration nginx/php-fpm, etc., à partir de modèles et de diverses formes de données de configuration.

par exemple. mon fichier de configuration source nginx ressemble à ceci:

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

Et puis j'ai un fichier de configuration avec les variables définies:

phpfpm.socket=/var/run/php-fpm.socket
mysite.root.directory=/home/mysite

Et puis je génère le fichier de configuration en utilisant cela. Il semble que vous soyez un type Python mec, donc un exemple basé sur PHP peut ne pas vous aider, mais pour tous les autres utilisateurs de 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);
}

?>

Et puis deployConfig.ini ressemble à ceci:

[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
65
Danack

Une version modifiée python de @ danack PHP génère un script. Elle génère tous les fichiers et dossiers qui résident à l'intérieur de build/ dans le répertoire parent, en remplaçant tous les {{placeholder}} allumettes. Vous devez cd dans build/ _ avant d'exécuter le script.

structure de fichier

build/
-- (files/folders you want to generate)
-- build.py

sites-available/...
sites-enabled/...
nginx.conf
...

build.py

import os, re

# Configurations
target = os.path.join('.', '..')
variables = {
  'placeholder': 'your replacement here'
}


# Loop files
def loop(cb, subdir=''):
  dir = os.path.join('.', subdir);

  for name in os.listdir(dir):
    file = os.path.join(dir, name)
    newsubdir = os.path.join(subdir, name)

    if name == 'build.py': continue
    if os.path.isdir(file): loop(cb, newsubdir)
    else: cb(subdir, name)


# Update file
def replacer(subdir, name):
  dir  = os.path.join(target, subdir)
  file = os.path.join(dir, name)
  oldfile = os.path.join('.', subdir, name)

  with open(oldfile, "r") as fin:
    data = fin.read()

  for key, replacement in variables.iteritems():
    data = re.sub(r"{{\s*" + key + "\s*}}", replacement, data)

  if not os.path.exists(dir):
    os.makedirs(dir)

  with open(file, "w") as fout:
    fout.write(data)


# Start variable replacements.
loop(replacer)
2
Ricky Boyce

Vous pouvez faire le contraire de ce que vous avez proposé.

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

location (/test_/something {
   set $folder $1;
}
0
rstackhouse