Gem asset files when using Nginx - ruby-on-rails

The asset files for a couple of gems I'm using aren't loading after using Nginx in production mode. I'm pretty certain it has to do with the location blocks in my Nginx config, but I'm not sure what to add so that Nginx will point to where the files are located.
The gems in question are sidekiq and rack-mini-profiler
upstream cable {
server unix:///tmp/cable.sock;
}
server {
listen 80;
server_name 66.207.0.133;
root /home/john/rails/cable/public/assets;
location / {
proxy_pass http://cable;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* \.(css|js|otf|woff|ttf|svg|eot)$ {
root /home/john/rails/cable/public/;
}
}
The error in the Nginx log is:
2016/11/07 21:04:36 [error] 22745#22745: *51175 open() "/home/john/rails/cable/public/sidekiq/javascripts/dashboard.js" failed (2: No such file or directory), client: 69.49.80.136, server: 66.207.0.133, request: "GET /sidekiq/javascripts/dashboard.js HTTP/1.1", host: "66.207.0.133", referrer: "http://66.207.0.133/sidekiq"
Obviously the second location block is redirecting all requests for the needed .js and .css files to the wrong location, but how and to where can I redirect requests to /sidekiq/*.js to the correct files?

You first need to find where the correct files are in your filesystem.
find / -path "*/javascripts/dashboard.js"
A web search reveals that it might be /home/site/homepage_production/shared/bundle/ruby/1.9.1/gems/sidekiq-2.16.1/web/assets/javascripts/dashboard.js.
So, if you gotta serve that from /sidekiq/javascripts/dashboard.js on the web, and provided that all requests within /sidekiq/ are for static assets, then the following should be used:
location ^~ /sidekiq/ {
alias /home/site/homepage_production/shared/bundle/ruby/1.9.1/gems/sidekiq-2.16.1/web/assets/;
}
For more details, see:
http://nginx.org/r/location
http://nginx.org/r/alias

Related

Nginx reverse proxy want to use virtual directory for redirect

I have, what I hope is, a simple question. I am running Nginx and some applications in Docker containers. Some of the applications run on the same host as Nginx. I can access an application using, for example, app.example.com, but I want to access the same application using example.com/app. I cannot figure out how to define the server block with location /app. I would like to achieve something like:
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass app-srv:port;
}
}
server {
listen 80;
server_name example.com;
location /app {
What do I place here?
}
}
Edit: with additional information.
My server configuration is:
server {
listen 80;
server_name openhab.aronica-sys;
location / {
proxy_pass http://openhab:8081;
}
}
server {
listen 80;
server_name aronica-sys;
location /openhab/ {
proxy_pass http://openhab:8081/;
}
}
openhab in the proxy_pass statements is the Docker virtual address for the openHAB server.
'openhab.aronica-sys' gets:
VM6:1 XHR finished loading: GET "http://openhab.aronica-sys/rest/ui/tiles".
VM6:1 XHR finished loading: GET "http://openhab.aronica-sys/rest/".
VM6:1 XHR finished loading: GET "http://openhab.aronica-sys/rest/habot/greet".
VM6:1 XHR finished loading: GET "http://openhab.aronica-sys/rest/ui/components/ui:widget".
VM6:1 XHR finished loading: GET "http://openhab.aronica-sys/rest/ui/components/ui:page".
VM6:1 XHR finished loading: GET "http://openhab.aronica-sys/rest/items?metadata=semantics,listWidget,widgetOrder".
VM6:1 XHR finished loading: POST "http://openhab.aronica-sys/rest/events/states/2e0eee99-770f-498b-bd9f-736777096c30".
VM6:1 XHR finished loading: POST "http://openhab.aronica-sys/rest/events/states/2e0eee99-770f-498b-bd9f-736777096c30".
aronica-sys/openhab gets:
VM6:1 GET http://aronica-sys/rest/ui/tiles 404 (Not Found)
VM6:1 GET http://aronica-sys/rest/ 404 (Not Found)
VM6:1 XHR failed loading: GET "http://aronica-sys/rest/ui/tiles".
aronica-sys/:1 Uncaught (in promise) Not Found
aronica-sys/:1 Uncaught (in promise) Not Found
VM6:1 XHR failed loading: GET "http://aronica-sys/rest/".
I do not know how to interpret the above information nor how to proceed.
You will need something like:
server {
listen 8080;
server_name app.example.com;
location / {
proxy_pass http://localhost:9090;
}
}
server {
listen 8080;
server_name example.com;
location /app/ {
proxy_pass http://localhost:9090/;
}
}
Please be careful with the slashes used in location and in proxy pass, they are quite important! For an explanation on the slashes, you can check: https://stackoverflow.com/a/51225241/83037
Edit: with the above configuration your actual sever process will receive the request without any modification to the host part. If you use in a browser http://app.example.com/file.html the server will receive a request for http://app.example.com/file.html (same host app.example.com). If you use in a browser http://example.com/app/file.html the server will receive a request for http://example.com/file.html (same host example.com, different path).
Generally, a server could "care" about the hostname, and/or could care "care" about the path, in the example above if it does not "care" about hostname will "interpret" the request as "give me /file.html", but if he "cares" about hostname, it will be configured to work only for a set of hostnames - server might answer or example.com but not for app.example.com.
Based on your addition, your server is configured to answer only to one specific hostname (he "cares" about hostname). In that case you can make nginx "rewrite" the incoming request such that your server "sees" only one hostname. Like if you use in a browser http://example.com/app/file.html the server will receive a request for http://app.example.com/file.html (notice example.com changed to app.example.com).
The configuration for that is:
server {
listen 8080;
server_name app.example.com;
location / {
proxy_pass http://localhost:9090;
proxy_set_header Host app.example.com;
}
}
server {
listen 8080;
server_name example.com;
location /app/ {
proxy_pass http://localhost:9090/;
proxy_set_header Host app.example.com;
}
}
WARNING! The server can still show you links to the domain it is configured to. In your case, the server might show (or build with javascript) a link to "http://openhab.aronica-sys/my_page.html". If that is an issue for you, I would suggest to open another question - this question is about the virtual directory.

