nginx rewrite rules with Passenger - ruby-on-rails

I'm trying to migrate to nginx from Apache using Passenger in both instances to host a Rails app. The app takes a request, which is for an image- if the image exists at /system/logos/$requestedimage then it should get served, or it should be allowed to hit the Rails app to generate it if needed (where it is then cached to /system/logos).
In Apache I used the following:
RewriteCond %{DOCUMENT_ROOT}/system/logos/%{REQUEST_FILENAME} -f
RewriteRule ^/(.*)$ http://assets.clg.eve-metrics.com/system/logos/$1
This worked fine. The assets. subdomain is another subdomain but with the same root, just Passenger disabled, specifically set up for hosting static files (expires-wise).
In nginx I am using the following:
server {
listen 80;
passenger_enabled on;
server_name clg.eve-metrics.com www.clg.eve-metrics.com;
root /opt/www/clg/current/public;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain application/xml text/css application/javascript;
gzip_disable msie6;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
if (-f $document_root/system/logos$request_filename) {
rewrite ^/(.*)$ http://assets.clg.eve-metrics.com/system/logos/$1 break;
}
}
This doesn't work so well. At all, in fact. It never redirects to the cached path and it never hits the Rails app. It's like nginx is assuming it's a static asset so not passing it on to Passenger. Is there a way to stop this behaviour so it hits the app?

My rails application is running on nginx and passenger. I have moved my rails cache directory from the default /public to /public/system/cache/. To make it work, I had to insert this into my vhost config file:
if (-f $document_root/system/cache/$uri/index.html) {
rewrite (.*) /system/cache/$1/index.html break;
}
if (-f $document_root/system/cache/$uri.html) {
rewrite (.*) /system/cache/$1.html break;
}
I remember that I too tried to make it work with $request_filename, but didn't get it to work. Try with $uri instead and see if it works :-)

James, please try this configuration file
https://gist.github.com/711913
and pay attention on this location config:
location ~* \.(png|gif|jpg|jpeg|css|js|swf|ico)(\?[0-9]+)?$ {
access_log off;
expires max;
add_header Cache-Control public;
}
passenger won't let Rails to manage your assets files if you have right permissions (user run nginx should has permissions to access to file directly)

Related

Nginx how to serve digest favicon file when request is for non-digest favicon.ico

I'm using Nginx in front of a rails app. Nginx is serving static assets from public with the following location rule:
location ~ ^/assets/ {
gzip_static on;
gzip off;
expires 1y;
add_header Cache-Control public;
add_header Last-Modified "";
add_header ETag "";
break;
}
This is working fine for the standard Rails digest assets but every now and then I get a request for /favicon.ico directly which will fail as it is a non-digest asset.
What I'd like to do is use a Nginx location directive to map/alias/rewrite /favicon.ico to /assets/favicons/favicon-somereallylongdigest.ico.
As rails will keep up to the last 3 assets there could be three files which match, I'm not worried about that and are happy to match any of the files found.
I'm not strong on Nginx config so any help is appreciated.
You could use a permanent redirect:
location = /favicon.ico {
return 301 $scheme://$host/assets/favicons/favicon-somereallylongdigest.ico;
}

Load Balancing - Web Applications with NGINX

I have a web application ruby on rails who is not configured to multithreading.
In nginx config, I set up an upstream block to be load balanced.
Like this :
upstream myapp {
server 127.0.0.1:3075;
server 127.0.0.1:3076;
server 127.0.0.1:3077;
}
I set up also 3 process thin with 3 ports (3075,3076,3077).
I think when my first application '127.0.0.1:3075' is busy, all the request will be balanced automatically to my second application '127.0.0.1:3076' or the third one.
But load balancing is not work, even though my three web applications are running correctly independent.
Please help me to find errors.
------------------- nginx config --------------------
upstream myapp_hosts {
server 127.0.0.1:3075;
server 127.0.0.1:3076;
server 127.0.0.1:3077;
}
server {
listen 80;
server_name myapp.mydomain.com;
rewrite ^(.*)$ https://myapp.mydomain.com$1 permanent; # rewrite for https, i have another bloc server listen 443.
access_log /var/log/nginx/myapp.access.log;
location / {
proxy_pass http://myapp_hosts/;
proxy_connect_timeout 900;
proxy_send_timeout 900;
proxy_read_timeout 900;
proxy_buffer_size 16k;
proxy_buffers 32 16k;
proxy_busy_buffers_size 64k;
}
location /public {
root /var/www/nemo/;
}
location /images {
root /var/www/nemo/assets/;
}
location /javascripts {
root /var/www/nemo/assets/;
}
location /stylesheets {
root /var/www/nemo/assets/;
}
client_max_body_size 10m;
client_body_buffer_size 128k;
client_header_buffer_size 64k;
}
What is the purpose of your rewrite?
rewrite ^(.*)$ http://myapp.mydomain.com$1 permanent;
It looks like it's going to constantly redirect anything to itself based off of those rules, resulting in a redirect loop. You may have mixed this line up with an HTTPS redirect configuration you found somewhere else, perhaps?
Try removing that line and see if it works.

HTTP_IF_MODIFIED_SINCE header not passed to Rails app (Nginx, Passenger)

