jRuby deployment into a subfolder in Tomcat - ruby-on-rails

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.

Related

Does Puppet Dashboard work in Ruby Passenger 5?

Has anyone encountered problem of running Puppet Dashboard on Ruby Passenger 5? If yes does it really work with that Passenger version?
I've already setup and configured the necessary files required to run Puppet Dashboard via Passenger. Currently, the Apache test page is shown instead of the dashboard menu. This will not appear if Puppet-Dashboard is run in the lightweight Webrick server.
While scouring most of the installation samples and the manuals on how to install and configure it for Centos 6. I've seen most of them were based on Passenger 3 / 4. I am currently using 5.0.10 as it is used in conjunction with Puppet 3.8.1. One thing certain is that RailsAutoDetect is deprecated in version 5 and that has been commented out.
Below my puppet-dashboard.conf file (the load module has been moved to another file to avoid double-instantiation)
On the logs, the first error reported is that the path of /usr/share/puppet-dashboard/public/reports/upload is not there, so I've created those sub-folders to see if what would be the next error.
The next error in the log file after that is now shown like:
Attempt to serve directory: /usr/share/puppet-dashboard/public/reports/upload/
External node and node terminus option has been commented out as not to disrupt normal puppet run-interval activities during office hours.
PassengerHighPerformance on
PassengerMaxPoolSize 6
PassengerPoolIdleTime 1500
PassengerStatThrottleRate 120
Listen 3000
<VirtualHost *:3000>
ServerName mi-cloud-mgmt-config-01
ServerAlias mi-cloud-mgmt-config-01.mimos.local
RailsBaseURI /
PassengerAppRoot /usr/share/puppet-dashboard/
DocumentRoot /usr/share/puppet-dashboard/public/
# UPDATE THIS TO YOUR FQDN
<Directory /usr/share/puppet-dashboard/public/>
Options None
Order allow,deny
allow from all
</Directory>
ErrorLog /var/log/httpd/dashboard_error.log
LogLevel debug
CustomLog /var/log/httpd/dashboard_access.log combined
ServerSignature Off
</VirtualHost>
Yes I have encountered the same issue. I tried to be clever and use the latest passenger for my Puppet Master as per the Puppet guide... https://docs.puppetlabs.com/guides/passenger.html#install-rackpassenger
But it looks like Dashboard doesn't support Passenger 5.x. Which is fair enough considering Dashboard is basically dead.
I noticed the structure of the directories under the <DocumentRoot> and <Directory> were different for Dashboard compared to Puppet Master, namely no config.ru being present.
So on CentOS 6 I tried the version of mod_passenger from EPEL repo mod_passenger-3.0.21-11.el6 and that worked for both Puppet Master and Dashboard.
According to some knowledgeable folks in #puppet IRC there should only be a minor lowering in performance with 3.x compared to 5.x.
Although it might need some tweaking it does work on passenger 5.
I use Nginx but if it works using Nginx it should on apache as well.
I use passenger-5.0.13 with ruby 1.9.1 to run puppet dashboard.

Capistrano and XSendFile configuration

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!

Wamp server 2.5 wrong page redirection

