Assets precompiled but not showing with puma & nginx (Rails 4) - ruby-on-rails

In my local machine when I do:
RAILS_ENV=production bundle exec rake assets:precompile
RAILS_ENV=production bundle exec puma -e production
Everything works fine. However I have the exact same app in a docker container for production that runs with nginx. I can see the application.css & application.js files in the assets folder with the chrome dev tools and they're not empty. But I have a page with no css/js, it should have something to do with nginx but I'm really confused.
/var/etc/nginx/nginx.conf:
user app sudo;
http{
upstream app {
server unix:/home/app/puma.sock fail_timeout=0;
}
server {
listen 80 default;
root /home/app/app/public;
try_files $uri/index.html $uri #app;
location #app {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://app;
}
}
}
events {worker_connections 1024;}
config/environments/production.rb:
Rails.application.configure do
...
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
config.serve_static_files = true
config.assets.js_compressor = :uglifier
config.assets.compile = false
config.assets.digest = true
...
end
Please do not hesitate to suggest anything. :)
update:
I've just realised that I have these 2 errors in my console:
new:11 Resource interpreted as Stylesheet but transferred with MIME type text/plain: "http://localhost/assets/application-5574b338d88d13681ef38b9b0800bc47.css".
new:12 Resource interpreted as Script but transferred with MIME type text/plain: "http://localhost/assets/application-ea59e17aff7f15a316e3e03d49f3daf4.js".

If you want nginx to serve your static assets, you'll need to set config.serve_static_files = false so Rails doesn't try to do it for you.

Related

Rails app SSL is not being applied to the whole platform.

I am running my rails app on nginx server. I am trying make the platform HTTPS secure. I purchased SSL certificate and configured it on the EC2 instance and configured the nginx.conf file accordingly too. After everything was done I entered domain.com on browser. For first time it redirected to https. But that's about it. Only home page was HTTPS the rest of the application as I went on exploring was still on HTTP
I am attaching my nginx.conf file and config/environment/production.rb files :
nginx.conf
upstream puma {
server unix:///home/deploy/apps/appname/shared/tmp/sockets/appname-puma.sock;
}
server {
#listen 80 default_server deferred;
listen 80;
listen 443 default ssl;
server_name domain.com;
ssl_certificate /etc/nginx/ssl/5532202b90020bc.crt;
ssl_certificate_key /etc/nginx/ssl/domain.key;
root /home/deploy/apps/vendaxoprod/current/public;
access_log /home/deploy/apps/appname/current/log/nginx.access.log;
error_log /home/deploy/apps/appname/current/log/nginx.error.log info;
#location ^~ /assets/ {
#gzip_static on;
#expires max;
#add_header Cache-Control public;
#}
location ^~ /(assets|fonts|swfs|images)/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #puma;
location #puma {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://puma;
}
}
config/environment/production.rb
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
Rails.application.config.assets.precompile += %w( *.js ^[^_]*.css *.css.erb )
config.cache_classes = true
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = true
config.action_controller.perform_caching = true
config.action_mailer.raise_delivery_errors = true
# Enable Rack::Cache to put a simple HTTP cache in front of your application
# Add `rack-cache` to your Gemfile before enabling this.
# For large-scale production use, consider using a caching reverse proxy like
# NGINX, varnish or squid.
# config.action_dispatch.rack_cache = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
#config.serve_static_assets = ENV['RAILS_SERVE_STATIC_FILES'].present?
config.serve_static_assets = false
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
# config.assets.css_compressor = :sass
# Do not fallback to assets pipeline if a precompiled asset is missed.
config.assets.compile = true
#config.assets.precompile = ['*.js', '*.css', '*.css.erb']
# Asset digests allow you to set far-future HTTP expiration dates on all assets,
# yet still be able to expire them through the digest params.
config.assets.digest = true
# `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = false
# Use the lowest log level to ensure availability of diagnostic information
# when problems arise.
config.log_level = :debug
config.action_mailer.default_url_options = { host: ENV["SMTP_HOST"] }
config.action_mailer.asset_host = ENV["SMTP_HOST"]
# config.action_mailer.delivery_method = :letter_opener
config.action_mailer.raise_delivery_errors = false
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
#Enter the smtp provider here ex: smtp.mandrillapp.com
address: ENV["SMTP_ADDRESS"],
port: ENV['SMTP_PORT'].to_i,
#Enter the smtp domain here ex: vendaxo.com
domain: ENV["SMTP_DOMAIN"],
#Enter the user name for smtp provider here
user_name: ENV["SMTP_USERNAME"],
#Enter the password for smtp provider here
password: ENV["SMTP_PASSWORD"],
authentication: 'plain',
enable_starttls_auto: true
}
# Prepend all log lines with the following tags.
# config.log_tags = [ :subdomain, :uuid ]
# Use a different logger for distributed setups.
# config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new)
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.action_controller.asset_host = 'http://assets.example.com'
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true
# Send deprecation notices to registered listeners.
config.active_support.deprecation = :notify
# Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
end
You should add separate server blocks for handle redirection to https.Like this:
server {
listen 80;
listen [::]:80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 default ssl;
server_name example.com;
ssl_certificate <certificate_path>;
ssl_certificate_key <certificate_key>;
}
It should work.
You should change your virtual file in Nginx as follows,
Add a separate section for requests that come in port 80 and redirect all such requests to port 443 (or HTTPS)
server {
listen 80;
server_name my.domain.com;
return 301 https://$server_name$request_uri;
}
Then, in your current configuration remove listen 80
server {
listen 443 ssl;
server_name my.domain.com;
# add Strict-Transport-Security to prevent man in the middle attacks
add_header Strict-Transport-Security "max-age=31536000";
}
Hope this works.

