Question

ipv6 results in 502, ipv4 doesn't.

I have recently set up a new droplet using the Django One-Click Application Image. During installation I enabled ipv6, but now I can’t get it working: Requests using ipv6 result in a 502, and for the past hours I was unable to figure out why.

I have setup nginx to listen for ipv6 requests:

upstream app_server { # server 127.0.0.1:9000 fail_timeout=0; server unix:/home/django/gunicorn.socket fail_timeout=0; }

server { listen 80 default_server; listen [::]:80 default_server ipv6only=on; server_name myaddress.net www.myaddress.net;

return 301 https://$server_name$request_uri;

}

server { listen 443 ssl http2 default_server; listen [::]:443 ssl http2 ipv6only=on; server_name myaddress.net www.myaddress.net;

(…)

location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
        proxy_buffering off;

        proxy_pass http://app_server;
}

}

But requests using ipv6 result in the following error:

2017/05/11 04:05:07 [error] 31425#31425: *8 upstream prematurely closed connection while reading response header from upstream, client: (requesting ipv6), server:(servername), request: “GET / HTTP/2.0”, upstream: “http://unix:/home/django/gunicorn.socket:/”, host: “(droplet ipv6)”

Requests directly to https://(ipv4-address) result in the “Welcome to Django”-page being displayed.

I have tried to figure this out for the last four hours or so, but at this point I have no idea where I could continue looking.

Any ideas/pointers into some direction?


Submit an answer

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Sign In or Sign Up to Answer

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in Q&A, subscribe to topics of interest, and get courses and tools that will help you grow as a developer and scale your project or business.

Okay, I got it.

I set the ALLOWED_HOSTS variable correctly, but it was overriden. In the very bottom of the settings.py file the following was added:

Find out what the IP addresses are at run time

This is necessary because otherwise Gunicorn will reject the connections

def ip_addresses(): ip_list = [] for interface in netifaces.interfaces(): addrs = netifaces.ifaddresses(interface) for x in (netifaces.AF_INET, netifaces.AF_INET6): if x in addrs: ip_list.append(addrs[x][0][‘addr’]) return ip_list

Discover our IP address

ALLOWED_HOSTS = ip_addresses()

When this code executes it changes the ALLOWED_HOSTS variable. Apparently it can only detect the IPv4 address. When commenting out the very last line

Discover our IP address

ALLOWED_HOSTS = ip_addresses()

Everything works as intended.

I used the checkbox “IPv6” during setup.

When I look into the gunicorn errorlogs it shows me the following:

(…) File “/usr/lib/python2.7/dist-packages/django/template/base.py”, line 849, in _resolve_lookup current = current() File “/usr/lib/python2.7/dist-packages/django/http/request.py”, line 152, in build_absolute_uri host=self.get_host(), File “/usr/lib/python2.7/dist-packages/django/http/request.py”, line 102, in get_host raise DisallowedHost(msg) DisallowedHost: Invalid HTTP_HOST header: ‘[myIPv6]’. You may need to add ‘[myIPv6]’ to ALLOWED_HOSTS.

(…) File “/usr/lib/python2.7/dist-packages/django/template/base.py”, line 849, in _resolve_lookup current = current() File “/usr/lib/python2.7/dist-packages/django/http/request.py”, line 152, in build_absolute_uri host=self.get_host(), File “/usr/lib/python2.7/dist-packages/django/http/request.py”, line 102, in get_host raise DisallowedHost(msg) DisallowedHost: Invalid HTTP_HOST header: ‘www.myaddress.net’. You may need to add u’www.myaddress.net’ to ALLOWED_HOSTS.

Depenging on whether or not I request directly via IP or via my address.

This puzzles me, since djangos settings.py file looks like this:

ALLOWED_HOSTS = [‘‘, u’jmyaddress.net’,u’www.myaddress.net’,'[]’,]

and AFAIK the ‘*’ entry should allow all connections.

@antoniocarlosdimeo

From NGINX 1.3.4 and up, the default for ipv6only is set to on, so that part of your configuration isn’t needed and can be removed from the server blocks.

NGINX also has an issue with setting ipv6only multiple times which causes it to fail to start, so even if this option was required, you could only set it on one server block per port. The reason it works in the configuration you’ve posted is because you have it set on two different ports (80 and 443). If you tried to set it on another server block using the same ports, it’s cause the issue mentioned.

So:

listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

becomes:

listen 80 default_server;
listen [::]:80 default_server;

and:

listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 ipv6only=on;

becomes:

listen 443 ssl http2 default_server;
listen [::]:443 ssl http2;

That said, additionally, you shouldn’t need the ssl directive in the second server block as HTTP/2 is SSL only. So the second server block should actually be:

listen 443 http2 default_server;
listen [::]:443 http2;

Unless you’re planning on hosting multiple domains on this Droplet, and you need a catch-all of sorts for requests that don’t match other domains, you can also remove the default_server directives too.

So all cleaned up, we’d end up with:

listen 80;
listen [::]:80;

and

listen 443 http2;
listen [::]:443 http2;

Beyond the above changes, the rest of the configuration appears to be valid.

Was IPv6 enabled on this Droplet when you deployed it or was it enabled after deployment? Do you have logging setup for your Flask app? If so, what’s the log file showing?