Cómo reescribir Nginx para obtener una URL limpia de los números de página

Jan 15 2020

Recientemente nos hemos mudado a Nginx desde Apache. Bajo apache solía ser muy fácil, simplemente poner algunas cosas en .htaccess y listo.

RewriteEngine on
RewriteBase /

# only rewrite if the requested file doesn't exist
RewriteCond %{REQUEST_FILENAME} !-s

# pass the rest of the request into index.php to handle
RewriteRule ^(.*)$ /index.php/$1 [L]

Lo anterior sirvió muy bien para limpiar la URL y permitir que index.php maneje todas las solicitudes. pero en Nginx necesitábamos reescribir cada URL única en el bloque de ubicación. Sin embargo, esto no es "automático" como Apache.

Pocos ejemplos de nuestro bloque de ubicación de reescritura

location / {
try_files $uri $uri/ /index.php;
}

location /p {
rewrite ^/p(?:/([a-z_]+))?$ /index.php?p=$1 last;
rewrite ^/p/all_articles/user/(.*)?$ /index.php?p=all_articles&user=$1 last;
try_files $uri $uri/ /index.php;
}

location /about_us {
rewrite ^/about_us /index.php?about_us last;
try_files $uri $uri/ /index.php;
}

location /search {
rewrite ^/search/(.*) /index.php?search=$1; rewrite ^/search/(.*)/page/(.*)?$ /index.php?search=$1&page=$2 last;
try_files $uri $uri/ /index.php;
}

location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}

lo anterior hace un buen trabajo en una URL limpia, pero cuando necesitamos obtener páginas, por ejemplo

/ p / all_articles / user / ABC / page / 2

/index.php?p=all_articles&user=ABC&page=2

hemos tratado

rewrite ^/p/all_articles/user/(.*)/pg(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&pg=$2 last;

esto solo funciona cuando lo colocamos en un bloque de ubicación separado

location /page/all_articles {
rewrite ^/p/all_articles/user/(.*)/pg(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&pg=$2 last; try_files $uri $uri/ /index.php;
}

y cuando lo hiciera, no dejaría

/ p / all_articles / user / ABC

cargar.

Además, las páginas de resultados de búsqueda no funcionarían en absoluto.


otro problema que encontramos es en la carpeta .htaccess

Order deny,allow
Deny from all
Options -Indexes

Bajo apache, esto evitaría cualquier acceso a esa carpeta y archivos, excepto el script php. Nosotros tratamos,

location /(data|img)/ {
   deny all;
   return 404;
}

Bloquea el acceso a la carpeta pero, si especifica el nombre del archivo, seguirá sirviendo, sin denegar el acceso, por ejemplo;

/data/backup_01012020.zip bajo apache .htaccess, solo ciertos usuarios pudieron acceder a esto, mientras estaban conectados. y fuera de él, apache negará cualquier acceso. Pero bajo nginx, aunque da 404 al intentar acceder a / data /. Incluso cuando no haya iniciado sesión, serviría el archivo backup_01012020.zip inmediatamente.

Ahora no podemos averiguar qué podemos hacer, lo que solía ser pan comido con apache. Nuestra aplicación está basada en PHP e index.php es capaz de manejar todas las solicitudes de URL limpias. Podría haber sido genial si Nginx simplemente pasara todas las solicitudes al índice y lo dejara manejar en lugar de muchas reescrituras y bloques de ubicación. Cualquier ayuda sería genial.

Respuestas

2 PiotrP.Karwasz Jan 15 2020 at 07:07

Es posible que le interesen las preguntas con la etiqueta de reescritura , ya que contiene muchas variaciones de su problema.

Tu regla de reescritura de Apache:

RewriteRule ^(.*)$ /index.php/$1 [L]

agrega el URI de solicitud completo a /index.php. En nginx, la ruta del URI (normalizada) está disponible en la variable $ uri . Si también necesita los argumentos de consulta, puede usar $ request_uri en su lugar.

Por tanto, una traducción estricta de sus reglas de reescritura sería:

location / {
    # Size zero static files are served.
    # I don't believe that is an issue.
    try_files $uri /index.php$request_uri;
}
# If no other .php files are accessible a prefix location of '/index.php/'
# is safer.
location /index.php/ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    # Probably duplicates the contents of fastcgi-php.conf
    # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    # include fastcgi_params;
}

Su denydirectiva sobre la /(data|img)/ubicación no funciona, ya que está utilizando una coincidencia de prefijo, en lugar de una coincidencia de expresiones regulares:

location ~ ^/(data|img)/ {
   # Only one is required
   deny all;
   # return 404;
}
HelenSaepp Jan 17 2020 at 00:04

Solución para reescribir

location /search {
rewrite ^/search/(.*)/page/(.*)?$ /index.php?search=$1&page=$2 last; rewrite ^/search/(.*) /index.php?search=$1 last;
try_files $uri $uri/ /index.php;
}

location /p/all_articles {
rewrite ^/p/all_articles/user/(.*)/page(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&page=$2 last; rewrite ^/p/all_articles/user/(.*)?$ /index.php?p=all_articles&user=$1 last; try_files $uri $uri/ /index.php;
}

Fíjense, todo lo que hice fue intercambiar líneas. Créditos a Richard Smith


Gracias a Piotr P. Karwasz , por la otra solución, podría ayudar a alguien cuyo script sea 100% compatible a manejar una URL limpia por sí misma.

location / {
    # Size zero static files are served.
    # I don't believe that is an issue.
    try_files $uri /index.php$request_uri; } # If no other .php files are accessible a prefix location of '/index.php/' # is safer. location /index.php/ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php7.0-fpm.sock; # Probably duplicates the contents of fastcgi-php.conf # fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    # include fastcgi_params;
}

la solución anterior es un camino a seguir siempre que su script funcione con una URL limpia al 100%. Aquí, no necesita poner cientos de bloques de ubicación de reescritura, y nginx agregará el URI de solicitud completo a /index.php, lo cual es muy interesante y útil, probablemente esta es la solución real, pero en mi caso, mi script no era 100. % compatible con esto. Aún así, esta es una buena solución inteligente.


Soution para evitar el acceso a carpetas y archivos

location ~ ^/(data|img)/ {
   # Only one is required
   deny all;
   # return 404;
}

Los créditos a Piotr P. Karwasz señalaron que el problema deny allestaba siendo anulado por algo, al bloquear el servidor limpio, resolvió el problema. También asegúrese de usar uno deny all;o return 404;pero no juntos.