I am trying to use the HTTP_IF_MODIFIED_SINCE header in my app to determine if resources are stale/fresh and render 200/304 in those cases.
In my dev environment everything works fine but I can't for the life of me get it to work in production.
I am using Passenger 3.0.11 and Nginx 1.0.13.
As you see below, I tried proxy_pass_header, proxy_set_header, passenger_pass_header and passenger_set_cgi_param. The last one actually sets a HTTP_IF_MODIFIED_SINCE header but it is empty...
Any help/ideas would be greatly appreciated!
My config:
server {
listen 80 default_server;
root /home/rails/myapp/current/public;
passenger_enabled on;
charset utf-8;
proxy_pass_header If-Modified-Since;
proxy_set_header If-Modified-Since $http_if_modified_since;
passenger_pass_header If-Modified-Since;
passenger_set_cgi_param HTTP_IF_MODIFIED_SINCE $http_if_modified_since;
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html break;
}
location ~ \.(aspx|jsp|cgi)$ {
return 410;
}
location ~ ^/(assets)/ {
# http://guides.rubyonrails.org/asset_pipeline.html#server-configuration
# gzip_static on;
expires 1y;
add_header Cache-Control public;
add_header Last-Modified "";
add_header ETag "";
break;
}
}
to get it working with non-standard headers, containing underscores, do this inside your http or server block in the nginx.conf file:
underscores_in_headers on;
ignore_invalid_headers off;
and in the server block:
proxy_pass_header HTTP_IF_MODIFIED_SINCE
This can be useful if you have legacy HTTP headers which you need to deal with, and which contain underscores.
This was a user error after all. I sent the header to the app in the wrong format (IF_MODIFIED_SINCE instead of If-Modified-Since). After fixing that, it worked without any of the extra directives.

Maintenance page with nginx for one domain_name among others

I have a rail app that serves multiple domain_name and is deployed by nginx & passenger. I need to put one domain under maintenance mode while the other still work as usual. Here is my config:
server {
listen 80;
server_name domain1.com domain2.com domain3.com domain4.com;
error_page 503 http://$host/maintenance.html;
location /maintenance.html {
# Allow requests
}
location / {
root /var/www/myapp/public; # <--- be sure to point to 'public'!
error_page 503 http://$host/maintenance.html;
passenger_enabled on;
rails_env development;
passenger_use_global_queue on;
if (-f /var/www/myapp/public/maintenance.html) {
return 503;
}
}
}
The above config would cause all domains under maintenance. However, I want to put domain1.com is under maintenance mode. How would I achieve this?
you can add another server entry for server "domain1.com" which serve request for this domain only. like:
server {
listen 80;
server_name domain1.com
error_page 503 http://$host/maintenance.html;
root /your/root/directory/
if (-f $document_root/maintenance.html){
rewrite ^(.*)$ /maintenance.html last;
break;
}
location /maintenance.html {
# Allow requests
}}
you need to ensure following
The "domain1.com" should be removed from previous server
entry
maintenance.html page should be
present in /your/root/directory/

Nginx raises 404 when using format => 'js'

I upload images to my App using Ajax and an Iframe. In Development everything works like a charm. But in production Nginx suddenly raises a 404 error. When I look into the log, the request never hits the Rails app. So I guess it has something to do with my Nginx configuration (maybe gzip compression).
The failing requests is send to "/images.js".
Any ideas on how to solve this? Google couldn't help me...
My Nginx config:
server {
listen 80;
server_name www.myapp.de;
root /var/www/apps/myapp/current/public; # <--- be sure to point to 'public'!
passenger_enabled on;
rails_env production;
# set the rails expires headers: http://craigjolicoeur.com/blog/setting-static-asset-expires-headers-with-nginx-and-passenger
location ~* \.(ico|css|js|gif|jp?g|png)(\?[0-9]+)?$ {
expires max;
break;
}
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;
# make sure gzip does not lose large gzipped js or css files
# see http://blog.leetsoft.com/2007/7/25/nginx-gzip-ssl
gzip_buffers 16 8k;
# this rewrites all the requests to the maintenance.html
# page if it exists in the doc root. This is for capistrano?^?^?s
# disable web task
if (-f $document_root/system/maintenance.html) {
rewrite ^(.*)$ /system/maintenance.html last;
break;
}
# Set the max size for file uploads to 10Mb
client_max_body_size 10M;
error_page 500 502 503 504 /500.html;
location = /500.html {
root /var/www/apps/myapp/current/public;
}
}
nginx will serve the request for /images.js from your root /var/www/apps/myapp/current/public since it matches
location ~* \.(ico|css|js|gif|jp?g|png)(\?[0-9]+)?$ {
expires max;
break;
}
(the break directive only applies to rewrite rules afaik so it can be removed)
If you want to serve /images.js from rails you need to enable rails for that location.
It's worth noting that any .json requests will get caught if you use the regex above. Add a $ to avoid that.
location ~* \.(ico|css|js$|gif|jp?g|png)(\?[0-9]+)?$ {
expires max;
break;
}
For this purpose I use this location directives:
location ~* ^.+\.(jpg|jpeg|gif|png|css|swf|ico|mov|flv|fla|pdf|zip|rar|doc|xls)$
{
expires 12h;
add_header Cache-Control private;
}
location ~* ^/javascripts.+\.js$
{
expires 12h;
add_header Cache-Control private;
}
I ran into a very similar issue, and put format.json instead of format.js - this made a URL that had a .json extension, but allowed me to not modify my Nginx config.

Resources