Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to connect through 127.0.0.1 when bound to localhost #782

Closed
Tonkpils opened this issue Sep 11, 2015 · 36 comments
Closed

Unable to connect through 127.0.0.1 when bound to localhost #782

Tonkpils opened this issue Sep 11, 2015 · 36 comments

Comments

@Tonkpils
Copy link

I'm not sure if this issue has been raised and I can't find any reference to it here but stemming from: rails/rails#19815 (comment)

Using rails s on WebRick allows using localhost and 127.0.0.1 to connect but when switching to puma this behavior changes and does not allow 127.0.0.1

Is this intended behavior for Puma or would you be open for a fix?

@ArturT
Copy link

ArturT commented Sep 18, 2015

I had this problem and I was looking for solution. I'm not sure what is exactly the reason of this behaviour but here are things I found out and solution to fix this in my app.

When I start rails server then puma listens on localhost:3000

$ rails server
=> Booting Puma
=> Rails 4.2.3 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
Puma 2.13.4 starting...
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:3000

and http://127.0.01:3000 doesn't work.

When I start puma explicitly without config file then it listens on tcp://0.0.0.0:3000 and http://127.0.01:3000 does work.

Read more https://github.com/puma/puma#configuration-file

$ puma -C '-'
Puma starting in single mode...
* Version 2.13.4 (ruby 2.2.3-p173), codename: A Midsummer Code's Dream
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://0.0.0.0:3000

When I created my custom config file then it works as well
bundle exec puma -C config/puma.rb

# config/puma.rb
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end

@Tonkpils
Copy link
Author

From my understanding both rails and rack moved away from defaulting the listening host to 0.0.0.0 as it caused security implications. They then moved to listening on localhost. Starting the app with puma command actually does listening on 0.0.0.0 which pretty much listens on all network interfaces.

On other webservers, namely Unicorn and Webrick listening on localhost allows accessing the server from 127.0.0.1 as well as localhost. Puma doesn't seem to follow that same behavior though.

@evanphx
Copy link
Member

evanphx commented Sep 18, 2015

If anyone can replicate the issue, I'd be happy to fix it. I tried a bunch of combos of rails/puma/ruby this morning and couldn't get it to pop up.

@Tonkpils
Copy link
Author

@evanphx I simply started puma with rails s and tried curling 127.0.0.1 which gives me connection refused. Once I curl localhost it works just fine.

image

@evanphx
Copy link
Member

evanphx commented Sep 18, 2015

@Tonkpils What version of ruby? What OS? Because ruby and the OS translate localhost into an address, I think those are the variables here.

@Tonkpils
Copy link
Author

Ruby 2.2.1 and OS X Yosemite.

@Tonkpils
Copy link
Author

So, it seems that accessing '[::1]:3000' works instead of 127.0.0.1. So correct me if I'm wrong, Puma is being asked to connect to localhost but Ruby or the OS translates that to IPv6 or IPv4 and puma then uses that to connect?

@evanphx
Copy link
Member

evanphx commented Sep 18, 2015

Well, puma passes whatever the host you want to bind to directly to TCPServer.new, it doesn't do anything with it other than passing it along. So the handling of localhost as the value is entirely up to Ruby and and the OS.

@Tonkpils
Copy link
Author

I'm assuming unicorn and webrick are connecting some different way than TCPServer.

In any case, I'll close this as a non-issue since this is not puma's issue.

@graudeejs
Copy link

Having this issue on FreeBSD as well

Commenting out

::1         localhost

in /etc/hosts
seams to fix this issue.

I think it's Puma issue

@chadzink
Copy link

chadzink commented Jan 4, 2016

@evanphx: Having this same issue on OSX El Capitan, this definitely seems like a puma issue. The trick ^^^ worked, not sure what ::1 localhost means in the hosts file though.

@Tonkpils
Copy link
Author

Tonkpils commented Jan 4, 2016

@chadzink ::1 localhost simply means that accessing localhost will point to IPv6 address ::1. It's simply a name resolution.

@gryphon
Copy link

gryphon commented Jan 20, 2016

The same for me. Got this issue after El Capitan upgrade.
Seems that Puma checks hostname of HTTP request to be equal to what it is binded to.

@kshahkshah
Copy link

If you're visiting this thread you may be forgetting that you might now, by default, be using IPv6 networking. As a result your resolution of localhost turns to ::1 rather than 127.0.0.1. So any aliases you had on that line in your /etc/hosts need to be duplicated or moved to the ::1 line.

@himdel
Copy link

himdel commented Feb 24, 2016

To clarify, it's still a puma bug if localhost can resolve to both 127.0.0.1 and ::1 - which it does on some systems.

@modx-space
Copy link

Hi @himdel , any plan to fix this?

@himdel
Copy link

himdel commented Mar 1, 2016

@shawzt not sure.. I'd love to, but essentially what happens is TCPServer.new('localhost', port) - which makes me think the bug is not quite a puma bug but a TCPServer bug.

If you need a workaround and use puma only from rails, this works...

