Ignore Rails logging for requests based on IP - ruby-on-rails

I've got a rails app that is behind HAProxy and I'd like to ignore all of the Rails logging coming from the pings from the HAProxy servers. The servers are pinging ~1/sec and are really cluttering up the log file.

Haven't tested this, but it should work:
class Rails::Rack::Logger
def call_with_filter(env)
if env['REMOTE_ADDR'] == '10.0.0.1'
#app.call(env)
else
call_without_filter(env)
end
end
alias_method_chain :call, :filter
end
see railties-3.0.7/lib/rails/rack/logger.rb for the original.

The solution that I opted for was a little bit more systemic. I created a static textfile in the public directory and switched HAProxy to use this as its ping location. There is no logging and is less complex than a code solution.
I did try the example above and was able to get it working, but doing a monkey patch for this issue doesn't seem necessary, however if the requirements were a bit more complex (i.e. HAProxy had to hit the particular controller) then I'd opt for Roman's solution

The solution that I ended up going with was relatively low tech.
The goal of using HAProxy is not just to load balance, but to ensure that the nodes that are being directed traffic are actually up. This means that we wanted to have HAProxy not just hit the server to see if its up, but also test that Nginx and Passenger are up and functioning.
I put a static text file in the public assets of the rails project and have HAProxy hit the file. The file will be served up by the full stack and be a decent indicator that the services are up. As its a public asset, the hit does not appear in the log and the spamming is stopped.
Although this does not test much deeper into the Rails stack, the time to implement is lower than any coded solution, it doesn't add any additional complexity to the application and can be rolled into any future applications.

Related

Block an undesirable proxy from accessing a Rails 2.3.15 app on Heroku

