Opencart 语言前缀导致 Nginx 404
Opencart language prefix causes Nginx 404
环境:nginx + php-fpm
我已经安装了OC 2.1
当我在网站周围使用 SEO URL 时没有问题。
example.com/news - [OK, 200]
示例。com/de/news - [好的,200]
但有时我没有 SEO URL
example.com/index.php?route=information/testimonials&testimonial_id=6 - [OK, 200]
例如。com/en/index.php?route=information/testimonials&testimonial_id=6 - [错误, 404]
NGINX:
server {
server_name example.com;
root /var/www/example.com;
index index.php index.html index.htm;
charset UTF-8;
autoindex off;
# Show "Not Found" 404 errors in place of "Forbidden" 403 errors, because
# forbidden errors allow attackers potential insight into your server's
# layout and contents
error_page 403 =404;
# It's always good to set logs, note however you cannot turn off the error log
# Setting error_log off; will simply create a file called 'off'
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
# SEO URL Settings
# Nginx configuration of OC htaccess
rewrite ^/sitemap.xml$ /index.php?route=feed/sitemap last;
rewrite ^/sitemap([^\.]+).xml$ /index.php?route=feed/sitemap&path= last;
location = /googlebase.xml {
rewrite ^(.*)$ /index.php?route=feed/google_base;
}
location / {
# This try_files directive is used to enable SEO-friendly URLs for OpenCart
try_files $uri $uri/ @opencart;
}
location @opencart {
rewrite ^([^?]*) /index.php?_route_= last;
}
# End SEO settings
# Make sure files with the following extensions do not get loaded by nginx because nginx would display the source code, and these files can contain PASSWORDS!
location ~* \.(engine|inc|info|ini|install|log|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$|\.php_ {
deny all;
}
# Do not log access to the favicon, to keep the logs cleaner
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /apple-touch-icon.png {
log_not_found off;
access_log off;
}
location = /apple-touch-icon-precomposed.png {
log_not_found off;
access_log off;
}
# This block will catch static file requests, such as images, css, js
# The ?: prefix is a 'non-capturing' mark, meaning we do not require
# the pattern to be captured into which should help improve performance
location ~* \.(?:3gp|gif|jpg|jpe?g|png|ico|wmv|avi|asf|asx|mpg|mpeg|mp4|pls|mp3|mid|wav|swf|flv|txt|js|css|exe|zip|tar|rar|gz|tgz|bz2|uha|7z|doc|docx|xls|xlsx|pdf|iso|woff|woff2|eot|otf|ttf)$ {
# Some basic cache-control for static files to be sent to the browser
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
access_log off;
log_not_found off;
deny all;
}
location ~ ~$ {
access_log off;
log_not_found off;
deny all;
}
# Deny access to any files with a .php extension in these directories
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:cache|logs|image|download)/.*\.php$ {
deny all;
}
# Make sure these get through
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Fix for Firefox issue with cross site font icons
location ~* \.(eot|otf|ttf|woff)$ {
add_header Access-Control-Allow-Origin *;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/www;
}
# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ [^/]\.php(/|$) {
# Regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_pass unix:/run/php/php5.6-fpm.sock;
fastcgi_index index.php;
# Uncomment if site is HTTPS
fastcgi_param HTTPS on;
include fastcgi.conf;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
} # End of server block.
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name example.com;
return 404; # managed by Certbot
}
但在 ENV 中:php + apache2 一切正常,运行良好:)
Options +FollowSymlinks
Options -Indexes
<FilesMatch "(?i)((\.tpl|\.ini|\.log|(?<!robots)\.txt))">
Order deny,allow
Deny from all
</FilesMatch>
RewriteEngine On
#RewriteCond %{HTTP_HOST} ^www.dev.example.com
#RewriteRule ^(.*)$ http://dev.example.com/ [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\ HTTP/
RewriteRule ^index\.html$ / [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\ HTTP/
RewriteRule ^index\.php$ / [R=301,L]
RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/sitemap [L]
RewriteRule ^sitemap([^\.]+).xml$ index.php?route=feed/sitemap&path= [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_= [L,QSA]
php_value max_input_vars 10000
php_value suhosin.post.max_vars 10000
php_value suhosin.request.max_vars 10000
我猜 nginx 规则和指令有些问题,它尝试打开 /de/ 目录并导致 404 错误页面,但 apache2 工作正常并且不会尝试打开 /de/ 目录。
我错过了什么?
这是您的 nginx 配置发生的情况。当一些一般请求(比如 /de/news
)到达您的服务器时,它由 location / { ... }
块处理,其中 try_files
指令首先检查 /var/www/example.com/de/news
文件存在,然后是您定义的索引文件存在于 /var/www/example.com/de/news
目录中,然后使用 @opencart
命名位置继续请求处理,您的请求在此处转换为 /index.php?_route_=/de/news
。之后 rewrite
nginx 指令的 last
标志强制 nginx 为这个转换后的请求搜索一个新位置,即 location ~ [^/]\.php(/|$) { ... }
一个。但是当你收到像 /en/index.php?route=information/testimonials&testimonial_id=6
这样的请求时,它会绕过默认的 location / { ... }
直接转到该位置,正则表达式匹配位置优先于前缀位置。在 fastcgi_split_path_info
指令之后,您的 $fastcgi_script_name
变量等于 /en/index.php
并且 try_files $fastcgi_script_name =404;
显然会给您一个 HTTP 404 错误。
你可以尝试做什么?例如,您可以尝试 try_files $fastcgi_script_name /index.php?_route_=$uri&$args;
。该指令会将您的 /en/index.php?route=information/testimonials&testimonial_id=6
请求转换为 /index.php?_route_=/en/index.php&route=information/testimonials&testimonial_id=6
。您可以重写您的 URI,将此语言前缀移动到某个查询变量,例如
location ~ [^/]\.php(/|$) {
if ($uri ~ ^/(?<lang>en|de|fr)(?<path>/.*)) {
set $args $args&language=$lang;
rewrite ^ $path break;
}
...
}
你可以做任何你想做的事,总有几种方法可以解决与 IT 相关的任务。我希望您了解一般情况。
后记
而不是
location / {
# This try_files directive is used to enable SEO-friendly URLs for OpenCart
try_files $uri $uri/ @opencart;
}
location @opencart {
rewrite ^([^?]*) /index.php?_route_= last;
}
你可以只使用
location / {
# This try_files directive is used to enable SEO-friendly URLs for OpenCart
try_files $uri $uri/ /index.php?_route_=$uri&$args;
}
通过 rewrite ^([^?]*) /index.php?_route_= last;
你可能意味着在没有查询字符串的情况下获取 URI 部分,但是 rewrite
指令(以及 location
指令)与规范化的 URI 一起工作无论如何不包括查询字符串。如果您想保留两个 location
块,可以安全地将此规则更改为 rewrite ^ /index.php?_route_=$uri last;
.
环境:nginx + php-fpm
我已经安装了OC 2.1
当我在网站周围使用 SEO URL 时没有问题。
example.com/news - [OK, 200]
示例。com/de/news - [好的,200]
但有时我没有 SEO URL
example.com/index.php?route=information/testimonials&testimonial_id=6 - [OK, 200]
例如。com/en/index.php?route=information/testimonials&testimonial_id=6 - [错误, 404]
NGINX:
server {
server_name example.com;
root /var/www/example.com;
index index.php index.html index.htm;
charset UTF-8;
autoindex off;
# Show "Not Found" 404 errors in place of "Forbidden" 403 errors, because
# forbidden errors allow attackers potential insight into your server's
# layout and contents
error_page 403 =404;
# It's always good to set logs, note however you cannot turn off the error log
# Setting error_log off; will simply create a file called 'off'
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
# SEO URL Settings
# Nginx configuration of OC htaccess
rewrite ^/sitemap.xml$ /index.php?route=feed/sitemap last;
rewrite ^/sitemap([^\.]+).xml$ /index.php?route=feed/sitemap&path= last;
location = /googlebase.xml {
rewrite ^(.*)$ /index.php?route=feed/google_base;
}
location / {
# This try_files directive is used to enable SEO-friendly URLs for OpenCart
try_files $uri $uri/ @opencart;
}
location @opencart {
rewrite ^([^?]*) /index.php?_route_= last;
}
# End SEO settings
# Make sure files with the following extensions do not get loaded by nginx because nginx would display the source code, and these files can contain PASSWORDS!
location ~* \.(engine|inc|info|ini|install|log|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php)?|xtmpl)$|^(\..*|Entries.*|Repository|Root|Tag|Template)$|\.php_ {
deny all;
}
# Do not log access to the favicon, to keep the logs cleaner
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /apple-touch-icon.png {
log_not_found off;
access_log off;
}
location = /apple-touch-icon-precomposed.png {
log_not_found off;
access_log off;
}
# This block will catch static file requests, such as images, css, js
# The ?: prefix is a 'non-capturing' mark, meaning we do not require
# the pattern to be captured into which should help improve performance
location ~* \.(?:3gp|gif|jpg|jpe?g|png|ico|wmv|avi|asf|asx|mpg|mpeg|mp4|pls|mp3|mid|wav|swf|flv|txt|js|css|exe|zip|tar|rar|gz|tgz|bz2|uha|7z|doc|docx|xls|xlsx|pdf|iso|woff|woff2|eot|otf|ttf)$ {
# Some basic cache-control for static files to be sent to the browser
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
# Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~ /\. {
access_log off;
log_not_found off;
deny all;
}
location ~ ~$ {
access_log off;
log_not_found off;
deny all;
}
# Deny access to any files with a .php extension in these directories
# Works in sub-directory installs and also in multisite network
# Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
location ~* /(?:cache|logs|image|download)/.*\.php$ {
deny all;
}
# Make sure these get through
location = /robots.txt {
allow all;
log_not_found off;
access_log off;
}
# Fix for Firefox issue with cross site font icons
location ~* \.(eot|otf|ttf|woff)$ {
add_header Access-Control-Allow-Origin *;
}
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/www;
}
# Pass all .php files onto a php-fpm/php-fcgi server.
location ~ [^/]\.php(/|$) {
# Regex to split $uri to $fastcgi_script_name and $fastcgi_path
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
# Bypass the fact that try_files resets $fastcgi_path_info
# see: http://trac.nginx.org/nginx/ticket/321
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
fastcgi_pass unix:/run/php/php5.6-fpm.sock;
fastcgi_index index.php;
# Uncomment if site is HTTPS
fastcgi_param HTTPS on;
include fastcgi.conf;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
} # End of server block.
server {
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name example.com;
return 404; # managed by Certbot
}
但在 ENV 中:php + apache2 一切正常,运行良好:)
Options +FollowSymlinks
Options -Indexes
<FilesMatch "(?i)((\.tpl|\.ini|\.log|(?<!robots)\.txt))">
Order deny,allow
Deny from all
</FilesMatch>
RewriteEngine On
#RewriteCond %{HTTP_HOST} ^www.dev.example.com
#RewriteRule ^(.*)$ http://dev.example.com/ [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\ HTTP/
RewriteRule ^index\.html$ / [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\ HTTP/
RewriteRule ^index\.php$ / [R=301,L]
RewriteBase /
RewriteRule ^sitemap.xml$ index.php?route=feed/sitemap [L]
RewriteRule ^sitemap([^\.]+).xml$ index.php?route=feed/sitemap&path= [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_= [L,QSA]
php_value max_input_vars 10000
php_value suhosin.post.max_vars 10000
php_value suhosin.request.max_vars 10000
我猜 nginx 规则和指令有些问题,它尝试打开 /de/ 目录并导致 404 错误页面,但 apache2 工作正常并且不会尝试打开 /de/ 目录。
我错过了什么?
这是您的 nginx 配置发生的情况。当一些一般请求(比如 /de/news
)到达您的服务器时,它由 location / { ... }
块处理,其中 try_files
指令首先检查 /var/www/example.com/de/news
文件存在,然后是您定义的索引文件存在于 /var/www/example.com/de/news
目录中,然后使用 @opencart
命名位置继续请求处理,您的请求在此处转换为 /index.php?_route_=/de/news
。之后 rewrite
nginx 指令的 last
标志强制 nginx 为这个转换后的请求搜索一个新位置,即 location ~ [^/]\.php(/|$) { ... }
一个。但是当你收到像 /en/index.php?route=information/testimonials&testimonial_id=6
这样的请求时,它会绕过默认的 location / { ... }
直接转到该位置,正则表达式匹配位置优先于前缀位置。在 fastcgi_split_path_info
指令之后,您的 $fastcgi_script_name
变量等于 /en/index.php
并且 try_files $fastcgi_script_name =404;
显然会给您一个 HTTP 404 错误。
你可以尝试做什么?例如,您可以尝试 try_files $fastcgi_script_name /index.php?_route_=$uri&$args;
。该指令会将您的 /en/index.php?route=information/testimonials&testimonial_id=6
请求转换为 /index.php?_route_=/en/index.php&route=information/testimonials&testimonial_id=6
。您可以重写您的 URI,将此语言前缀移动到某个查询变量,例如
location ~ [^/]\.php(/|$) {
if ($uri ~ ^/(?<lang>en|de|fr)(?<path>/.*)) {
set $args $args&language=$lang;
rewrite ^ $path break;
}
...
}
你可以做任何你想做的事,总有几种方法可以解决与 IT 相关的任务。我希望您了解一般情况。
后记
而不是
location / {
# This try_files directive is used to enable SEO-friendly URLs for OpenCart
try_files $uri $uri/ @opencart;
}
location @opencart {
rewrite ^([^?]*) /index.php?_route_= last;
}
你可以只使用
location / {
# This try_files directive is used to enable SEO-friendly URLs for OpenCart
try_files $uri $uri/ /index.php?_route_=$uri&$args;
}
通过 rewrite ^([^?]*) /index.php?_route_= last;
你可能意味着在没有查询字符串的情况下获取 URI 部分,但是 rewrite
指令(以及 location
指令)与规范化的 URI 一起工作无论如何不包括查询字符串。如果您想保留两个 location
块,可以安全地将此规则更改为 rewrite ^ /index.php?_route_=$uri last;
.