diff --git a/lib/puma/binder.rb b/lib/puma/binder.rb
index 6cb8909..2751484 100644
--- a/lib/puma/binder.rb
+++ b/lib/puma/binder.rb
@@ -236,6 +236,12 @@ module Puma
     # allow to accumulate before returning connection refused.
     #
     def add_tcp_listener(host, port, optimize_for_latency=true, backlog=1024)
+      if host == 'localhost'
+        add_tcp_listener('127.0.0.1', port, optimize_for_latency, backlog)
+        add_tcp_listener('::1', port, optimize_for_latency, backlog)
+        return
+      end
+
       host = host[1..-2] if host and host[0..0] == '['
       s = TCPServer.new(host, port)
       if optimize_for_latency

(but it's clearly not the right place to fix this).

@himdel
Copy link

himdel commented Mar 1, 2016

... and according to ext/socket/tcpserver.c, it is supposed to return the first successfully created socket for one of the addresses returned by getaddrinfo.

So I guess I'll leave it to somebody who's already touched puma before :)

@alecguintu
Copy link

+1 here. Just want to know how/where will I add those snippet code to @himdel?

@himdel
Copy link

himdel commented Mar 30, 2016

@alecguintu if you look at it carefully, you'll see that it mentions both the file name and the line numbers..

@alecguintu
Copy link

Haha. I mean, where do I find the file binder.rb? I've checked on rails app, there is no puma folder under lib folder.

@insanux
Copy link

insanux commented Mar 30, 2016

/.rvm/gems/ruby-2.2.4/gems/puma-3.2.0/lib/puma/binder.rb

@himdel
Copy link

himdel commented Mar 30, 2016

@alecguintu probably the safest way to find the right file would be gem contents puma (should list all the files from the puma gem, with their whole actual paths)

@alecguintu
Copy link

Thanks so much for this @himdel!

@Eduzenet
Copy link

Thank you @himdel! now it works with 127.0.0.1 and ::1

@agrberg
Copy link

agrberg commented May 2, 2016

For those coming here who access their Rails server via an alias you can simply duplicate your alias as @whistlerbrk said. For example, if your alias is www.fakewebsite.com you'll want the following two lines in your /etc/hosts file:

127.0.0.1    www.fakewebsite.com
::1    www.fakewebsite.com

Looking at what @graudeejs and @himdel said in this comment it seems like puma is matching the first valid address in your /etc/hosts file. If yours is like mine it'll start with:

127.0.0.1 localhost
::1    localhost

so for IPv4 you get 127.0.0.1 and for IPv6 you get ::1. Removing the latter doesn't seem to force IPv4 for me as it may have for @graudeejs so I just added the second alias for ::1.

I'll comment back if I figure out anything more or how this potentially effects production.

@tomascharad
Copy link

Hi guys,

This is a very important issue.

I was trying to proxy some requests from webpack-dev-server and had a very hard time to figure that I should change localhost:3000 to [::1]:3000.

@RobinDaugherty
Copy link
Contributor

I just want to mention why this is such an issue. Issues like this cause developers to turn off IPv6 on their machine rather than a more complicated workaround. This is bad for the community and the Internet at large. We need to encourage IPv6 adoption, and every "minor" issue like this is a blocker.

@evanphx
Copy link
Member

evanphx commented Jul 18, 2016

Hi y'all,

I'm going to go ahead and release @himdel's fix, I think it's a perfectly acceptable way to manage this issue. Sorry for the delay, the release will be out later today.

@yohayg
Copy link

yohayg commented Jan 19, 2017

I'm using: bundle exec rails server Puma -b 0.0.0.0 -p 3000 which works just fine

@babinslava
Copy link

I'm using rackup -p 7000 -o 127.0.0.1

@RobinDaugherty
Copy link
Contributor

This bug has been fixed, so localhost should work correctly with or without IPv6. Using 0.0.0.0 makes the server available to everyone on every wireless network you connect to, and 127.0.0.1 does not work with IPv6. Please leave it the default or use localhost.

@yohayg: your advice leaves people open to unintended public access. It would be best if you remove your comment.

@sfcgeorge
Copy link

I had this same issue that I couldn't connect locally to Puma aka curl [::1]:3000 failed. Fixed it without disabling IPv6 by forcing Puma to listen on localhost rather than 127.0.0.1 which it was for some reason using by default.

bundle exec rails s -b localhost -p 3000 

So the above command works with IPv4 and IPv6.

@RobinDaugherty
Copy link
Contributor

RobinDaugherty commented Jun 18, 2018

@sfcgeorge glad to hear that localhost is working as intended. Do you know where that default value of 127.0.0.1 was coming from? Was it in your puma.rb or somewhere like that?

@sfcgeorge
Copy link

@RobinDaugherty I don't wish to be the harbinger of reopened issues but I believe our app is just using the defaults. My machine is macOS High Sierra (experiencing the issue), whereas my colleague's machine running an older version of macOS is unaffected and seems to work fine.

@RobinDaugherty
Copy link
Contributor

And in my case, the default is 0.0.0.0, running Rails 4.2 on High Sierra. I suspect it's a Rails default, but I haven't had time to dig deeper.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests