Skip to content

Commit 962e798

Browse files
authored
Configure gunicorn to bind to the IPv6 interface (#241)
By default when the `PORT` env var is set, gunicorn binds to the IPv4 interface `0.0.0.0:$PORT`: https://docs.gunicorn.org/en/stable/settings.html#bind Now, we configure it to bind to the IPv6 interface `[::]:$PORT` instead, allowing the app to work in IPv6-only environments. We don't have it bind to both the IPv4 and IPv6 interfaces, since otherwise on Linux by default gunicorn would fail to boot with: ``` [ERROR] connection to ('::', 5006) failed: [Errno 98] Address already in use ``` ...and when binding to the IPv6 interface IPv4 connections will still work (so long as `IPV6_V6ONLY` hasn't been enabled). If this strategy causes issues, we could always start using the `reuse_port` option, however, that makes the DX worse for the local development use-case (it's then possible to leave a stale gunicorn process running, which will serve requests and give the impression code changes aren't taking effect). I've added a `gunicorn.conf.py` config file rather than passing CLI args to the `gunicorn` command, since it allows for more flexibility with the configuration (and there are other settings we'll be adding soon). See: https://docs.gunicorn.org/en/stable/configure.html GUS-W-17280180.
1 parent 0c83b7c commit 962e798

File tree

3 files changed

+18
-2
lines changed

3 files changed

+18
-2
lines changed

Procfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
web: gunicorn gettingstarted.wsgi
1+
web: gunicorn --config gunicorn.conf.py gettingstarted.wsgi
22

33
# Uncomment this `release` process if you are using a database, so that Django's model
44
# migrations are run as part of app deployment, using Heroku's Release Phase feature:

gettingstarted/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
if IS_HEROKU_APP:
5454
ALLOWED_HOSTS = ["*"]
5555
else:
56-
ALLOWED_HOSTS = [".localhost", "127.0.0.1", "[::1]", "0.0.0.0"]
56+
ALLOWED_HOSTS = [".localhost", "127.0.0.1", "[::1]", "0.0.0.0", "[::]"]
5757

5858

5959
# Application definition

gunicorn.conf.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Gunicorn configuration file:
2+
# https://docs.gunicorn.org/en/stable/configure.html
3+
# https://docs.gunicorn.org/en/stable/settings.html
4+
# Note: The classic Python buildpack currently sets a few gunicorn settings automatically via
5+
# the `GUNICORN_CMD_ARGS` env var (which take priority over the settings in this file):
6+
# https://github.com/heroku/heroku-buildpack-python/blob/main/vendor/python.gunicorn.sh
7+
8+
import os
9+
10+
# The `PORT` env var is set automatically for web dynos and when using `heroku local`:
11+
# https://devcenter.heroku.com/articles/dyno-startup-behavior#port-binding-of-web-dynos
12+
# https://devcenter.heroku.com/articles/heroku-local
13+
_port = os.environ.get("PORT", 5006)
14+
# Bind to the IPv6 interface instead of the gunicorn default of IPv4, so the app works in IPv6-only
15+
# environments. IPv4 connections will still work so long as `IPV6_V6ONLY` hasn't been enabled.
16+
bind = [f"[::]:{_port}"]

0 commit comments

Comments
 (0)