Rails/Passenger/Node.js: ExecJS "Could not find a JavaScript runtime"
Asked Answered
S

3

12

I'm trying to use Node.js as the JavaScript runtime for my Rails application. I'm using the Phusion Passenger module with Nginx as my web server on Ubuntu 12.0.4. Every time I visit my Rails application I get an error page that appears to be generated from Passenger stating that ExecJS can't find a JavaScript runtime. I've seen numerous posts on here that either suggest that you install Node--which I have done via sudo apt-get install node--or suggest using therubyracer + execjs in your Gemfile. That latter solution does in fact work, but I would really prefer to use Node, especially since Heroku has stated that they discourage the use of therubyracer do to the fact that it uses a "very large amount of memory".

I ran into a tutorial which suggests that the user that my web server runs as may not have Node in it's path. I checked this out by running sudo -u www-data which node and it returns /usr/bin/node. The user www-data is the user that nginx runs as, and the user that owns all the files in my Rails application. I've also looked at /etc/environment, and I can see that /usr/bin is in the system-wide path. Running sudo -u www-data node -v also returns the Node version as expected, so it is executable.

When I run RAILS_ENV=production bundle exec rake assets:precompile I don't get any errors. When I load ExecJS into an interactive session with IRB I'm able to get it to return a valid runtime. I've also tried explicitly adding EXECJS_RUNTIME=Node as an environment variable, but then it just says "Node.js (V8) runtime is not available" instead. I've tried many things and I just can't get this to work!

Here's the error I get when I visit my Rails app. When I look at the Nginx log file I see pretty much the same thing.

Web application could not be started

Could not find a JavaScript runtime. See https://github.com/sstephenson/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)
  /usr/lib/ruby/gems/2.1.0/gems/execjs-2.0.2/lib/execjs/runtimes.rb:51:in `autodetect'
  /usr/lib/ruby/gems/2.1.0/gems/execjs-2.0.2/lib/execjs.rb:5:in `<module:ExecJS>'
  /usr/lib/ruby/gems/2.1.0/gems/execjs-2.0.2/lib/execjs.rb:4:in `<top (required)>'
  /usr/lib/ruby/gems/2.1.0/gems/uglifier-2.5.0/lib/uglifier.rb:3:in `require'
  /usr/lib/ruby/gems/2.1.0/gems/uglifier-2.5.0/lib/uglifier.rb:3:in `<top (required)>'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:76:in `require'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:76:in `block (2 levels) in require'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:72:in `each'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:72:in `block in require'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:61:in `each'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler/runtime.rb:61:in `require'
  /usr/lib/ruby/gems/2.1.0/gems/bundler-1.6.1/lib/bundler.rb:132:in `require'
  /srv/www/app/config/application.rb:7:in `<top (required)>'
  /srv/www/app/config/environment.rb:2:in `require'
  /srv/www/app/config/environment.rb:2:in `<top (required)>'
  config.ru:3:in `require'
  config.ru:3:in `block in <main>'
  /usr/lib/ruby/gems/2.1.0/gems/rack-1.5.2/lib/rack/builder.rb:55:in `instance_eval'
  /usr/lib/ruby/gems/2.1.0/gems/rack-1.5.2/lib/rack/builder.rb:55:in `initialize'
  config.ru:1:in `new'
  config.ru:1:in `<main>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:112:in `eval'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:112:in `preload_app'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:158:in `<module:App>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:29:in `<module:PhusionPassenger>'
  /usr/share/passenger/helper-scripts/rack-preloader.rb:28:in `<main>'
Seleucid answered 17/4, 2014 at 4:43 Comment(4)
Were you able to solve this problem? I am experiencing the same on my Amazon EC2 instance - everything works fine when I run ExecJS::Runtimes.autodetect from the console (on the server), yet breaks from inside PassengerMucus
Nope. I couldn't figure it out. I decided to just use therubyracer & execjs gems and call it good.Seleucid
Can confirm that this is a persistent, show-stopping error. I was able to get Rails 4.1, Ruby 2.0 working with the default Amazon Linux AMI, but as soon as I rebooted the server, this error inexplicably comes up, even though nothing has changed.Pulchia
gotta love how even though i'm working with a RoR app, I still need nodejs. fsck it, i'd rather go node all the way.Gradation
R
25

I had this problem too. This is what fixed it for me. I added this to the top of my nginx.conf

env PATH;

http://wiki.nginx.org/CoreModule#env

As I zeroed in on this solution I also found this post which helped me start barking up the right tree: https://forums.freebsd.org/viewtopic.php?&t=35539 -- he edits the execjs code to give an absolute path to node. This worked and helped me find out how to give the path to passenger.

Recognizor answered 27/8, 2014 at 20:13 Comment(1)
It really work,Thanks.But I have no idea of why passenger could not find the path of nodejs?Inapplicable
M
5

So, I found the issue.

First, my installation of Node was not for all users. That said, it was installed and available for the user that Nginx was supposed to be run as. Still, you need to remember to have this in your nginx.conf:

user  ec2-user;
...

http {
    passenger_root /usr/local/rvm/gems/ruby-2.1.0/gems/passenger-4.0.42;
    passenger_ruby /usr/local/rvm/gems/ruby-2.1.0/wrappers/ruby;
    passenger_nodejs /usr/local/bin/node;
    passenger_default_user ec2-user;
...

Second, you also need to make the path to Node available for non-login shells, ie add it to /etc/bashrc and export.

Your environment may be different, but this is the gist.

Mucus answered 16/5, 2014 at 18:28 Comment(2)
I just tried this and unfortunately it didn't work for my server.Seleucid
adding passenger_nodejs to the server config block or nginx.conf solved my issue. thank you.Crystlecs
P
1

Spoke too soon in my above comment. Things were working fine on my Hello World Rails app (4.1, with the default Gemfile and config), I stopped the EC2 instance to snapshot it, then upon reboot, I ran into that Exec.js error despite node (~ 0.11) being installed at /usr/local/bin

However, I edited my `/etc/sudoers/ file from

Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin

to:

Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

I restarted the server and Apache and things were working as expected.

Pulchia answered 13/5, 2014 at 19:52 Comment(1)
Unfortunately that doesn't work for me. Node is installed at /usr/bin on my server, which is in secure_path by default. In any case, why would editing /etc/sudoers fix the problem?Seleucid

© 2022 - 2024 — McMap. All rights reserved.