Wrong IP-Address with nginx + Unicorn + rails - ruby-on-rails-3

I check the ip-address in the controller with
request.env['REMOTE_ADDR']
this works fine in my test environment.
But on the production server with nginx + unicorn I always get 127.0.0.1.
This is my nginx config for the site:
upstream unicorn {
server unix:/tmp/unicorn.urlshorter.sock fail_timeout=0;
}
server {
listen 80 default deferred;
# server_name example.com;
root /home/deployer/apps/urlshorter/current/public;
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri #unicorn;
location #unicorn {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}

I had trouble with this too; I found this question, but the other answer didn't help me.
I looked at Rails 3.2.8's implementation of Rack::Request#ip to see how it decided what to say; to get it to use an address passed via the environment without filtering out addresses from my local network (it's trying to filter out intermediate proxies, but that's not what I wanted), I had to set the HTTP_CLIENT_IP from my nginx proxy configuration block in addition to what you've got above (X-Forwarded-For has to be there too for this to work!):
proxy_set_header CLIENT_IP $remote_addr;

If you use request.remote_addr you'll get the of your Nginx proxy.
To get the real IP address of your user, you can use request.remote_ip.
According to Rails' source code, it checks for various http headers to give you the most relevant one : in Rails 3.2 or Rails 4.0.0.beta1

The answer is in your config file :) The following should do what you want:
real_ip = request.headers["X-Real-IP"]
more here: http://api.rubyonrails.org/classes/ActionDispatch/Request.html#method-i-headers
UPDATE: The proper answer is here in another Q:
https://stackoverflow.com/a/4465588
or in this thread:
https://stackoverflow.com/a/15883610
spoiler:
use request.remote_ip

For ELB - nginx - rails you want to follow this guide:
http://engineering.blopboard.com/resolving-real-client-ip-with-amazon-elb-nginx-and-php-fpm
See:
server {
listen 443 ssl spdy proxy_protocol;
set_real_ip_from 10.0.0.0/8;
real_ip_header proxy_protocol;
location /xxx {
proxy_http_version 1.1;
proxy_pass <api-endpoint>;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-By $server_addr:$server_port;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header CLIENT_IP $remote_addr;
proxy_pass_request_headers on;
}
...

The proxy_set_header CLIENT_IP $remote_addr; didn't work for me. Here's what did..
The solution I found after reviewing the actiondispatch code remote_ip.rb source. Now I get proper IP in my devise/warden processes as well as any other routine I'm looking at request.remote_ip
My config...
Ruby 2.2.1 - Rails 4.2.1 - NGINX v1.8.0 - Unicorn v4.9.0 - Devise v3.4.1
nginx.conf
HTTP_CLIENT_IP vs CLIENT_IP
location #unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HTTP_CLIENT_IP $remote_addr; <-----
proxy_redirect off;
proxy_pass http://unicorn;
}
Source actionpack-4.2.1/lib/action_dispatch/middleware/remote_ip.rb
Line 114:
client_ips = ips_from('HTTP_CLIENT_IP').reverse
Line 126:
"HTTP_CLIENT_IP=#{#env['HTTP_CLIENT_IP'].inspect} " +

Related

Mailcow SOGO with Nginx login errors with a 502

I have an Nginx Proxy Manager server sitting in front of the mailcow Nginx server. Everything works fine ... the Sogo page loads. But when I try to login it issues a 502... logs on all servers don't really point to any issues.
Add the following to your Custom Nginx Configuration found in the advanced tab
location / {
proxy_pass http://site.you.want:9007/;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
client_max_body_size 0;
proxy_buffer_size 128k;
proxy_buffers 64 512k;
proxy_busy_buffers_size 512k;
}

Nginx proxy for vue and fastapi

I am trying to deploy my app with vue.js as frontend and fastapi as backend. But I am having issue when deploy the app on the cloud. I have nginx configure like below.
I am binding backend to port 8080 and frontend to 8000. But with this configuration, I can only see my frontend page. The backend api is not respond. Can anyone show me how to fix it?
server {
listen 80;
server_name example.com;
charset utf-8;
root vis/dist;
index index.html index.htm;
location /api/ {
proxy_pass http://127.0.0.1:8000;
}
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_redirect off;
proxy_connect_timeout 90s;
proxy_read_timeout 90s;
proxy_send_timeout 90s;
}
error_log /var/log/nginx/vue-app-error.log;
access_log /var/log/nginx/vue-app-access.log;
}

Running Apache Zeppelin with nginx as reverse proxy

