I'm looking for a solution to cache 404s in long term (a few days/weeks) on the webserver. My current setup is NGINX with memcached_pass proxy and PHP-FPM to deliver uncached pages (PHP also writes the contents to memcached).
The crawlers all around the web seem to like my pages and generate a few thousand 404 requests a day. All of them hit PHP directly since I can't cache 404 response header informations together with the contents in memcached, hence the memcached_pass lookup always fails.
How can I cache all those requests that return a 404? Is the HTTPProxModule for Nginx what I'm looking for? Or should I rather go for Varnish?
From my current point of view, I'm not keen to change my entire setup and drop the memcached_pass directive from nginx. It's pretty neat so far, because php decides wheter a request can(should) be cached in memcached or not. It's also pretty easy to flush the cache when necessary.
My current NGINX configuration file:
server {
listen 80;
server_name _;
gzip on;
gzip_http_version 1.0;
gzip_vary on;
gzip_comp_level 6;
gzip_proxied any;
gzip_types text/plain text/html text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
location / {
gzip on;
default_type "text/html; charset=utf-8";
charset utf-8;
add_header Content-Encoding gzip;
if ($request_method = GET)
{
expires max;
set $memcached_key $http_host$request_uri;
memcached_pass 127.0.0.1:11211;
error_page 404 = #fallback;
#error_page 502 = #fallback;
break;
}
root /var/www/html/;
index index.php index.html;
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?q=$1 last;
break;
}
}
location #fallback {
internal;
root /var/www/html/;
index index.php index.html;
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?q=$1 last;
break;
}
}
location ~ \.php$ {
root /var/www/html/;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
}
An example configuration either for Nginx or Varnish would be great.
Thank you! :)
Use the fastcgi_cache_valid directive: http://wiki.nginx.org/HttpFcgiModule#fastcgi_cache_valid
Related
I'm switching a Laravel Website from Apache (htaccess) to NGinx. I have built an Image Serving that produces a uri with the appropriate parameters for resizing ex : pics/images/max24h/music_video_red_icon.png.
I Apache does not find the file it would redirect it to a route image/images/max24h/music_video_red_icon.png where an Action in laravel creates and returns the image. In .htaccess it works with this code :
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^pics(.*)\.(jpe?g|png|gif|ico|bmp)$ /image$1.$2 [R=307,L]
Now in NGinx conf, How do I redirect it properly? I tried a lot of suggestions like :
# Redirect pics file not found to php laravel route to create the image
location #img_proxy {
rewrite ^/pics(.*)\.(jpe?g|png|gif|ico|bmp)$ /image$1.$2;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
It does not work at all, the server works if I remove those lines. I'm using Mac High Sierra 10.13.6 . Could it be some config conflict? Here is the full nginx.conf :
user _www _www;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80 default_server;
server_name localhost;
root /var/www/megalobiz/public;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
charset utf-8;
gzip on;
gzip_vary on;
gzip_disable "msie6";
gzip_comp_level 6;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types
text/plain
text/css
text/js
text/xml
text/javascript
application/javascript
application/x-javascript
application/json
application/xml
application/xml+rss;
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
error_page 404 /index.php;
# removes trailing slashes (prevents SEO duplicate content issues)
#if (!-d $request_filename)
#{
# rewrite ^/(.+)/$ /$1 permanent;
#}
# Redirect pics file not found to php laravel route to create the image
location ~ ^/pics(.*)\.(jpe?g|png|gif|ico|bmp)$ {
try_files $uri #img_proxy;
}
location #img_proxy {
rewrite ^/pics(.*)\.(jpe?g|png|gif|ico|bmp)$ /image$1.$2;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc|svg|woff|woff2|ttf)\$ {
expires 1M;
access_log off;
add_header Cache-Control "public";
}
location ~* \.(?:css|js)\$ {
expires 7d;
access_log off;
add_header Cache-Control "public";
}
location ~ /\.(?!well-known).* {
deny all;
}
location ~ /\.ht {
deny all;
}
}
include servers/*;
}
The main difference between the function of the .htaccess file and your rewrite statement is that Apache will perform an external redirect using a 307 response, while Nginx performs an internal redirect instead. See this document for details.
To force Nginx to perform an external redirect, append the permanent or redirect flag to the rewrite statement, which generates a 301 or 302 response respectively.
For example:
location #img_proxy {
rewrite ^/pics(.*)\.(jpe?g|png|gif|ico|bmp)$ /image$1.$2 redirect;
}
The difference between a 302 and a 307 response, is that the latter will redirect a POST request method without changing it to a GET.
If you need to redirect POST requests, you will need to capture the relevant parts of the URI with a regular expression location or if block and use a return 307 instead.
For example:
location #img_proxy {
if ($uri ~ ^/pics(.*)\.(jpe?g|png|gif|ico|bmp)$) {
return 307 /image$1.$2$is_args$args;
}
}
See this caution on the use of if.
I need your help on tuning a bit Nginx and my server.
I've got a website which is hosted on my server, and an API, also hosted on this server.
The website sends Ajax requests to the API. The problem is, once I've opened a page, which sends Ajax requests to the API, I cannot browse the website anymore using this browser because, I've reached the number of allowed connection for this browser on the website's server.
How can I change Nginx or the server configuration in order to increase the number of connections allowed per browser?
Thanks for your help.
EDIT
Server conf
worker_processes 4;
worker_connections 1024;
multi_accept on;
keepalive_timeout 65;
Server block
server {
listen 80;
server_name mywebsite.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443;
ssl on;
ssl_certificate /path/to/pem;
ssl_certificate_key /path/to/key;
# Set the server name
server_name mywebsite.com;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000";
root /path/to/root/folder;
index index.php;
# Logs
error_log /path/to/error.log;
access_log /path/to/access.log;
# strip app_test.php/ prefix if it is present
rewrite ^/index\.php/?(.*)$ /$1 permanent;
location / {
index index.php;
try_files $uri #rewriteapp;
}
location #rewriteapp {
rewrite ^(.*)$ /index.php/$1 last;
}
# pass the PHP scripts to FastCGI server from upstream phpfcgi
location ~ ^/(index)\.php(/|$) {
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
fastcgi_read_timeout 43200;
internal;
}
# Define error pages
# Error pages are located in the app folder
error_page 403 403.html;
location = 403.html {
root /path/to/error-pages;
internal;
}
error_page 404 404.html;
location = 404.html {
root /path/to/error-pages;
internal;
}
error_page 500 502 503 504 50x.html;
location = 50x.html {
root /path/to/error-pages;
internal;
}
}
I've just set HVVM on debian machine. My issue is that when I access a laravel route it returns this strange message: 404 File Not Found , however, if I make a new .php file in the public directory of the laravel, everything works safe and sound. Here are my nginx and hhvm conf files:
hhvm.conf:
location ~ \.(hh|php)$ {
fastcgi_keep_conn on;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;
include fastcgi_params;
}
nginx configuration:
server {
# Make site accessible from http://localhost/
server_name ***;
gzip on;
gzip_comp_level 2;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# Disable for IE < 6 because there are some known problems
gzip_disable "MSIE [1-6].(?!.*SV1)";
# Add a vary header for downstream proxies to avoid sending cached gzipped files to IE6
gzip_vary on;
listen 80 default_server;
root /var/www/***/public_html/laravel/public;
index index.php index.html index.htm;
location / {
try_files $uri $uri/ index.php?$query_string;
}
include hhvm.conf;
location /doc/ {
alias /usr/share/doc/;
autoindex on;
allow 127.0.0.1;
allow ::1;
deny all;
}
}
So what may be wrong?
Well, in my case the problem was the nginx block configuration.
Replacing:
location / {
try_files $uri $uri/ index.php?$query_string;
}
with:
location / {
try_files \$uri \$uri/ /index.php?\$query_string;
}
did the trick.
I am running magento under the Wordpress(Wordpress on the root and mangento under a subdirectory "/shop"). Previously I was running this under the Apache, So everything was running fine with separate .htaccess under the /shop folder.
As I move the server over NginX, all the internal magento URL showing 404. Please help me to solve this problem. Please suggest me how can I run the Magento under the /shop folder with Wordpress.
Here is my NginX Configuration file:
server {
listen 80;
server_name domain.com www.domain.com;
root /var/www/html;
index index.php index.html index.htm;
error_log /var/www/logs/error.log;
access_log /var/www/logs/access.log;
### gZip Setting ###
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
### gZip End ###
location / {
if ($http_host !~ "^www\."){
rewrite ^(.*)$ http://www.$http_host/$1 redirect;
}
try_files $uri $uri/ =404;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location /shop/ {
try_files $uri $uri/ /index.php?$args;
}
location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
rewrite ^(.*.php)/ $1 last;
}
if (!-e $request_filename)
{
rewrite ^(.+)$ /index.php?q=$1 last;
}
location ~ .php$ { ## Execute PHP scripts
if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
expires off; ## Do not cache dynamic content
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; ## See /etc/nginx/fastcgi_params
}
}
I got the solution, Here is my new configuration file:
server {
listen 80;
server_name domain.com www.domain.com;
root /var/www/html;
index index.php index.html index.htm;
error_log /var/www/logs/domain-error-ssl.log;
access_log /var/www/logs/domain-access-ssl.log;
### gZip Setting ###
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
### gZip End ###
location / {
if ($http_host !~ "^www\."){
rewrite ^(.*)$ https://www.$http_host/$1 redirect;
}
try_files $uri $uri/ /index.php?$args;
}
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location ~ .php/ { ## Forward paths like /js/index.php/x.js to relevant handler
rewrite ^(.*.php)/ $1 last;
}
### Configuration for shop ###
location /shop {
index index.html index.php;
try_files $uri $uri/ #handler;
expires 30d;
if ($uri ~ "^/index.php/admin.*$"){
rewrite ^/index.php/admin(.*) /admin$1 redirect;
}
}
location ~ ^/shop/(app|includes|lib|media/downloadable|pkginfo|report/config.xml|var)/ { internal; }
location /shop/var/export/ { internal; }
location #handler { rewrite / /shop/index.php; }
### END Configuration for shop ###
location ~ .php$ { ## Execute PHP scripts
expires off; ## Do not cache dynamic content
fastcgi_read_timeout 120;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
#fastcgi_param HTTPS $fastcgi_https;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; ## See /etc/nginx/fastcgi_params
}
}
Some of you may have already noticed the recent Optimizing Magento For Peak Performance white paper released by Magento a few days ago. Even though it was mainly written for EE users, I believe we can use most of the tips for the Community edition as well.
After a good reading, I went ahead and merged their suggested Nginx + fastcgi/proxy cache config with my standard virtual host config for Magento and a few minor improvements. Here’s what I came up with:
fastcgi_cache_path /tmp/fcgi levels=1:2 keys_zone=MAGE:64m max_size=128m inactive=10h;
server {
listen 99999; ## Nginx port
server_name domain.com www.domain.com;
root /www/magento; ## App folder
index index.php;
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
expires max;
access_log off;
log_not_found off;
}
location /index {
try_files $uri #fcgi_nocache;
}
location /checkout {
try_files $uri #fcgi_nocache;
}
location / {
try_files $uri #fcgi_cache;
if ($cookie_frontend) { return 413; }
if ($cookie_CUSTOMER_AUTH) { return 413; }
if ($request_method = POST ) { return 413; }
error_page 413 = #fcgi_nocache;
}
# Deny access to hidden files
location ~ (/(app/|includes/|/pkginfo/|var/|report/config.xml)|/\.svn/|/.hta.+) {
deny all;
}
# Forward paths like /js/index.php/x.js to relevant handler
location ~ .php/ {
rewrite ^(.*.php)/ $1 last;
}
# Manually purge pages
location ~ /purge(/.*) {
fastcgi_cache_purge MAGE "$scheme$request_method$host$1";
}
location #fcgi_cache {
#if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
fastcgi_pass unix:/var/spool/phpfpm.sock; ## php-fpm socket
include fastcgi_params;
fastcgi_connect_timeout 60;
fastcgi_send_timeout 60;
fastcgi_read_timeout 60;
fastcgi_buffer_size 4k;
fastcgi_buffers 512 4k;
fastcgi_busy_buffers_size 8k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors off;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_param SCRIPT_NAME /index.php;
#fastcgi_keep_conn on; # NGINX 1.1.14
fastcgi_temp_path /tmp/fcgi2 1 2;
fastcgi_cache MAGE;
#fastcgi_cache_key "$request_method|$http_if_modified_since|$http_if_none_match|$host|$request_uri"; ## Original
fastcgi_cache_key "$scheme$request_method$host$request_uri$http_if_modified_since$http_if_none_match";
#fastcgi_cache_lock on 5s; # NGINX 1.1.12
fastcgi_cache_valid 200 301 302 304 1h;
fastcgi_hide_header "Set-Cookie";
if ($http_cookie !~ "X-Store=1" ) {
add_header Set-Cookie "X-Store=1; path=/";
}
fastcgi_ignore_headers "Cache-Control" "Expires" "Set-Cookie";
fastcgi_cache_min_uses 1;
fastcgi_cache_valid 30m;
fastcgi_cache_use_stale updating error timeout invalid_header http_500;
fastcgi_cache_bypass $cookie_EXTERNAL_NO_CACHE $cookie_CUSTOMER_AUTH;
fastcgi_no_cache $cookie_EXTERNAL_NO_CACHE $cookie_CUSTOMER_AUTH;
#add_header X-Cache-Status $upstream_cache_status; # Test
}
location #fcgi_nocache {
#if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
fastcgi_pass unix:/var/spool/phpfpm.sock; ## php-fpm socket
include fastcgi_params;
fastcgi_connect_timeout 60;
fastcgi_send_timeout 60;
fastcgi_read_timeout 60;
fastcgi_buffer_size 4k;
fastcgi_buffers 512 4k;
fastcgi_busy_buffers_size 8k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors off;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
fastcgi_param SCRIPT_NAME /index.php;
#fastcgi_keep_conn on; # NGINX 1.1.14
fastcgi_temp_path /tmp/fcgi2 1 2;
if ($http_cookie !~ "X-Store=1" ) {
add_header Set-Cookie "X-Store=1; path=/";
}
#add_header X-Cache-Status $upstream_cache_status; # Test
}
}
After some tests, the results seem impressive via AB, but I’m really not that confident if they are accurate and if the cache system is fully working as expected. Could someone elaborate what is the actual logic behind #fcgi_cache and #fcgi_nocache and the cookies? Who is actually getting the cached pages? The stale cache doesn’t seems to be working when PHP-FPM is turned off (?). I’m a bit stucked and somewhat confused with the different headers I’m getting.
Suggestions anyone??
this type of config is absolutely useless for magento, they used it only to get maximum "dummy" throughput, and this config logics even breaks in few places.
you would better configure hole-punching full page cache extension, it will reinsert your dynamic blocks and will keep your site always in cache. there must be as well cache refresh for newly added products and qty changes, etc.
I know this is an old question, but in case anybody stumbles upon this thread, I just wanted to point out that the newest Magento releases (>=1.13 enterprise & >=1.8 community) will break this nginx caching method.
Once upgraded, and caching is enabled, your users will no longer be able to add to cart if they are looking at a cached page. The reason behind this, is that Magento added in a url form key for the "Add to Cart" button to prevent cross site scripting. With nginx cache turned on, the first URL form key will be cached, and the next set of users will be loading an invalid form key not attached to their session. As far as I could tell, there isn't a way to hole punch nginx cache either, which (to quote ADM) makes "nginx caching absolutely useless". If anybody out there knows if there IS a way to hole punch nginx cache, I'm all ears.
If you continued to use the nginx cache, I highly recommend seeing how you could stand up without it as disabling it, will save you many headaches when upgrading to the newest Magento release.