Capistrano and XSendFile configuration - ruby-on-rails

I am trying to configure Rails production server with Apache 2.2, Passenger 4.0.59 and XSendFile 0.12. Application is deployed via Capistrano.
Deployed application produces (maybe large) PDF to #{Rails.root}/tmp and serves this file using send_file.
The problem is that Capistrano uses symlinks to point to currently deployed version of application. XSendFile on the other hand dereferences symlinks and refuses to serve a file if its real location is outside document root even if it is allowed by XSendFilePath. Apache's error.log states:
(20023)The given path was above the root path: xsendfile: unable to find file: /resolved/path/to/file.pdf
Everything works well when I set PassengerAppRoot and XSendFilePath to the real location of current version of application, without symlinks on the path. But it's OK until next deploy, which requires apache reconfiguration. Not very useful.
How should I configure Capistrano deploy and XSendFile parameters to make it work together?
I tried solutions with ln -nFs described in Capistrano & X-Sendfile and in mod_xsendfile with symbolic links but none works.

I finally managed to make it work. A few tips for the ones who will have problems with XSendFile
I set XSendFilePath to user's $HOME, there are no symlinks on the path to $HOME, so it works. I can accept this from functional and security point of view, but it is obviously a workaround.
Be aware that XSendFilePath is sensitive to paths containing multiple slashes /like//this. I am using apache macros and while concatenatingXSendFilePath parameter from a few macro parameters I put some obsolete slashes. This caused XSendFile to refuse to send files.
Good luck!

Related

How to Tell Engine Yard to Not Delete a File in the .gitignore

To give you some context, I'm trying to use Figaro to safely add in environment variables without having to worry about security risks. The problem is is that I can't seem to get Engine Yard to play nice with production.
I went and did a touch application.yml and then vim application.yml, i, and then command+v to insert that api keys and what not. I know the ENV['VARIABLES'] work because of development and all my rspec and cucumber tests (which utilize the APIs), passed.
When I've got everything ready, I add within the .gitignore:
# Ignore application configuration
/config/application.yml
Afterwards, I deploy the site. I open it up and data isn't going to the APIs anymore. OK...
cd into config and discover application.yml isn't there anymore. Paste it back in... Redeploy the site since now it understands it has to ignore that file and I'm not seeing changes on production. Check back... and its gone again!
Stumped on what's going on.
Simply putting a file into your deployed application's filesystem will not work because you get a clean environment each time you deploy. EngineYard cannot know that you want that particular file copied to that particular location without a little bit of extra work.
Their official recommendation is to put your YAML configuration files in /data/<app>/shared/config and symlink them to /data/<app>/current/config each time you deploy using deploy hooks.

Rails application issue after deployment - 404 error

I'm new to RoR.
I was able to install Rails and host it in Webrick (Sample App with "Welcome" controller) in my windows.
Now i have a Unix Weblogic Server along with a dedicated domian.
After exporting the .WAR file using Warbler, i accessed the Oracle Admin Console from where i deployed the .WAR file in the dedicated domain. I did all this for the Sample app with only the Welcome controller in it.
But even after deploying the WAR file, on accessing the Domain along with the Port Number (:9002) i ended up with 404 file not found error On looking at the server logs,there wasn't any records relating to any error. The Application must have been deployed properly. I assume that i must have missed out on some basic configurations in the routes.rb or similar files before deploying. Can anyone Guess what are all the possibilities and if possible can anyone help me by pointing to any tuts that cover the Steps to be carried out for configuration before deployment. do i need to install both JRuby and Rails inside the server before depolyment?
I can't really guess with Eror 404 only.
You can try mapping your rails app rack config to a different base_uri.
All you need to do is wrap the existing 'run' command in a map block
try doing this in your rails 'config.ru' file:
map '/mydepartment' do
run Myapp::Application
end
Now when you 'rails server' the app should be at localhost:3000/mydepartment .
Not sure if this will give you the desired outcome, but worth a try.
One more thing you also add this to your config/environments/production.rb and config/environments/development.rb (if on production mode):
config.action_controller.asset_path = proc { |path| "/abc#{path}" }
otherwise when you call your helpers such as stylesheet_link_tag in your views, they will generate links without the "/abc".
Also, find some guides you may refer for good support.
JRubyOnRailsOnBEAWeblogic.
Use JRuby with JMX for Oracle WebLogic Server 11g
Let me know if it is not resolved.

Rails 3.1 application deployment tutorial

