Rails + Passenger + Nginx error Request Origin (domainname.com) does not match Request Base_url (IP Address)

1.3k views Asked by At

Set up: Rails 5.1.3, Dreamhost VPS with Passenger and Nginx. As it is a VPS, I do not have root access to perform any function that would require root permissions.

Situation: Currently, I have redone a previous rails app with ActionCable functionality. Earlier configuration was with Apache instead of Nginx for the http server. Everything works fine except for websockets, and I read quite a few articles, all confirming action cables + apache will not work.

At which point, I switched to NginX. With NginX, my first observation was that the application constantly tries the 'get cable/' process and fails to upgrade to websocket. After reading through various discussions I managed to solve this with:

location /cable {
    proxy_pass http://127.0.0.1:8000/cable;
    proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

}

As I do not have root permission to access the usual dt/etc/nginx/.../***.conf file, with the dreamhost VPS package, I can add a file at /home/username/nginx/(appname.com)/(any-file-name.conf) and this would add on to the nginx "server block", as per dreamhost documentation.

^^So the above block of code alone in a file called "redis.conf" in that directory sorted the action cables issue. It successfully starts streaming on channels everything is fine.

The main issue, I later realize, is that I cannot perform any of the create, update, destroy actions - anything that needs POST or DELETE methods as it results in an authenticity token error, saying "The Request Origin (http ://siik.io - this being the app & domain name) did not match the request.base_url (http ://127.0.0.1).

Detail Error:

I, [2017-09-11T03:27:28.623080 #7273]  INFO -- : [50a21156-0333-413e-94b

8-07b791c209fc] Completed 200 OK in 83ms (Views: 56.0ms | ActiveRecord: 16.6ms)
I, [2017-09-11T03:27:31.950732 #7273]  INFO -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] Started POST "/conversations/1/messages" for 106.208.156.243 at 2017-09-11 03:27:31 -0700
I, [2017-09-11T03:27:31.953339 #7273]  INFO -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] Processing by MessagesController#create as JS
I, [2017-09-11T03:27:31.953511 #7273]  INFO -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d]   Parameters: {"utf8"=>"✓", "message"=>{"user_id"=>"1", "body"=>"sdfgh"}, "commit"=>"Send", "conversation_id"=>"1"}
W, [2017-09-11T03:27:31.954325 #7273]  WARN -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] HTTP Origin header (http://www.siik.io) didn't match request.base_url (http://127.0.0.1:8000)
I, [2017-09-11T03:27:31.954890 #7273]  INFO -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms)
F, [2017-09-11T03:27:31.956888 #7273] FATAL -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d]   
F, [2017-09-11T03:27:31.956969 #7273] FATAL -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
F, [2017-09-11T03:27:31.957017 #7273] FATAL -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d]   
F, [2017-09-11T03:27:31.957126 #7273] FATAL -- : [dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal/request_forgery_protection.rb:195:in `handle_unverified_request'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal/request_forgery_protection.rb:227:in `handle_unverified_request'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] devise (4.3.0) lib/devise/controllers/helpers.rb:253:in `handle_unverified_request'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal/request_forgery_protection.rb:222:in `verify_authenticity_token'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/callbacks.rb:413:in `block in make_lambda'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/callbacks.rb:197:in `block (2 levels) in halting'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/abstract_controller/callbacks.rb:12:in `block (2 levels) in <module:Callbacks>'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/callbacks.rb:198:in `block in halting'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/callbacks.rb:507:in `block in invoke_before'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/callbacks.rb:507:in `each'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/callbacks.rb:507:in `invoke_before'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/callbacks.rb:130:in `run_callbacks'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/abstract_controller/callbacks.rb:19:in `process_action'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal/rescue.rb:20:in `process_action'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/notifications.rb:166:in `block in instrument'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/notifications.rb:166:in `instrument'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal/params_wrapper.rb:252:in `process_action'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activerecord (5.1.3) lib/active_record/railties/controller_runtime.rb:22:in `process_action'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/abstract_controller/base.rb:124:in `process'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionview (5.1.3) lib/action_view/rendering.rb:30:in `process'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal.rb:189:in `dispatch'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_controller/metal.rb:253:in `dispatch'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/routing/route_set.rb:31:in `serve'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/journey/router.rb:46:in `block in serve'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/journey/router.rb:33:in `each'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/journey/router.rb:33:in `serve'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/routing/route_set.rb:834:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] remotipart (1.3.1) lib/remotipart/middleware.rb:32:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] warden (1.2.7) lib/warden/manager.rb:36:in `block in call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] warden (1.2.7) lib/warden/manager.rb:35:in `catch'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] warden (1.2.7) lib/warden/manager.rb:35:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] rack (2.0.3) lib/rack/etag.rb:25:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] rack (2.0.3) lib/rack/conditional_get.rb:38:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] rack (2.0.3) lib/rack/head.rb:12:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] rack (2.0.3) lib/rack/session/abstract/id.rb:232:in `context'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] rack (2.0.3) lib/rack/session/abstract/id.rb:226:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/middleware/cookies.rb:613:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/middleware/callbacks.rb:26:in `block in call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/callbacks.rb:97:in `run_callbacks'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/middleware/callbacks.rb:24:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] railties (5.1.3) lib/rails/rack/logger.rb:36:in `call_app'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] railties (5.1.3) lib/rails/rack/logger.rb:24:in `block in call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/tagged_logging.rb:69:in `block in tagged'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/tagged_logging.rb:26:in `tagged'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/tagged_logging.rb:69:in `tagged'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] railties (5.1.3) lib/rails/rack/logger.rb:24:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/middleware/request_id.rb:25:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] rack (2.0.3) lib/rack/method_override.rb:22:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] rack (2.0.3) lib/rack/runtime.rb:22:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] activesupport (5.1.3) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] actionpack (5.1.3) lib/action_dispatch/middleware/executor.rb:12:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] rack (2.0.3) lib/rack/sendfile.rb:111:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] railties (5.1.3) lib/rails/engine.rb:522:in `call'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] passenger (5.1.8) src/ruby_supportlib/phusion_passenger/rack/thread_handler_extension.rb:97:in `process_request'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] passenger (5.1.8) src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb:160:in `accept_and_process_next_request'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] passenger (5.1.8) src/ruby_supportlib/phusion_passenger/request_handler/thread_handler.rb:113:in `main_loop'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] passenger (5.1.8) src/ruby_supportlib/phusion_passenger/request_handler.rb:416:in `block (3 levels) in start_threads'
[dd8e08f7-f28b-497b-9ae9-e57a6a45c35d] passenger (5.1.8) src/ruby_supportlib/phusion_passenger/utils.rb:113:in `block in create_thread_and_abort_on_exception'

BUT, when I access the site through http ://siik.io:8000 EVERYTHING works perfectly, even the websockets bit without the need for redis.conf file.

I've gone through a week's worth of various fixes and documentations and have failed to find the solution for this. I think the basic requirement is to add more headers onto a location / {} block to add on to the nginx.conf file... (I've listed some examples I've tried below.)

listen 80;
listen *:80;
server_name siik.io www.siik.io http://siik.io;
location / {

        proxy_redirect off;
        proxy_set_header Host $host:8000;

        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;


        proxy_http_version 1.1;

        proxy_set_header   X-Real-IP $remote_addr:8000;
        proxy_set_header  X-Forwarded-Port $server_port;

        proxy_pass http://127.0.0.1:8000/;
}

.. So I've basically being trying various combinations & permutations for the above values to see what works because clearly, I have no clue how this works - I have some conceptual knowledge on reverse proxying and http servers.

Yes, I know the request.origin == request.base_url thing is from the protect_from_forgery bit of rails, I don't feel switching it off is a solution, although, I did read somewhere that including the right headers will solve this issue. I've tried a few variations of this header sets and none worked, and am wondering if including the right headers should reach a point where the http origin header will change from domainname.io to an IP address or the request.base_url will change from the IP address to the domainname??

Oh yes, when I add the location / {} block in a new file proxy.conf next to redis.conf it completely breaks. The website via domainname.io refuses to connect, while domainname.io:8000 works perfectly. Even an empty block under location / breaks it - I was testing to see if any specific proxy_set commands were causing it to break - but no. Just the bits "location / {}" breaks it - maybe this is expected?

Why does this work perfectly when I access it via siik.io:8000, with the port number explicitly?

Any help is EXTREMELY appreciated!!!!

2

There are 2 answers

2
Camden Narzt On BEST ANSWER

You shouldn't need to run your action cable server on another port, try following these instructions: https://www.phusionpassenger.com/library/config/nginx/action_cable_integration/

Copied here per THE RULES™:

Running the Action Cable server on the same host and port, under a sub-URI

This is the default setup as recommended by Rails and is also the easiest. It works by mounting ActionCable.server to a certain path in your config/routes.rb. That way, your Action Cable server will be running on the same host and port as your application, but under a sub-URI.

For example, your routes.rb may contain:

# Serve websocket cable requests in-process
mount ActionCable.server => '/cable'

(Although the routes.rb comment says that mounting ActionCable.server is meant for serving it in-process, Passenger actually insists on running it as a separate process.)

To make this work in Passenger + Nginx, you need to add a snippet to your Nginx virtual host. Suppose that you already had a virtual host for your application, which looks like this:

server {
    listen 80;
    server_name www.foo.com;
    root /path-to-your-app/public;
    passenger_enabled on;
}

You need to insert a location block which configures the Action Cable end point, like this:

server {
    listen 80;
    server_name www.foo.com;
    root /path-to-your-app/public;
    passenger_enabled on;

    ### INSERT THIS!!! ###
    location /cable {
        passenger_app_group_name YOUR_APP_NAME_HERE_action_cable;
        passenger_force_max_concurrent_requests_per_process 0;
    }
}

Replace /cable with the actual Action Cable path as is specified in your routes.rb.

Replace YOUR_APP_NAME_HERE with a unique identifier that doesn't appear anywhere else in the Nginx configuration file.

The passenger_force_max_concurrent_requests_per_process option tunes Passenger for optimal WebSocket performance.

0
Shanthanu Varma On

FIXED.

I'm not completely sure how this was resolved, I'm still trying to figure out why everything is working. Basically, the issue seemed to be with the way in which the Passenger+Nginx configuration was maintained. - This is a dreamhost specific issue I believe.

My initial VPS configuration was done with Apache as the http server following a tutorial by Dave Jones on youtube. In the domain hosting section of the Dreamhost panel there's a checkbox to use Passenger with the ruby application which was left unchecked as per the original tutorial I was following. Reading up on @Camden's links - very helpful - I decided to reconfigure everything from scratch, and checked this Passenger Box on the control panel, along with the HTTPS secure bit, added a certificate from 'Let's Encrypt SSL' and restarted my server. Everything started working perfectly as required. I also added the headers for the 443 port under the location block for '/cable' in the CONF file - and added the http://www.domainnam.io in the production.rb file, with config.force_ssl set to true.

So, in conclusion, I understand the problem was with improper configuration of the passenger nginx integration. Thank you @Camden for the links.