Amazon ELB + Django HTTPS issues - django

I have been searching on SO but none of the solutions seem to work for my case:
I have a Classic Elastic Load Balancer from AWS, passing requests to my Nginx docker containers that also proxy passes to my python Gunicorn containers.
Nginx config:
server {
listen 80;
listen [::]:80;
...
if ($http_x_forwarded_proto = 'http') {
return 301 https://$server_name$request_uri;
}
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
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;
proxy_set_header X-Scheme $scheme;
proxy_pass http://app_server;
}
}
In my Django Settings I have :
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = False
The problem is, when a request is made to an endpoint, if I print(request.META.get('HTTP_X_FORWARDED_PROTO')) I get http instead of https. This causes my DRF auto-generated doc links to be generated in http instead of https.
Is there something wrong with my configurations?
How can I force https behind an ELB?

Just add
proxy_set_header X-Forwarded-Proto https;
in your nginx config. Your nginx will always be serving the clients using https as the ELB is configured to receive https traffic.
Also the reason $scheme may not have worked is because your nginx is still on http protocol and not https protocol

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 $proxy_x_forwarded_proto;

Related

Nginx proxy pass failed to proxy pass to Zipkin

I'm having trouble exposing Zipkin UI (running in a container) behind Nginx.
I have a spring microservices that I have deployed on an ec2 instance on AWS, and I used Nginx as a load balancer to map locations to upstream using proxy_pass, and I've configured a location mapped to Zipkin upstream just like this:
location /tracing/ {
return 302 /tracing/;
}
location /tracing {
proxy_pass http://localhost:9411/;
}
but when I enter this location in the browser it redirects me to another location / which is binded to another upstream
location / {
proxy_pass http://localhost:4200/;
}
I think this may help you
location /zipkin {
proxy_pass http://localhost:9411;
proxy_set_header Host $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-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-Proto $scheme;
}

Django next url to HTTPS (Nginx)

I have added a SSL certificate to my nginx application, everything works fine, but when django paginates for the next url it uses: http:// not https:// How can I change this?
I have solved the issue: Under proxy_pass http://django; SET
proxy_set_header Host $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;
Also need to set
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
in setting.py file.

How can I get public ip address in Django with Nginx as http server and gunicorn?

I want to get public IP address of clients but I just get 127.0.0.1 almost always.
I tested some solution, but no right answer found with my configuration (Django, Nginx and Gunicorn)
Here is my Nginx proxy config.
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
}
First, you should make nginx pass the client's remote address to the upstream server (gunicorn):
server {
location / {
proxy_pass http://proxy_addr;
proxy_set_header X-Real-IP $remote_addr;
}
}
Then you can access the remote addr in the django request's META like this:
ip_address = request.META["HTTP_X_REAL_IP"]
Note that you can use also dict.get to avoid a KeyError while running runserver:
ip_address = request.META.get("HTTP_X_REAL_IP")

Nginx Share Cookies Between Subdomains without Access to Backend