I installed wamp server 2.5 with PHP 5.5. Now, when i try to access my project pages from the front page(wamp home page), it redirect to a wrong url and shows google cannot find this page.
The problem definition is
I enter to wamp using http://localhost
There I have many project. Suppose I click on sample_project
Then the page redirects to sample_projects/
And Google Chrome displays the error chrome cannot find this webpage
There are two fields are swown red marks in my wamp PHP extensions area. They are php_enchant and php_opcache
What is the problem with my wamp??am I missing something? Help please
Honestly I think its highly inefficient to create Virtual Host for every.. single.. project. So after investigating I found a key variable in:
wamp/www/index.php.
After quick analysis, the variable's obvious purpose is to remove the 'localhost' in projects links.
Change this line:
$suppress_localhost = true;
To this:
$suppress_localhost = false;
WAMPServer 2.5 Homepage the Your Projects Menu and Virtual Hosts
There has been a change of concept in WampServer 2.5 and there is a good reason for this change!
In WampServer 2.5 it is now STRONGLY encouraged to create a Virtual Host for each of your projects, even if you hold then in a \wamp\www\subfolder structure.
Virtual Hosts Documentation
Virtual Host Examples
The WampServer home page ( \wamp\www\index.php ) now expects you to have created a Virtual Host for all your projects and will therefore work properly only if you do so.
History
In order to make life easier for beginners using WampServer to learn PHP Apache and MySQL it was suggested that you create subfolders under the \wamp\www\ folder.
wamp
|-- www
|-- Chapter1
|-- Chapter2
|-- etc
These subfolders would then show as links in the WampServer Homepage under a menu called 'Your Projects' and these links would contain a link to localhost/subfoldername.
Acceptable only for simple tutorials
This made life easy for the complete beginner, and was perfectly acceptable for example for those following tutorials to learn PHP coding.
However it was never intended for use when developing a real web site that you would later want to copy to your live hosted server.
In fact if you did use this mechanism it often caused problems as the live sites configuration would not match your development configuration.
The Problem for real website development.
The reason for this is of course that the default DocumentRoot setting for wamp is
DocumentRoot "c:/wamp/www/"
regardless of what your subfolder was called.
This ment that often used PHP code that queried the structure or your site received different information when running on your development WampServer to what it would receive when running on a live hosted server, where the DocumentRoot configuration points to the folder at the top of the website file hierarchy.
This kind of code exists in many frameworks and CMS's for example WordPress and Joomla etc.
For Example
Lets say we have a project called project1 held in wamp\www\project1 and run incorrectly as localhost/project1/index.php
This is what would be reported by some of the PHP command in question:
$_SERVER['HTTP_HOST'] = localhost
$_SERVER['SERVER_NAME'] = localhost
$_SERVER['DOCUMENT_ROOT'] = c:/wamp/www
Now if we had correctly defined that site using a Virtual Host definition and ran it as http://project1 the results on the WAMPServer devlopment site will match those received when on a live hosted environment.
$_SERVER['HTTP_HOST'] = project1
$_SERVER['SERVER_NAME'] = project1
$_SERVER['DOCUMENT_ROOT'] = c:/wamp/www/project1
Now this difference may seem trivial at first but if you were to use a framework like WordPress or one of the CMS's like Joomla for example, this can and does cause problems when you move your site to a live server.
How to create a Virtual Host in WampServer
Actually this should work basically the same for any wndows Apache server, with differences only in where you may find the Apache config files.
There are 3 steps to create your first Virtual Host in Apache, and only 2 if you already have one defined.
Create the Virtual Host definition(s)
Add your new domain name to the HOSTS file.
Uncomment the line in httpd.conf that includes the Virtual Hosts definition file.
Step 1, Create the Virtual Host definition(s)
Edit the file called httpd-hosts.conf which for WampServer lives in
\wamp\bin\apache\apache2.4.9\conf\extra\httpd-hosts.conf
(Apache version numbers may differ, engage brain before continuing)
If this is the first time you edit this file, remove the default example code, it is of no use.
I am assuming we want to create a definition for a site called project1 that lives in
\wamp\www\project1
Very important, first we must make sure that localhost still works so that is the first VHOST definition we will put in this file.
<VirtualHost *:80>
DocumentRoot "c:/wamp/www"
ServerName localhost
ServerAlias localhost
<Directory "c:/wamp/www">
AllowOverride All
Require local
</Directory>
</VirtualHost>
Now we define our project: and this of course you do for each of your projects as you start a new one.
<VirtualHost *:80>
DocumentRoot "c:/wamp/www/project1"
ServerName project1
<Directory "c:/wamp/www/project1">
AllowOverride All
Require local
</Directory>
</VirtualHost>
NOTE: That each Virtual Host as its own DocumentRoot defined. There are also many other parameters you can add to a Virtual Hosts definition, check the Apache documentation.
Small aside
The way virtual hosts work in Apache: The first definition in this file will also be the default site, so should the domain name used in the browser not match any actually defined virtually hosted domain, making localhost the first domain in the file will therefore make it the site that is loaded if a hack attempt just uses your IP Address.
So if we ensure that the Apache security for this domain is ALWAYS SET TO
Require local
any casual hack from an external address will receive an error and not get into your PC, but should you misspell a domain you will be shown the WampServer homepage, because you are on the same PC as WampServer and therfore local.
Setp 2:
Add your new domain name to the HOSTS file.
Now we need to add the domain name that we have used in the Virtual Host definition to the HOSTS file so that windows knows where to find it. This is similiar to creating a DNS A record, but it is only visible in this case on this specific PC.
Edit C:\windows\system32\drivers\etc\hosts
The file has no extension and should remain that way. Watch out for notepad, as it may try and add a .txt extension if you have no better editor.
I suggest you download Notepad++, its free and a very good editor.
Also this is a protected file so you must edit it with administrator privileges, so launch you editor using the Run as Administrator menu option.
The hosts file should look like this when you have completed these edits
127.0.0.1 localhost
127.0.0.1 project1
::1 localhost
::1 project1
Note that you should have definitions in here for the IPV4 loopback address 127.0.0.1 and also the IPV6 loopback address ::1 as Apache is now IPV6 aware and the browser will use either IPV4 or IPV6 or both. I have no idea how it decides which to use, but it can use either if you have the IPV6 stack turned on, and most window OS's do as of XP SP3.
Now we must tell windows to refresh its domain name cache, so launch a command window again using the Run as Administrator menu option again, and do the following.
net stop dnscache
net start dnscache
This forces windows to clear its domain name cache and reload it, in reloading it will re-read the HOSTS file so now it knows about the domain project1.
Step 3: Uncomment the line in httpd.conf that includes the Virtual Hosts definition file.
Edit your httpd.conf, use the wampmanager.exe menus to make sure you edit the correct file.
Find this line in httpd.conf
# Virtual hosts
#Include conf/extra/httpd-vhosts.conf
And just remove the # to uncomment that line.
To activate this change in you running Apache we must now stop and restart the Apache service.
wampmanager.exe -> Apache -> Service -> Restart Service
Now if the WAMP icon in the system tray does not go GREEN again, it means you have probably done something wrong in the \wamp\bin\apache\apache2.4.9\conf\extra\httpd-hosts.conf file.
If so here is a useful mechanism to find out what is wrong. It uses a feature of the Apache exe (httpd.exe) to check its config files and report errors by filename and line numbers.
Launch a command window.
cd \wamp\bin\apache\apache2.4.9\bin
httpd -t
So fix the errors and retest again until you get the output
Syntax OK
Now there is one more thing.
There are actually 2 new menu items on the wampmanager menu system. One called [b]'My Projects'[/b] which is turned on by default.
And a second one, called [b]'My Virtual Hosts'[/b], which is not activated by default.
'My Projects' will list any sub directory of the \wamp\www directory and provide a link to launch the site in that sub directory.
As I said earlier, it launches 'project1` and not 'localhost/project1' so to make the link work we must create a Virtual Host definition to make this link actually launch that site in your browser, without the Virtual Host definition it's likely to launch a web search for the site name as a keyword or just return a site not found condition.
The 'My Virtual Hosts' menu item is a little different. It searches the file that is used to define Virtual Hosts ( we will get to that in a minute ) and creates menu links for each ServerName parameter it finds and creates a menu item for each one.
This may seem a little confusing as once we create a Virtual Host definition for the sub directories of the \wamp\www folder some items will appear on both of the 'My Projects' menu and the 'My Virtual Hosts' menu's.
How do I turn this other 'My Virtual Hosts' menu on?
Make a backup of the \wamp\wampmanager.tpl file, just in case you make a mistake, its a very important file.
Edit the \wamp\wampmanager.tpl
Find this parameter ;WAMPPROJECTSUBMENU, its in the '[Menu.Left]' section.
Add this new parameter ;WAMPVHOSTSUBMENU either before or after the ;WAMPPROJECTSUBMENU parameter.
Save the file.
Now right click the wampmanager icon, and select 'Refresh'. If this does not add the menu, 'exit' and restart wampmanager.
Big Note
The new menu will only appear if you already have some Virtual Hosts defined! Otherwise you will see no difference until you define a VHOST.
I can't believe that Wampserver now expects everyone to create a virtual host for every project under development offline on their laptops?
Your instructions seem to be very good but probably much too complicated for beginners (also, I suspect that the file path in your instructions for step2: adding the new domain to the HOSTS file only applies to 32-bit Windows)?
The solution from Rogue above (change $suppress_localhost="true"; to $suppress_localhost="false"; in c:/wamp/www/index.php) will work perfectly for 99% of the users who develop more than one website on their laptops.
Also uploading a completed website to an online server should not cause any real problems.
BUt perhaps Wampserver had another reason for adding the $suppress_localhost code?

