mirror of
https://github.com/kennethreitz/responder.git
synced 2026-06-05 14:50:19 +00:00
278 lines
19 KiB
HTML
278 lines
19 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<html lang="en" data-content_root="./">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
|
||
<title>Deployment — responder 3.6.2 documentation</title>
|
||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=5ecbeea2" />
|
||
<link rel="stylesheet" type="text/css" href="_static/basic.css?v=b08954a9" />
|
||
<link rel="stylesheet" type="text/css" href="_static/alabaster.css?v=27fed22d" />
|
||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css?v=76b2166b" />
|
||
<link rel="stylesheet" type="text/css" href="_static/design-elements.e5416f61bae5d36adc6d722a2b6f8cff.css?v=452a8e97" />
|
||
<script src="_static/documentation_options.js?v=c0c9fa11"></script>
|
||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||
<script src="_static/copybutton.js?v=fd10adb8"></script>
|
||
<script>
|
||
</script>
|
||
<script src="_static/design-elements.bbdccc18c4abea9397628f9fea3d48c2.js?v=03c7770e"></script>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
<link rel="next" title="Testing" href="testing.html" />
|
||
<link rel="prev" title="Feature Tour" href="tour.html" />
|
||
|
||
<link rel="stylesheet" href="_static/custom.css" type="text/css" />
|
||
|
||
|
||
|
||
|
||
|
||
</head><body>
|
||
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
|
||
|
||
<div class="body" role="main">
|
||
|
||
<section id="deployment">
|
||
<h1>Deployment<a class="headerlink" href="#deployment" title="Link to this heading">¶</a></h1>
|
||
<p>Responder applications are standard <a class="reference external" href="https://asgi.readthedocs.io/">ASGI</a>
|
||
apps. ASGI (Asynchronous Server Gateway Interface) is the modern successor
|
||
to WSGI — it supports async, WebSockets, and HTTP/2. This means you can
|
||
deploy a Responder app anywhere that runs Python, using any ASGI server.</p>
|
||
<section id="running-locally">
|
||
<h2>Running Locally<a class="headerlink" href="#running-locally" title="Link to this heading">¶</a></h2>
|
||
<p>During development, <code class="docutils literal notranslate"><span class="pre">api.run()</span></code> is all you need:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
||
<span class="n">api</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This starts a <a class="reference external" href="https://www.uvicorn.org/">uvicorn</a> server on
|
||
<code class="docutils literal notranslate"><span class="pre">127.0.0.1:5042</span></code>. Uvicorn is a lightning-fast ASGI server built on
|
||
<a class="reference external" href="https://uvloop.readthedocs.io/">uvloop</a> — it handles thousands of
|
||
concurrent connections efficiently and protects against slowloris attacks,
|
||
making a reverse proxy like nginx optional for many deployments.</p>
|
||
</section>
|
||
<section id="docker">
|
||
<h2>Docker<a class="headerlink" href="#docker" title="Link to this heading">¶</a></h2>
|
||
<p>Docker is the most common way to package and deploy web applications.
|
||
Here’s a minimal Dockerfile:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">FROM</span> <span class="n">python</span><span class="p">:</span><span class="mf">3.13</span><span class="o">-</span><span class="n">slim</span>
|
||
<span class="n">WORKDIR</span> <span class="o">/</span><span class="n">app</span>
|
||
<span class="n">COPY</span> <span class="o">--</span><span class="n">from</span><span class="o">=</span><span class="n">ghcr</span><span class="o">.</span><span class="n">io</span><span class="o">/</span><span class="n">astral</span><span class="o">-</span><span class="n">sh</span><span class="o">/</span><span class="n">uv</span><span class="p">:</span><span class="n">latest</span> <span class="o">/</span><span class="n">uv</span> <span class="o">/</span><span class="n">usr</span><span class="o">/</span><span class="n">local</span><span class="o">/</span><span class="nb">bin</span><span class="o">/</span><span class="n">uv</span>
|
||
<span class="n">COPY</span> <span class="o">.</span> <span class="o">.</span>
|
||
<span class="n">RUN</span> <span class="n">uv</span> <span class="n">pip</span> <span class="n">install</span> <span class="o">--</span><span class="n">system</span> <span class="n">responder</span>
|
||
<span class="n">ENV</span> <span class="n">PORT</span><span class="o">=</span><span class="mi">80</span>
|
||
<span class="n">EXPOSE</span> <span class="mi">80</span>
|
||
<span class="n">CMD</span> <span class="p">[</span><span class="s2">"python"</span><span class="p">,</span> <span class="s2">"api.py"</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Build and run:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ docker build -t myapi .
|
||
$ docker run -p 8000:80 myapi
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">python:3.13-slim</span></code> image is about 150MB — small enough for fast
|
||
deploys but includes everything you need. Using <code class="docutils literal notranslate"><span class="pre">uv</span></code> for installs
|
||
is significantly faster than pip. For even smaller images, you can use
|
||
<code class="docutils literal notranslate"><span class="pre">python:3.13-alpine</span></code>, though some packages may need extra build
|
||
dependencies.</p>
|
||
</section>
|
||
<section id="cloud-platforms">
|
||
<h2>Cloud Platforms<a class="headerlink" href="#cloud-platforms" title="Link to this heading">¶</a></h2>
|
||
<p>Responder automatically honors the <code class="docutils literal notranslate"><span class="pre">PORT</span></code> environment variable. When
|
||
<code class="docutils literal notranslate"><span class="pre">PORT</span></code> is set, the server binds to <code class="docutils literal notranslate"><span class="pre">0.0.0.0</span></code> on that port — this is
|
||
the convention that virtually every cloud platform uses.</p>
|
||
<p>This means zero configuration on:</p>
|
||
<ul class="simple">
|
||
<li><p><strong>Fly.io</strong> — <code class="docutils literal notranslate"><span class="pre">fly</span> <span class="pre">launch</span></code> and you’re done</p></li>
|
||
<li><p><strong>Railway</strong> — push your code, Railway sets <code class="docutils literal notranslate"><span class="pre">PORT</span></code></p></li>
|
||
<li><p><strong>Render</strong> — set start command to <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">api.py</span></code></p></li>
|
||
<li><p><strong>Google Cloud Run</strong> — containerize and deploy</p></li>
|
||
<li><p><strong>Azure Container Apps</strong> — same pattern</p></li>
|
||
<li><p><strong>AWS App Runner</strong> — and here too</p></li>
|
||
</ul>
|
||
<p>The pattern is always the same: deploy your code, set the start command
|
||
to <code class="docutils literal notranslate"><span class="pre">python</span> <span class="pre">api.py</span></code>, and the platform handles the rest.</p>
|
||
</section>
|
||
<section id="health-check-endpoint">
|
||
<h2>Health Check Endpoint<a class="headerlink" href="#health-check-endpoint" title="Link to this heading">¶</a></h2>
|
||
<p>Every production deployment needs a health check — a lightweight endpoint
|
||
that monitoring tools, load balancers, and orchestrators can poll to verify
|
||
your service is running:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@api</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">"/health"</span><span class="p">)</span>
|
||
<span class="k">def</span><span class="w"> </span><span class="nf">health</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">resp</span><span class="p">):</span>
|
||
<span class="n">resp</span><span class="o">.</span><span class="n">media</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"status"</span><span class="p">:</span> <span class="s2">"healthy"</span><span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Keep it simple. Don’t query the database or do expensive work — the health
|
||
check should return instantly. Cloud platforms, Docker, and Kubernetes all
|
||
look for an HTTP 200 to confirm your service is alive.</p>
|
||
<p>For Docker, add a <code class="docutils literal notranslate"><span class="pre">HEALTHCHECK</span></code> instruction:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">HEALTHCHECK</span> <span class="o">--</span><span class="n">interval</span><span class="o">=</span><span class="mi">30</span><span class="n">s</span> <span class="o">--</span><span class="n">timeout</span><span class="o">=</span><span class="mi">3</span><span class="n">s</span> \
|
||
<span class="n">CMD</span> <span class="n">curl</span> <span class="o">-</span><span class="n">f</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">localhost</span><span class="o">/</span><span class="n">health</span> <span class="o">||</span> <span class="n">exit</span> <span class="mi">1</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="uvicorn-directly">
|
||
<h2>Uvicorn Directly<a class="headerlink" href="#uvicorn-directly" title="Link to this heading">¶</a></h2>
|
||
<p>For production deployments where you want more control, bypass
|
||
<code class="docutils literal notranslate"><span class="pre">api.run()</span></code> and use uvicorn directly:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ uvicorn api:api --host 0.0.0.0 --port 8000 --workers 4
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">--workers</span></code> flag spawns multiple processes, each handling requests
|
||
independently. A good starting point is 2-4 workers per CPU core.</p>
|
||
<p>Uvicorn supports many options — SSL certificates, access logging, graceful
|
||
shutdown timeouts, and more. See the
|
||
<a class="reference external" href="https://www.uvicorn.org/deployment/">uvicorn documentation</a> for details.</p>
|
||
<p>For platforms like Heroku or Railway that use a <code class="docutils literal notranslate"><span class="pre">Procfile</span></code>:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>web: uvicorn api:api --host 0.0.0.0 --port $PORT --workers 4
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="docker-compose">
|
||
<h2>Docker Compose<a class="headerlink" href="#docker-compose" title="Link to this heading">¶</a></h2>
|
||
<p>For local development with databases and other services, Docker Compose
|
||
ties everything together:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># docker-compose.yml</span>
|
||
<span class="n">services</span><span class="p">:</span>
|
||
<span class="n">api</span><span class="p">:</span>
|
||
<span class="n">build</span><span class="p">:</span> <span class="o">.</span>
|
||
<span class="n">ports</span><span class="p">:</span>
|
||
<span class="o">-</span> <span class="s2">"5042:80"</span>
|
||
<span class="n">environment</span><span class="p">:</span>
|
||
<span class="o">-</span> <span class="n">PORT</span><span class="o">=</span><span class="mi">80</span>
|
||
<span class="o">-</span> <span class="n">DATABASE_URL</span><span class="o">=</span><span class="n">postgresql</span><span class="o">+</span><span class="n">asyncpg</span><span class="p">:</span><span class="o">//</span><span class="n">user</span><span class="p">:</span><span class="k">pass</span><span class="nd">@db</span><span class="o">/</span><span class="n">myapp</span>
|
||
<span class="o">-</span> <span class="n">SECRET_KEY</span><span class="o">=</span><span class="n">dev</span><span class="o">-</span><span class="n">secret</span>
|
||
<span class="n">depends_on</span><span class="p">:</span>
|
||
<span class="o">-</span> <span class="n">db</span>
|
||
|
||
<span class="n">db</span><span class="p">:</span>
|
||
<span class="n">image</span><span class="p">:</span> <span class="n">docker</span><span class="o">.</span><span class="n">io</span><span class="o">/</span><span class="n">postgres</span><span class="p">:</span><span class="mi">16</span><span class="o">-</span><span class="n">alpine</span>
|
||
<span class="n">environment</span><span class="p">:</span>
|
||
<span class="n">POSTGRES_USER</span><span class="p">:</span> <span class="n">user</span>
|
||
<span class="n">POSTGRES_PASSWORD</span><span class="p">:</span> <span class="k">pass</span>
|
||
<span class="n">POSTGRES_DB</span><span class="p">:</span> <span class="n">myapp</span>
|
||
<span class="n">volumes</span><span class="p">:</span>
|
||
<span class="o">-</span> <span class="n">pgdata</span><span class="p">:</span><span class="o">/</span><span class="n">var</span><span class="o">/</span><span class="n">lib</span><span class="o">/</span><span class="n">postgresql</span><span class="o">/</span><span class="n">data</span>
|
||
|
||
<span class="n">volumes</span><span class="p">:</span>
|
||
<span class="n">pgdata</span><span class="p">:</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Run with <code class="docutils literal notranslate"><span class="pre">docker</span> <span class="pre">compose</span> <span class="pre">up</span></code>. The API waits for <code class="docutils literal notranslate"><span class="pre">db</span></code> to start, then
|
||
connects using the <code class="docutils literal notranslate"><span class="pre">DATABASE_URL</span></code> environment variable.</p>
|
||
</section>
|
||
<section id="reverse-proxy">
|
||
<h2>Reverse Proxy<a class="headerlink" href="#reverse-proxy" title="Link to this heading">¶</a></h2>
|
||
<p>For high-traffic production deployments, you may want a reverse proxy like
|
||
<a class="reference external" href="https://nginx.org/">nginx</a> or <a class="reference external" href="https://caddyserver.com/">Caddy</a> in
|
||
front of your application for:</p>
|
||
<ul class="simple">
|
||
<li><p><strong>SSL/TLS termination</strong> — let the proxy handle HTTPS certificates</p></li>
|
||
<li><p><strong>Load balancing</strong> — distribute traffic across multiple app instances</p></li>
|
||
<li><p><strong>Static asset serving</strong> — offload static files to the proxy</p></li>
|
||
<li><p><strong>Rate limiting</strong> — at the infrastructure level</p></li>
|
||
</ul>
|
||
<p>A minimal Caddy config that handles HTTPS automatically:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Caddyfile</span>
|
||
<span class="n">example</span><span class="o">.</span><span class="n">com</span> <span class="p">{</span>
|
||
<span class="n">reverse_proxy</span> <span class="n">localhost</span><span class="p">:</span><span class="mi">5042</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Responder’s <code class="docutils literal notranslate"><span class="pre">TrustedHostMiddleware</span></code> and <code class="docutils literal notranslate"><span class="pre">HTTPSRedirectMiddleware</span></code> work
|
||
correctly behind proxies that set standard forwarding headers
|
||
(<code class="docutils literal notranslate"><span class="pre">X-Forwarded-For</span></code>, <code class="docutils literal notranslate"><span class="pre">X-Forwarded-Proto</span></code>).</p>
|
||
<p>That said, uvicorn is production-ready on its own. Many applications run
|
||
uvicorn directly without a reverse proxy and do just fine.</p>
|
||
</section>
|
||
<section id="production-checklist">
|
||
<h2>Production Checklist<a class="headerlink" href="#production-checklist" title="Link to this heading">¶</a></h2>
|
||
<p>Before going live:</p>
|
||
<ul class="simple">
|
||
<li><p><strong>Set a secret key</strong> — <code class="docutils literal notranslate"><span class="pre">SECRET_KEY</span></code> env var, never the default</p></li>
|
||
<li><p><strong>Disable debug mode</strong> — <code class="docutils literal notranslate"><span class="pre">DEBUG=false</span></code> or omit it entirely</p></li>
|
||
<li><p><strong>Set allowed hosts</strong> — restrict to your actual domain names</p></li>
|
||
<li><p><strong>Use multiple workers</strong> — <code class="docutils literal notranslate"><span class="pre">--workers</span> <span class="pre">4</span></code> or more, depending on CPU cores</p></li>
|
||
<li><p><strong>Add a health check</strong> — <code class="docutils literal notranslate"><span class="pre">/health</span></code> endpoint for monitoring</p></li>
|
||
<li><p><strong>Enable HTTPS</strong> — via your proxy, cloud platform, or uvicorn’s <code class="docutils literal notranslate"><span class="pre">--ssl-*</span></code> flags</p></li>
|
||
<li><p><strong>Set up logging</strong> — uvicorn logs requests by default; pipe them to your log aggregator</p></li>
|
||
<li><p><strong>Pin your dependencies</strong> — use a lock file or pinned requirements for reproducible deploys</p></li>
|
||
</ul>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="Main">
|
||
<div class="sphinxsidebarwrapper"><p class="logo">
|
||
<a href="index.html">
|
||
<img class="logo" src="_static/responder.png" />
|
||
</a>
|
||
</p>
|
||
<p>
|
||
<strong>Responder</strong> — a familiar HTTP service framework for Python.
|
||
<br />
|
||
<small>v3.6.2</small>
|
||
</p>
|
||
<h3>Useful Links</h3>
|
||
<ul>
|
||
<li><a href="https://github.com/kennethreitz/responder">Responder @ GitHub</a></li>
|
||
<li><a href="https://pypi.org/project/responder/">Responder @ PyPI</a></li>
|
||
<li><a href="https://github.com/kennethreitz/responder/issues">Issue Tracker</a></li>
|
||
</ul>
|
||
<div>
|
||
<h3><a href="index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Deployment</a><ul>
|
||
<li><a class="reference internal" href="#running-locally">Running Locally</a></li>
|
||
<li><a class="reference internal" href="#docker">Docker</a></li>
|
||
<li><a class="reference internal" href="#cloud-platforms">Cloud Platforms</a></li>
|
||
<li><a class="reference internal" href="#health-check-endpoint">Health Check Endpoint</a></li>
|
||
<li><a class="reference internal" href="#uvicorn-directly">Uvicorn Directly</a></li>
|
||
<li><a class="reference internal" href="#docker-compose">Docker Compose</a></li>
|
||
<li><a class="reference internal" href="#reverse-proxy">Reverse Proxy</a></li>
|
||
<li><a class="reference internal" href="#production-checklist">Production Checklist</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
</div>
|
||
<search id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</search>
|
||
<script>document.getElementById('searchbox').style.display = "block"</script>
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="footer">
|
||
©2018-2026, Kenneth Reitz.
|
||
|
||
|
|
||
<a href="_sources/deployment.rst.txt"
|
||
rel="nofollow">Page source</a>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
</body>
|
||
</html> |