TLDR: How to share cookies between subdomains for a backend application sever that I cannot "configure" using nginx (1.8.x) as a proxy - some magical combination of proxy_*?
A tornado web server is running on "127.0.0.1:9999/ipython" that I cannot configure (it's running as part of an ipython notebook server). I'm using nginx to proxy from "www.mysite.com" to 127.0.0.1:9999 successfully (http traffic at least).
However, part of the backend application requires Websockets. Because I am using CloudFlare, I have to use a separate domain for Websockets ("Websockets are currently only available for Enterprise customers ... All other customers ... should create a subdomain for Websockets in their CloudFlare DNS and disable the CloudFlare proxy"). I'm using "ws.mysite.com".
When a user logs in at "https :// www.mysite.com", a cookie is set by the tornado web server for "www.mysite.com" (I can't seem to configure it, otherwise I would just set it to ".mysite.com"). When the websocket part of the application kicks in, it sends a request to "wss :// ws.mysite.com", but fails to authenticate because the cookie is set for a different domain("www.mysite.com").
Is it possible for nginx to "spoof" the domain so the tornado webserver registers it for ".mysite.com"? proxy_cookie_domain doesn't seem to work as I'd expect... Should I hard code "proxy_set_header Host"?
I was thinking a nginx conf similar to....
upstream ipython_server {
server 127.0.0.1:8888;
}
server {
listen 443;
server_name www.mysite.com;
ssl_certificate cert.crt;
ssl_certificate_key cert.key;
ssl on;
# **** THIS DOESN'T WORK ??? ****
proxy_cookie_domain www.mysite.com .mysite.com;
location /ipython/static {
proxy_pass https://ipython_server$request_uri;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /ipython/api/sessions {
proxy_pass https://ipython_server$request_uri;
proxy_set_header Host $host;
proxy_set_header Origin "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /ipython {
proxy_pass https://ipython_server$request_uri;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
try_files $uri $uri/ =404;
}
}
server {
listen 443;
server_name ws.azampagl.com;
ssl_certificate cert.crt;
ssl_certificate_key cert.key;
ssl on;
# **** THIS DOESN'T WORK ??? ****
proxy_cookie_domain ws.mysite.com .mysite.com;
# This is the websocket location
location /ipython/api/kernels/ {
proxy_pass https://ipython_server$request_uri;
proxy_redirect off;
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_read_timeout 86400;
proxy_set_header Host $host;
proxy_set_header Origin "";
proxy_set_header Upgrade websocket;
proxy_set_header Connection "upgrade";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
I've been looking in the nginx lua module? It looks like you can set cookie domains, but it looks hackish...
Thanks greatly in advance for your assistance!
(Side note: I do technically have access to the tornado configuration, but there is zero documentation on how to set the "cookie domain" for the server. i.e.
c.NotebookApp.tornado_settings = {'cookie_domain????':'.mysite.com'}
)

How can I run multiple Ring apps on the same server?

I’m new to Ring (and Clojure server-side programming in general). I have a Ring-based app that works well in “development mode”, i.e. it can listen on localhost:3000 and it responds appropriately. As part of deploying this app I’d like to change the base URL for the app to something like myserver.com/analytics/v1, so that for example a request that previously went to localhost:3000/foo should now go to myserver.com/analytics/v1/foo.
I guess I have two closely-related questions here: How can I tell Ring/Jetty to listen only at a certain URL that is not the root URL of the server? And how can I set this up so that I could add another app (for example, myserver.com/analytics/v2) without downtime for the first app? Do I need to write another Ring app that will listen on myserver.com/ and route the requests to my other apps as appropriate?
The way I'm currently handling this is let each Ring app run in it's own embedded Jetty instance, each listens on their own port, like for example: 8080 en 8085.
On the server I block these ports externally, so only localhost can access them.
Then I setup Nginx to select the right app based on the subdomain:
http://twitter.michielborkent.nl
http://tictactoe.michielborkent.nl
There are more advanced setups possible, but for me this is the one with least configuration.
Here is my nginx.conf. If you want to have more configuration details, just let me know.
server { listen 80;
server_name twitter.michielborkent.nl;
access_log /var/log/twitter-service.log;
location / {
proxy_pass http://localhost: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;
}
}
server { listen 80;
server_name tictactoe.michielborkent.nl;
access_log /var/log/tictactoe.log;
location / {
proxy_pass http://localhost:8085;
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;
}
}
Here’s how I adapted #Michiel Borkent’s nginx.conf to fit my needs:
server {
listen 80;
server_name www.myserver.com;
location /analytics/v1/ {
proxy_pass http://localhost:3001/;
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;
}
location /trac/ {
proxy_pass http://localhost:3002/trac/;
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;
}
}
With this situation I can just set my Ring app to serve on port 3001; I have Trac serving on port 3002, or I could have another Ring app or whatever. Both of these applications are accessible from www.myserver.com (port 80), just under different paths.