<h1>Gunicorn<aclass="headerlink"href="#gunicorn"title="Link to this heading">¶</a></h1>
<p><aclass="reference external"href="https://gunicorn.org/">Gunicorn</a> is a pure Python WSGI server with simple configuration and
multiple worker implementations for performance tuning.</p>
<ulclass="simple">
<li><p>It tends to integrate easily with hosting platforms.</p></li>
<li><p>It does not support Windows (but does run on WSL).</p></li>
<li><p>It is easy to install as it does not require additional dependencies
or compilation.</p></li>
<li><p>It has built-in async worker support using gevent or eventlet.</p></li>
</ul>
<p>This page outlines the basics of running Gunicorn. Be sure to read its
<aclass="reference external"href="https://docs.gunicorn.org/">documentation</a> and use <codeclass="docutils literal notranslate"><spanclass="pre">gunicorn</span><spanclass="pre">--help</span></code> to understand what features
are available.</p>
<sectionid="installing">
<h2>Installing<aclass="headerlink"href="#installing"title="Link to this heading">¶</a></h2>
<p>Gunicorn is easy to install, as it does not require external
dependencies or compilation. It runs on Windows only under WSL.</p>
<p>Create a virtualenv, install your application, then install
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">-w</span></code> option specifies the number of processes to run; a starting
value could be <codeclass="docutils literal notranslate"><spanclass="pre">CPU</span><spanclass="pre">*</span><spanclass="pre">2</span></code>. The default is only 1 worker, which is
probably not what you want for the default worker type.</p>
<p>Logs for each request aren’t shown by default, only worker info and
errors are shown. To show access logs on stdout, use the
<h2>Binding Externally<aclass="headerlink"href="#binding-externally"title="Link to this heading">¶</a></h2>
<p>Gunicorn should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as <aclass="reference internal"href="nginx.html"><spanclass="doc">nginx</span></a> or <aclass="reference internal"href="apache-httpd.html"><spanclass="doc">Apache httpd</span></a> should be used
in front of Gunicorn.</p>
<p>You can bind to all external IPs on a non-privileged port using the
<codeclass="docutils literal notranslate"><spanclass="pre">-b</span><spanclass="pre">0.0.0.0</span></code> option. Don’t do this when using a reverse proxy setup,
otherwise it will be possible to bypass the proxy.</p>
<p><codeclass="docutils literal notranslate"><spanclass="pre">0.0.0.0</span></code> is not a valid address to navigate to, you’d use a specific
IP address in your browser.</p>
</section>
<sectionid="async-with-gevent-or-eventlet">
<h2>Async with gevent or eventlet<aclass="headerlink"href="#async-with-gevent-or-eventlet"title="Link to this heading">¶</a></h2>
<p>The default sync worker is appropriate for many use cases. If you need
asynchronous support, Gunicorn provides workers using either <aclass="reference external"href="https://www.gevent.org/">gevent</a>
or <aclass="reference external"href="https://eventlet.net/">eventlet</a>. This is not the same as Python’s <codeclass="docutils literal notranslate"><spanclass="pre">async/await</span></code>, or the
ASGI server spec. You must actually use gevent/eventlet in your own code
to see any benefit to using the workers.</p>
<p>When using either gevent or eventlet, greenlet>=1.0 is required,
otherwise context locals such as <codeclass="docutils literal notranslate"><spanclass="pre">request</span></code> will not work as expected.