In our current architecture we have two apache front servers, in front of them, we have an nginx load balancer. And in front of that an nginx reverse proxy.
My problem is that i'm trying to run Apache Zeppelin through the reverse proxy, and i'm having some problems with the websockets.
I get an error like this : 400 HTTP method GET is not supported by this URL
And here is a screenshot of what the Chrome's Networks tab shows :
I add my reverse proxy config for Zeppelin:
error_log /var/log/nginx/nginx_error.log warn;
server {
listen 80;
server_name localhost;
location /zeppelin/ {
proxy_pass http://zeppelin:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection upgrade;
}
# fallback
location / {
return 301 http://ci.blablalablab.com/app/;
}
}
Zeppelin is running inside a docker container, and i have exposes the 8080 port, its host name is : zeppelin.
If you have any questions on the architecture or so, don't hesitate to ask.
Thank you very much guys !
you can add to your reverse proxy configuration
location /ws { # For websocket support
proxy_pass http://zeppelin:8080/ws;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection upgrade;
proxy_read_timeout 86400;
}
Reference: Zeppelin 0.7 auth docs
After a lot of digging around, i ended up with this configuration :
location /zeppelin/ {
proxy_pass http://zeppelin:8080/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
}
location /zeppelin/ws {
proxy_pass http://zeppelin:8080/ws;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
This is working pretty good, thank you everyone for your efforts ;)

Configure Nginx as reverse proxy for Couchdb

I have a Couchdb database that should not be accessed directly, so I need to use a reverse proxy.
How to configure Nginx or apache as a reverse proxy for Couchdb?
To reverse proxy in nginx, you need a config that looks like this https://www.nginx.com/resources/admin-guide/reverse-proxy/
upstream mycouch {
server 192.168.0.100:
}
server {
listen *:80;
server_name mycouch.mydomain.whatever.com;
underscores_in_headers on;
location / {
expires off;
proxy_pass http://mycouch;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
This will proxy HTTP calls for your couchdb. Since you tagged this question with docker, if you wanted to bake a container with this stuff, I'd suggest you start FROM nginx, https://hub.docker.com/_/nginx/ (or, just mount a config file in to nginx image as is)
Based on #djcrabhat replay, I created this config to enables replication
...
location / {
proxy_pass http://192.168.99.100:5984 //couchdb address
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~ ^/(.*)/_changes {
proxy_pass http://192.168.99.100:5984 //couchdb address
proxy_redirect off;
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
...

neo4j webinterface behind nginx reverse proxy

I'm trying to expose a neo4j database to the internet.
For security reasons, I'd like to hide it behind a SSL/basic_auth combination via nginx. Here is the corresponding nginx config:
location /neo4j/ {
proxy_pass https://localhost:7473/;
proxy_read_timeout 600;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X_FORWARDED_PROTO https;
proxy_set_header Host $http_host;
proxy_buffering off;
proxy_redirect off;
auth_basic "restricted";
auth_basic_user_file /etc/nginx/auth/htpasswd;
proxy_headers_hash_max_size 1024;
proxy_headers_hash_bucket_size 128;
proxy_ssl_session_reuse off;
rewrite /neo4j/(.*) /$1 break;
}
While I'm able to access https://example.com/neo4j/browser, the webinterface tells me, that it can't connect to the neo4j and my webbrowser's console gets filled up with OPTIONS https://example.com/db/data 405(Not allowed)
I also tried the neo4j built in https server in conjunction with the authentication extension (https://github.com/neo4j-contrib/authentication-extension).
With this option, I also can access the webinterface.
But the interface also displays, that it's not able to connect to the neo4j and the webbrowser's console gets filled up with OPTIONS http://example.com:7473/db/data/ net::ERR_EMPTY_RESPONSE and the hint The page at 'https://example.com:7473/browser/' was loaded over HTTPS, but displayed insecure content from 'http://example.com:7473/db/data/': this content should also be loaded over HTTPS.
Does anyone know, how to get it working? Many thanks in advance!
I came across the same problem and it's kind of weird the lack of info about Nginx as a webserver combined with neo4j. It's odd the only reference to a reverse proxy in the official doc is Apache - not impressed.
Just FYI I'm using a dockerised neo4j (https://github.com/neo4j/docker-neo4j/tree/master/2.3.2) as it comes by default (in case you want to know other settings). It should not matter if you run neo4j natively outside docker. The following Nginx conf will be the same.
location /neo4j/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://YOUR-IP:7474/browser/;
}
location /db/data/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://YOUR-IP:7474/db/data/;
}
Replace YOUR-IP by yours and change 7474 for 7473 if you are using HTTPS instead of HTTP.
This worked for me.
The OPTIONS request is needed to verify the connection to the Neo4j server. I think of it as a heartbeat to verify the connection. It seems that Nginx does not support OPTIONS requests, but the request can be intercepted with something like this:
location / {
if ($request_method = OPTIONS ) {
add_header Access-Control-Allow-Origin "https://example.com";
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization";
add_header Access-Control-Allow-Credentials "true";
add_header Content-Length 0;
add_header Content-Type text/plain;
return 200;
}
}
Source: http://blog.rogeriopvl.com/archives/nginx-and-the-http-options-method/