Why does grails URL params decoding behave differently on server vs. local

Let's say I have the following entry in my grails URLMappings.groovy:
"/actionName/param1"(controller:'myController', action:'myAction')
When I call an URL where param1 includes + as a special character, the URL is encoded correctly to /actionName/my%2Bparam for example, both in my local and in my server environment.
In my local environment - also using "prod" as the environment parameter - this is correctly resolved to my+param in the controller. However in my "real" production environment (Amazon Web Service EC2 instance), the URL is resolved to "my param" which is wrong.
I have no idea what the reason for this could be. Both environments use TomCat, and as stated above I'm even using the prod environment settings in my local environment so it can't be a differing configuration between development and production.
Does anybody have an idea where I could dig deeper to identify the problem?
Is the EC2 instance running Apache in front of Tomcat? I've had issues before with params being decoded twice, once by Apache and then again by Tomcat. From memory, I think I adjusted the configuration of the ProxyPass directive in Apache to correct it.
EDIT:
I found the following instructions I'd left with the source code for my app :)
Apache httpd.conf additions
AllowEncodedSlashes On
ProxyTimeout 3600
We also upgraded apache 2.2.12+ to fix HEAD > GET rewrite bug using a startup shell script.
I also added 'nocanon' option to ProxyPass directive to stop auto decoding by mod_proxy in /etc/httpd/conf.d/cluster.conf
I think I had to do this on the server as you can't modify this using the GUI. I also have a note that says it causes they query string to be encoded. Perhaps I had to add an extra decode in my app to handle this (sorry can't remember for sure!)
Tomcat startup parameters
-Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true
-Dorg.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH=true
I think this was to get tomcat to handle slashes correctly
cheers
Lee
That's a known bug that has been introduced in Groovy 1.3.4 or few build versions before. It has been fixed in current version 1.3.5.
this is correctly resolved to my+param
in the controller
No, the expected resolution is "my param" (with a space).
As that works at the Amazon host, you'd upgrade Grails to 1.3.5, locally.

