Nginx with docker not proxy my ruby ​​app correctly

I have two Docker containers (built from custom configured nginx and Ruby images) and when I start the containers and make requests, they seem to be proxy requests to the correct locations (but one of the services that are proxied doesn't handle the request perfectly correctly).

i.e. when I try to proxy to my Ruby container, I either get the error "Sinatra does not recognize this error" OR "301 redirects"?

Note: the code can also be found here https://github.com/Integralist/Docker-Examples/tree/master/Nginx

Below is the Dockerfile for nginx:

FROM ubuntu

# install nginx
RUN apt-get update && apt-get install -y nginx
RUN rm -rf /etc/nginx/sites-enabled/default

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log
RUN ln -sf /dev/stderr /var/log/nginx/error.log

EXPOSE 80 443
CMD ["nginx", "-g", "daemon off;"]

      

Below is the Dockerfile for the Ruby application:

FROM ruby:2.1-onbuild
CMD ["ruby", "app.rb"]

      

Note:
Someone asked how my app.rb

and other dependencies are loaded (since mine docker run

didn't mount them and the Dockerfile doesn't seem to add them). If you look at the ruby ​​"onbuild" tagged version of the image, you can see COPY

all these files for us https://github.com/docker-library/ruby/2.0/onbuild/Dockerfile

A Ruby application looks like this:

require "sinatra"

set :bind, "0.0.0.0"

get "/" do
  "Hello World"
end

      

And the file nginx.conf

looks like this:

user nobody nogroup;
worker_processes auto;          # auto-detect number of logical CPU cores

events {
  worker_connections 512;       # set the max number of simultaneous connections (per worker process)
}

http {
  upstream app {
    server app:4567;            # app is automatically defined inside /etc/hosts by Docker
  }

  server {
    listen *:80;                # Listen for incoming connections from any interface on port 80
    server_name "";             # Don't worry if "Host" HTTP Header is empty or not set
    root /usr/share/nginx/html; # serve static files from here

    location /app/ {            # catch any requests that start with /app/
      proxy_pass http://app;    # proxy requests onto our app server (i.e. a different container)
    }
  }
}

      

I start a Ruby container like this:

docker run --name ruby-app -p 4567:4567 -d my-ruby-app

      

I start nginx container like this:

docker run --name nginx-container \
  -v $(pwd)/html:/usr/share/nginx/html:ro \
  -v $(pwd)/docker-nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
  --link ruby-app:app \
  -P -d my-nginx

      

If I run it curl http://$(boot2docker ip):32785/app/

, I get back to the error "Sinatra is not know this ditty"; and if i run curl http://$(boot2docker ip):32785/app

will i return the message 301 Moved Permanently

?

I'm sure I'm missing something very obvious (maybe how Sinatra is set up? How do I need to configure the route /app

? Or should I use the directive alias

in nginx.conf

)

Any help was appreciated.

+3


source to share


2 answers


So it seems that the answer is subtlety about how nginx layout blocks work ...

If you don't put a slash / at the end of the ascending name, you will see that nginx passes the request as / app /, not just /

By placing / after the upstream name, it acts more like a directive alias

.

So this works ...



location /app/ {
  proxy_pass http://app/; # this is what I want
}

      

But that won't work ...

location /app/ {
  proxy_pass http://app; # this ISN'T what I want
}

      

0


source


So, I think there are only a few fundamental problems with what you are configuring and what you are testing.

First, you say to nginx: "When you get / app /, proxy into a container with sinatra":

location /app/ {            # catch any requests that start with /app/
  proxy_pass http://app;    # proxy requests onto our app server (i.e. a different container)
}

      

So this will be passed to Sinatra with the request URI being /app/

.

As you, your sinatra app didn't figure out this route, why are you getting "Sinatra doesn't know this melody".

The reason you get a 301 when you try to use it without a trailing slash is because sinatra will automatically redirect anything without a trailing slash.

As Dirk says, the reason you get "Hello world" on hit is:



curl http://$(boot2docker ip):4567/

      

This is because this route is defined in your sinatra itineraries if you click:

curl http://$(boot2docker ip):4567

      

then you should get 301 redirects to /.

To fix the problem, you need to:

  • Change your sinatra itinerary to "/ app".
  • Change your nginx location to / instead of / app /.

Option 2 will be the most flexible as any request to the nginx container will map directly to the sinatra container, as you added another route that you will need to update for the nginx config to add this proxying route to the sinatra container.

0


source







All Articles