Introduction
When you set up a development environment using docker, you sometimes want to test your rails application with an nginx proxy. When using a non standard port (not 80 or 443), you get into the minor issue that nginx listens to port 80 in the container, but you map a different port in your docker-compose.yml
file.
nginx:
image: nginx:latest
ports:
- 8088:80
- ./contrib/nginx.dev.conf:/etc/nginx/conf.d/default.conf
My nginx configuration
upstream docdeposit {
server docdeposit:3000;
}
server {
#--- here lays dragons
listen 80;
server_name docdepos.it;
location / {
proxy_pass http://docdeposit;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Debugging your Rails application
class ApplicationController < ActionController::Base
...
def authorized
if signed_in?
true
else
ap request.env
redirect_to '/login'
end
end
end
# Testing the default behavior
So when testing my application I want to be redirected to http://localhost:8085/login.
```bash
$ curl -v http://localhost:8085
* Trying 127.0.0.1:8085...
* Connected to localhost (127.0.0.1) port 8085 (#0)
> GET / HTTP/1.1
> Host: localhost:8085
...
< HTTP/1.1 302 Found
...
< Location: http://localhost/login
...
<html><body>You are being <a href="http://localhost/login">redirected</a>.</body></html>
The debug output shows us that the application gets from the nginx server through the http headers.
"SERVER_PROTOCOL" => "HTTP/1.0",
"HTTP_HOST" => "localhost",
"HTTP_X_FORWARDED_FOR" => "172.26.0.1",
"HTTP_X_FORWARDED_PROTO" => "http",
"HTTP_CONNECTION" => "close",
"HTTP_USER_AGENT" => "curl/7.81.0",
"HTTP_ACCEPT" => "*/*",
"puma.request_body_wait" => 0.0034820139408111572,
"SERVER_NAME" => "localhost",
"SERVER_PORT" => "80",
"PATH_INFO" => "/",
So, now we change the following:
- Simple change in the
docker-compose.yml
file - One small change to the
default.conf
nginx configuration
In the docker-compose.yml
file, you can either reference to a variable set in your .env
file, or hard code it. I call the variable NGINX_PORT:
version: "3.9"
services:
nginx:
image: nginx:latest
links:
- docdeposit
ports:
- ${NGINX_PORT:-80}:80
volumes:
#- ./contrib/nginx.dev.conf:/etc/nginx/conf.d/default.conf
- ./contrib/nginx.dev.conf:/etc/nginx/templates/default.conf.template
environment:
#--- hard coded
#NGINX_PORT: "8085"
#--- Dynamicaly override the NGINX port in the config, so that rails redirect works properly
#--- in your local .env file, by setting the variable NGINX_PORT to something
#--- that is free on your computer (i.e `NGINX_PORT=8085`)
NGINX_PORT: "${NGINX_PORT:-80}"
The minor change in your nginx.dev.conf/default.conf
file:
upstream docdeposit {
server docdeposit:3000;
}
server {
#--- here lays dragons
listen 80;
server_name docdepos.it;
location / {
proxy_pass http://docdeposit;
# proxy_set_header Host $host;
proxy_set_header Host $host:${NGINX_PORT};
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
This is what you want to see, a proper redirect without having to reconfigure your rails application, only using the headers passed on from nginx:
(venv) [maglub@Magnuss-MBP-2:~/dev/kmg/demo/docdeposit (main)]$ curl -v http://localhost:8085
* Trying 127.0.0.1:8085...
* Connected to localhost (127.0.0.1) port 8085 (#0)
> GET / HTTP/1.1
> Host: localhost:8085
...
< HTTP/1.1 302 Found
...
< Location: http://localhost:8085/login
...
<html><body>You are being <a href="http://localhost:8085/login">redirected</a>.</body></html>
And this is what the debug output from the rails application looks like:
"SERVER_PROTOCOL" => "HTTP/1.0",
"HTTP_HOST" => "localhost:8085",
"HTTP_X_FORWARDED_FOR" => "172.26.0.1",
"HTTP_X_FORWARDED_PROTO" => "http",
"HTTP_CONNECTION" => "close",
"HTTP_USER_AGENT" => "curl/7.81.0",
"HTTP_ACCEPT" => "*/*",
"puma.request_body_wait" => 0.0033560097217559814,
"SERVER_NAME" => "localhost",
"SERVER_PORT" => "8085",
"PATH_INFO" => "/",