-
-
Notifications
You must be signed in to change notification settings - Fork 14
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
One second delay to resolve DNS query on localhost? #7
Comments
Try
|
Try
|
You need something like auto = AutoServer.new([
[:udp, '127.0.0.1', $port],
[:udp, '::1', $port]
]) Honestly, RubyDNS / async-dns is one of the oldest parts of this project and should be updated to fit with how endpoints work now. |
Using What is a quick summary of the reason why? |
When you run the server on IPv4 only, but you try to use |
Let me know if you need more details. Happy to explain in explicit detail. |
If we hook this into a resolver, can this little bit of code be used instead of having to run |
Yes, people have already done it, but it's something worth exploring if it interests you. https://rubygems.org/gems/rubydns/reverse_dependencies e.g. vagrant-dns |
On # macos: create a resolver for a TLD
tld=test
sudo mkdir -p /etc/resolver
sudo bash -c "echo -e 'nameserver 127.0.0.1\nport 2346' > /etc/resolver/${tld}" This resolver would then "answer for" any requests being made to our given TLD (which is By doing things this way, we have a super simple way to resolve wildcard hostnames and always return our If we combine this with creating a single wildcard SSL certificate for the same domain, we wouldn't need to do all the complex stuff with LetsEncrypt. I've got a way to create a simple wildcard SSL cert and a way to auto-trust it on mac. This would "close the loop" and allow us to support wilcard https for development, in a very simple way! |
That makes sense, and it's great to see a summary of how it all fits together. I would be cautious of putting platform specific stuff into falcon. That being said, maybe there is room for a tool to do this in development. The purpose of Lets Encrypt/ACME protocol is for seamless production deployment. Your enthusiasm makes me happy. |
For example, this concept might fit with the localhost gem. https://github.com/socketry/localhost If we can support both Linux and macOS, that would be ideal. If we put this into that gem, it probably makes the most sense to me. Essentially: Generate a certificate for this hostname with this TLD, and make sure the local OS responds to it. It's not directly part of certificate creation, but I imagine it can be useful to expose another interface that works together well. |
I've got something working that should be a great option for "seamless, out of the box" local development with Falcon using HTTP/2 (which requires https and SSL/TLS certificates). Let's say that we are developing three local apps,
You can handle (1) by manually updating the You can handle (2) by either creating a new self-signed certificate for each app and then importing it into the certificate store or using the ACME protocol with a service like LetsEncrypt to generate a per-site or per-app SSL certificate. These approaches require manual tweaking for each app and installing additional software to run a LetsEncrypt agent and have it periodically update the certificates, since they have relatively short expiration periods. In short, both areas don't really have good solutions, which can make it sort of painful to use them with HTTP/2 for local development with Falcon. To solve these two items, we can do the following:
For (1), we actually have two things that we need to do. Not only do we need to run a DNS server that will respond with # macOS: Create a resolver for our base domain
base=local.dev
sudo mkdir -p /etc/resolver
sudo bash -c "echo -e 'nameserver 127.0.0.1\nport 2346' > /etc/resolver/${base}" If we now try to lookup a host such as The DNS server that Falcon can launch for us looks like this: #!/usr/bin/env ruby
require 'async/dns'
$ipv4 = '127.0.0.1'
$ipv6 = '::1'
$port = 2346
class AutoServer < Async::DNS::Server
def process(who, rsc, txn)
txn.respond! $ipv4 # $ipv4
end
end
puts "autoserver listening on #{$ipv4}:#{$port}"
auto = AutoServer.new([
[:udp, $ipv4, $port],
[:tcp, $ipv4, $port],
])
auto.run With the above resolver and server, then any request such as ping -o something.local.dev
PING something.local.dev (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.036 ms
--- something.local.dev ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 0.036/0.036/0.036/0.000 ms So, with very little effort we are now able to resolve any of our apps' hostnames to point to Falcon. One down, one to go. For (2), we need a way to generate a wildcard SSL certificate that will work for all of our apps. On macOS, here's how this was accomplished: # enter our base domain (we'll prepend each app name)
base=local.dev
# create the config file for the wildcard SSL certificate
cat > ${base}.cnf <<-end
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
CN = ${base}
[v3_req]
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = ${base}
DNS.2 = *.${base}
end
# from the wildcard SSL config file, generate the key and cert files
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 -sha1 \
-config ${base}.cnf \
-keyout ${base}.key \
-out ${base}.crt
# import and trust our new wildcare SSL certificate
sudo /usr/bin/security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ${base}.crt As a side note, these Now that we have created the key and cert files, we give them to Falcon so we can properly serve secure content over HTTP/2. Here's the #!/usr/bin/env ruby
require "bundler/setup"
require "falcon"
require "async"
require "async/http"
# variables
cfgfile = "config.ru"
pub_url = "https://foo.local.dev:8443"
ssl_crt = "local.dev.crt"
ssl_key = "local.dev.key"
ps_name = "Falcon Server"
Async.logger.level = Logger::INFO
context = OpenSSL::SSL::SSLContext.new
context.add_certificate(
OpenSSL::X509::Certificate.new(File.read(ssl_crt)),
OpenSSL::PKey.read(File.read(ssl_key))
)
endpoint = Async::HTTP::URLEndpoint.parse(pub_url, ssl_context: context)
bound_endpoint = Async do
Async::IO::SharedEndpoint.bound(endpoint)
end.wait
rack_app, options = Rack::Builder.parse_file(cfgfile)
middleware = Falcon::Server.middleware(rack_app)
Async::Container::Forked.new(concurrency: 8, name: ps_name) do |task, instance|
server = Falcon::Server.new(middleware, bound_endpoint, endpoint.protocol, endpoint.scheme)
server.run
task.children.each(&:wait)
end With this in place, we just launch Falcon by running == NOTE: This is still pretty experimental, the instructions above are only for macOS, they don't really show how to actually serve up multiple apps from within Falcon (although all the hard parts are explained above). In essence, this "pretty much works", but needs some love to make it solid. Also, for those interested... on the SSL certificates you can create certificates as follows:
If you notice above, we use the following in the certificate configuration file:
This means that our base domain ( This blurb has turned into a long-winded crazy post, but I wanted to try to at least capture everything here in one place for future reference (or ridicule!). |
Sorry that this is posted to |
This all makes sense and is a good proof of concept. I think the logical place for the certificate stuff is in |
…7-dns-forwarding-query-upstream-fails-due-encoding-error to eblocker * commit '1cf8843514dd236901a4d281b9132cf960f24156': [EB1-1907] Workaround for ruby's (< 2.3) object.inspect bug triggered by queries containing UTF-8 encoded characters.
@shreeve where did we get to with this? |
The original issue has been resolved, so closing this. Feel free to open a discussion if you want to discuss how the other parts of this issue can be moved forward. Note that my recommended approach for local development with TLS is to use FQDNs e.g. |
If I run the following code,
Each response seems to be throttled at 1 second minimum. For example:
The
1.018s
,1.021s
, and1.018s
are so close to1.000s
that they imply there is a 1 second timeout somewhere.Any ideas?
The text was updated successfully, but these errors were encountered: