How do I make nginx cache rewritten assets? - cakephp

I'm using cakephp1.3, and some assets are themed assets (js, img etc) and others are not themed assets.
Non themed assets are cached correctly; but themed assets are not getting the correct expiration headers. I use rewrites in the location block to help to help find themed assets, but for some reason, nginx then does not apply the correct cache headers.
I have attached a copy of my nginx config below. Has anyone solved how to cache rewritten assets?
user nginx;
worker_processes 2;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
#-----------------------------------------------------------------------------------------------------
http {
include /etc/nginx/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 /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:100m inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server {
listen 80;
server_name ag_production;
access_log /var/log/nginx/ag.access.log;
error_log /var/log/nginx/ag.error.log;
rewrite_log on;
root /var/www/html/app/webroot/;
index index.php index.html index.htm;
set $no_cache 0;
location / {
try_files $uri $uri/ #rules;
}
location #rules {
rewrite ^(.+)$ /index.php?url=$1 last;
}
# Pass the PHP scripts to FastCGI server
# listening on 127.0.0.1:9000
location ~ \.php$ {
#try_files $uri =404;
fastcgi_cache my_cache;
fastcgi_cache_valid 200 60m; # Only cache 200 responses, cache for 60 minutes
fastcgi_cache_methods GET HEAD; # Only GET and HEAD methods apply
add_header X-Fastcgi-Cache $upstream_cache_status;
fastcgi_cache_bypass $no_cache; # Don't pull from cache based on $no_cache
fastcgi_no_cache $no_cache; # Don't save to cache based on $no_cache
fastcgi_buffer_size 128k;
fastcgi_buffers 256 4k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
# fastcgi_pass unix:/tmp/php-fastcgi.sock;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_intercept_errors on; # to support 404s for PHP files not found
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~* \.(?:manifest|appcache|html?|xml|json)$ {
try_files $uri $uri/ #rules;
expires -1;
access_log logs/static.log; # I don't usually include a static log
}
# Feed
location ~* \.(?:rss|atom)$ {
try_files $uri $uri/ #rules;
expires 1h;
add_header Pragma "public";
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
# Media: images, icons, video, audio, HTC
location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ {
expires 1M;
access_log off;
add_header Pragma "public";
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
try_files $uri $uri/ #rules;
}
# CSS and Javascript
location ~* \.(?:css|js)$ {
try_files $uri $uri/ #rules;
expires 1y;
access_log off;
add_header Pragma "public";
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
# Deny access to .htaccess files,
# git & svn repositories, etc
location ~ /(\.ht|\.git|\.svn) {
deny all;
}
}
}

Yes, theme assets are slower in CakePHP, it has been also described here in their official documentation.
The solution is to serve these theme assets through nginx, using try_files.
Here is an example nginx configuration for the above purpose:
# Serve CakePHP plugin assets directly
location ~ /(.+)/(img|css|js|files)/(.*) {
access_log off;
expires 10d;
add_header Cache-Control public;
try_files $uri $uri/ /../plugins/$1/webroot/$2/$3 /../../plugins/$1/webroot/$2/$3 /index.php?url=$uri;
}
(source)

Related

Nginx conflicts static files when serving multiple React apps

I'm currently trying to set up multiple projects of React Apps using Nginx. So far, whenever I had static files conflicting, I'd just copy everything from a folder into the other (yes, it's an awful solution, but it was working so far). The problem is that now I have multiple projects on the same server, and although the previous solution would still work, it wouldn't be long before it's a complete mess. I've looked up Stack Overflow and many websites, and I've come to a configuration that looks like what I want to do, but it's not working properly.
This is my nginx.conf file:
#user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/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 /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
server_names_hash_bucket_size 64;
#gzip on;
index index.html index.htm;
map $http_referer $webroot {
"/project1/main" "/home/username/project1main/build";
"/project1/admin" "/home/username/project1admin/build";
"/project2/main" "/home/username/project2main/build";
"/project2/admin" "/home/username/project2admin/build";
}
include /etc/nginx/conf.d/*.conf;
}
This is my server.conf file:
server {
listen 80;
server_name gcloud-server;
location /project1/main {
alias /home/username/project1main/build;
try_files $uri $uri/ /index.html =404;
}
location /project1/admin {
alias /home/username/project1admin/build;
try_files $uri $uri/ /index.html =404;
}
location /project2/main {
alias /home/username/project2main/build;
try_files $uri $uri/ /index.html =404;
}
location /project2/admin {
alias /home/username/project2admin/build;
try_files $uri $uri/ /index.html =404;
}
location /static {
root $webroot;
}
}
Is there a way to solve this problem like this? Or am I stuck into setting one /static location in which I'll have to copy every single projects' static files?
Thanks in advance.
As far a I can remember how an alias directive worked, you came into the following problem. Lets assume you've got a /project1/main/some/path/file request:
location /project1/main {
alias /home/username/project1main/build;
# here our internal variables are:
# $document_root = "/home/username/project1main/build"
# $uri = "/project1/main/some/path/file"
try_files $uri $uri/ /index.html =404;
# 1) try_files checks the existence of $document_root$uri physical file
# this is "/home/username/project1main/build/project1/main/some/path/file"
# which is absent
# 2) try_files checks the existence of $document_root$uri/ directory
# this is "/home/username/project1main/build/project1/main/some/path/file/"
# which is absent
# 3) you've got a 404 HTTP error
}
This problem didn't happen when you are using a root directive, but alias works this way. What you can do is
# use regex location match and capture URI suffix in a $1 variable
location ~ /project1/main(.*) {
alias /home/username/project1main/build;
# here our internal variables are:
# $document_root = "/home/username/project1main/build"
# $uri = "/project1/main/some/path/file"
# $1 = "/some/path/file"
try_files $1 $1/index.html =404;
# checked file is $document_root$1
# this is "/home/username/project1main/build/some/path/file"
# request would be served if this file exists
}

nginx - serving backend and frontend on different endpoints and same domain

I have installed nginx on OS X with php7.1, mysql and so on... and the basic testing example is working.
When I try to configure nginx to serve Laravel backend on user.domain.dev/api/... and Angular frontend on user.domain.dev/... I am getting 404 or 403. Nginx error log is mostly
/Users/name/Projects/domain.dev/api.domain.dev/" is forbidden
or
/Users/name/Projects/domain.dev/frontend.domain.dev/build/index.php" failed (2: No such file or directory)
I can't seem to understand nginx's location directive and so they're pointing to a wrong directories. Thanks for any advices or guidance.
My config is:
nginx.conf
user name staff;
worker_processes auto;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
ssl_certificate ssl/nginx.crt;
ssl_certificate_key ssl/nginx.key;
access_log /usr/local/var/log/nginx/access.log;
error_log /usr/local/var/log/nginx/error.log;
sendfile on;
keepalive_timeout 5;
gzip on;
include servers/*.conf;
}
servers/domain.dev.conf
server {
listen 80;
listen 443 ssl http2 default_server;
server_name domain.dev *.domain.dev www.domain.dev;
charset utf-8;
# removes trailing slashes (prevents SEO duplicate content issues)
if (!-d $request_filename)
{
rewrite ^/(.+)/$ /$1 permanent;
}
# enforce NO www
if ($host ~* ^www\.(.*))
{
set $host_without_www $1;
rewrite ^/(.*)$ $scheme://$host_without_www/$1 permanent;
}
##
## Backend HTTP server
##
location /api {
root /Users/name/Projects/domain.dev/api.domain.dev;
index index.php;
try_files $uri $uri/ /index.php?$query_string;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
try_files $fastcgi_script_name =404;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi.conf;
}
}
##
## Frontend HTTP server
##
location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
access_log off;
expires max;
}
location = /favicon.ico {
access_log off;
log_not_found off;
}
location = /robots.txt {
access_log off;
log_not_found off;
}
location / {
root /Users/name/Projects/domain.dev/frontend.domain.dev/build;
index index.html;
}
location ~ /\. {
deny all;
}
}
The main problem is an inconsistent use of the root directive. You have two document roots, one for each application, but only specified in two of your locations. There is no root specified at the server { ... } block level, therefore if (!-d $request_filename) is meaningless, location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ will always result in a 404 response, etc.
Read this document to understand how nginx processes a request.
But you should probably set the frontend root in the server block and override it with the backend root in the location /api block.
server {
root /Users/name/Projects/domain.dev/frontend.domain.dev/build;
location / { ... }
location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ { ... }
location ^~ /api {
root /Users/name/Projects/domain.dev/api.domain.dev;
...
}
}
This would place the backend document root at: /Users/name/Projects/domain.dev/api.domain.dev/api -- note that the URI is always appended to the root.
Note also, the ^~ modifier is used to make the prefix location take precedence over regular expression locations at the same level. See this document for details.
I do not like the naked if blocks in your design. The if (!-d $request_filename) should probably be replaced with a try_files directive, and if ($host ~* ^www\.(.*)) should probably be replaced by using a separate server block. See this document for more.
The try_files statement in your location /api block contains an incorrect default URI, it should probably be /api/index.php?$query_string.

nginx try_files and index not performing as expected

location /social {
index index.php;
try_files $uri /social/index.php;
}
When a user hits up a directory, it needs to run the local ./index.php
So far, when people hit up /social/ it runs index.php
When the user visits all unknown URLs, they get /social/index.php
However, when a user vists /social/subdir/ and there is a /social/subdir/index.php, it still runs /social/index.php. I need it to run /social/subdir/index.php
if I change the config to:
location /social {
index index.php;
try_files $uri $uri/index.php /social/index.php;
}
Then nginx serves up the CONTENT of social/subdir/index.php as content-type: octet/stream.
I thought index index.php would look for the paths index file.
php rendering block:
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 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
I think your main issue is that you didn't use http:// before 127.0.0.1:9000 , also make sure that your php uses port 9000 not a sock file, otherwise you change the fastcgi_pass to unix socket.
Here's my simplified config.
Remove the index index.php from the /social block if it's the same value in the server block.
location /social {
# index index.php; # remove if not needed
try_files $uri $uri/ /social/index.php;
}
location ~* \.php$ {
include fastcgi_params;
fastcgi_pass http://127.0.0.1:9000;
}
First remove the index.php from the try_files directive so it will look like this
location /social {
index index.php;
try_files $uri $uri/ /social/index.php =404;
}
Also make sure that no other location block catches the /social/subdir/ request.
Lastly (irrelevant to your question, but very important) remove this line
if (!-e $request_filename) { rewrite / /index.php last; } ## Catch 404s that try_files miss
It is totally redundant and evil. try_files does not miss 404s. Have a look at this for more info IfIsEvil

how to configure cakephp in nginx

Currently i am working on cakephp with nginx. I setup a cakephp environment on a Centos server running Nginx with Fact CGI. The problem is that I cannot get the rewrite rules to setup correct in my vhost so that cake renders pages correctly i.e. with styling and so on.
My .conf file is as -
#The default server
server {
listen 80 default_server;
server_name 1 23.123.123.123;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /usr/share/nginx/html;
index index.php index.html index.htm;
}
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
}
# 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/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
include fastcgi_params;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
}
Luchomolina's answer below got me started in the right direction. However, CSS and JS files stopped working on URLs that were not top-level URLs, e.g. /posts worked but /posts/title123 didn't.
This is what ended up working for me:
location / {
if (-f $request_filename) {
break;
}
if (!-f $request_filename) {
rewrite ^/(.+)$ /index.php?url=$1 last;
break;
}
set $new_uri $uri;
}
use the blow code
location / {
if (-f $request_filename) {
break;
}
if (!-f $request_filename) {
rewrite ^/(.+)$ /index.php?url=$1 last;
break;
}
set $new_uri $uri;
}
This works for me:
server {
listen 80 ;
server_name example.com;
root /www/example.com/app/webroot;
index index.html index.php;
location / {
try_files $uri $uri/ /index.php?$uri&$args;
set $new_uri $uri;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param PATH_INFO $new_uri;
}
location ~ /(\.ht|\.git|\.svn) {
deny all;
}
}
The $new_uri rules were added to make some special routes work on my site, maybe that won't apply to you, but note that CakePHP assumes PATH_INFO is set, so those rules won't harm leaving it there.
Hope it helps.

CakePHP and Nginx configuration

So I've been tasked with creating a site using CakePHP, so I downloaded the latest 2.2.3, and I need to configure it on my local nginx 1.2.4 server.
I have the server_block working, but for some reason I can't load any css. The test home page also reports that url rewriting isn't working properly.
I've been reading a number of articles and questions, but none seem to be able to solve the issue. So far I've referenced,
Issue with Cakephp application running on nginx 1.0.8 + subdirectory
http://book.cakephp.org/2.0/en/installation/advanced-installation.html#pretty-urls-on-nginx
http://www.littlehart.net/atthekeyboard/2007/09/14/configuring-cakephp-to-work-with-nginx/
http://www.littlehart.net/atthekeyboard/2009/01/25/cakephp-nginx-configuration-update/
http://kvz.io/blog/2010/02/24/cakephp-and-nginx/
My css links look like this,
<link rel="stylesheet" type="text/css" href="/Users/david/Sites/example.com/css/cake.generic.css" />
I need to figure out why Nginx isn't letting my CSS load. So far I can only find out that it's appending the $_SERVER['DOCUMENT_ROOT'] to all my links which obviously means my css will be incorrectly linked. I need to find out who to stop cakephp from picking up this extra information. Links are being passed into the HtmlHelper as follows string '/Users/david/Sites/example.com//Users/david/Sites/example.com/css/cake.generic.css' (length=86)
Currently my nginx config server block looks like the following.
server {
server_name example.com;
root /Users/david/Sites/example.com/app/webroot/;
access_log /usr/local/var/log/nginx/example.com.access.log;
error_log /usr/local/var/log/nginx/example.com.error.log;
listen 80;
rewrite_log on;
# rewrite rules for cakephp
location / {
index index.php index.html;
# If the file exists as a static file serve it
# directly without running all
# the other rewite tests on it
if (-f $request_filename) {
break;
}
if (!-f $request_filename) {
rewrite ^(.+)$ /index.php?url=$1 last;
break;
}
}
location ~* \favicon.ico$ {
expires 6m;
}
location ~ ^/img/ {
expires 7d;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9001;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SERVER_NAME example.com;
include fastcgi_params;
}
location ~ /\.ht {
deny all;
}
}
FastCGIParams
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $request_filename;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param HTTPS $https if_not_empty;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
So I've managed to figure out what the issue was. It turns out that it's a variable in core.php
If you change Configure::write('App.baseUrl', env('SCRIPT_NAME')); to be Configure::write('App.baseUrl', '/'); then it seems to all work and will route correctly to you css files.
My nginx config looks like the following.
server {
listen 127.0.0.1:80;
server_name example.com.ukwm157;
root /Users/david/Sites/example.com/app/webroot;
index index.php index.html;
log_not_found off;
charset utf-8;
access_log /usr/local/var/log/nginx/example.com.access.log main;
error_log /usr/local/var/log/nginx/example.com.error.log;
location / {
index index.php index.html index.htm;
if (-f $request_filename) {
break;
}
if (-d $request_filename) {
break;
}
rewrite ^(.+)$ /index.php?q=$1 last;
}
# Static files.
# Set expire headers, Turn off access log
location ~* \favicon.ico$ {
access_log off;
expires 1d;
add_header Cache-Control public;
}
location ~ ^/(img|cjs|ccss)/ {
access_log off;
expires 7d;
add_header Cache-Control public;
}
# Deny access to .htaccess files,
# git & svn repositories, etc
location ~ /(\.ht|\.git|\.svn) {
deny all;
}
location ~ .php?$ {
#if (!-e $document_root$document_uri){return 404;}
fastcgi_pass 127.0.0.1:9001;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Following configuration works for me with Cake 2.x
server {
listen 80;
server_name myprojecy.xyz;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
root /var/www/html/project-forlder/app/webroot;
index index.php index.html index.htm;
if (-f $request_filename) {
break;
}
if (-d $request_filename) {
break;
}
rewrite ^(.+)$ /index.php?q=$1 last;
}
location ~ .*\.php[345]?$ {
include /etc/nginx/fastcgi.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME
/var/www/html/project-forlder/app/webroot$fastcgi_script_name;
}
}
I think the problem is you’re using a file path and not a URL.

Resources