Problèmes d'emplacement multiple Nginx

14

J'essaie actuellement de séparer 3 applications d'un référentiel en 3, mais en conservant la structure d'URL, donc essentiellement des emplacements différents sous le même domaine doivent être fournis par différentes applications.

Ce avec quoi je me bats, c'est qu'une des applications doit être la solution de remplacement pour les URL inexistantes, donc si la première ne correspond pas, et la seconde non, alors la troisième devrait gérer la demande

La structure que j'ai est la suivante:

/ etc / nginx / sites-enabled / main_site, ici, à part nom_serveur et journaux que j'ai include /etc/nginx/subsites-enabled/*, où j'ai 3 fichiers de configuration, un pour chacune des applications.

Chacun des 3 fichiers de configuration contient un bloc d'emplacement.

J'ai essayé l'anticipation négative dans regex (essentiellement en essayant de coder en dur les URL que les autres applications gèrent), mais j'ai échoué.

Donc, pour résumer:

/ et / communauté doit être fourni par /etc/nginx/subsites-enabled/example.org/home (quelques scripts Perl)

/ les nouvelles doivent être fournies par /etc/nginx/subsites-enabled/example.org/news (wordpress)

tout le reste doit être livré par /etc/nginx/subsites-enabled/example.org/app (cake app)