I'm looking for a good deployment tutorial for a Rails 3.1.1 application on a server. And by good I actually mean complete. The reason I'm posting this question is that although there are tons of tutorials out there on the web (google, blogs, books, other stackoverflow questions etc...) all of them seem to focus either on a problem with the deployment process or make some assumptions about the deployment environment that do not match with what I need.
I realize that deploying a Rails app on a server requieres a variety of different programs and tools that need to be configured and somehow I always get stuck on apparently "little" things that make me very frustrated.
So, let's begin from the start. What I have now is a server that I can access through SSH and a domain name, let's call it www.example.com. The server runs a fresh Ubuntu 10.04 x64 and has just a user installed, namely root (through root I access the server with SSH).
Note! There is no Apache, Ruby, PHP, MySQL, cPanel or any other panel installed, just the bare minimum that comes with a fresh installation.
Also the web server will host a single application and the database will run on the same machine.
From my knowledge the process of deploying a Rails application follows the following scenarios:
Installing Ruby
I already did this by using RVM using the Multi-User install process (simply because I have just the root user and it does it automatically). This seems to work fine aftewards but I do have some questions:
Would it make more sense to install Ruby directly and not through RVM (I'm thinking maybe in terms of efficiency - also RVM does a little bit of magic behind the scences modifying some bash_profile files in ways that I don't understand and this somehow seems invasive...)?
Would it make more sense to install as a separate user through RVM (can there any safety problems arise)?
Necessary gems
Now that Ruby is installed what would be the best initial set of gems to install along side it?
I installed just bundler, so that once I upload my application on the server I can run a bundle install command which will install in turn the required app gems.
Question - Should I install the rails gem before hand? Are there any other gems that need to be installed?
Web server
This is where it gets tricky for me. I'm trying to use apache and mod-passenger for deployment (they seem to be the most popular). So I installed the apache web server and the passenger gem and all the related dependencies (libraries mentioned by passenger).
Now, the problems arise. First thing is user related. How does Apache run? I mean under each user? If I installed it and (re)started it using the root user, will it permanently run under the root user? Is this a bad thing? If yes, should I create another user? If yes, how? In what groups should I put the new user in, what rights should he have (namely what folders should he have access to). How to start the apache in this case (under root, under that user, add a line somewhere in the configuration file, etc.)
Website configuration
Where to put the website configuration stuff? Is it OK to put it into apache.conf, or should I create a new file in sites-available? Or should I simply reuse the default file that is already present there? If a new user has been created at the previous step, what rights should he have in relation to the config files?
Also... where to eventually put the rails application? In what folder would it be best? Somewhere under home? Maybe under /var/www? I want to know how would this affect the rights of the apache process serving the app? (Generally I have problems while serving an app, it complains that it doesn't have rights on a specific folder. Also, using the new asset pipelines - which I don't fully understand - asset files are being created and they seem not to inherit the parent folder rights...)
Database
As database I'm using MySQL and installing it is pretty straightforward. The question that I have here is again user related. Should I use a special user for the database? How does MySQL actually manage users (are they internal, or are they the Linux users or ...?). Should the database user be the same as the "web user" from above? Or should it be a different one?
Assets
Here I get really lost. I really have troubles making the assets pipeline works. I've checked the railscasts episode and also the rails website tutorial and I do seem to theoretically understand the thing, yet I have problems in practice.
So the questions here would be - what commands should I run to precompile the assets? (Trying to run rake assets:precompile). Is it ok? What should I change in the production.rb file? How do the assets generated work in relation with the webuser or database users created above? I am personally getting a problem in this step namely the log files say that some css files are not accessible (for example I have jqplot library installed under the vendor/assets folder and its files cannot be accessed - should I add a manifest file here somehow?).
It would be really great if someone could point me towards a nice article, or resource that explains all this stuff. The main area which I'm having problems in is how does Apache, Passenger, Ruby, Rails and MySQL interact with a Linux user. How to properly set up the permissions for the Rails app folder? How does the assets pipeline affect this user permission stuff?
Thank you
Here's my way of deploying Rails:
Installing Ruby
I would not use RVM because it's very tricky to get it running properly in combination with stuff like cron jobs. Doable (with wrappers for example), but a bit of a hassle. If you don't need other Ruby versions on that machine, just install it from source yourself.
Gems
Just let Bundler work its magic. Remember to install with the flags --without test development --deployment. I wouldn't do that up front though. Just make sure you have bundler.
Web server
Using Passenger (with either Apache or Nginx) is a fine and easy choice. When you install Apache from apt, it will run in a special user.
Apache is configured correctly automatically on Ubuntu. It will start on reboot.
Website configuration
All configuration be in /etc/apache2. Place your virtual host configuration in /etc/apache2/sites-available and use a2ensite to enable it.
Put your app in /var/www, since that is the default location in Ubuntu. I usually make a deploy user.
Make sure that user can access your application by assigning your app to the www-data group.
Database
MySQL has its own user system. Log in as root user and create a new user with SQL: GRANT ALL ON 'application_production'.* TO 'deploy' IDENTIFIED BY 'some password';
Assets
Assets should be generated as the user owning the application. You should add any css and javascript files to production.rb. For example:
config.assets.precompile += %w(backend.css)
Conclusion
It helps to use a deploy tool like Capistrano. When you run capify, uncomment the appropriate line in the Capfile to get assets compilation. Here's mine:
ENV['RAILS_ENV'] = 'production'
load 'deploy' if respond_to?(:namespace) # cap2 differentiator
load 'deploy/assets'
load 'config/deploy'
require 'capistrano/ext/multistage'
require "bundler/capistrano"
require 'capistrano_colors'
This is just how I normally install my rails apps. I hope this will get you going. Recently I've written a gem for integrating Chef-solo with Capistrano, called capistrano-chef-solo. It's very alpha and might be a bit too complicated if you're just starting with deployment, but it might help you.