Nginx + Rails + sendfile : file not found

Been having a problem setting up sendfile for nginx+rails lately. We have one kind of file download that's already handled by nginx, and we wanted to add a second rule to deal with another kind of files at another location, but we have no success so far.
Ruby controller :
def download_file
send_file("/srv/www/myapp/shared/tmp/directory/file.zip")
end
Environment configuration file:
Rails.application.configure do
# ..
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# ..
end
Nginx configuration :
upstream myapp {
server 127.0.0.1:9292;
}
server {
listen 80;
server_name myapp.tld;
client_max_body_size 10M;
root /srv/www/myapp/current/public;
# This first block works perfectly
location /__working_file {
internal;
alias /var/lib/myapp;
}
# This second block does not work at all
location /__new_files {
internal;
alias /srv/www/myapp/shared/tmp/directory;
}
location / {
root /srv/www/myapp/current/public;
try_files $uri #app;
}
location #app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
# This first rule works perfectly
proxy_set_header X-Accel-Mapping /var/lib/myapp/=/__working_file/;
# This second rule doesn't
proxy_set_header X-Accel-Mapping /srv/www/myapp/shared/tmp/directory/=/__new_files/;
proxy_pass_header Server;
proxy_read_timeout 300;
proxy_pass http://myapp;
}
}
Result
When accessing the controller action, the send_file command is triggered, then we get a "File not found" in the browser, nothing gets downloaded, and the rails log shows this:
Sent file /srv/www/myapp/shared/tmp/directory/file.zip (0.4ms)
Completed 200 OK in 169ms (ActiveRecord: 37.5ms)
Started GET "/srv/www/myapp/shared/tmp/directory/file.zip" for 109.190.197.126 at 2018-11-20 11:34:44 +0100
ActionController::RoutingError (No route matches [GET] "/srv/www/myapp/shared/tmp/directory/file.zip"):
The file does exist and is readable but nginx can't seem to access it. Any idea?
The problem comes from the way the two X-Accel-Mapping are set. Rack is indeed able to deal with several mappings since the merge of this PR #1187.
However, as of today, this PR has been merged on master but not released yet (2.0.6 is currently the latest release).
The only thing is, the correct way of setting several mappings is by using one single proxy_set_header rule, and separate each mapping with a comma, like this:
proxy_set_header X-Accel-Mapping, /var/lib/myapp/=/__working_file/,/srv/www/myapp/shared/tmp/directory/=/__new_files/
while routing it is not getting . you have to provide proper route to work.

Nginx does not cache cross domain requests (CORS)