Le bit perl fonctionne bien. Le problème que j'ai, c'est que l'application prend le relais de l'actualité (probablement parce qu'elle correspond. *), J'ai essayé différentes options (j'y suis depuis 2 jours) mais aucune n'a résolu tous les problèmes (parfois les actifs statiques ne fonctionneraient pas, etc.).

Ma configuration est:

/etc/nginx/sites-enabled/example.org:

server {
    listen   80;
    server_name example.org;
    error_log /var/log/nginx/example.org.log;

    include /etc/nginx/subsites-enabled/example.org/*;
}

/etc/nginx/subsites-enabled/example.org/home:

location = / {
  rewrite ^.*$ /index.pl last;
}

location ~* /community(.*) {
  rewrite ^.*$ /index.pl last;
}

location ~ \.pl {
  root   /var/www/vhosts/home;
  access_log /var/log/nginx/home/access.log;
  error_log /var/log/nginx/home/error.log;

  include /etc/nginx/fastcgi_params;
  fastcgi_index index.pl;
  fastcgi_param SCRIPT_FILENAME /var/www/vhosts/home$fastcgi_script_name;
  fastcgi_pass  unix:/var/run/fcgiwrap.socket;
}

/ etc / ngins / subsites-enabled / news

location /news {
  access_log /var/log/nginx/news/access.log;
  error_log /var/log/nginx/news/error.log debug;

  error_page 404 = /news/index.php;

  root /var/www/vhosts/news;

  index index.php;

  if (!-e $request_filename) {
      rewrite ^.*$ /index.php last;
  }

  location ~ \.php {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www/vhosts/news$fastcgi_script_name;
  }
}

/ etc / nginx / subsites-enabled / app:

location ~ .* {
  access_log /var/log/nginx/app/access.log;
  error_log /var/log/nginx/app/error.log;

  rewrite_log on;

  index index.php;
  root /var/www/vhosts/app/app/webroot;

  if (-f $request_filename) {
    expires 30d;
    break;
  }

  if (!-e $request_filename) {
    rewrite ^.*$ /index.php last;
  }

  location ~ \.php {
    include /etc/nginx/fastcgi_params;
    fastcgi_pass  127.0.0.1:9000;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /var/www/vhosts/app/app/webroot$fastcgi_script_name;
  }
}
Andrei Serdeliuc
la source
a) postez votre configuration avec quelques exemples de destinations de diverses redirections (y compris celles pour les URL inexistantes). b) utilisez try_files avec un bloc d'emplacement nommé (en utilisant le @préfixe) qui correspond à votre application par défaut. Vous pouvez également configurer une page d'erreur qui mappe un 404 à un emplacement nommé.
cyberx86
@ cyberx86 J'ai ajouté plus de détails et ma config
Andrei Serdeliuc
Un coup d'œil rapide suggère quelques choses: a) la correspondance d'expressions régulières a priorité sur les chaînes conventionnelles - donc votre bloc d'application correspondra à la place de votre bloc de nouvelles - essayez location ^~ /news. b) pour votre bloc d'application, vous devriez pouvoir le faire location /(ce n'est pas la même chose location = /, mais doit correspondre à tout ce qui ne l'est pas déjà. c) dans certains cas (en particulier les regex), l'ordre importe - vous pouvez combiner les 3 fichiers dans un seul fichier avec les blocs dans le bon ordre. Utilisez également try_files au lieu de !-e. Voir enfin wiki.nginx.org/HttpCoreModule#location .
cyberx86
J'ai essayé à peu près toutes les variantes de celles-ci, y compris en les combinant en un seul fichier (même si elles doivent être séparées car elles sont déployées séparément), aucune ne fonctionne. Les nouvelles sont simplement gérées par l'application.
Andrei Serdeliuc
Eh bien, je pense que je l'ai résolu - un peu plus délicat que ce à quoi je m'attendais au départ - mais certainement agréable à comparer avec les esprits. Merci pour le puzzle.
cyberx86

Réponses:

45

Il y a quelques petites choses qui ne vont pas dans votre configuration, les deux pertinentes étant:

  1. Les chemins dans un bloc d'emplacement incluent toujours le chemin correspondant.
  2. Réécrit avec «dernier» continue en recherchant tous les emplacements disponibles pour un match (ils sortent du bloc d'emplacement actuel).

Par exemple, prenez l'URL example.org/news/test.htm

  • Le location /newsbloc correspondra
  • Le chemin utilisé est alors /news/test.htm- cela ne change pas, juste parce qu'il est dans le bloc de localisation
  • En ajoutant le chemin vers le document_root, vous obtenez: /var/www/vhosts/news/news/test.htm
  • Votre if (!-e $request_filename)déclaration doit capturer ce fichier inexistant
  • Vous réécrivez le chemin vers /index.php
  • Puisque vous utilisez lastles processus recommence (rupture du bloc de localisation)
  • /index.phpest maintenant capturé par le location /app block.

Le problème mentionné ci-dessus, avec la directive racine, est aggravé lorsque vous accédez au bloc d'emplacement de votre application. Contrairement au bloc `` news '', où vous pouvez simplement supprimer `` news '' du chemin (car il sera ajouté à nouveau), vous ne pouvez pas le faire pour le chemin de l'application, qui se termine par 'webroot'.

La solution réside dans la aliasdirective. Cela ne change pas le document_root, mais cela change le chemin d'accès au fichier qui est utilisé pour servir la demande. Malheureusement, rewriteet try_filesont tendance à se comporter un peu de façon inattendue avec alias.

Commençons par un exemple simple - pas de PHP - juste du HTML et votre bloc Perl - mais avec une structure de dossiers correspondant à la vôtre (testé sur Nginx 1.0.12, CentOS 6):

server {
    server_name example.org;
    error_log /var/log/nginx/example.org.error.log notice;
    access_log /var/log/nginx/example.org.access.log;
    rewrite_log on;

    location = / {
        rewrite ^ /index.pl last;
    }

    location ^~ /community {
        rewrite ^ /index.pl last;
    }

    location ~ \.pl {
        root   /var/www/vhosts/home;

        [fastcgi_stuff...]
    }


    location ^~ /news {
        alias /var/www/vhosts/news;
        index index.htm;

        try_files $uri $uri/ /news/index.htm;
    }

    location ^~ /app {
        alias /var/www/vhosts/app/app/webroot;
        index index.htm;

        try_files $uri $uri/ /app/index.htm;
    }

    location / {
        rewrite ^/(.*) /app/$1 last;
    }
}
  • location = / - ne correspondra qu'au chemin racine
  • location ^~ /community - correspondra à chaque chemin commençant par / communauté
  • location ~ \.pl - correspondra à tous les fichiers contenant .pl
  • location ^~ /news - correspondra à chaque chemin commençant par / news
  • location ^~ /app - correspondra à chaque chemin commençant par / app
  • location / - correspondra à tous les chemins non correspondants ci-dessus

Vous devriez pouvoir supprimer le ^~- mais cela peut offrir une légère amélioration des performances, car il arrête la recherche une fois qu'une correspondance est trouvée.

Bien qu'il devrait être simple d'ajouter à nouveau les blocs PHP, il y a, malheureusement, une légère difficulté - try_files(et votre réécriture) ne finissent pas par passer le chemin souhaité vers le bloc d'emplacement imbriqué - et à utiliser aliaslorsque seule l'extension est spécifié dans le bloc d'emplacement ne fonctionne pas.

Une solution consiste à utiliser des blocs d'emplacement séparés qui effectuent une capture avec la directive alias - ce n'est pas tout à fait élégant, mais pour autant que je sache, cela fonctionne (encore une fois, testé sur Nginx 1.0.12, CentOS 6 - de bien sûr, je n'ai pas configuré CakePHP, Wordpress et Perl - j'ai juste utilisé quelques fichiers PHP et HTML dans chaque dossier)

server {
    server_name example.org;
    error_log /var/log/nginx/example.org.error.log notice;
    access_log /var/log/nginx/example.org.access.log;
    rewrite_log on;

    location = / {
        rewrite ^ /index.pl last;
    }

    location ^~ /community {
        rewrite ^ /index.pl last;
    }

    location ~ \.pl {
        root   /var/www/vhosts/home;
        access_log /var/log/nginx/home.access.log;
        error_log /var/log/nginx/home.error.log;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.pl;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass  unix:/var/run/fcgiwrap.socket;
    }

    location /news {
        access_log /var/log/nginx/news.access.log;
        error_log /var/log/nginx/news.error.log notice;
        alias /var/www/vhosts/news;
        index index.php;
        try_files $uri $uri/ /news/index.php;
    }

    location ~* ^/news/(.*\.php)$ {
        access_log /var/log/nginx/news.php.access.log;
        error_log /var/log/nginx/news.php.error.log notice;
        alias /var/www/vhosts/news/$1;
        try_files "" /news/index.php;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_NAME $1;
        fastcgi_param SCRIPT_FILENAME /var/www/vhosts/news/$1;
        fastcgi_pass  127.0.0.1:9000;
    }

    location /app {
        alias /var/www/vhosts/app/app/webroot;
        access_log /var/log/nginx/app.access.log;
        error_log /var/log/nginx/app.error.log notice;
        index index.php;
        try_files $uri $uri/ /app/index.php;
    }

    location ~* ^/app/(.*\.php)$ {
        access_log /var/log/nginx/news.access.log;
        error_log /var/log/nginx/news.error.log notice;
        alias /var/www/vhosts/app/app/webroot/$1;
        try_files "" /app/index.php;
        include /etc/nginx/fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_NAME $1;
        fastcgi_param SCRIPT_FILENAME /var/www/vhosts/app/app/webroot/$1;
        fastcgi_pass  127.0.0.1:9000;
    }

    location / {
        rewrite ^/(.*) /app/$1 last;
    }
}

La configuration ci-dessus, prend la simple ci-dessus et apporte deux modifications:

  • Ajoutez deux blocs d'emplacement:
    • location ~* ^/news/(.*\.php)$ - correspondra à tous les fichiers se terminant par .php, avec des chemins commençant par / news /
    • location ~* ^/app/(.*\.php)$ - correspondra à tous les fichiers se terminant par .php, avec des chemins commençant par / app /
  • Supprimez la ^~correspondance - cela est nécessaire pour que les deux blocs d'emplacement ajoutés puissent correspondre aux chemins (sinon la correspondance s'arrêterait sur les blocs / news ou / app).

Il convient de noter que l'ordre de correspondance d'emplacement est très important ici:

  • Correspondances exactes en premier (en utilisant =)
  • Correspond à la ^~seconde
  • Blocs d'expression rationnelle correspondants
  • Chaînes conventionnelles - uniquement si aucune expression régulière correspondante n'est trouvée

Un regex correspondant remplacera une chaîne droite!

Un point important à mentionner est que lorsque les captures sont utilisées avec un alias, l'URL entière est remplacée - pas seulement le dossier principal. Malheureusement, cela signifie qu'il $fastcgi_script_nameest laissé vide - donc, j'ai utilisé $1ci-dessus à la place.

Je suis sûr que vous devrez apporter quelques modifications, mais le principe de base devrait être fonctionnel. Vous devriez être en mesure de séparer les blocs en plusieurs fichiers selon vos besoins - la commande ne devrait pas affecter la configuration.

cyberx86
la source
2
Mec, j'aimerais pouvoir te voter 100 fois. Tu es vraiment génial. Merci!
Andrei Serdeliuc