Is it a bad idea to put apache conf files in my rails app's config directory?

I have a dedicated CentOS server. I manage all my users, apps, and virtual hosts manually. I'm using Apache 2.2.3 and Passenger 3.0.7 to serve my apps. I have a typical httpd.conf file in /etc/httpd/conf/ that includes all *.conf files in my /etc/httpd/conf/vhosts/ directory. Normally for each app I create a new sample-domain.com.conf file in the vhosts directory.
However, I have a particular app that needs frequent apache configuration changes, and I'd like it to be more a part of my app and its version control. So I've moved my apache configuration file into the apps config directory. I added a script to my Capistrano deploy.rb that sets the permissions on the apache conf file in the app to 755. I added an include line in my vhosts that includes the symlinked current version of the apache conf file from the app.
Which brings me to my simple question: is this safe or a bad idea?
For frequent config changes in Apache, consider using a .htaccess file instead. Changing .conf files requires bouncing/hupping the server, and if a .conf file has an error, that'll kill the whole server and take down all sites. A .htaccess error will take down just the one site/directory where the file is.

jRuby deployment into a subfolder in Tomcat

While developing a jRuby application using webbrick as the webserver, all my code is written with http://localhost:3000 as the root.
When deploying to Tomcat, I create a WAR file and it creates a subfolder under the webapps/ folder: localhost:8080/project_name/
This causes a load of problems with my code. Is there anything I can do in my ruby routes.rb file to deal with this?
Should I resort to using some sort of virtual host in Tomcat?
Although this question is quite old, we ran into a similar problem with a current project of ours. The project is done with JRuby on Rails, using Tomcat 6.x (7.0.26 in development for testing purposes), needing multiple deployments of the same application on the same servlet container, having individual server names. It took me quite some time to find a good enough solution and I like to share it with you.
Continue reading, if root context is no option for you (as cosmikduster described it above). If it is, use it.
TL;DR
Use virtual hosts for each app provided by Tomcat to give yourself root context for individual apps deployed on the Tomcat servlet container. The explanation provided below is based on this and is just an illustrative example with a step by step solution attached.
The problem
The problem arises when deploying a *.war file to Tomcat, as per default, the deployed app, let's call it awesome_app_uno for now, will live under http://localhost:8080/awesome_app_uno. This is all fine and dandy but can cause problems with the internal path generation of rails, which by default will now use /awesome_app_uno for every path generated.
Explanation & initial setup
Now, JRuby Rack, which is the rack implementation for JRuby is kind enough to include a feature that automatically sets the relative_url_root for you, I quote from the README:
The Rails controller setting ActionController::Base.relative_url_root is set for you automatically according to the context root where your webapp is deployed.
Normally, I would cheer - but in the real world, we'd probably do not want something like this, as we'll have something like a proxy to get ourselves some nice domainname, e.g.
http://awesomeappuno.com/
And now we're screwed. If we take a naive solution for this, we'd probably end up using an Apache (or an nginx, whatever you like) to function as a proxy. We'll want something like
http://awesomeappuno.com/ -> http://localhost:8080/awesome_app_uno
Just for the fun of it, lets look at the configuration for an apache config file:
<VirtualHost *:80>
ServerName awesomeappuno.com
ErrorLog /var/log/apache2/awesomeappuno_error.log
LogLevel warn
CustomLog /var/log/apache2/awesomeappuno_access.log combined
<Proxy *>
Order allow,deny
Allow from all
</Proxy>
ProxyPreserveHost On
ProxyRequests off
ProxyPass / http://localhost:8080/awesome_app_uno
ProxyPassReverse / http://localhost:8080/awesome_app_uno
</VirtualHost>
Kindly stolen from here.
The madness
With that being your configuration, you can now visit http://awesomeappuno.com.
This is where you'll notice, that despite now having a clean root without prefixes, Rails will still generate paths with the /aweseome_app_uno prefix, i.e.
http://awesomeappuno.com/awesome_app_uno/the/path/you/wanted
This is generally undesirable. While some of you could propably live with this, I couldn't. Moreover, there's awesome_app_dos coming up on the horizon which needs to be deployed on the same Tomcat instance, needing it's own domain name http://awesomeappdos.com, along with the two ugly cousins awesome_staging and awesome_integration behind it. The gist is, if you're forced to use the same Tomcat container for all these apps, giving on app root context is not really an option.
You can try some solutions like writing custom initializers, resetting the ENV hash, which gets initially filled by the jruby-rack (see comments and answers above). You might find yourself rewriting the paths manually or using absolute urls. Or you create hacks for a single environment. Or you could try to use rewrites. Or mod_subsitute. You could even try using multiple tomcat instances running everything under root context.
Don't do that.
Please.
Virtual Hosts to the rescue
While reading up on the issue (and trying everything described in the last paragraph), I stumpled on an entry in the ruby forum.
You can create virtual hosts with Tomcat, providing a root context for each app. To get more in depth knowledge, you can start here or here. In short, suppose your Tomcat (7.x) is located under /usr/local/tomcat, this would be the quick and dirty version:
Create a virtual host
The host will have it's appBase within the tomcat installation for this. If this isn't your stale, change it.
(cd /usr/local/tomcat/libexec)
I am using an installation via homebrew here, I am on a mac under OSX 10.7.4 - however with slight alterations this should work on a standard Debian as well.
Open up conf/server.xml and within the engine tag create another host:
<Host name="awesome_app_uno" alias="awesomeappuno" appBase="awesome_app/uno" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">
<Context path="" docBase="ROOT"></Context>
</Host>
After that, create a file called conf/Catalina/awesome_app_uno/ROOT.xml. These are the contents:
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="${catalina.base}/awesome_app/uno/ROOT.war">
</Context>
Afterwards, place the awesomeappuno.war as /usr/local/tomcat/libexec/awesome_app/uno/ROOT.war and restart Tomcat. You can check the virtual host via http://localhost:8080/host-manager/html.
You should be able to visit http://awesome_app_uno:8080 and find your app there. Paths should now be correct, however, port 8080 isn't that user friendly. With slight changes to the previously shown apache config, we can also get a nice name for this:
<VirtualHost *:80>
ServerName awesomeappuno.com
ErrorLog /var/log/apache2/awesomeappuno_error.log
LogLevel warn
CustomLog /var/log/apache2/awesomeappuno_access.log combined
<Proxy *>
Order allow,deny
Allow from all
</Proxy>
ProxyPreserveHost On
ProxyRequests off
ProxyPass / http://awesome_app_uno:8080/
ProxyPassReverse / http://awesome_app_uno:8080/
</VirtualHost>
Reload your apache and you should now have no further problems with pathing, routing, because everything now happens under the root context of the tomcat virtual host.
Rinse and repeat for additional apps on the same tomcat instance.
The end
Hope i could help you with this.
lg,
flo
There is code in JRuby-Rack to deal with this. Depending on the version of Tomcat and/or Rails, it may not be detecting the extra context path correctly.
The environment variable that is supposed to take effect is called ENV['RAILS_RELATIVE_URL_ROOT']. You might print out the value of that expression during boot time and see whether it's getting set when you run in Tomcat.
The code in question is here:
https://github.com/nicksieger/jruby-rack/blob/master/src/main/ruby/jruby/rack/rails.rb#L32-38
The versions of Tomcat, Rails and JRuby-Rack you're using would help diagnose the problem further.
Your app should almost never care about the host/domain/port it will run under. To deploy at the relative path /, instead of /myapp, simply rename the WAR to ROOT.war instead of myapp.war when you copy it to the tomcat/webapps folder.

Resources