Rails 4 generates an empty manifest.json file when I run RAILS_ENV=production rake assets:precompile

On my staging server, I am having some troubles.
When I run
RAILS_ENV=production rake assets:precompile
Then
ls public/assets/
manifest-e694d7a3911e13a1b7c31ee3a73ccc9d.json>
Then
$ cat public/assets/manifest-e694d7a3911e13a1b7c31ee3a73ccc9d.json
{}
However, if I just run rake assets:precompile (without the RAILS_ENV=production flag), then I get a bunch of CSS and JS, as well as my images, put into the public/assets folder. Unfortunately, however, there are two problems:
1) The fingerprint (the md5 hash ) on the .js and .css files doesn't match what javascript_include_tag and stylesheet_link_tag automatically spit out
2) Inside the generated CSS file, I see references to my static asset, but they don't include the md5 hash fingerprint, even though I explicitly ask for it; e.g.
background-image: url(image-path('home/logo.png'));
It just generates
background-image: url("/assets/home/logo.png");
Even though the file that gets generated is,
logo-a412c0ad6a034e4da4324436fff2f871.png
The relevant (I think) bits of the appropriate files:
Here is my application.rb
config.assets.enabled = true
Here is my development.rb
config.assets.compress = false
config.assets.debug = true
Here is my production.rb
config.serve_static_assets = true
config.assets.compress = true
config.assets.js_compressor = :uglifier
config.assets.compile = true
config.assets.digest = true
config.assets.precompile = true
Here is my nginx conf
server {
listen 80;
server_name staging.mysite.com;
root /var/www/myuser/current/public;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location / {
proxy_pass http://appname; # match the name of upstream directive which is defined above
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ ^/(assets)/ {
root /var/www/myuser/current/public;
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;
}
}
Thank you for your help. I have been banging my head here for a while now. Please let me know if I should share more information.

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.

Unicorn Rails stack + Vagrant not serving some assets

I'm using a Rails Stack with nginx + unicorn + rails meant for a production server, but I'm staging it under Vagrant for testing purposes. While doing this, I encountered a strange behavior of the rails application, where very often one or other asset wasn't being served, i.e. application.css isn't being served and therefore the whole page is displayed without any styles applied to it.
I've googled the problem and found that Vagrant's FS driver isn't completely implemented and that would bring some problems while using Apache (haven't found any mentions to nginx). The solution to this problem was to disable sendfile by adding sendfile off; to the configuration file. And... it didn't work.
Further, I went through the logs (Rails, unicorn and nginx) and found that when the file isn't served, there isn't any mention to it in any of the logs. This brought me to the question that the problem can be in the mechanism used by Vagrant to share the rails app folder through the VM. As mentioned in vagrant's website, Vagrant uses Virtual Box's Shared Folders, which is quite slow comparing to other alternatives (as shown here), and the workaround is to set up NFS Shared Folders. So, I decided to give NFS a try and the result was... the same. Unfortunately, some assets are kept from being served.
Does anyone have any ideas on this? I've searched for quite a while but haven't found any pointers additional to those I described here.
I'm using:
Mac OS X 10.6.8 + rbenv (to develop)
Vagrant + nginx + rbenv + unicorn + bundler (to stage)
unicorn.rb
rails_env = ENV['RAILS_ENV'] || 'production'
app_directory = File.expand_path(File.join(File.dirname(__FILE__), ".."))
worker_processes 4
working_directory app_directory
listen "/tmp/appname.sock", :backlog => 64
#listen "#{app_directory}/tmp/sockets/appname.sock", :backlog => 64
timeout 30
pid "#{app_directory}/tmp/pids/unicorn.pid"
stderr_path "#{app_directory}/log/unicorn.stderr.log"
stdout_path "#{app_directory}/log/unicorn.stdout.log"
preload_app true
GC.respond_to?(:copy_on_write_friendly=) and
GC.copy_on_write_friendly = true
before_fork do |server, worker|
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
end
after_fork do |server, worker|
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
/etc/nginx/sites-enabled/appname
upstream unicorn_server {
server unix:/tmp/appname.sock fail_timeout=0;
}
server {
listen 80;
client_max_body_size 4G;
server_name _;
keepalive_timeout 5;
# Location of our static files
root /home/appname/www/current/public;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
if (!-f $request_filename) {
proxy_pass http://unicorn_server;
break;
}
}
error_page 500 502 503 504 /500.html;
location = /500.html {
root /home/hemauto/www/current/public;
}
}

