Git Product home page Git Product logo

rack-reverse-proxy's Introduction

A Reverse Proxy for Rack

TravisCI

This is a simple reverse proxy for Rack that pretty heavily rips off Rack Forwarder. It is not meant for production systems (although it may work), as the webserver fronting your app is generally much better at this sort of thing.

Installation

The gem is available on rubygems. Assuming you have a recent version of Rubygems you should just be able to install it via:

gem install rack-reverse-proxy

For your Gemfile use:

gem "rack-reverse-proxy", require: "rack/reverse_proxy"

Usage

Rack::ReverseProxy should ideally be the very first middleware in your stack. In a typical use case it is being used to proxy an entirely different website through your application, so it's unlikely that you will want any other middleware to modify the requests or responses. The examples below reflect this.

Generic Rack app example

require 'rack/reverse_proxy'

use Rack::ReverseProxy do
  # Set :preserve_host to true globally (default is true already)
  reverse_proxy_options preserve_host: true

  # Forward the path /test* to http://example.com/test*
  reverse_proxy '/test', 'http://example.com/'

  # Forward the path /foo/* to http://example.com/bar/*
  reverse_proxy /^\/foo(\/.*)$/, 'http://example.com/bar$1', username: 'name', password: 'basic_auth_secret'
end

app = proc do |env|
  [ 200, {'Content-Type' => 'text/plain'}, ["b"] ]
end
run app

Ruby on Rails app example

This example use config.middleware.insert(0 to ensure that Rack::ReverseProxy is first in the stack. It is possible that other code in your app (usually in application.rb, development.rb, or production.rb) will take over this position in the stack. To ensure that this is not the case, view the stack by running rails middleware. You should see Rack::ReverseProxy at the top. Note that the middleware stack will likely differ slightly in each environment. All that said, it's a pretty safe bet to put the below code into application.rb.

# config/application.rb
config.middleware.insert(0, Rack::ReverseProxy) do
  reverse_proxy_options preserve_host: true
  reverse_proxy '/wiki', 'http://wiki.example.com/'
end

Rules

As seen in the Rack example above, reverse_proxy can be invoked multiple times with different rules, which will be commulatively added.

Rules can be a regex or a string. If a regex is used, you can use the subcaptures in your forwarding url by denoting them with a $.

Right now if more than one rule matches any given route, it throws an exception for an ambiguous match. This will probably change later. If no match is found, the call is forwarded to your application.

Options

reverse_proxy_options sets global options for all reverse proxies. Available options are:

  • :preserve_host Set to false to omit Host headers
  • :username username for basic auth
  • :password password for basic auth
  • :matching is a global only option, if set to :first the first matched url will be requested (no ambigous error). Default: :all.
  • :timeout seconds to timout the requests
  • :force_ssl redirects to ssl version, if not already using it (requires :replace_response_host). Default: false.
  • :verify_mode the OpenSSL::SSL verify mode passed to Net::HTTP. Default: OpenSSL::SSL::VERIFY_PEER.
  • :x_forwarded_headers sets up proper X-Forwarded-* headers. Default: true.
  • :stripped_headers Array of headers that should be stripped before forwarding reqeust. Default: nil. e.g. stripped_headers: ["Accept-Encoding", "Foo-Bar"]

If reverse_proxy_options is invoked multiple times, the invocations will have a commulative effect, only overwritting the values which they specify. Example of how this could be useful:

config.middleware.insert(0, Rack::ReverseProxy) do
  reverse_proxy_options preserve_host: false
  if Rails.env.production? or Rails.env.staging?
    reverse_proxy_options force_ssl: true, replace_response_host: true
  end
  reverse_proxy /^\/blog(\/?.*)$/, 'http://blog.example.com/blog$1'
end

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don't break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Contributors

  • Jon Swope, creator
  • Oleksii Fedorov, maintainer

rack-reverse-proxy's People

Contributors

anujdas avatar arc279 avatar brianewing avatar carlhoerberg avatar ehlertij avatar ekosz avatar hubertlepicki avatar janraasch avatar jaswope avatar jjb avatar jjthrash avatar joliss avatar josephruscio avatar jphenow avatar knapo avatar markbates avatar maxilev avatar natejgreene avatar pex avatar pigoz avatar rmanalan avatar sinm avatar waterlink avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

rack-reverse-proxy's Issues

Caching?

Is it possible to cache pages using memcache?

1.0 release?

Hi @waterlink! :)

I'm wondering if you would consider merging my documentation PRs and doing a 1.0 release? I still am pointing at a particular commit in my Gemfile and I'm about to use this in a new project, it would be nice to be on the mainline release.

Let me know if I can be of any help!

OpenSSL::SSL::SSLError: hostname "XYZ" does not match the server certificate

Hi,

I'm having issues trying to use rack-reverse-proxy to host a wordpress blog from another site on my heroku domain. I'm using puma server and when I try to go to https://mydomain.com/blog I get the following error:

OpenSSL::SSL::SSLError: hostname "XYZ" does not match the server certificate

Everything seems to work fine if I don't use SSL. I have verified that the certificates on my wordpress blog and heroku site match (other than the wordpress blog has a different hostname I guess), but can't figure out how to resolve this. Any help is much appreciated.

Very helpful gem btw.

Thanks! Aaron

