Problemas de ubicación múltiple de Nginx

14

Actualmente estoy tratando de separar 3 aplicaciones de un repositorio en 3, pero manteniendo la estructura de la url, por lo que, básicamente, diferentes aplicaciones bajo el mismo dominio tienen que ser entregadas por diferentes aplicaciones.

Con lo que estoy luchando es que una de las aplicaciones debe ser la alternativa para las URL inexistentes, por lo que si la primera no coincide y la segunda no, entonces la tercera debe manejar la solicitud

La estructura que tengo es:

/ etc / nginx / sites-enabled / main_site, aquí, aparte del nombre_servidor y los registros que tengo include /etc/nginx/subsites-enabled/*, donde tengo 3 archivos de configuración, uno para cada una de las aplicaciones.

Cada uno de los 3 archivos de configuración contiene un bloque de ubicación.

He intentado con anticipación negativa en expresiones regulares (básicamente tratando de codificar las URL que manejan las otras aplicaciones) pero fallé.

Entonces, para resumir:

/ y / community deben ser entregados por /etc/nginx/subsites-enabled/example.org/home (algunos scripts en perl)

/ news debe ser entregado por /etc/nginx/subsites-enabled/example.org/news (wordpress)

todo lo demás debe ser entregado por /etc/nginx/subsites-enabled/example.org/app (aplicación de pastel)

El bit perl funciona bien. El problema que tengo es que la aplicación se está haciendo cargo de las noticias (probablemente porque coincide. *), He probado varias opciones (he estado en esto durante 2 días) pero ninguna de ellas resolvió todos los problemas (a veces los activos estáticos no funcionarían, etc.).

Mi configuracion es:

/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
fuente
a) publique su configuración junto con algunos ejemplos de dónde deben ir varios redireccionamientos (incluidos aquellos para URL inexistentes). b) use try_files con un bloque de ubicación con nombre (usando el @prefijo) que se asigna a su aplicación predeterminada. También puede configurar un error_page que asigna un 404 a una ubicación con nombre.
cyberx86
@ cyberx86 Agregué más detalles y mi configuración
Andrei Serdeliuc
Un vistazo rápido sugiere algunas cosas: a) la coincidencia de expresiones regulares tiene prioridad sobre las cadenas convencionales, por lo que su bloque de aplicaciones coincidirá en lugar de su bloque de noticias, intente location ^~ /news. b) para el bloqueo de su aplicación, debería poder hacer location /(esto no es lo mismo que location = /, pero debería coincidir con todo lo que no coincide). c) en algunos casos (particularmente expresiones regulares), el orden sí importa; puede combinar los 3 archivos en un solo archivo con los bloques en el orden correcto. Además, use try_files en lugar de !-e. Finalmente vea wiki.nginx.org/HttpCoreModule#location .
cyberx86
Intenté prácticamente todas las variaciones de esos, incluida la combinación de ellos en un solo archivo (aunque necesitan estar separados ya que se implementan por separado), ninguno de ellos funciona. Las noticias solo son manejadas por la aplicación.
Andrei Serdeliuc
Bueno, creo que lo he resuelto, un poco más complicado de lo que esperaba inicialmente, pero ciertamente es agradable para enfrentarlo. Gracias por el acertijo.
cyberx86

Respuestas:

45

Hay algunas cosas mal con su configuración, las dos relevantes son:

  1. Las rutas dentro de un bloque de ubicación aún incluyen la ruta coincidente.
  2. Las reescrituras con 'último' continúan buscando en todas las ubicaciones disponibles una coincidencia (salen del bloque de ubicación actual).

Por ejemplo, tome la URL example.org/news/test.htm

  • El location /newsbloque lo igualará
  • La ruta utilizada es entonces /news/test.htm: esto no cambia, solo porque está en el bloque de ubicación
  • Al agregar la ruta a document_root, obtienes: /var/www/vhosts/news/news/test.htm
  • Su if (!-e $request_filename)declaración debe capturar este archivo inexistente
  • Reescribes el camino a /index.php
  • Dado que está utilizando lastlos procesos, comienza de nuevo (rompiendo el bloque de ubicación)
  • /index.phpahora es capturado por el location /app block.

El problema mencionado anteriormente, con la directiva raíz, se agrava cuando va al bloque de ubicación de su aplicación. A diferencia del bloque 'noticias', donde posiblemente podría eliminar 'noticias' de la ruta (ya que se agregará nuevamente), no puede hacer esto para la ruta de la aplicación, que termina en 'raíz web'.

La solución está en la aliasdirectiva. Esto no cambia la raíz del documento, pero sí cambia la ruta del archivo que se utiliza para atender la solicitud. Lamentablemente, rewritey try_filestienden a comportarse un poco inesperadamente con alias.

Comencemos con un ejemplo simple, sin PHP, solo HTML y su bloque Perl, pero con una estructura de carpetas que coincida con la suya (probado en 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 = / - solo coincidirá con la ruta raíz
  • location ^~ /community - coincidirá con cada ruta que comience con / community
  • location ~ \.pl - coincidirá con todos los archivos que contienen .pl
  • location ^~ /news - coincidirá con cada ruta que comience con / news
  • location ^~ /app - coincidirá con cada ruta que comience con / app
  • location / - coincidirá con todos los caminos no coincidentes arriba

Debería poder eliminar el ^~, pero puede ofrecer una ligera mejora en el rendimiento, ya que deja de buscar una vez que se encuentra una coincidencia.

Si bien debería ser una cuestión simple agregar los bloques PHP nuevamente, desafortunadamente, existe una ligera dificultad try_files(y su reescritura) no termina pasando la ruta deseada al bloque de ubicación anidado, y se usa aliascuando solo la extensión es especificado en el bloque de ubicación no funciona.

Una solución es usar bloques de ubicación separados que realicen una captura junto con la directiva de alias: no es muy elegante, pero por lo que puedo decir, funciona (de nuevo, probado en Nginx 1.0.12, CentOS 6 - de Por supuesto, no configuré CakePHP, Wordpress y Perl, solo usé un par de archivos PHP y HTML en cada carpeta)

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 configuración anterior, toma la simple anterior y realiza dos cambios:

  • Agregue dos bloques de ubicación:
    • location ~* ^/news/(.*\.php)$ - coincidirá con todos los archivos que terminan en .php, con rutas que comienzan con / news /
    • location ~* ^/app/(.*\.php)$ - coincidirá con todos los archivos que terminan en .php, con rutas que comienzan con / app /
  • Elimine la ^~coincidencia: esto es necesario para que los dos bloques de ubicación agregados puedan coincidir con las rutas (de lo contrario, la coincidencia se detendría en los bloques / news o / app).

Cabe señalar que el orden de coincidencia de ubicación es muy importante aquí:

  • Las coincidencias exactas primero (usando =)
  • Partidos con el ^~segundo
  • Bloques de expresiones regulares coincidentes
  • Cadenas convencionales: solo si no se encuentra una expresión regular coincidente

¡Una expresión regular coincidente reemplazará una cadena recta!

Un punto importante de mención es que cuando se utilizan capturas con alias, se reemplaza toda la URL, no solo la carpeta principal. Desafortunadamente, esto significa que $fastcgi_script_namese deja vacío, por lo tanto, he usado $1anteriormente en su lugar.

Estoy seguro de que tendrá que hacer algunos cambios, pero la premisa básica debe ser funcional. Debería poder separar los bloques en varios archivos según sea necesario; el pedido no debería afectar la configuración.

cyberx86
fuente
2
Amigo, desearía poder votarte 100 veces. Eres pura asombroso. ¡Gracias!
Andrei Serdeliuc