Problemas de localização múltipla do Nginx


14

Atualmente, estou tentando separar três aplicativos de um repositório em três, mas mantendo a estrutura do URL, portanto, basicamente, diferentes locais no mesmo domínio precisam ser entregues por aplicativos diferentes.

O que eu estou enfrentando é que um dos aplicativos precisa ser o substituto para URLs inexistentes; portanto, se o primeiro não corresponder e o segundo não, o terceiro deverá lidar com a solicitação

A estrutura que eu tenho é:

/ etc / nginx / sites-enabled / main_site, aqui, além do server_name e dos logs que tenho include /etc/nginx/subsites-enabled/*, onde tenho 3 arquivos de configuração, um para cada um dos aplicativos.

Cada um dos 3 arquivos de configuração contém um bloco de localização.

Eu tentei lookahead negativo no regex (basicamente tentando codificar os URLs que os outros aplicativos manipulam), mas falhei.

Então, para resumir:

/ e / community devem ser entregues por /etc/nginx/subsites-enabled/example.org/home (alguns scripts perl)

/ news deve ser entregue em /etc/nginx/subsites-enabled/example.org/news (wordpress)

todo o resto deve ser entregue por /etc/nginx/subsites-enabled/example.org/app (aplicativo de bolo)

O bit perl funciona bem. O problema que estou enfrentando é que o aplicativo está assumindo as notícias (provavelmente porque corresponde. *). Tentei várias opções (já estou nisso há 2 dias), mas nenhuma delas resolveu todos os problemas (às vezes ativos estáticos não funcionariam etc.).

Minha configuração é:

/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 / ativado por subsites / 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;
  }
}

a) publique sua configuração junto com alguns exemplos de onde vários redirecionamentos (incluindo aqueles para URLs inexistentes) devem ir. b) use try_files com um bloco de localização nomeado (usando o @prefixo) que mapeia para o aplicativo padrão. Você também pode configurar uma página de erro que mapeia um 404 para um local nomeado.
22812 cyberx86

@ cyberx86 eu adicionei mais detalhes e minha configuração #
Andrei Serdeliuc

Uma rápida olhada sugere algumas coisas: a) a correspondência de expressões regulares tem precedência sobre as sequências convencionais - para que o seu bloco de aplicativos corresponda ao invés do seu bloco de notícias - tente location ^~ /news. b) para o seu bloco de aplicativos, você deve poder fazer location /(isso não é o mesmo que location = /, mas deve corresponder a tudo que ainda não corresponde). c) em alguns casos (principalmente regexes), a ordem importa - você pode combinar os 3 arquivos em um único arquivo com os blocos na ordem correta. Além disso, use try_files em vez de !-e. Por fim, consulte wiki.nginx.org/HttpCoreModule#location .
22812 cyberx86

Tentei praticamente todas as variações, incluindo combiná-las em um único arquivo (mesmo que elas precisem ser separadas porque são implantadas separadamente), nenhuma delas funciona. As notícias são tratadas pelo aplicativo.
Andrei Serdeliuc 17/02/2012

Bem, acho que resolvi isso - um pouco mais complicado do que eu esperava inicialmente - mas certamente agradável de se comparar. Obrigado pelo quebra-cabeça.
18135 cyberx86

Respostas:


45

Existem algumas coisas erradas na sua configuração, sendo as duas relevantes:

  1. Os caminhos dentro de um bloco de localização ainda incluem o caminho correspondente.
  2. As regravações com 'last' continuam procurando por todos os locais disponíveis para uma partida (eles quebram o bloco de local atual).

Por exemplo, use o URL example.org/news/test.htm

  • O location /newsbloco irá corresponder
  • O caminho usado é então /news/test.htm- isso não muda, apenas porque está no bloco de localização
  • Adicionando o caminho ao document_root, você obtém: /var/www/vhosts/news/news/test.htm
  • Sua if (!-e $request_filename)declaração deve capturar esse arquivo inexistente
  • Você reescreve o caminho para /index.php
  • Como você está usando lastos processos, recomeça (quebrando o bloco de localização)
  • /index.phpagora é capturado pelo location /app block.

O problema mencionado acima, com a diretiva raiz, é agravado quando você acessa o bloco de localização do aplicativo. Diferente do bloco 'news', no qual você pode simplesmente remover 'news' do caminho (já que será adicionado novamente), não é possível fazer isso no caminho do aplicativo, que termina em 'webroot'.

A solução está na aliasdiretiva. Isso não altera a raiz do documento, mas altera o caminho do arquivo usado para atender à solicitação. Infelizmente, rewritee try_filestendem a se comportar um pouco inesperadamente com alias.

Vamos começar com um exemplo simples - sem PHP - apenas HTML e seu bloco Perl - mas com uma estrutura de pastas correspondente à sua (testada no 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 = / - corresponderá apenas ao caminho raiz
  • location ^~ /community - corresponderá a todos os caminhos que começam com / community
  • location ~ \.pl - corresponderá a todos os arquivos que contêm .pl
  • location ^~ /news - corresponderá a todos os caminhos que começam com / news
  • location ^~ /app - corresponderá a todos os caminhos que começam com / app
  • location / - corresponderá a todos os caminhos que não correspondem acima

Você deve conseguir remover o ^~- mas ele pode oferecer uma ligeira melhora no desempenho, pois para de procurar quando a correspondência é encontrada.

Embora deva ser simples adicionar os blocos PHP novamente, há, infelizmente, uma pequena dificuldade - try_files(e sua reescrita) não acaba passando o caminho desejado para o bloco de localização aninhado - e usando aliasquando apenas a extensão é especificado no bloco de localização não funciona.

Uma solução é usar blocos de localização separados que executam uma captura juntamente com a diretiva de alias - não é muito elegante, mas tanto quanto posso dizer, funciona (novamente, testado no Nginx 1.0.12, CentOS 6 - of claro, não configurei CakePHP, Wordpress e Perl - usei apenas alguns arquivos PHP e HTML em cada pasta)

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;
    }
}

A configuração acima, pega a simples acima e faz duas alterações:

  • Adicione dois blocos de localização:
    • location ~* ^/news/(.*\.php)$ - corresponderá a todos os arquivos que terminam em .php, com caminhos iniciados por / news /
    • location ~* ^/app/(.*\.php)$ - corresponderá a todos os arquivos que terminam em .php, com caminhos iniciados por / app /
  • Remover a ^~correspondência - isso é necessário para que os dois blocos de localização adicionados possam corresponder aos caminhos (caso contrário, a correspondência seria interrompida nos blocos / news ou / app).

Note-se que a ordem para correspondência de local é muito importante aqui:

  • Correspondências exatas primeiro (usando =)
  • Corresponde com o ^~segundo
  • Blocos regex correspondentes
  • Sequências convencionais - somente se nenhuma regex correspondente for encontrada

Um regex correspondente substituirá uma string reta!

Um ponto importante de menção é que, quando as capturas são usadas com alias, todo o URL é substituído - não apenas a pasta principal. Infelizmente, isso significa que $fastcgi_script_nameé deixado vazio - então, eu usei $1acima.

Estou certo de que você precisará fazer algumas alterações, mas a premissa básica deve ser funcional. Você deve poder separar os blocos em vários arquivos, conforme necessário - a ordem não deve afetar a configuração.


2
Cara, eu gostaria de poder te votar 100 vezes. Você é pura demais. Obrigado!
Andrei Serdeliuc
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.