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?
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!
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:
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
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
Everything works as intended.
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?
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.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.