Rails, favicon.ico not found

This is soo odd, I've been receiving:
ActionController::RoutingError (No route matches "/favicon.ico")
but I have the favicon.ico in my public directory... any ideas how to solve this? Nginx doesn't throw an error at all.
Run
rake assets:precompile
then set
config.serve_static_assets = true
in config\environments\production.rb file.
Then restart your server.
But I think rake assets:precompile is not required.
It seems that nginx doesn't handle your static assets (since this request for static file goes to the ActionController). Check public root in nginx config file nginx.conf.
Here is an example with Capistrano deployments:
server {
listen 80;
root /var/www/my_project/current/public;
}
And do you use a favicon_link_tag helper in your head :) ?
If you want to keep config.serve_static_assets = false, which is recommended if you have nginx or apache, you can tell nginx to statically serve the files directly. This is especially important for performance reasons, as you don't want rails serving these assets.
Below is a sample which also correctly has nginx statically serve the assets directory:
server {
listen 80;
root /var/www/my_project/current/public;
location / {
proxy_pass http://mysite;
proxy_redirect off;
proxy_set_header X_FORWARDED_PROTO https;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
# static resource routing - both assets folder and favicon.ico
location ~* ^/assets/|favicon.ico {
# Per RFC2616 - 1 year maximum expiry
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
expires 1y;
add_header Cache-Control public;
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
add_header Last-Modified "";
add_header ETag "";
break;
}
}
Make sure that the favicon.ico file isn't empty (byte size > 0). For some reason I had an empty favicon.ico file which was triggering the same error, even though the file did exist.
delete slash sign before favicon.ico and try to use something like:
<link rel="shortcut icon" type="image/png" href="favicon.ico" />
I was facing the same problem when I first clone code from git repository and run with RAILS_ENV=production. Since there was no assets directory in my git repository, I needed to run rake assets:precompile.
Also I was run with rails s, so config.serve_static_assets = true worked. Thanks #Jiemurat

Resources