I have rails application and nginx.
There are parts of the nginx config:
http {
...
proxy_cache_path /var/cache/nginx levels= keys_zone=cache:50m inactive=1d;
...
}
server {
...
location #rails {
proxy_pass http://rails_server;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_read_timeout 300m;
proxy_cache cache;
proxy_cache_valid 1h;
set $proxy_hide_header 'Set-Cookie';
proxy_hide_header $proxy_hide_header;
proxy_ignore_headers "Cache-Control" "Expires";
}
...
}
I have a promblem with caching cross domain requests.
Cache files are created when I open the url my_domain/data.js directly.
Cache files are created when I open the url my_domain/data.js from my_domain/index.html using ajax request.
Cache files are not created when I open the url my_domain/data.js from my_domain2/index.html using ajax request.
Content and http code are ok in all cases.
The problem was in rails (not in nginx).
Rails add "Set-Cookie" header for cross domain requests even if cookie is already set (I don't know why, maybe it's rails bug).
So my solution is:
proxy_ignore_headers "Set-Cookie";

rails fallback to assets pipeline

I'm trying to deploy a rails4 (ruby-2.0.0) app to my server. Almost all of my assets are precompiled, and served by nginx.
One js.erb, generates a dynamic html-list, by getting models from my database. This asset can't be precompiled, because it must remain dynamic.
I'm excluding this asset from asset.precompile, and turned on
config.assets.compile = true
to fall back to the asset pipeline, for this one asset.
In my local production env, everthing is working, but on my server (nginx, unicorn) the asset pipeline fall back won't work. I get a simple 404 Error
nginx error log:
2013/09/13 08:54:54 [error] 27442#0: *58 open() "/XXX/current/public/assets/rails_admin/rails_admin_switchable-051203ae1d7aca2c08092e5c92bcdf15.js" failed (2: No such file or directory), client: XXX, server: , request: "GET /assets/rails_admin/rails_admin_switchable-051203ae1d7aca2c08092e5c92bcdf15.js HTTP/1.1", host: "XXX", referrer: "http://XXX/admin"
unicorn and rails don't show any errors.
Any ideas, how I can solve this?
best,
Franz
It looks like your nginx server definition isn't properly integrated with your app server. It should be configured to pass a request that doesn't match a physical file on to the app server.
Here is a standard configuration for a rails app living in /app with nginx via a unicorn/UNIX-socket integration:
upstream app_server {
server unix:/tmp/nginx.socket fail_timeout=0;
}
server {
listen <%= ENV["PORT"] %>;
server_name _;
keepalive_timeout 5;
# path for static files
root /app/public;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app_server;
}
# Rails error pages
error_page 500 502 503 504 /500.html;
location = /500.html {
root /app/public;
}
}
If your asset pipeline compiles to /app/public/assets you should be good to go.

Nginx doesn't recognize my Rails 3 application

I have set up nginx + REE + passenger on my Linode VPS, which has been running great for past six month, both for Rails 2.3.x and Sinatra applications.
However this week I tried to add Rails 3 application to the stack, and I keep on getting 404 Not Found. Logs show that nginx doesn't recognize Rails application and is trying to serve it as static.
2010/11/29 23:44:44 [error] 12464#0: *29 "/var/app/modelky/public/index.html"
is not found (2: No such file or directory), client: 90.177.23.122, server:
reedink.com, request: "GET / HTTP/1.1", host: "reedink.com"
2010/11/29 23:44:44 [error] 12464#0: *30 open() "/var/app/modelky/public/favicon.ico"
failed (2: No such file or directory), client: 90.177.23.122,
server: reedink.com, request: "GET /favicon.ico HTTP/1.1", host: "reedink.com"
However, I'm using the same configuration as I use for all my other Rails 2.3.5 and Sinatra applications that works without any problems
server {
listen 80;
server_name www.reedink.com;
rewrite ^(.*) http://reedink.com$1 permanent;
}
server {
listen 80;
server_name reedink.com;
root /var/app/modelky/public;
passenger_enabled on;
}
From what I understand, Rails 3 should be rack compatible, so from the server's point of view, it's no different than any Sinatra application right?
I just built out a rail 3 box on linode this weekend. I started w/ this stackscript
http://www.linode.com/stackscripts/view/?StackScriptID=1288
and then went from there.
here's a copy of my server conf from the nginx.conf
server {
listen 80;
server_name localhost;
root /home/deploy/foo.bar.com/current/public;
passenger_enabled on;
}
i'd also try adding a static index.html file, get nginx working properly and then try and bootstrap the rails app.
Looks like your request is not hitting Rails. I would try to:
put a static index.html in /var/app/modelky/public to see if it shows up
check if the Rails app is in the given path and restart nginx
prestart Passenger on that server and see how it reacts
To prestart Passenger:
http {
server {
listen 80;
server_name www.reedink.com;
rewrite ^(.*) http://reedink.com$1 permanent;
}
server {
listen 80;
server_name reedink.com;
root /var/app/modelky/public;
passenger_enabled on;
}
passenger_pre_start http://reedink.com/;
}

Resources