I'm looking for a way to block a specific proxy, for example this one:
http://demosites.conversionsupport.com/reverseproxydemo?domainpath=http://stackoverflow.com
I don't want it accessing/displaying my rails 2.3.15 app on Heroku. I've played with the gems rack-rewrite and rack-block, but had no luck going that route because I need to block by domain name, not IP address (the thing is hosted on ghs.google.com, which I'd rather not block)
In a perfect world I could redirect to my canonical URL, but I'd also settle for a 503 or a 404.
(The reverse-proxy in question is used to show off the proxy owner's chat widget app, but on any website, instead of restricting use to sites owned by the proxy owner's potential clients. It also causes some nasty crawl bot errors to be logged in google's web master tools. That in and of itself isn't a big deal, but when coupled with that breaking-the-site-functionality thing, and the fact that my site has a Creative Commons license which requests the site not be reused for commercial purposes, it makes me want to put a stop to it.)
Rack::Attack!!! seems quite thorough. I has support for blacklisting, which sounds like what you need. It doesn't mention Rails 2.3 support, but you can configure it directly using your config.ru regardless.
The example given in the README, shows this
Rack::Attack.blacklist('block bad UA logins') do |req|
req.path == '/login' && req.post? && req.user_agent == 'BadUA'
end
It looks like the Rack request (req) object is passed to the block so you should be able to use any of the methods available on that object.
Since none of the gems we mentioned above can be used with rails 2.3.15 (which I've since updated to 2.3.18), and I don't have the time to do the arduous upgrade from rails 2 to rails 3, I ended up going with the solution below. (Note: this solution only applies to pages served from /app. It does not apply to pages served from /public. I'm still looking for a solution to protecting the pages served from /public.)
I dropped the bits of code below into /app/controllers/application_controller.rb
1.2.3.* is a placeholder for the block of IP addresses that I'm actually blocking. Replace 1.2.3 with the first three octets of the 0/24 range that you want to block, or replace 1.2.3.* with a single ip address to block a single IP. You'll also want to replace http://YourCanonicalDomain.tld/503.html with the address of your 503 page, or other page you want to send users to so they can view your page at the URL it was meant to be displayed at, instead of leaving them at the reverse proxy's URL:
before_filter: block_ip
then later in the file:
def block_ip
if request.remote_ip.match('1.2.3.*')
redirect_to "http://YourCanonicalDomain.tld/503.html"
return
end
end
My 503.html, which resides in /public, displays a note to the user that they're trying to view content in a way that is not allowed, and that they'll shortly be redirected to the homepage for the site. The 503.html contains this within the :
<meta http-equiv="REFRESH" content="15;url=http://YourCanonicalDomain.tld">
Replace http://YourCanonicalDomain.tld with the page you want to redirect users to. Raise or lower the number 15 to raise or lower the amount of time the page is displayed before the user is redirected.

How to block an ip address from linode?

I have rails application running in linode server .Some guy is continuously spamming (writing bullsh*t in my site).Can anybody tell how to block that person ip.Any other help would be appreciated.
I would suggest you don't only look into blocking that one person but rather into making sure this can't happen again.
Spams usually originate from bots that randomly try to fill in their marketing message into input fields on pages they encounter.
You block one, another will find your page and continue.
The only ways to prevent this kind of automated spam I know of are either using some sort of CAPTCHA or by securing your site through authentication.
There are some very nice captcha gems like reCaptcha or look around in the captcha category on Ruby Toolbox and you should be up and running soon.
If it's really a person that is annoying you with writing bad stuff to your site, while not ideal an IP block is easily set up through apache. Just put the following into your VirtualHost file inside the <Directory> node and then enable the mod_authz_host module through a2enmod authz_host
Deny from 192.168.205
You can do this in the web server config file, here is the example for Nginx:
http://www.cyberciti.biz/faq/linux-unix-nginx-access-control-howto/

What's a smart way to implement a Maintenance page in a Heroku app?

is there a clean, elegant way to implement a Maintenance page in a Heroku app? So that if something breaks you can very easily turn a switch and the maintenance page goes up for all requests? Preferably a way that doesn't require a push?
Ideas? Thanks
NOTE This answer addresses nginx or Rack setups, as it was written before edits to the original question made it clear that was looking for an answer specific to Heroku. The accepted answer is best for Heroku apps.
When you say "in your app" do you really mean in your app?
Because typically the solution is to drop a maintenance file in your web root. If the file is found, it is served with a 503 Service Not Available immediately. The request never even makes it to your app, which is presumably "down for maintenance".
In nginx, something like this:
location / {
if (-f $document_root/maintenance.html) {
return 503;
}
# continued server directives
}
error_page 503 #maintenance;
location #maintenance {
rewrite ^(.*)$ /maintenance.html break;
}
It wouldn't really require a push per se, but perhaps a simple rake task or something to add/remove that maintenance file from your app. You could probably also replace any given filename in the -f check, and simply touch an empty arbitrary maintenance.whatever file in your web root, which would then direct nginx to serve the mainenance.html.
If you don't want to (or can't) mess around with the server config, this very simple Rack middleware does essentially the same thing: https://github.com/ddollar/rack-maintenance
or use Heroku's own Maintenance mode exactly for this scenario - http://devcenter.heroku.com/articles/maintenance-mode
To add on Emanuel's answer:
Trackman helps with your maintenance pages from dev to prod.
You can
Scaffold them using your current site layout (~0 html editing)
Link your current assets within your static page
Look at your page layout within your dev environment
It will deploy everything to S3 when you push to Heroku and you don't even have to setup an account on S3.
You also have to run
rake trackman:setup
So Heroku points to your S3 pages while on maintenance mode.
http://www.trackman-addon.com
This would probably be easily accomplished by appending a before_filter at the beginning of the filter chain that checks for a maintenance mode condition and redirects to the maintenance page when appropriate.
The answeres above are all right for a basic scenario.
For the smart part of your question here is an addon that will get you there:
https://addons.heroku.com/trackman

Rails + SSL: Per controller or application-wide?

I could use some wisdom from any developers who have worked with Rails and SSL. I have a fairly simple app and I'm in the process of implementing payment processing. Obviously payment processing calls for SSL, so I'm setting that up now.
My intention when I started working on this today was to find the simplest / cleanest way to enforce SSL on specific controller actions - namely anything having to do with payment. I figured there was no reason to run the rest of my site on SSL.
I found the ssl_requirement gem which seems to take care of setting SSL per-controller-action without much difficulty, so that's good. I also found this question which seems to indicate that handling SSL with a gem is now out-of-style.
I also found several answers / comments etc. suggesting that a site should just use Rack middleware like Rack-SSL to force the entire site to SSL mode.
So now I'm kind of confused, and not sure what I should do. Could anyone with experience working with Rails 3 and SSL help me understand:
Whether I should force the whole site to SSL, or only per certain actions.
What gotchas to look out for using SSL in Rails (I've never done it before).
If per-controller is the way to go, whether it makes sense to use the ssl-requirement gem or whether I should just use the new routing and link helper options...
I'd very much appreciate your insight, this has become a paralyzing decision for me. Thanks!
I've found myself "paralyzed" by this decision in the past, and here's what I think about each time.
First, keep in mind that some browsers will throw pop-up warnings if you keep switching out of and into SSL, or if you serve some content (the page) with SSL and other content (images, css) without. Obviously that's not a good experience for users.
The only possible downside to requiring SSL everywhere is performance. But unless you're expecting 1000+ users/day who will be doing lots of things that *don't * require SSL, this is negligible.
SSL is handled at the Apache/Nginx/whatever level. So if you decide to put your entire app behind SSL, it makes most sense to deal with it at the Webserver level (redirect http:/yoursite.com to https://yoursite.com.
And if, for performance reasons, you decide not to put everything behind SSL, then it still could make sense to handle SSL redirects at the Webserver level. Allowing your user through your Webserver, then sending him through half Rails stack, just to boot him back out to start over again is very wasteful.
Of course there's something to be said for simplicity and domains of knowledge, which would suggest handling redirects in your Rails app or middleware, since it "knows" what's safe and unsafe.
But those are things you'll have to weigh yourself. It depends on whether raw performance or simplicity of development/maintenance is more important.
I usually end up with a virtual host for http://mysite.com which redirects everything (or sometimes only certain uris) to https://mysite.com/$1. Hope that's helpful.

Is it possible to use modify nginx config file and use X-Accel-Redirect on Heroku?

Reading this article on nginx website, I'm interested in using X-Accel-Redirect header in the way that Apache or Lighttpd users might use the X-Sendfile header to help with the serving of large files.
Most tutorials I've found require you to modify the nginx config file.
Can I modify the nginx config file on Heroku and if so, how?
Secondly,
I found this X-Accel-Redirect plugin on github which looks like it removes the need to manually alter the nginx config file - it seems to let you add the redirect location in your controller code - does anyone know if this works on heroku? I can't test it out until tonight.
NB - I have emailed both Heroku support and goncalossilva to ask them the same questions but I have no idea when they will get back to me. I will post back with whatever it is they tell me though.
Although Heroku seem to be using Nginx for their reverse-proxy component, the thing about a platform-as-a-service stack like this is that no individual tenant has to (nor even gets to) configure or tune distinct elements of the stack for any given application.
Requests in and out could be routed through any number of different elements to and from your Rails app so it's their platform infrastructure (and not any particular tenant) that manages all of the internal configuration and behavior. You give up the fine-grained control for the other conveniences offered by a PaaS such as this.
If you really need what you've described then I'd suggest you might need to look elsewhere for Rails app hosting. I'd be surprised if their answer would be anything else but no.

Resources