Bypassing CORS error

Hi,

I would like to use rack-reverse-proxy in order to bypass a CORS error while accessing youtube via ajax from my website. I have the following JS code client-side:

    xhr = xhr.open 'GET', '/watch?v=0xc3XdOiGGI', true

    xhr.onload = ->
      console.log("XHR SUCCESS")
      return

    xhr.onerror = ->
      console.log("XHR ERROR")
      return

    xhr.send()

And the following Ruby on Rails code server-side:

    config.middleware.insert(0, Rack::ReverseProxy) do
      reverse_proxy_options preserve_host: true
      reverse_proxy '/watch', 'http://youtube.com/'
    end

I'm still getting a CORS error on the client-side. I've been playing with different reverse_proxy_options but couldn't make it work so far.

Is it possible to achieve this with rack-reverse-proxy? Which options should I use?

Thanks for your help

Receiving (binary?) symbols instead of HTML

Hi, I followed the instructions on the GitHub page to set up my config.ru

# This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment',  __FILE__)
use Rack::Deflater
use Rack::ReverseProxy do  
   reverse_proxy /^\/blog(\/.*)$/, 'http://blog.sexycrets.com$1', opts={:preserve_host => true}
end
run Sxs::Application

when I hit .../blog/ the server fetches something that is returned on the browser as:
���5:B���V[o�6������ۛ.���M" ȭ]��-�v����-Q���THʊ����%�0���s�|�P���Og_��|�*]�t��?�0/��p������(���(��TD'^�����H��n�r��M���|= �D�MW�x(�\��J�� �K�g��5I�O�����P�5B��JGs]%9�Ќ���#ʩ���_�왕F��H�M�{�8X�Z�1��p�A���J�G�����[$ K,�(�� u�oh����w-��h���y��k�õ�!YK��� �UT�=�'i��дh��qJ}�������z��^M>ظN8f[0�>�֐��:���J^'�����?�� �rx�������Yش��bY�f"���o�,���I������1N }3o���;t_f�5Y��$�'�����/��������Xmy����T�<���K��(r�R���=%0�djR�6�Ϧ�Xt>\�6.���2�'�3�-������xZ+�,�dv<��K<���'>����������`i������D�ṡ7����Rog�)��ܽ�[����<�gZ�

I tried pointing to multiple blogs other than ours and I tried to run the RoR app from multiple servers in and outside of Heroku but the result does not change.

Any ideas? Thank you very much!

Is a particular port required to work?

The only mention I could find of ports is in the spec. There is says port 80.
I'm having lockups when reverse proxy is called into action and port 80 on my vagrant box can be funny.

ideal to always be very first middleware?

Thanks for a fantastically useful project!

Wouldn't it be ideal in almost all use cases for this to be the very first middleware, so that other middleware don't do useless computation? So then the recommendation would be:

config.middleware.insert(0, Rack::ReverseProxy) 

errors appear after a while, always fixed by restart