How can mod_perl and Passenger run on the same Apache server?

Is this even possible?
I have a Rails app running on Passenger and a mod_perl site that need to run on the same server. I've tried setting up two VirtualHosts and I've tried just using one VH and an Alias/Location for the mod_perl. In both cases, Passenger tries to serve the mod_perl app and tells me it can't find the correct files. Anyone know what I'm doing wrong?
Here's my setup atm:
NameVirtualHost *:80
RailsAutoDetect off
<VirtualHost *:80>
DocumentRoot (home of rails app)/public
RailsBaseURI /
</VirtualHost>
PerlModule Apache::DBI
PerlRequire /opt/rt3/bin/webmux.pl
Alias /rt /opt/rt3/share/html <== mod_perl app
<Location /rt>
AddDefaultCharset UTF-8
SetHandler perl-script
PerlHandler RT::Mason
</Location>
Well, for right now I've just set them up as two different VirtualHosts using different ports to connect. That works, but it's a little messy for my site to use and if anyone has a better idea, I'm all ears. Thanks.
Edit: Got it working! I ended up setting up two VirtualServers on different ports, then used mod-proxy to redirect traffic to the /rt site to the mod-perl VirtualServer (leaving the Passenger one as the default). This works great, and best of all my mod_perl site believes it's still in the same place as Passenger, which smooths out a lot of compatibility issues I was dealing with as well. I knew I was missing something simple! Just putting this up in case anyone else is having issues with this.

Resources