My setup (https://github.com/waterlink/rack-reverse-proxy/wiki/How-to-stream-a-WordPress-blog-through-a-Rack-app) will work quite well, and then I'll suddently start to get errors that look like this (i replaced my blog host with blog.example.com):

Errno::ECONNREFUSED: Connection refused - connect(2) for "blog.example.com" port 80
File "/app/vendor/ruby-2.4.0/lib/ruby/2.4.0/net/http.rb" line 904 in initialize
File "/app/vendor/ruby-2.4.0/lib/ruby/2.4.0/net/http.rb" line 904 in open
File "/app/vendor/ruby-2.4.0/lib/ruby/2.4.0/net/http.rb" line 904 in block in connect
File "/app/vendor/ruby-2.4.0/lib/ruby/2.4.0/timeout.rb" line 93 in block in timeout
File "/app/vendor/ruby-2.4.0/lib/ruby/2.4.0/timeout.rb" line 103 in timeout
File "/app/vendor/ruby-2.4.0/lib/ruby/2.4.0/net/http.rb" line 902 in connect
File "/app/vendor/ruby-2.4.0/lib/ruby/2.4.0/net/http.rb" line 887 in do_start
File "/app/vendor/ruby-2.4.0/lib/ruby/2.4.0/net/http.rb" line 882 in start
File "/app/vendor/bundle/ruby/2.4.0/gems/rack-proxy-0.6.0/lib/rack/http_streaming_response.rb" line 70 in session
File "/app/vendor/bundle/ruby/2.4.0/gems/rack-proxy-0.6.0/lib/rack/http_streaming_response.rb" line 59 in response
File "/app/vendor/bundle/ruby/2.4.0/gems/rack-proxy-0.6.0/lib/rack/http_streaming_response.rb" line 29 in headers
File "/app/vendor/bundle/ruby/2.4.0/gems/rack-reverse-proxy-0.11.0/lib/rack_reverse_proxy/roundtrip.rb" line 165 in rack_response_headers
File "/app/vendor/bundle/ruby/2.4.0/gems/rack-reverse-proxy-0.11.0/lib/rack_reverse_proxy/roundtrip.rb" line 156 in build_response_headers
File "/app/vendor/bundle/ruby/2.4.0/gems/rack-reverse-proxy-0.11.0/lib/rack_reverse_proxy/roundtrip.rb" line 152 in response_headers
...

A restart always solves the problem.

So my guess is it's some sort of leak of a resource, such as memory, file descriptors, or something else in the network stack. In theory a memory leak would present as memory problems with my app overall, which doesn't seem to be the case. But I'm not ruling anything out.

Looking through the code, here are candidates for possible resource leak problems:

this call to clone

https://github.com/waterlink/rack-reverse-proxy/blob/master/lib/rack_reverse_proxy/rule.rb#L106 -- looks like that url variable is something that can have call called on it, so it's not a string. i attempted to follow the code to figure out what it is, but was unable to.

http connections not being closed?

https://github.com/waterlink/rack-reverse-proxy/blob/master/lib/rack_reverse_proxy/roundtrip.rb#L200-L202 — target_response is a Rack::HttpStreamingResponse, which the documentation says "Wraps the hacked net/http in a Rack way". Is there a resource that needs to be closed? Looking in the code for rack-proxy, I find the http session opened here, but finish is never called https://github.com/ncr/rack-proxy/blob/master/lib/rack/http_streaming_response.rb#L64 -- maybe this is done intentionally, so that the connection will be reused? I don't know what the behavior is if the remote server times out the persistent connection, will net:http close on its side, or perpetually keep resources around?

here's the relevant net::http docs https://docs.ruby-lang.org/en/2.0.0/Net/HTTP.html

  • If you wish to re-use a connection across multiple HTTP requests without automatically closing it you can use ::new instead of ::start. request will automatically open a connection to the server if one is not currently open. You can manually close the connection with finish.
  • finish Finishes the HTTP session and closes the TCP connection. Raises IOError if the session has not been started.

Solving for SAMEORIGIN problem in iframe

Hi

I'm a Rails noob and this is my first intro to proxies so go light on me :)

I'm trying to use this gem to display a site (google.com in this case) that has a "X-Frame-Options: SAMEORIGIN" header response inside an iframe. I suppose I'm trying to go for something like this but without having to touch nginx (for now): http://distinctplace.com/infrastructure/2013/10/14/internal-redirect-to-another-domain-with-proxy_pass-and-nginx/

The iframe currently sits in the users/:id view.

Now if I do:

config.middleware.insert_before(Rack::Runtime, Rack::ReverseProxy) do 
      reverse_proxy_options preserve_host: true
      reverse_proxy '/users', 'http://google.com'
end

then this obviously redirects localhost:3000/users to google.com/users -- not exactly what I'm after!

To be honest I don't really know where to go from here :/

Any help or direction that you could give to make me able to render google.com in an iframe would be brilliant! I'm only trying to display the site - I don't need to be logging into an app through the iframe etc.

Thanks in advance

Nino

XML sitemap is not returned properly

Hi,

Everything works perfectly BUT the sitemap is not returned properly.

Although I am sure the sitemap.xml is where it is supposed to be, you can see it loads properly with direct URL:
http://blog.sexycrets.com/sitemap.xml

When I try to get it using the reverse proxy (which works perfectly for http://www.sexycrets.com/blog/):
http://www.sexycrets.com/blog/sitemap.xml
the XML is not returned.

What should I do? The only reason why I am using the reverse proxy is for SEO purposes but if the sitemap is not returned that defeats the whole purpose.

Thanks!

Session always times out

Hi,

I'm trying to proxy my blog, located at blog.mywebsite.com to mywebsite.com/blog.

I've followed the Readme and added this code to /config.rb

config.middleware.insert(0, Rack::ReverseProxy) do
    reverse_proxy_options preserve_host: false
    if Rails.env.production? or Rails.env.staging?
        reverse_proxy_options force_ssl: true, replace_response_host: true
    end
    reverse_proxy /^\/blog(\/?.*)$/, 'https://blog.mywebsite.com$1'
end

However when I try and visit mywebsite.com/blog it always times out.

It's also worth mentioning that it was working ok until I updated the gem.
Before I was just added this to my /config.ru file

use Rack::ReverseProxy do  
  reverse_proxy(/^\/blog(\/.*)$/,
    'https://blog.mywebsite.com$1',
    opts = {:preserve_host => true})
end  

run Rails.application

Can anyone please help me out?

Thanks

Request never completes when using a custom matcher/transformer class and StringIO

Just posting this here in case someone runs into the same issue. This is kind of related to #36.

TL:DR; If you're going to change the body, make sure you update the Content-Length header!

I found #51 and 2a0174f, so I followed the example in the test and set up my own matcher/transformer class like this:

class BlogProxyMatcherAndTransformer
  def self.match(path)
    return BlogProxyMatcherAndTransformer.new if path.match?(/^\/blog\//)
    false
  end

  def url(path)
    blog_path = path.sub(/^\/blog\//, '/')
    [ENV['BLOG_ROOT_URL'], blog_path].join('')
  end

  def transform(response, request_uri)
    Rails.logger.info "[rack-reverse-proxy]: #{request_uri}"
    status, headers, body = response

    headers['Cache-Control'] = 'public, max-age=31464028'
    headers['Expires'] = 1.year.from_now.httpdate

    unless response[1]['Content-Type']&.include?('text/html')
      return [status, headers, body] 
    end

    replaced_body = body.to_s
      .gsub(/<meta name="?robots"? content="?noindex"?>/, '')
    [status, headers, StringIO.new(replaced_body)]
  end
end

reverse_proxy BlogProxyMatcherAndTransformer

I didn't want any search engines to crawl the blog on a different domain, in case they find it. So I added the noindex meta tag, and then stripped it from the proxied response.

I found the StringIO example in this comment and thought I'd try that (but I wasn't calling target_response.send(:session).finish.)

I tried this out, but was getting errors on staging:

screen shot 2019-01-03 at 2 10 42 am

$ curl https://mystagingapp.com/blog/
...
curl: (92) HTTP/2 stream 1 was not closed cleanly: INTERNAL_ERROR (err 2)

Also:

$ curl http://localhost:3000/blog/
...
curl: (18) transfer closed with 34 bytes remaining to read

Then I saw that I could just use a plain array (in #36), so I tried that.

This still gave me the same error when trying it locally. The curl request would hang, and then give me the error:

curl: (18) transfer closed with 34 bytes remaining to read

So I went back to #41 and tried adding the #finish method as well. That didn't work - when I called to_s on the body, this already closes the HTTP session.

I started looking at rack-proxy. Realized why #to_s was closing the HTTP session.

At this point I double-checked to make sure my code was causing the issue. I just returned the original instance of Rack::HttpStreamingResponse, and this worked fine (the curl request completed normally.)

I tried a new StreamWrapper class:

        class StreamingResponseWrapper
          def initialize(streaming_response)
            @streaming_response = streaming_response
          end

          def each
            @streaming_response.each do |string|
              replaced_string = string
                .gsub(/<meta name="?robots"? content="?noindex"?>/, '')
              yield(replaced_string)
            end
          end
        end

But this had the same issue. When I returned the original string, everything worked. When I removed the meta tag, the curl request hung, and it also didn't work in the browser.

Then I finally realized that it was because I was sending the original Content-Length header! I was removing bytes from the response, and curl was still waiting for me to send them.

I tried deleting the Content-Length header to see if Rack would recreate it, but it just sent "Content-Length: 0".

So I finally got it working by calling: headers['Content-Length'] = replaced_body.length.to_s

Then I also realized that I was doing this for HEAD requests with curl -I, which set the Content-Length to 0 (because body was an empty string), so that also needed to be fixed. I was able to find the request method by calling body.instance_variable_get('@request').method, and then checking that it equals GET. (Then this actually returns the wrong Content-Length, because it doesn't know about the removed bytes. I don't know if this really matters, since browsers will only be making GET requests.)

Here's the working code:

class BlogProxyMatcherAndTransformer
  def self.match(path)
    if path.match?(/^\/blog\//)
      return BlogProxyMatcherAndTransformer.new
    end

    false
  end

  def url(path)
    blog_path = path.sub(/^\/blog\//, '/')
    [ENV['BLOG_ROOT_URL'], blog_path].join('')
  end

  def transform(response, request_uri)
    Rails.logger.info "[rack-reverse-proxy]: #{request_uri}"
    status, headers, body = response

    headers['Cache-Control'] = 'public, max-age=31464028'
    headers['Expires'] = 1.year.from_now.httpdate

    method = body.instance_variable_get('@request').method

    # Ignore HEAD requests and anything that's not HTML
    unless method == 'GET' && headers['Content-Type']&.include?('text/html')
      return response
    end

    replaced_body = body.to_s
      .gsub(/<meta name="?robots"? content="?noindex"?>/, '')

    # IMPORTANT: Also update the content length!
    headers['Content-Length'] = replaced_body.length.to_s

    [status, headers, [replaced_body]]
  end
end

reverse_proxy BlogProxyMatcherAndTransformer

[SSL] Read error: #<NoMethodError: undefined method `each' for "":String>

Hi,

I'm using Rack::ReverseProxy on a Rails app which is pointed by a custom domain jeparticipe.bordeaux.fr, and redirect to another Rails app.

I'm using SSL on my custom domain so I've added the following configuration on the proxy app :

use Rack::ReverseProxy do
reverse_proxy /^\/?(.*)$/, 'http://jetaide.herokuapp.com/$1', force_ssl: true, replace_response_host: true
end

but I get the following error as I test the SSL redirection throught http://jeparticipe.bordeaux.fr:
Read error: #<NoMethodError: undefined method `each' for "":String> and you can fin attached the full trace.

Any idea where the problem could come from?

Thanks,

Lucas
screen shot 2016-09-26 at 23 57 42

Not Found The requested URL /blog/ was not found on this server.

I installed the gem and add this code in my config/application.rb

class Application < Rails::Application
config.middleware.insert(0, Rack::ReverseProxy) do
reverse_proxy_options preserve_host: true
reverse_proxy /^/blog(/?.*)$/, 'http://exemple.com'
end
end

When I visit the page "mysite.com/blog" this message appear: "Not Found The requested URL /blog/ was not found on this server."

Any idea? (My site is hosted on Heroku)
Thx

Custom response based on source request

Use-case

My company's main web application (heroku) and marketing site (wordpress) are served at the same subdomain (www). The root/empty path (e.g. https://www.mysite.com) and some other whitelisted paths are reverse-proxied to wordpress, while the rest are served by a Rails app.

We wanted to make it such that if a request comes in for the root path AND they have a specific cookie (a session cookie for our app), redirect them into the application. Otherwise, reverse-proxy as usual to wordpress.

Solution

Currently I've monkey-patched this gem to support this use-case:

module RackReverseProxy
  class RoundTrip
    private

    alias_method :proxy_original, :proxy

    def proxy
      return app.call(env) if uri.nil?

      if options[:custom_response]
        response = options[:custom_response].call(source_request)
        return response if response
      end

      proxy_original
    end
  end
end

# In config.ru:
custom_response = proc do |request|
  [302, { 'Location' => "#{request.base_url}/app" }, []] if request.cookies['_my_app_session']
end

reverse_proxy(/^$/, passback_host, :custom_response => custom_response)

Just wondering if this is something other people have run into and/or this is something you'd want to bake into this gem. I'm happy turn this into a PR if so.

Extra characters in response from rails puma nginx centos server

For example, original response is

[{"id":87494,"price":5880,"brand":{"name":"Versace"},"image":{"source":"/http/img10.360buyimg.com/n1/jfs/t1477/195/122968247/98768/683edf16/555c57f1N8501c015.jpg"}}]

from http://api.secipin.com/guide/products.json?per=1

Using reverse_proxy /.*/, 'http://api.secipin.com' I got response

a5
[{"id":87494,"price":5880,"brand":{"name":"Versace"},"image":{"source":"/http/img10.360buyimg.com/n1/jfs/t1477/195/122968247/98768/683edf16/555c57f1N8501c015.jpg"}}]
0

It is not recurred on OS X nginx or puma.

Request starts timing out after a while

Dear Repo Maintainer - @waterlink ,

Thanks for developing this gem, it helped us lot!

I have been using this gem for a while on my site - https://www.activityhero.com to server blog under https://www.activityhero.com/blog it worked great for couple of days but now request to any url for blog just times out :(

Please help me solve this issue (Gem.lock).

I am using this version of gem:

rack-reverse-proxy (0.12.0)
   rack (>= 1.0.0)
   rack-proxy (~> 0.6, >= 0.6.1)

Here is my config (application.rb)

config.middleware.insert(0, Rack::Deflater)
config.middleware.use Rack::Attack
  config.middleware.insert(0, Rack::ReverseProxy) do
    reverse_proxy_options preserve_host: true
    reverse_proxy %r{^\/blog(\/?.*)$}, 'https://activityheroblog.com$1'
 end

Logs I seeing on my heroku server are as follows:

29 Jan 2018 21:32:18.846188 <190>1 2018-01-29T16:02:18.546116+00:00 app web.1 - - E, [2018-01-29T16:02:18.546003 #26] ERROR -- : app error: execution expired (Net::OpenTimeout)
29 Jan 2018 21:32:18.847210 <190>1 2018-01-29T16:02:18.546143+00:00 app web.1 - - E, [2018-01-29T16:02:18.546087 #26] ERROR -- : /app/vendor/ruby-2.3.4/lib/ruby/2.3.0/net/http.rb:880:in `initialize'
29 Jan 2018 21:32:18.847204 <190>1 2018-01-29T16:02:18.546146+00:00 app web.1 - - E, [2018-01-29T16:02:18.546110 #26] ERROR -- : /app/vendor/ruby-2.3.4/lib/ruby/2.3.0/net/http.rb:880:in `open'
29 Jan 2018 21:32:18.847216 <190>1 2018-01-29T16:02:18.546150+00:00 app web.1 - - E, [2018-01-29T16:02:18.546129 #26] ERROR -- : /app/vendor/ruby-2.3.4/lib/ruby/2.3.0/net/http.rb:880:in `block in connect'
29 Jan 2018 21:32:18.847206 <190>1 2018-01-29T16:02:18.546178+00:00 app web.1 - - E, [2018-01-29T16:02:18.546146 #26] ERROR -- : /app/vendor/ruby-2.3.4/lib/ruby/2.3.0/timeout.rb:101:in `timeout'
29 Jan 2018 21:32:18.847207 <190>1 2018-01-29T16:02:18.546193+00:00 app web.1 - - E, [2018-01-29T16:02:18.546170 #26] ERROR -- : /app/vendor/ruby-2.3.4/lib/ruby/2.3.0/net/http.rb:878:in `connect'
29 Jan 2018 21:32:18.847208 <190>1 2018-01-29T16:02:18.546220+00:00 app web.1 - - E, [2018-01-29T16:02:18.546191 #26] ERROR -- : /app/vendor/ruby-2.3.4/lib/ruby/2.3.0/net/http.rb:863:in `do_start'
29 Jan 2018 21:32:18.847205 <190>1 2018-01-29T16:02:18.546244+00:00 app web.1 - - E, [2018-01-29T16:02:18.546213 #26] ERROR -- : /app/vendor/ruby-2.3.4/lib/ruby/2.3.0/net/http.rb:858:in `start'
29 Jan 2018 21:32:18.847244 <190>1 2018-01-29T16:02:18.546268+00:00 app web.1 - - E, [2018-01-29T16:02:18.546237 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-proxy-0.6.3/lib/rack/http_streaming_response.rb:71:in `session'
29 Jan 2018 21:32:18.847245 <190>1 2018-01-29T16:02:18.546293+00:00 app web.1 - - E, [2018-01-29T16:02:18.546261 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-proxy-0.6.3/lib/rack/http_streaming_response.rb:60:in `response'
29 Jan 2018 21:32:18.847244 <190>1 2018-01-29T16:02:18.546318+00:00 app web.1 - - E, [2018-01-29T16:02:18.546286 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-proxy-0.6.3/lib/rack/http_streaming_response.rb:29:in `headers'
29 Jan 2018 21:32:18.847268 <190>1 2018-01-29T16:02:18.546343+00:00 app web.1 - - E, [2018-01-29T16:02:18.546311 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/roundtrip.rb:166:in `rack_response_headers'
29 Jan 2018 21:32:18.847269 <190>1 2018-01-29T16:02:18.546367+00:00 app web.1 - - E, [2018-01-29T16:02:18.546336 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/roundtrip.rb:157:in `build_response_headers'
29 Jan 2018 21:32:18.848263 <190>1 2018-01-29T16:02:18.546392+00:00 app web.1 - - E, [2018-01-29T16:02:18.546361 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/roundtrip.rb:153:in `response_headers'
29 Jan 2018 21:32:18.848269 <190>1 2018-01-29T16:02:18.546417+00:00 app web.1 - - E, [2018-01-29T16:02:18.546385 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/roundtrip.rb:182:in `need_replace_location?'
29 Jan 2018 21:32:18.848270 <190>1 2018-01-29T16:02:18.546442+00:00 app web.1 - - E, [2018-01-29T16:02:18.546410 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/roundtrip.rb:172:in `replace_location_header'
29 Jan 2018 21:32:18.848269 <190>1 2018-01-29T16:02:18.546466+00:00 app web.1 - - E, [2018-01-29T16:02:18.546435 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/roundtrip.rb:197:in `setup_response_headers'
29 Jan 2018 21:32:18.848252 <190>1 2018-01-29T16:02:18.546490+00:00 app web.1 - - E, [2018-01-29T16:02:18.546459 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/roundtrip.rb:209:in `proxy'
29 Jan 2018 21:32:18.848250 <190>1 2018-01-29T16:02:18.546514+00:00 app web.1 - - E, [2018-01-29T16:02:18.546484 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/roundtrip.rb:21:in `call'
29 Jan 2018 21:32:18.848251 <190>1 2018-01-29T16:02:18.546538+00:00 app web.1 - - E, [2018-01-29T16:02:18.546507 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/rack-reverse-proxy-0.12.0/lib/rack_reverse_proxy/middleware.rb:25:in `call'
29 Jan 2018 21:32:18.848269 <190>1 2018-01-29T16:02:18.546562+00:00 app web.1 - - E, [2018-01-29T16:02:18.546532 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-4.3.0.335/lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
29 Jan 2018 21:32:18.848224 <190>1 2018-01-29T16:02:18.546586+00:00 app web.1 - - E, [2018-01-29T16:02:18.546555 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.9/lib/rails/engine.rb:518:in `call'
29 Jan 2018 21:32:18.848229 <190>1 2018-01-29T16:02:18.546611+00:00 app web.1 - - E, [2018-01-29T16:02:18.546579 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.9/lib/rails/application.rb:165:in `call'
29 Jan 2018 21:32:18.848232 <190>1 2018-01-29T16:02:18.546635+00:00 app web.1 - - E, [2018-01-29T16:02:18.546603 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.9/lib/rails/railtie.rb:194:in `public_send'
29 Jan 2018 21:32:18.849235 <190>1 2018-01-29T16:02:18.546659+00:00 app web.1 - - E, [2018-01-29T16:02:18.546628 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/railties-4.2.9/lib/rails/railtie.rb:194:in `method_missing'
29 Jan 2018 21:32:18.849269 <190>1 2018-01-29T16:02:18.546684+00:00 app web.1 - - E, [2018-01-29T16:02:18.546653 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/newrelic_rpm-4.3.0.335/lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
29 Jan 2018 21:32:18.849240 <190>1 2018-01-29T16:02:18.546708+00:00 app web.1 - - E, [2018-01-29T16:02:18.546677 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:606:in `process_client'
29 Jan 2018 21:32:18.849237 <190>1 2018-01-29T16:02:18.546732+00:00 app web.1 - - E, [2018-01-29T16:02:18.546701 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:702:in `worker_loop'
29 Jan 2018 21:32:18.849247 <190>1 2018-01-29T16:02:18.546756+00:00 app web.1 - - E, [2018-01-29T16:02:18.546725 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:549:in `spawn_missing_workers'
29 Jan 2018 21:32:18.849231 <190>1 2018-01-29T16:02:18.546785+00:00 app web.1 - - E, [2018-01-29T16:02:18.546750 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/unicorn-5.3.0/lib/unicorn/http_server.rb:142:in `start'
29 Jan 2018 21:32:18.849227 <190>1 2018-01-29T16:02:18.546811+00:00 app web.1 - - E, [2018-01-29T16:02:18.546778 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/unicorn-5.3.0/bin/unicorn:126:in `<top (required)>'
29 Jan 2018 21:32:18.849195 <190>1 2018-01-29T16:02:18.546834+00:00 app web.1 - - E, [2018-01-29T16:02:18.546804 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/bin/unicorn:22:in `load'
29 Jan 2018 21:32:18.849207 <190>1 2018-01-29T16:02:18.546858+00:00 app web.1 - - E, [2018-01-29T16:02:18.546828 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/bin/unicorn:22:in `<top (required)>'
29 Jan 2018 21:32:18.849227 <190>1 2018-01-29T16:02:18.546882+00:00 app web.1 - - E, [2018-01-29T16:02:18.546851 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/cli/exec.rb:74:in `load'
29 Jan 2018 21:32:18.849234 <190>1 2018-01-29T16:02:18.546906+00:00 app web.1 - - E, [2018-01-29T16:02:18.546876 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/cli/exec.rb:74:in `kernel_load'
29 Jan 2018 21:32:18.849226 <190>1 2018-01-29T16:02:18.546931+00:00 app web.1 - - E, [2018-01-29T16:02:18.546900 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/cli/exec.rb:27:in `run'
29 Jan 2018 21:32:18.849223 <190>1 2018-01-29T16:02:18.546955+00:00 app web.1 - - E, [2018-01-29T16:02:18.546924 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/cli.rb:360:in `exec'
29 Jan 2018 21:32:18.850246 <190>1 2018-01-29T16:02:18.546981+00:00 app web.1 - - E, [2018-01-29T16:02:18.546948 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
29 Jan 2018 21:32:18.850261 <190>1 2018-01-29T16:02:18.547005+00:00 app web.1 - - E, [2018-01-29T16:02:18.546973 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
29 Jan 2018 21:32:18.850244 <190>1 2018-01-29T16:02:18.547032+00:00 app web.1 - - E, [2018-01-29T16:02:18.546998 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/vendor/thor/lib/thor.rb:369:in `dispatch'
29 Jan 2018 21:32:18.850226 <190>1 2018-01-29T16:02:18.547057+00:00 app web.1 - - E, [2018-01-29T16:02:18.547026 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/cli.rb:20:in `dispatch'
29 Jan 2018 21:32:18.850246 <190>1 2018-01-29T16:02:18.547081+00:00 app web.1 - - E, [2018-01-29T16:02:18.547050 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/vendor/thor/lib/thor/base.rb:444:in `start'
29 Jan 2018 21:32:18.850223 <190>1 2018-01-29T16:02:18.547106+00:00 app web.1 - - E, [2018-01-29T16:02:18.547075 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/cli.rb:10:in `start'
29 Jan 2018 21:32:18.872333 <158>1 2018-01-29T16:02:18.631439+00:00 heroku router - - at=info method=POST path="/provider_stats_events.json" host=www.activityhero.com request_id=372edaa0-3cea-4205-a1b0-dee6d722bad9 fwd="42.2.184.175,162.158.178.44" dyno=web.2 connect=1ms service=27ms status=200 bytes=1174 protocol=https
29 Jan 2018 21:32:18.925235 <190>1 2018-01-29T16:02:18.547130+00:00 app web.1 - - E, [2018-01-29T16:02:18.547099 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/exe/bundle:30:in `block in <top (required)>'
29 Jan 2018 21:32:18.925251 <190>1 2018-01-29T16:02:18.547223+00:00 app web.1 - - E, [2018-01-29T16:02:18.547123 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/lib/bundler/friendly_errors.rb:121:in `with_friendly_errors'
29 Jan 2018 21:32:18.925226 <190>1 2018-01-29T16:02:18.547250+00:00 app web.1 - - E, [2018-01-29T16:02:18.547217 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/gems/bundler-1.15.2/exe/bundle:22:in `<top (required)>'
29 Jan 2018 21:32:18.925194 <190>1 2018-01-29T16:02:18.547275+00:00 app web.1 - - E, [2018-01-29T16:02:18.547244 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/bin/bundle:22:in `load'
29 Jan 2018 21:32:18.925196 <190>1 2018-01-29T16:02:18.547297+00:00 app web.1 - - E, [2018-01-29T16:02:18.547268 #26] ERROR -- : /app/vendor/bundle/ruby/2.3.0/bin/bundle:22:in `<main>'

Intentionally handling a not found error in pass through request

I've set up a proxy to redirect a wildcard for my blog. Would like to have some intentional handling around a 404 error if the path I'm passing through doesn't have a destination and gets a 404.

What's the best way to go about this?

config.middleware.insert(0, Rack::ReverseProxy) do
  reverse_proxy /^\/blog(\/?.*)$/, 'http://blog.mysite.com$1'
end

In this example, let's say the following are valid:

  • /blog (goes to http://blog.mysite.com)
  • /blog/my-article (goes to http://blog.mysite.com/my-article)

But the following is NOT valid

  • /blog/does-not-exist (gets a 404 from http://blog.mysite.com/does-not-exist)

I'd like to catch that error and redirect to a page in my Rails app (not something behind the reverse proxy). Is this possible? and how?

Location getting mangled

My rails app is on example.com, my wordpress blog is hosted on blog.example.com, and I'm using rack-reverse-proxy to stream the blog through example.com/blog.

I'm using force_ssl so I also have replace_response_host.

Most things are working pretty well, but on some wordpress actions the Location afterward gets mangled. example:

Wordpress produces: users.php?update=add&id=16

rack-reverse-proxy rewrites it as: http://example.comusers.php?update=add&id=16

The full URL should be: http://example.com/blog/wp-admin/users.php?update=add&id=16

Backing up a bit: I'm actually not sure what standalone replace_response_host is useful for, or why it ever has to run other than when redirecting http -> https.

Let me know what you think and I'll try to contribute a PR, either to code or documentation.

Thanks for a 🌈super helpful✨ project!

Replace (proxy) at all body links

first of all thanks for your gem.

when i use the gem at mydomain.com/blog if proxies perfect pointing to my mydomain.wordpress.com blog. The problem is when I click any link it redirect to my mydomain.wordpress.com/link . I'd like to keep it under same domain for every click for SEO purposes.

Matching on the host and path?

First off, thanks very much this gem, I find it most useful

I would love to do something like this:

reverse_proxy /^http://(.+?).example.com/foo$/, 'http://$1.otherplace.com/'

As you can see it involves matching on the whole URL.

Is there anyway to do this currently?

Content Download Taking too long when Connection: "keep-alive"

I've configured 3 Rails App to be my backend and, to avoid configuring nginx on localhost, I hosted my frontend app inside an Rails App that works as reverse proxy.

Everything works fine, except the fact that each request takes at least 20 seconds to respond.
Looking in detail at these requests, I've found this curl to simulate my browser requests:

curl 'http://localhost:3000/iss_towns/7175/history.json' -H 'Host: localhost:3000' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0' -H 'Accept: application/json, text/plain, /' -H 'Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3' --compressed -H 'X-XSRF-TOKEN: dZ1BnjPkR47qsDPTx5HvifkkBPy2H9vpogrEh4L98vcdls8HyZqj7asSvW0kGLOYfiMApyxhs4IGgMnAp6a8Ww==' -H 'Referer: http://localhost:3000/' -H 'Cookie: XSRF-TOKEN=dZ1BnjPkR47qsDPTx5HvifkkBPy2H9vpogrEh4L98vcdls8HyZqj7asSvW0kGLOYfiMApyxhs4IGgMnAp6a8Ww%3D%3D; -H 'Connection: keep-alive' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache'

If I do the same request without -H 'Connection: keep-alive' everything works fine. Do you guys have some workaround or know which may be causing this issue?

Thanks a lot!

Relative url does not work

I set this in application.rb
config.middleware.insert(0, Rack::ReverseProxy) do
reverse_proxy_options preserve_host: false
reverse_proxy_options replace_response_host: true
reverse_proxy %r{^/blog(/.*)$} , 'http://localhost:8089$1'
end

the initial path works fine, but when I try to navigate to a relative address, the rule is lost and I get the following error.
No route matches [GET] "/ path"
note that it points to the root and not the path established in the rule.

What can I do to solve this?

sorry for my bad English

No 'Access-Control-Allow-Origin' header is present on the requested resource

Hi,
Thanks for sharing this GEM.
I am trying to use the gem following this article https://medium.com/@parterburn/wordpress-inside-a-ruby-on-rails-app-c324fbf39ad8#.wjiweptf8 which is to setup a WP blog on '/blog' for Rails app.
Everything seems to be working fine except that the loaded page has access control issues: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I set the response header from WP to allow access control (it has Access-Control-Allow-Origin:* in the response header. but the page still seems to block some content.
Anything you can suggest that may resolve it?
Thanks

expected behavior for compressed responses?

None of my responses which are compressed on the source server end up compressed when coming back from the proxy server. I haven't investigated why this is yet. First wanted to ask, what is the expected behavior?

Remove rack-reverse-proxy

Hey there!
I was following this tut https://hackernoon.com/wordpress-inside-a-ruby-on-rails-app-c324fbf39ad8
in order to make it what it say, WordPress inside ruby on rails, the result is that I fail to complete this.

Anyway, I create the config.ru and add the gem to the gem file, now I want to remove it.

  • If I remove the config.ru when I want to boot the server I get: configuration config.ru not found
  • if I remove the gem from the gem file and run bundle, I get his: configuration config.ru not found

Now I have the config.ru and remove the gem from the gem file i get this:
config.ru:6:in block in

': uninitialized constant Rack::ReverseProxy (NameError)`

How should I approach this?

Timeout with Heroku

I am trying this gem for production on Heroku but after few seconds, I have some timeout requests (it fails with only 15 online users)

2019-04-11T21:28:29.469474+00:00 heroku[router]: at=error code=H12 desc="Request timeout" method=GET path="/fr/foo/bar" host=mywebsite.com request_id=9c3c8364-e483-44ad-9d55-d030fcb10c6b fwd="90.46.112.209" dyno=web.1 connect=0ms service=30000ms status=503 bytes=0 protocol=https

My configuration is pretty simple:

reverse_proxy /\/fr\/foo(\/?.*)$/i, "#{ENV['NEW_APP_URL']}/fr/foo$1"

Am I missing something?

Proxy all requests that not found

I tried by hacking matcher#match. Is there a better way to do that?

Rails.application.config.middleware.use Rack::ReverseProxy do
  matcher = Class.new
  matcher.define_singleton_method :match do |url|
    !File.exist?(File.join(Rails.root, 'public', url)) && url !~ /^\/assets\// && !(Rails.application.routes.recognize_path(url) rescue nil)
  end
  reverse_proxy matcher, 'http://api.secipin.com'
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.