diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..65098c18a --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,72 @@ +name: Docs + +on: + push: + branches: [ main ] + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'requirements_dev.txt' + - '.github/workflows/docs.yml' + pull_request: + paths: + - 'docs/**' + - 'mkdocs.yml' + - 'requirements_dev.txt' + - '.github/workflows/docs.yml' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements_dev.txt + + - name: Build documentation + run: mkdocs build + + - name: Upload site artifact + uses: actions/upload-artifact@v4 + with: + name: gunicorn-site + path: site + retention-days: 7 + + deploy: + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements_dev.txt + + - name: Build documentation + run: mkdocs build + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: site + publish_branch: gh-pages + commit_message: "docs: deploy {sha}" diff --git a/.gitignore b/.gitignore index 581094b7f..74eecc706 100755 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ examples/frameworks/pylonstest/pylonstest.egg-info/ MANIFEST nohup.out setuptools-* +site/ +docs/site/ diff --git a/Makefile b/Makefile index 3641cd5ab..2c7d8bc25 100644 --- a/Makefile +++ b/Makefile @@ -9,9 +9,15 @@ test: coverage: venv/bin/python setup.py test --cov +docs: + mkdocs build + +docs-serve: + mkdocs serve + clean: @rm -rf .Python MANIFEST build dist venv* *.egg-info *.egg @find . -type f -name "*.py[co]" -delete @find . -type d -name "__pycache__" -delete -.PHONY: build clean coverage test +.PHONY: build clean coverage docs docs-serve test diff --git a/docs/Makefile b/docs/Makefile deleted file mode 100644 index 7fa4085e6..000000000 --- a/docs/Makefile +++ /dev/null @@ -1,160 +0,0 @@ -# Makefile for Sphinx documentation -# -# if you want to compare this file to current sphinx defaults, recreate it: -# BUILDDIR=build sphinx-quickstart --sep --extensions=gunicorn_ext --templatedir=_templates --makefile --batchfile --no-use-make-mode --master=index - -# You can set these variables from the command line. -PYTHON = python -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -# the i18n builder cannot share the environment and doctrees with the others -I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html htmlview dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " htmlview to open the index page built by the html target in your browser" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " singlehtml to make a single large HTML file" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " devhelp to make HTML files and a Devhelp project" - @echo " epub to make an epub" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " latexpdf to make LaTeX files and run them through pdflatex" - @echo " text to make text files" - @echo " man to make manual pages" - @echo " texinfo to make Texinfo files" - @echo " info to make Texinfo files and run them through makeinfo" - @echo " gettext to make PO message catalogs" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -htmlview: html - $(PYTHON) -c "import webbrowser; webbrowser.open('build/html/index.html')" - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -singlehtml: - $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml - @echo - @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Gunicorn.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Gunicorn.qhc" - -devhelp: - $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp - @echo - @echo "Build finished." - @echo "To view the help file:" - @echo "# mkdir -p $$HOME/.local/share/devhelp/Gunicorn" - @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Gunicorn" - @echo "# devhelp" - -epub: - $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub - @echo - @echo "Build finished. The epub file is in $(BUILDDIR)/epub." - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make' in that directory to run these through (pdf)latex" \ - "(use \`make latexpdf' here to do that automatically)." - -latexpdf: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo "Running LaTeX files through pdflatex..." - $(MAKE) -C $(BUILDDIR)/latex all-pdf - @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." - -text: - $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text - @echo - @echo "Build finished. The text files are in $(BUILDDIR)/text." - -man: - $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man - @echo - @echo "Build finished. The manual pages are in $(BUILDDIR)/man." - -texinfo: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo - @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." - @echo "Run \`make' in that directory to run these through makeinfo" \ - "(use \`make info' here to do that automatically)." - -info: - $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo - @echo "Running Texinfo files through makeinfo..." - make -C $(BUILDDIR)/texinfo info - @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." - -gettext: - $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale - @echo - @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/docs/README.rst b/docs/README.rst index 9ec55d05a..6ce90ba95 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -4,16 +4,26 @@ Generate Documentation Requirements ------------ -To generate documentation you need to install: +Install the documentation dependencies with:: - - Python >= 3.7 - - Sphinx (https://www.sphinx-doc.org/) + pip install -r requirements_dev.txt +This provides MkDocs with the Material theme and supporting plugins. -Generate html -------------- + +Build static HTML +----------------- +:: + + mkdocs build + +The rendered site is emitted into the ``site/`` directory. + + +Preview locally +--------------- :: - $ make html + mkdocs serve -The command generates html document inside ``build/html`` dir. +This serves the documentation at http://127.0.0.1:8000/ with live reload. diff --git a/docs/source/2010-news.rst b/docs/content/2010-news.md similarity index 87% rename from docs/source/2010-news.rst rename to docs/content/2010-news.md index e58c48198..19e2816c1 100644 --- a/docs/source/2010-news.rst +++ b/docs/content/2010-news.md @@ -1,8 +1,7 @@ -Changelog - 2010 -================ + +# Changelog - 2010 -0.12.0 / 2010-12-22 -------------------- +## 0.12.0 / 2010-12-22 - Add support for logging configuration using a ini file. It uses the standard Python logging's module Configuration @@ -18,8 +17,7 @@ Changelog - 2010 - Fix setpgrp issue, can now be launched via ubuntu upstart - Set the number of workers to zero on WINCH -0.11.2 / 2010-10-30 -------------------- +## 0.11.2 / 2010-10-30 * Add SERVER_SOFTWARE to the os.environ * Add support for django settings environment variable @@ -30,8 +28,7 @@ Changelog - 2010 * Fix HUP with Paster applications * Fix readline in wsgi.input -0.11.1 / 2010-09-02 -------------------- +## 0.11.1 / 2010-09-02 * Implement max-requests feature to prevent memory leaks. * Added 'worker_exit' server hook. @@ -41,16 +38,14 @@ Changelog - 2010 * Fix the default proc name internal setting. * Workaround to prevent Gevent worker to segfault on MacOSX. -0.11.0 / 2010-08-12 -------------------- +## 0.11.0 / 2010-08-12 * Improve dramatically performances of Gevent and Eventlet workers * Optimize HTTP parsing * Drop Server and Date headers in start_response when provided. * Fix latency issue in async workers -0.10.1 / 2010-08-06 -------------------- +## 0.10.1 / 2010-08-06 * Improve gevent's workers. Add "egg:gunicorn#gevent_wsgi" worker using `gevent.wsgi `_ and @@ -63,8 +58,7 @@ Changelog - 2010 * Exit more quietly * Fix gevent dns issue -0.10.0 / 2010-07-08 -------------------- +## 0.10.0 / 2010-07-08 * New HTTP parser. * New HUP behaviour. Re-reads the configuration and then reloads all @@ -84,16 +78,14 @@ Changelog - 2010 * Internal refactoring and various bug fixes. * New documentation website. -0.9.1 / 2010-05-26 ------------------- +## 0.9.1 / 2010-05-26 * Support https via X-Forwarded-Protocol or X-Forwarded-Ssl headers * Fix configuration * Remove -d options which was used instead of -D for daemon. * Fix umask in unix socket -0.9.0 / 2010-05-24 ------------------- +## 0.9.0 / 2010-05-24 * Added *when_ready* hook. Called just after the server is started * Added *preload* setting. Load application code before the worker processes @@ -104,35 +96,30 @@ Changelog - 2010 * Fix reexec * Documentation improvements -0.8.1 / 2010-04-29 ------------------- +## 0.8.1 / 2010-04-29 * Fix builtins import in config * Fix installation with pip * Fix Tornado WSGI support * Delay application loading until after processing all configuration -0.8.0 / 2010-04-22 ------------------- +## 0.8.0 / 2010-04-22 * Refactored Worker management for better async support. Now use the -k option to set the type of request processing to use * Added support for Tornado_ -0.7.2 / 2010-04-15 ------------------- +## 0.7.2 / 2010-04-15 * Added --spew option to help debugging (installs a system trace hook) * Some fixes in async arbiters * Fix a bug in start_response on error -0.7.1 / 2010-04-01 ------------------- +## 0.7.1 / 2010-04-01 * Fix bug when responses have no body. -0.7.0 / 2010-03-26 ------------------- +## 0.7.0 / 2010-03-26 * Added support for Eventlet_ and Gevent_ based workers. * Added Websockets_ support @@ -140,26 +127,22 @@ Changelog - 2010 * Fix SIGWINCH on OpenBSD_ * Fix `PEP 333`_ compliance for the write callable. -0.6.5 / 2010-03-11 ------------------- +## 0.6.5 / 2010-03-11 * Fix pidfile handling * Fix Exception Error -0.6.4 / 2010-03-08 ------------------- +## 0.6.4 / 2010-03-08 * Use cStringIO for performance when possible. * Fix worker freeze when a remote connection closes unexpectedly. -0.6.3 / 2010-03-07 ------------------- +## 0.6.3 / 2010-03-07 * Make HTTP parsing faster. * Various bug fixes -0.6.2 / 2010-03-01 ------------------- +## 0.6.2 / 2010-03-01 * Added support for chunked response. * Added proc_name option to the config file. @@ -168,28 +151,24 @@ Changelog - 2010 * Improved performance when sending responses. * Workers are now murdered by age (the oldest is killed first). -0.6.1 / 2010-02-24 ------------------- +## 0.6.1 / 2010-02-24 * Added gunicorn config file support for Django admin command * Fix gunicorn config file. -c was broken. * Removed TTIN/TTOU from workers which blocked other signals. -0.6.0 / 2010-02-22 ------------------- +## 0.6.0 / 2010-02-22 * Added setproctitle support * Change privilege switch behavior. We now work like NGINX, master keeps the permissions, new uid/gid permissions are only set for workers. -0.5.1 / 2010-02-22 ------------------- +## 0.5.1 / 2010-02-22 * Fix umask * Added Debian packaging -0.5.0 / 2010-02-20 ------------------- +## 0.5.0 / 2010-02-20 * Added `configuration file `_ handler. * Added support for pre/post fork hooks diff --git a/docs/source/2011-news.rst b/docs/content/2011-news.md similarity index 84% rename from docs/source/2011-news.rst rename to docs/content/2011-news.md index 3bc2a1a2d..87de3ef83 100644 --- a/docs/source/2011-news.rst +++ b/docs/content/2011-news.md @@ -1,20 +1,17 @@ -Changelog - 2011 -================ + +# Changelog - 2011 -0.13.4 / 2011-09-23 -------------------- +## 0.13.4 / 2011-09-23 - fix util.closerange function used to prevent leaking fds on python 2.5 - (typo) + (typo.md) -0.13.3 / 2011-09-19 -------------------- +## 0.13.3 / 2011-09-19 - refactor gevent worker - prevent leaking fds on reexec - fix inverted request_time computation -0.13.2 / 2011-09-17 -------------------- +## 0.13.2 / 2011-09-17 - Add support for Tornado 2.0 in tornado worker - Improve access logs: allows customisation of the log format & add @@ -25,13 +22,11 @@ Changelog - 2011 - Fix sendfile support - Fix Django reloading -0.13.1 / 2011-08-22 -------------------- +## 0.13.1 / 2011-08-22 - Fix unix socket. log argument was missing. -0.13.0 / 2011-08-22 -------------------- +## 0.13.0 / 2011-08-22 - Improve logging: allows file-reopening and add access log file compatible with the `apache combined log format `_ @@ -48,8 +43,7 @@ Changelog - 2011 - Fix the use of sendfile in wsgi.file_wrapper -0.12.2 / 2011-05-18 -------------------- +## 0.12.2 / 2011-05-18 - Add wsgi.file_wrapper optimised for FreeBSD, Linux & MacOSX (use sendfile if available) @@ -58,8 +52,7 @@ Changelog - 2011 - Fix django localisation - Compatible with gevent 0.14dev -0.12.1 / 2011-03-23 -------------------- +## 0.12.1 / 2011-03-23 - Add "on_starting" hook. This hook can be used to set anything before the arbiter really start diff --git a/docs/source/2012-news.rst b/docs/content/2012-news.md similarity index 88% rename from docs/source/2012-news.rst rename to docs/content/2012-news.md index ce4f7cc4d..7d3380467 100644 --- a/docs/source/2012-news.rst +++ b/docs/content/2012-news.md @@ -1,8 +1,7 @@ -Changelog - 2012 -================ + +# Changelog - 2012 -0.17.0 / 2012-12-25 -------------------- +## 0.17.0 / 2012-12-25 - allows gunicorn to bind to multiple address - add SSL support @@ -13,13 +12,11 @@ Changelog - 2012 - fix PWD detection in arbiter - miscellaneous PEP8 fixes -0.16.1 / 2012-11-19 -------------------- +## 0.16.1 / 2012-11-19 - Fix packaging -0.16.0 / 2012-11-19 -------------------- +## 0.16.0 / 2012-11-19 - **Added support for Python 3.2 & 3.3** - Expose --pythonpath command to all gunicorn commands @@ -30,8 +27,7 @@ Changelog - 2012 - Reverted timeout for client socket. Fix issue on blocking issues. - Fixed gevent worker -0.15.0 / 2012-10-18 -------------------- +## 0.15.0 / 2012-10-18 - new documentation site on http://docs.gunicorn.org - new website on http://gunicorn.org @@ -49,8 +45,7 @@ Changelog - 2012 - fix graceful shutdown in gevent - fix limit request line check -0.14.6 / 2012-07-26 -------------------- +## 0.14.6 / 2012-07-26 - fix gevent & subproces @@ -58,13 +53,11 @@ Changelog - 2012 - fix keepalive = 0 - fix tornado worker -0.14.5 / 2012-06-24 --------------------- +## 0.14.5 / 2012-06-24 - fix logging during daemonisation -0.14.4 / 2012-06-24 -------------------- +## 0.14.4 / 2012-06-24 - new --graceful-timeout option - fix multiple issues with request limit @@ -77,8 +70,7 @@ Changelog - 2012 - **breaking change**: take the control on graceful reload back. graceful can't be overridden anymore using the on_reload function. -0.14.3 / 2012-05-15 -------------------- +## 0.14.3 / 2012-05-15 - improvement: performance of http.body.Body.readline() - improvement: log HTTP errors in access log like Apache @@ -90,8 +82,7 @@ Changelog - 2012 - fix: django1.4 support - fix: only load the paster application 1 time -0.14.2 / 2012-03-16 -------------------- +## 0.14.2 / 2012-03-16 - add validate_class validator: allows to use a class or a method to initialize the app during in-code configuration @@ -100,13 +91,11 @@ Changelog - 2012 - gevent_wsgi is now an alias of gevent_pywsgi - Fix gevent_pywsgi worker -0.14.1 / 2012-03-02 -------------------- +## 0.14.1 / 2012-03-02 - fixing source archive, reducing its size -0.14.0 / 2012-02-27 -------------------- +## 0.14.0 / 2012-02-27 - check if Request line is too large: You can now pass the parameter ``--limit-request-line`` or set the ``limit_request_line`` in your diff --git a/docs/source/2013-news.rst b/docs/content/2013-news.md similarity index 90% rename from docs/source/2013-news.rst rename to docs/content/2013-news.md index eb8cf556a..117ca7d1c 100644 --- a/docs/source/2013-news.rst +++ b/docs/content/2013-news.md @@ -1,8 +1,7 @@ -Changelog - 2013 -================ + +# Changelog - 2013 -18.0 / 2013-08-26 ------------------ +## 18.0 / 2013-08-26 - new: add ``-e/--env`` command line argument to pass an environment variables to gunicorn @@ -24,8 +23,7 @@ Changelog - 2013 - fix: after closing for error do not keep alive the connection - fix: responses 1xx, 204 and 304 should not force the connection to be closed -17.5 / 2013-07-03 ------------------- +## 17.5 / 2013-07-03 - new: add signals documentation - new: add post_worker_init hook for workers @@ -38,8 +36,7 @@ Changelog - 2013 - fix: give the initial global_conf to paster application - fix: fix 'Expect: 100-continue' support on Python 3 -New versioning: -++++++++++++++++ +### New versioning: With this release, the versioning of Gunicorn is changing. Gunicorn is stable since a long time and there is no point to release a "1.0" now. @@ -52,13 +49,11 @@ services releases: fixes and minor features added So from now we will apply the following versioning ``.``. For example ``17.5`` is a service release. -0.17.4 / 2013-04-24 -------------------- +## 0.17.4 / 2013-04-24 - fix unix socket address parsing -0.17.3 / 2013-04-23 -------------------- +## 0.17.3 / 2013-04-23 - add systemd sockets support - add ``python -m gunicorn.app.wsgiapp`` support @@ -72,8 +67,7 @@ service release. - fix gevent worker exit - fix ipv6 detection when the platform isn't supporting it -0.17.2 / 2013-01-07 -------------------- +## 0.17.2 / 2013-01-07 - optimize readline - make imports errors more visible when loading an app or a logging @@ -82,8 +76,7 @@ service release. - fix PEP3333: accept only bytetrings in the response body - fix support on CYGWIN platforms -0.17.1 / 2013-01-05 -------------------- +## 0.17.1 / 2013-01-05 - add syslog facility name setting - fix ``--version`` command line argument diff --git a/docs/source/2014-news.rst b/docs/content/2014-news.md similarity index 62% rename from docs/source/2014-news.rst rename to docs/content/2014-news.md index 3eec18fcd..ed1937c2b 100644 --- a/docs/source/2014-news.rst +++ b/docs/content/2014-news.md @@ -1,107 +1,90 @@ -================ -Changelog - 2014 -================ + +# Changelog - 2014 -.. note:: +!!! note + Please see [news](news.md) for the latest changes. - Please see :doc:`news` for the latest changes. -19.1.1 / 2014-08-16 -=================== +## 19.1.1 / 2014-08-16 -Changes -------- +### Changes -Core -++++ +### Core -- fix :issue:`835`: display correct pid of already running instance -- fix :pr:`833`: fix `PyTest` class in setup.py. +- fix [Issue #835](https://github.com/benoitc/gunicorn/issues/835): display correct pid of already running instance +- fix [PR #833](https://github.com/benoitc/gunicorn/pull/833): fix `PyTest` class in setup.py. -Logging -+++++++ +### Logging -- fix :issue:`838`: statsd logger, send statsd timing metrics in milliseconds -- fix :issue:`839`: statsd logger, allows for empty log message while pushing +- fix [Issue #838](https://github.com/benoitc/gunicorn/issues/838): statsd logger, send statsd timing metrics in milliseconds +- fix [Issue #839](https://github.com/benoitc/gunicorn/issues/839): statsd logger, allows for empty log message while pushing metrics and restore worker number in DEBUG logs -- fix :issue:`850`: add timezone to logging -- fix :issue:`853`: Respect logger_class setting unless statsd is on +- fix [Issue #850](https://github.com/benoitc/gunicorn/issues/850): add timezone to logging +- fix [Issue #853](https://github.com/benoitc/gunicorn/issues/853): Respect logger_class setting unless statsd is on -AioHttp worker -++++++++++++++ +### AioHttp worker -- fix :issue:`830` make sure gaiohttp worker is shipped with gunicorn. +- fix [Issue #830](https://github.com/benoitc/gunicorn/issues/830) make sure gaiohttp worker is shipped with gunicorn. -19.1 / 2014-07-26 -================= +## 19.1 / 2014-07-26 -Changes -------- +### Changes -Core -++++ +### Core -- fix :issue:`785`: handle binary type address given to a client socket address +- fix [Issue #785](https://github.com/benoitc/gunicorn/issues/785): handle binary type address given to a client socket address - fix graceful shutdown. make sure QUIT and TERMS signals are switched everywhere. -- :issue:`799`: fix support loading config from module -- :issue:`805`: fix check for file-like objects -- fix :issue:`815`: args validation in WSGIApplication.init -- fix :issue:`787`: check if we load a pyc file or not. +- [Issue #799](https://github.com/benoitc/gunicorn/issues/799): fix support loading config from module +- [Issue #805](https://github.com/benoitc/gunicorn/issues/805): fix check for file-like objects +- fix [Issue #815](https://github.com/benoitc/gunicorn/issues/815): args validation in WSGIApplication.init +- fix [Issue #787](https://github.com/benoitc/gunicorn/issues/787): check if we load a pyc file or not. -Tornado worker -++++++++++++++ +### Tornado worker -- fix :issue:`771`: support tornado 4.0 -- fix :issue:`783`: x_headers error. The x-forwarded-headers option has been removed +- fix [Issue #771](https://github.com/benoitc/gunicorn/issues/771): support tornado 4.0 +- fix [Issue #783](https://github.com/benoitc/gunicorn/issues/783): x_headers error. The x-forwarded-headers option has been removed in `c4873681299212d6082cd9902740eef18c2f14f1 `_. - The discussion is available on :pr:`633`. + The discussion is available on [PR #633](https://github.com/benoitc/gunicorn/pull/633). -AioHttp worker -++++++++++++++ +### AioHttp worker -- fix: fetch all body in input. fix :issue:`803` +- fix: fetch all body in input. fix [Issue #803](https://github.com/benoitc/gunicorn/issues/803) - fix: don't install the worker if python < 3.3 -- fix :issue:`822`: Support UNIX sockets in gaiohttp worker +- fix [Issue #822](https://github.com/benoitc/gunicorn/issues/822): Support UNIX sockets in gaiohttp worker -Async worker -++++++++++++ +### Async worker -- fix :issue:`790`: StopIteration shouldn't be caught at this level. +- fix [Issue #790](https://github.com/benoitc/gunicorn/issues/790): StopIteration shouldn't be caught at this level. -Logging -+++++++ +### Logging -- add statsd logging handler fix :issue:`748` +- add statsd logging handler fix [Issue #748](https://github.com/benoitc/gunicorn/issues/748) -Paster -++++++ +### Paster -- fix :issue:`809`: Set global logging configuration from a Paste config. +- fix [Issue #809](https://github.com/benoitc/gunicorn/issues/809): Set global logging configuration from a Paste config. -Extra -+++++ +### Extra -- fix RuntimeError in gunicorn.reloader (:issue:`807`) +- fix RuntimeError in gunicorn.reloader ([Issue #807](https://github.com/benoitc/gunicorn/issues/807)) -Documentation -+++++++++++++ +### Documentation - update faq: put a note on how `watch logs in the console `_ since many people asked for it. -19.0 / 2014-06-12 -================= +## 19.0 / 2014-06-12 Gunicorn 19.0 is a major release with new features and fixes. This version improve a lot the usage of Gunicorn with python 3 by adding `two @@ -110,11 +93,9 @@ to it: `gthread` a fully threaded async worker using futures and `gaiohttp` a worker using asyncio. -Breaking Changes ----------------- +### Breaking Changes -Switch QUIT and TERM signals -++++++++++++++++++++++++++++ +### Switch QUIT and TERM signals With this change, when gunicorn receives a QUIT all the workers are killed immediately and exit and TERM is used for the graceful shutdown. @@ -128,19 +109,16 @@ also it is complying with the way the signals are sent by heroku: https://devcenter.heroku.com/articles/python-faq#what-constraints-exist-when-developing-applications-on-heroku -Deprecations -++++++++++++ +### Deprecations `run_gunicorn`, `gunicorn_django` and `gunicorn_paster` are now completely deprecated and will be removed in the next release. Use the `gunicorn` command instead. -Changes -------- +### Changes -core -++++ +### core - add aiohttp worker named `gaiohttp` using asyncio. Full async worker on python 3. @@ -173,8 +151,7 @@ core - add: include access logs in the syslog handler. - add --reload option for code reloading - add the capability to load `gunicorn.base.Application` without the loading of - the arguments of the command line. It allows you to :ref:`embed gunicorn in - your own application `. + the arguments of the command line. It allows you to [embed gunicorn in your own application](custom.md). - improve: set wsgi.multithread to True for async workers - fix logging: make sure to redirect wsgi.errors when needed - add: syslog logging can now be done to a unix socket @@ -202,8 +179,7 @@ core - fix: sys imported twice -gevent worker -+++++++++++++ +### gevent worker - fix: make sure to stop all listeners - fix: monkey patching is now done in the worker @@ -214,15 +190,13 @@ gevent worker - fix: add support for multiple listener -eventlet worker -+++++++++++++++ +### eventlet worker - fix: merge duplicate EventletWorker.init_process method (fixes #657) - fix: missing errno import for eventlet sendfile patch - fix: add support for multiple listener -tornado worker -++++++++++++++ +### tornado worker - add graceful stop support diff --git a/docs/content/2015-news.md b/docs/content/2015-news.md new file mode 100644 index 000000000..0cec6d1fa --- /dev/null +++ b/docs/content/2015-news.md @@ -0,0 +1,187 @@ + +# Changelog - 2015 + +!!! note + Please see [news](news.md) for the latest changes. + + +## 19.4.3 / 2015/12/30 + +- fix: don't check if a file is writable using os.stat with SELINUX ([Issue #1171](https://github.com/benoitc/gunicorn/issues/1171)) + +## 19.4.2 / 2015/12/29 + +### Core + +- improvement: handle HaltServer in manage_workers ([Issue #1095](https://github.com/benoitc/gunicorn/issues/1095)) +- fix: Do not rely on sendfile sending requested count ([Issue #1155](https://github.com/benoitc/gunicorn/issues/1155)) +- fix: claridy --no-sendfile default ([Issue #1156](https://github.com/benoitc/gunicorn/issues/1156)) +- fix: LoggingCatch sendfile failure from no file descriptor ([Issue #1160](https://github.com/benoitc/gunicorn/issues/1160)) + +### Logging + +- fix: Always send access log to syslog if syslog is on +- fix: check auth before trying to own a file ([Issue #1157](https://github.com/benoitc/gunicorn/issues/1157)) + + +### Documentation + +- fix: Fix Slowloris broken link. ([Issue #1142](https://github.com/benoitc/gunicorn/issues/1142)) +- Tweak markup in faq.rst + +### Testing + +- fix: gaiohttp test ([Issue #1164](https://github.com/benoitc/gunicorn/issues/1164)) + +## 19.4.1 / 2015/11/25 + +- fix tornado worker ([Issue #1154](https://github.com/benoitc/gunicorn/issues/1154)) + +## 19.4.0 / 2015/11/20 + +### Core + +- fix: make sure that a user is able to access to the logs after dropping a + privilege ([Issue #1116](https://github.com/benoitc/gunicorn/issues/1116)) +- improvement: inherit the `Exception` class where it needs to be ([Issue #997](https://github.com/benoitc/gunicorn/issues/997)) +- fix: make sure headers are always encoded as latin1 RFC 2616 ([Issue #1102](https://github.com/benoitc/gunicorn/issues/1102)) +- improvement: reduce arbiter noise ([Issue #1078](https://github.com/benoitc/gunicorn/issues/1078)) +- fix: don't close the unix socket when the worker exit ([Issue #1088](https://github.com/benoitc/gunicorn/issues/1088)) +- improvement: Make last logged worker count an explicit instance var ([Issue #1078](https://github.com/benoitc/gunicorn/issues/1078)) +- improvement: prefix config file with its type ([Issue #836](https://github.com/benoitc/gunicorn/issues/836)) +- improvement: pidfile handing ([Issue #1042](https://github.com/benoitc/gunicorn/issues/1042)) +- fix: catch OSError as well as ValueError on race condition ([Issue #1052](https://github.com/benoitc/gunicorn/issues/1052)) +- improve support of ipv6 by backporting urlparse.urlsplit from Python 2.7 to + Python 2.6. +- fix: raise InvalidRequestLine when the line contains malicious data + ([Issue #1023](https://github.com/benoitc/gunicorn/issues/1023)) +- fix: fix argument to disable sendfile +- fix: add gthread to the list of supported workers ([Issue #1011](https://github.com/benoitc/gunicorn/issues/1011)) +- improvement: retry socket binding up to five times upon EADDRNOTAVAIL + ([Issue #1004](https://github.com/benoitc/gunicorn/issues/1004)) +- **breaking change**: only honor headers that can be encoded in ascii to comply to + the RFC 7230 (See [Issue #1151](https://github.com/benoitc/gunicorn/issues/1151)). + +### Logging + +- add new parameters to access log ([Issue #1132](https://github.com/benoitc/gunicorn/issues/1132)) +- fix: make sure that files handles are correctly reopened on HUP + ([Issue #627](https://github.com/benoitc/gunicorn/issues/627)) +- include request URL in error message ([Issue #1071](https://github.com/benoitc/gunicorn/issues/1071)) +- get username in access logs ([Issue #1069](https://github.com/benoitc/gunicorn/issues/1069)) +- fix statsd logging support on Python 3 ([Issue #1010](https://github.com/benoitc/gunicorn/issues/1010)) + +### Testing + +- use last version of mock. +- many fixes in Travis CI support +- miscellaneous improvements in tests + +### Thread worker + +- fix: Fix self.nr usage in ThreadedWorker so that auto restart works as + expected ([Issue #1031](https://github.com/benoitc/gunicorn/issues/1031)) + +### Gevent worker + +- fix quit signal handling ([Issue #1128](https://github.com/benoitc/gunicorn/issues/1128)) +- add support for Python 3 ([Issue #1066](https://github.com/benoitc/gunicorn/issues/1066)) +- fix: make graceful shutdown thread-safe ([Issue #1032](https://github.com/benoitc/gunicorn/issues/1032)) + +### Tornado worker + +- fix ssl options ([Issue #1146](https://github.com/benoitc/gunicorn/issues/1146), [Issue #1135](https://github.com/benoitc/gunicorn/issues/1135)) +- don't check timeout when stopping gracefully ([Issue #1106](https://github.com/benoitc/gunicorn/issues/1106)) + +### AIOHttp worker + +- add SSL support ([Issue #1105](https://github.com/benoitc/gunicorn/issues/1105)) + +### Documentation + +- fix link to proc name setting ([Issue #1144](https://github.com/benoitc/gunicorn/issues/1144)) +- fix worker class documentation ([Issue #1141](https://github.com/benoitc/gunicorn/issues/1141), [Issue #1104](https://github.com/benoitc/gunicorn/issues/1104)) +- clarify graceful timeout documentation ([Issue #1137](https://github.com/benoitc/gunicorn/issues/1137)) +- don't duplicate NGINX config files examples ([Issue #1050](https://github.com/benoitc/gunicorn/issues/1050), [Issue #1048](https://github.com/benoitc/gunicorn/issues/1048)) +- add `web.py` framework example ([Issue #1117](https://github.com/benoitc/gunicorn/issues/1117)) +- update Debian/Ubuntu installations instructions ([Issue #1112](https://github.com/benoitc/gunicorn/issues/1112)) +- clarify `pythonpath` setting description ([Issue #1080](https://github.com/benoitc/gunicorn/issues/1080)) +- tweak some example for python3 +- clarify `sendfile` documentation +- miscellaneous typos in source code comments (thanks!) +- clarify why REMOTE_ADD may not be the user's IP address ([Issue #1037](https://github.com/benoitc/gunicorn/issues/1037)) + + +### Misc + +- fix: reloader should survive SyntaxError ([Issue #994](https://github.com/benoitc/gunicorn/issues/994)) +- fix: expose the reloader class to the worker. + + + +## 19.3.0 / 2015/03/06 + +### Core + +- fix: [Issue #978](https://github.com/benoitc/gunicorn/issues/978) make sure a listener is inheritable +- add `check_config` class method to workers +- fix: [Issue #983](https://github.com/benoitc/gunicorn/issues/983) fix select timeout in sync worker with multiple + connections +- allows workers to access to the reloader. close [Issue #984](https://github.com/benoitc/gunicorn/issues/984) +- raise TypeError instead of AssertionError + +### Logging + +- make Logger.loglevel a class attribute + +### Documentation + +- fix: [Issue #988](https://github.com/benoitc/gunicorn/issues/988) fix syntax errors in examples/gunicorn_rc + + +## 19.2.1 / 2015/02/4 + +### Logging + +- expose loglevel in the Logger class + +### AsyncIO worker (gaiohttp.md) + +- fix [Issue #977](https://github.com/benoitc/gunicorn/issues/977) fix initial crash + +### Documentation + +- document security mailing-list in the contributing page. + +## 19.2 / 2015/01/30 + +### Core + +- optimize the sync workers when listening on a single interface +- add `--sendfile` settings to enable/disable sendfile. fix [Issue #856](https://github.com/benoitc/gunicorn/issues/856) . +- add the selectors module to the code base. [Issue #886](https://github.com/benoitc/gunicorn/issues/886) +- add `--max-requests-jitter` setting to set the maximum jitter to add to the + max-requests setting. +- fix [Issue #899](https://github.com/benoitc/gunicorn/issues/899) propagate proxy_protocol_info to keep-alive requests +- fix [Issue #863](https://github.com/benoitc/gunicorn/issues/863) worker timeout: dynamic timeout has been removed +- fix: Avoid world writable file + +### Logging + +- fix [Issue #941](https://github.com/benoitc/gunicorn/issues/941) set logconfig default to paster more trivially +- add statsd-prefix config setting: set the prefix to use when emitting statsd + metrics +- [Issue #832](https://github.com/benoitc/gunicorn/issues/832) log to console by default + +### Thread Worker + +- fix [Issue #908](https://github.com/benoitc/gunicorn/issues/908) make sure the worker can continue to accept requests + +### Eventlet Worker + +- fix [Issue #867](https://github.com/benoitc/gunicorn/issues/867) Fix eventlet shutdown to actively shut down the workers. + +### Documentation + +Many improvements and fixes have been done, see the detailed changelog for +more information. diff --git a/docs/content/2016-news.md b/docs/content/2016-news.md new file mode 100644 index 000000000..299713faf --- /dev/null +++ b/docs/content/2016-news.md @@ -0,0 +1,79 @@ + +# Changelog - 2016 + +!!! note + Please see [news](news.md) for the latest changes + + +## 19.6.0 / 2016/05/21 + +### Core & Logging + +- improvement of the binary upgrade behaviour using USR2: remove file locking ([Issue #1270](https://github.com/benoitc/gunicorn/issues/1270)) +- add the ``--capture-output`` setting to capture stdout/stderr tot the log + file ([Issue #1271](https://github.com/benoitc/gunicorn/issues/1271)) +- Allow disabling ``sendfile()`` via the ``SENDFILE`` environment variable + ([Issue #1252](https://github.com/benoitc/gunicorn/issues/1252)) +- fix reload under pycharm ([Issue #1129](https://github.com/benoitc/gunicorn/issues/1129)) + +### Workers + +- fix: make sure to remove the signal from the worker pipe ([Issue #1269](https://github.com/benoitc/gunicorn/issues/1269)) +- fix: **gthread** worker, handle removed socket in the select loop + ([Issue #1258](https://github.com/benoitc/gunicorn/issues/1258)) + +## 19.5.0 / 2016/05/10 + +### Core + +- fix: Ensure response to HEAD request won't have message body +- fix: lock domain socket and remove on last arbiter exit ([Issue #1220](https://github.com/benoitc/gunicorn/issues/1220)) +- improvement: use EnvironmentError instead of socket.error ([Issue #939](https://github.com/benoitc/gunicorn/issues/939)) +- add: new ``FORWARDED_ALLOW_IPS`` environment variable ([Issue #1205](https://github.com/benoitc/gunicorn/issues/1205)) +- fix: infinite recursion when destroying sockets ([Issue #1219](https://github.com/benoitc/gunicorn/issues/1219)) +- fix: close sockets on shutdown ([Issue #922](https://github.com/benoitc/gunicorn/issues/922)) +- fix: clean up sys.exc_info calls to drop circular refs ([Issue #1228](https://github.com/benoitc/gunicorn/issues/1228)) +- fix: do post_worker_init after load_wsgi ([Issue #1248](https://github.com/benoitc/gunicorn/issues/1248)) + +### Workers + +- fix access logging in gaiohttp worker ([Issue #1193](https://github.com/benoitc/gunicorn/issues/1193)) +- eventlet: handle QUIT in a new coroutine ([Issue #1217](https://github.com/benoitc/gunicorn/issues/1217)) +- gevent: remove obsolete exception clauses in run ([Issue #1218](https://github.com/benoitc/gunicorn/issues/1218)) +- tornado: fix extra "Server" response header ([Issue #1246](https://github.com/benoitc/gunicorn/issues/1246)) +- fix: unblock the wait loop under python 3.5 in sync worker ([Issue #1256](https://github.com/benoitc/gunicorn/issues/1256)) + +### Logging + +- fix: log message for listener reloading ([Issue #1181](https://github.com/benoitc/gunicorn/issues/1181)) +- Let logging module handle traceback printing ([Issue #1201](https://github.com/benoitc/gunicorn/issues/1201)) +- improvement: Allow configuring logger_class with statsd_host ([Issue #1188](https://github.com/benoitc/gunicorn/issues/1188)) +- fix: traceback formatting ([Issue #1235](https://github.com/benoitc/gunicorn/issues/1235)) +- fix: print error logs on stderr and access logs on stdout ([Issue #1184](https://github.com/benoitc/gunicorn/issues/1184)) + + +### Documentation + +- Simplify installation instructions in gunicorn.org ([Issue #1072](https://github.com/benoitc/gunicorn/issues/1072)) +- Fix URL and default worker type in example_config ([Issue #1209](https://github.com/benoitc/gunicorn/issues/1209)) +- update django doc url to 1.8 lts ([Issue #1213](https://github.com/benoitc/gunicorn/issues/1213)) +- fix: miscellaneous wording corrections ([Issue #1216](https://github.com/benoitc/gunicorn/issues/1216)) +- Add PSF License Agreement of selectors.py to NOTICE (:issue: `1226`) +- document LOGGING overriding ([Issue #1051](https://github.com/benoitc/gunicorn/issues/1051)) +- put a note that error logs are only errors from Gunicorn ([Issue #1124](https://github.com/benoitc/gunicorn/issues/1124)) +- add a note about the requirements of the threads workers under python 2.x ([Issue #1200](https://github.com/benoitc/gunicorn/issues/1200)) +- add access_log_format to config example ([Issue #1251](https://github.com/benoitc/gunicorn/issues/1251)) + +### Tests + +- Use more pytest.raises() in test_http.py + + +## 19.4.5 / 2016/01/05 + +- fix: NameError fileno in gunicorn.http.wsgi ([Issue #1178](https://github.com/benoitc/gunicorn/issues/1178)) + +## 19.4.4 / 2016/01/04 + +- fix: check if a fileobject can be used with sendfile(2.md) ([Issue #1174](https://github.com/benoitc/gunicorn/issues/1174)) +- doc: be more descriptive in errorlog option ([Issue #1173](https://github.com/benoitc/gunicorn/issues/1173)) diff --git a/docs/content/2017-news.md b/docs/content/2017-news.md new file mode 100644 index 000000000..803f363f9 --- /dev/null +++ b/docs/content/2017-news.md @@ -0,0 +1,42 @@ + +# Changelog - 2017 + +!!! note + Please see [news](news.md) for the latest changes + + +## 19.7.1 / 2017/03/21 + +- fix: continue if SO_REUSEPORT seems to be available but fails ([Issue #1480](https://github.com/benoitc/gunicorn/issues/1480)) +- fix: support non-decimal values for the umask command line option ([Issue #1325](https://github.com/benoitc/gunicorn/issues/1325)) + +## 19.7.0 / 2017/03/01 + +- The previously deprecated ``gunicorn_django`` command has been removed. + Use the [gunicorn-cmd](run.md#gunicorn) command-line interface instead. +- The previously deprecated ``django_settings`` setting has been removed. + Use the [raw-env](reference/settings.md#raw_env) setting instead. +- The default value of [ssl-version](reference/settings.md#ssl_version) has been changed from + ``ssl.PROTOCOL_TLSv1`` to ``ssl.PROTOCOL_SSLv23``. +- fix: initialize the group access list when initgroups is set ([Issue #1297](https://github.com/benoitc/gunicorn/issues/1297)) +- add environment variables to gunicorn access log format ([Issue #1291](https://github.com/benoitc/gunicorn/issues/1291)) +- add --paste-global-conf option ([Issue #1304](https://github.com/benoitc/gunicorn/issues/1304)) +- fix: print access logs to STDOUT ([Issue #1184](https://github.com/benoitc/gunicorn/issues/1184)) +- remove upper limit on max header size config ([Issue #1313](https://github.com/benoitc/gunicorn/issues/1313)) +- fix: print original exception on AppImportError ([Issue #1334](https://github.com/benoitc/gunicorn/issues/1334)) +- use SO_REUSEPORT if available ([Issue #1344](https://github.com/benoitc/gunicorn/issues/1344)) +- `fix leak `_ of duplicate file descriptor for bound sockets. +- add --reload-engine option, support inotify and other backends ([Issue #1368](https://github.com/benoitc/gunicorn/issues/1368), [Issue #1459](https://github.com/benoitc/gunicorn/issues/1459)) +- fix: reject request with invalid HTTP versions +- add ``child_exit`` callback ([Issue #1394](https://github.com/benoitc/gunicorn/issues/1394)) +- add support for eventlets _AlreadyHandled object ([Issue #1406](https://github.com/benoitc/gunicorn/issues/1406)) +- format boot tracebacks properly with reloader ([Issue #1408](https://github.com/benoitc/gunicorn/issues/1408)) +- refactor socket activation and fd inheritance for better support of SystemD ([Issue #1310](https://github.com/benoitc/gunicorn/issues/1310)) +- fix: o fds are given by default in gunicorn ([Issue #1423](https://github.com/benoitc/gunicorn/issues/1423)) +- add ability to pass settings to GUNICORN_CMD_ARGS environment variable which helps in container world ([Issue #1385](https://github.com/benoitc/gunicorn/issues/1385)) +- fix: catch access denied to pid file ([Issue #1091](https://github.com/benoitc/gunicorn/issues/1091)) +- many additions and improvements to the documentation + +### Breaking Change + +- **Python 2.6.0** is the last supported version diff --git a/docs/content/2018-news.md b/docs/content/2018-news.md new file mode 100644 index 000000000..3c36e808a --- /dev/null +++ b/docs/content/2018-news.md @@ -0,0 +1,64 @@ + +# Changelog - 2018 + +!!! note + Please see [news](news.md) for the latest changes + + +## 19.9.0 / 2018/07/03 + +- fix: address a regression that prevented syslog support from working + ([Issue #1668](https://github.com/benoitc/gunicorn/issues/1668), [PR #1773](https://github.com/benoitc/gunicorn/pull/1773)) +- fix: correctly set `REMOTE_ADDR` on versions of Python 3 affected by + `Python Issue 30205 `_ + ([Issue #1755](https://github.com/benoitc/gunicorn/issues/1755), [PR #1796](https://github.com/benoitc/gunicorn/pull/1796)) +- fix: show zero response length correctly in access log ([PR #1787](https://github.com/benoitc/gunicorn/pull/1787)) +- fix: prevent raising `AttributeError` when ``--reload`` is not passed + in case of a `SyntaxError` raised from the WSGI application. + ([Issue #1805](https://github.com/benoitc/gunicorn/issues/1805), [PR #1806](https://github.com/benoitc/gunicorn/pull/1806)) +- The internal module ``gunicorn.workers.async`` was renamed to ``gunicorn.workers.base_async`` + since ``async`` is now a reserved word in Python 3.7. + ([PR #1527](https://github.com/benoitc/gunicorn/pull/1527)) + +## 19.8.1 / 2018/04/30 + +- fix: secure scheme headers when bound to a unix socket + ([Issue #1766](https://github.com/benoitc/gunicorn/issues/1766), [PR #1767](https://github.com/benoitc/gunicorn/pull/1767)) + +## 19.8.0 / 2018/04/28 + +- Eventlet 0.21.0 support ([Issue #1584](https://github.com/benoitc/gunicorn/issues/1584)) +- Tornado 5 support ([Issue #1728](https://github.com/benoitc/gunicorn/issues/1728), [PR #1752](https://github.com/benoitc/gunicorn/pull/1752)) +- support watching additional files with ``--reload-extra-file`` + ([PR #1527](https://github.com/benoitc/gunicorn/pull/1527)) +- support configuring logging with a dictionary with ``--logging-config-dict`` + ([Issue #1087](https://github.com/benoitc/gunicorn/issues/1087), [PR #1110](https://github.com/benoitc/gunicorn/pull/1110), [PR #1602](https://github.com/benoitc/gunicorn/pull/1602)) +- add support for the ``--config`` flag in the ``GUNICORN_CMD_ARGS`` environment + variable ([Issue #1576](https://github.com/benoitc/gunicorn/issues/1576), [PR #1581](https://github.com/benoitc/gunicorn/pull/1581)) +- disable ``SO_REUSEPORT`` by default and add the ``--reuse-port`` setting + ([Issue #1553](https://github.com/benoitc/gunicorn/issues/1553), [Issue #1603](https://github.com/benoitc/gunicorn/issues/1603), [PR #1669](https://github.com/benoitc/gunicorn/pull/1669)) +- fix: installing `inotify` on MacOS no longer breaks the reloader + ([Issue #1540](https://github.com/benoitc/gunicorn/issues/1540), [PR #1541](https://github.com/benoitc/gunicorn/pull/1541)) +- fix: do not throw ``TypeError`` when ``SO_REUSEPORT`` is not available + ([Issue #1501](https://github.com/benoitc/gunicorn/issues/1501), [PR #1491](https://github.com/benoitc/gunicorn/pull/1491)) +- fix: properly decode HTTP paths containing certain non-ASCII characters + ([Issue #1577](https://github.com/benoitc/gunicorn/issues/1577), [PR #1578](https://github.com/benoitc/gunicorn/pull/1578)) +- fix: remove whitespace when logging header values under gevent ([PR #1607](https://github.com/benoitc/gunicorn/pull/1607)) +- fix: close unlinked temporary files ([Issue #1327](https://github.com/benoitc/gunicorn/issues/1327), [PR #1428](https://github.com/benoitc/gunicorn/pull/1428)) +- fix: parse ``--umask=0`` correctly ([Issue #1622](https://github.com/benoitc/gunicorn/issues/1622), [PR #1632](https://github.com/benoitc/gunicorn/pull/1632)) +- fix: allow loading applications using relative file paths + ([Issue #1349](https://github.com/benoitc/gunicorn/issues/1349), [PR #1481](https://github.com/benoitc/gunicorn/pull/1481)) +- fix: force blocking mode on the gevent sockets ([Issue #880](https://github.com/benoitc/gunicorn/issues/880), [PR #1616](https://github.com/benoitc/gunicorn/pull/1616)) +- fix: preserve leading `/` in request path ([Issue #1512](https://github.com/benoitc/gunicorn/issues/1512), [PR #1511](https://github.com/benoitc/gunicorn/pull/1511)) +- fix: forbid contradictory secure scheme headers +- fix: handle malformed basic authentication headers in access log + ([Issue #1683](https://github.com/benoitc/gunicorn/issues/1683), [PR #1684](https://github.com/benoitc/gunicorn/pull/1684)) +- fix: defer handling of ``USR1`` signal to a new greenlet under gevent + ([Issue #1645](https://github.com/benoitc/gunicorn/issues/1645), [PR #1651](https://github.com/benoitc/gunicorn/pull/1651)) +- fix: the threaded worker would sometimes close the wrong keep-alive + connection under Python 2 ([Issue #1698](https://github.com/benoitc/gunicorn/issues/1698), [PR #1699](https://github.com/benoitc/gunicorn/pull/1699)) +- fix: re-open log files on ``USR1`` signal using ``handler._open`` to + support subclasses of ``FileHandler`` ([Issue #1739](https://github.com/benoitc/gunicorn/issues/1739), [PR #1742](https://github.com/benoitc/gunicorn/pull/1742)) +- deprecation: the ``gaiohttp`` worker is deprecated, see the + [worker-class](reference/settings.md#worker_class) documentation for more information + ([Issue #1338](https://github.com/benoitc/gunicorn/issues/1338), [PR #1418](https://github.com/benoitc/gunicorn/pull/1418), [PR #1569](https://github.com/benoitc/gunicorn/pull/1569)) diff --git a/docs/source/2019-news.rst b/docs/content/2019-news.md similarity index 71% rename from docs/source/2019-news.rst rename to docs/content/2019-news.md index 28b69216b..8359edd66 100644 --- a/docs/source/2019-news.rst +++ b/docs/content/2019-news.md @@ -1,52 +1,45 @@ -================ -Changelog - 2019 -================ + +# Changelog - 2019 -.. note:: +!!! note + Please see [news](news.md) for the latest changes - Please see :doc:`news` for the latest changes -20.0.4 / 2019/11/26 -=================== +## 20.0.4 / 2019/11/26 - fix binding a socket using the file descriptor - remove support for the `bdist_rpm` build -20.0.3 / 2019/11/24 -=================== +## 20.0.3 / 2019/11/24 - fixed load of a config file without a Python extension - fixed `socketfromfd.fromfd` when defaults are not set -.. note:: we now warn when we load a config file without Python Extension - -20.0.2 / 2019/11/23 -=================== - -- fix changelog - -20.0.1 / 2019/11/23 -=================== - -- fixed the way the config module is loaded. `__file__` is now available -- fixed `wsgi.input_terminated`. It is always true. -- use the highest protocol version of openssl by default -- only support Python >= 3.5 -- added `__repr__` method to `Config` instance -- fixed support of AIX platform and musl libc in `socketfromfd.fromfd` function -- fixed support of applications loaded from a factory function -- fixed chunked encoding support to prevent any `request smuggling `_ -- Capture os.sendfile before patching in gevent and eventlet workers. - fix `RecursionError`. -- removed locking in reloader when adding new files -- load the WSGI application before the loader to pick up all files - -.. note:: this release add official support for applications loaded from a factory function - as documented in Flask and other places. - - -19.10.0 / 2019/11/23 -==================== +!!! note + ``` + ## 20.0.2 / 2019/11/23 + + - fix changelog + + ## 20.0.1 / 2019/11/23 + + - fixed the way the config module is loaded. `__file__` is now available + - fixed `wsgi.input_terminated`. It is always true. + - use the highest protocol version of openssl by default + - only support Python >= 3.5 + - added `__repr__` method to `Config` instance + - fixed support of AIX platform and musl libc in `socketfromfd.fromfd` function + - fixed support of applications loaded from a factory function + - fixed chunked encoding support to prevent any `request smuggling `_ + - Capture os.sendfile before patching in gevent and eventlet workers. + fix `RecursionError`. + - removed locking in reloader when adding new files + - load the WSGI application before the loader to pick up all files + +{note} +as documented in Flask and other places. +``` +## 19.10.0 / 2019/11/23 - unblock select loop during reload of a sync worker - security fix: http desync attack @@ -61,8 +54,7 @@ Changelog - 2019 - Clear tornado ioloop before os.fork - Miscellaneous fixes and improvement for linting using Pylint -20.0 / 2019/10/30 -================= +## 20.0 / 2019/10/30 - Fixed `fdopen` `RuntimeWarning` in Python 3.8 - Added check and exception for str type on value in Response process_headers method. @@ -112,8 +104,7 @@ Changelog - 2019 - Clear tornado ioloop before os.fork - Miscellaneous fixes and improvement for linting using Pylint -Breaking Change -+++++++++++++++ +### Breaking Change - Removed gaiohttp worker - Drop support for Python 2.x diff --git a/docs/content/2020-news.md b/docs/content/2020-news.md new file mode 100644 index 000000000..29195f687 --- /dev/null +++ b/docs/content/2020-news.md @@ -0,0 +1,7 @@ + +# Changelog - 2020 + +!!! note + Please see [news](news.md) for the latest changes + + diff --git a/docs/source/2021-news.rst b/docs/content/2021-news.md similarity index 90% rename from docs/source/2021-news.rst rename to docs/content/2021-news.md index 3057600de..d0572de10 100644 --- a/docs/source/2021-news.rst +++ b/docs/content/2021-news.md @@ -1,13 +1,11 @@ -================ -Changelog - 2021 -================ + +# Changelog - 2021 -.. note:: +!!! note + Please see [news](news.md) for the latest changes - Please see :doc:`news` for the latest changes -20.1.0 - 2021-02-12 -=================== +## 20.1.0 - 2021-02-12 - document WEB_CONCURRENCY is set by, at least, Heroku - capture peername from accept: Avoid calls to getpeername by capturing the peer name returned by @@ -37,7 +35,7 @@ Changelog - 2021 (the `logconfig_dict` setting in configuration files continues to work) -** Breaking changes ** +### Breaking changes - minimum version is Python 3.5 - remove version from the Server header @@ -51,4 +49,3 @@ Changelog - 2021 - miscellaneous changes in the code base to be a better citizen with Python 3 - remove dead code - fix documentation generation - diff --git a/docs/source/2023-news.rst b/docs/content/2023-news.md similarity index 62% rename from docs/source/2023-news.rst rename to docs/content/2023-news.md index b685d80d2..9526c0c7f 100644 --- a/docs/source/2023-news.rst +++ b/docs/content/2023-news.md @@ -1,32 +1,29 @@ -================ -Changelog - 2023 -================ + +# Changelog - 2023 -21.2.0 - 2023-07-19 -=================== +## 21.2.0 - 2023-07-19 - fix thread worker: revert change considering connection as idle . -*** NOTE *** +!!! note + This is fixing the bad file description error. + + 21.1.0 - 2023-07-18 -This is fixing the bad file description error. -21.1.0 - 2023-07-18 =================== - fix thread worker: fix socket removal from the queue -21.0.1 - 2023-07-17 -=================== +## 21.0.1 - 2023-07-17 - fix documentation build -21.0.0 - 2023-07-17 -=================== +## 21.0.0 - 2023-07-17 - support python 3.11 - fix gevent and eventlet workers -- fix threads support (gththread): improve performance and unblock requests +- fix threads support (gththread.md): improve performance and unblock requests - SSL: now use SSLContext object - HTTP parser: miscellaneous fixes - remove unnecessary setuid calls diff --git a/docs/source/news.rst b/docs/content/2024-news.md similarity index 53% rename from docs/source/news.rst rename to docs/content/2024-news.md index 2a61fafe3..8ae716118 100644 --- a/docs/source/news.rst +++ b/docs/content/2024-news.md @@ -1,36 +1,33 @@ -========= -Changelog -========= + +# Changelog - 2024 -23.0.0 - 2024-08-10 -=================== +## 23.0.0 - 2024-08-10 -- minor docs fixes (:pr:`3217`, :pr:`3089`, :pr:`3167`) -- worker_class parameter accepts a class (:pr:`3079`) -- fix deadlock if request terminated during chunked parsing (:pr:`2688`) -- permit receiving Transfer-Encodings: compress, deflate, gzip (:pr:`3261`) -- permit Transfer-Encoding headers specifying multiple encodings. note: no parameters, still (:pr:`3261`) -- sdist generation now explicitly excludes sphinx build folder (:pr:`3257`) -- decode bytes-typed status (as can be passed by gevent) as utf-8 instead of raising `TypeError` (:pr:`2336`) -- raise correct Exception when encounting invalid chunked requests (:pr:`3258`) -- the SCRIPT_NAME and PATH_INFO headers, when received from allowed forwarders, are no longer restricted for containing an underscore (:pr:`3192`) -- include IPv6 loopback address ``[::1]`` in default for :ref:`forwarded-allow-ips` and :ref:`proxy-allow-ips` (:pr:`3192`) +- minor docs fixes ([PR #3217](https://github.com/benoitc/gunicorn/pull/3217), [PR #3089](https://github.com/benoitc/gunicorn/pull/3089), [PR #3167](https://github.com/benoitc/gunicorn/pull/3167)) +- worker_class parameter accepts a class ([PR #3079](https://github.com/benoitc/gunicorn/pull/3079)) +- fix deadlock if request terminated during chunked parsing ([PR #2688](https://github.com/benoitc/gunicorn/pull/2688)) +- permit receiving Transfer-Encodings: compress, deflate, gzip ([PR #3261](https://github.com/benoitc/gunicorn/pull/3261)) +- permit Transfer-Encoding headers specifying multiple encodings. note: no parameters, still ([PR #3261](https://github.com/benoitc/gunicorn/pull/3261)) +- sdist generation now explicitly excludes sphinx build folder ([PR #3257](https://github.com/benoitc/gunicorn/pull/3257)) +- decode bytes-typed status (as can be passed by gevent) as utf-8 instead of raising `TypeError` ([PR #2336](https://github.com/benoitc/gunicorn/pull/2336)) +- raise correct Exception when encounting invalid chunked requests ([PR #3258](https://github.com/benoitc/gunicorn/pull/3258)) +- the SCRIPT_NAME and PATH_INFO headers, when received from allowed forwarders, are no longer restricted for containing an underscore ([PR #3192](https://github.com/benoitc/gunicorn/pull/3192)) +- include IPv6 loopback address ``[::1]`` in default for [forwarded-allow-ips](reference/settings.md#forwarded_allow_ips) and [proxy-allow-ips](reference/settings.md#proxy_allow_ips) ([PR #3192](https://github.com/benoitc/gunicorn/pull/3192)) -** NOTE ** +!!! note + - The SCRIPT_NAME change mitigates a regression that appeared first in the 22.0.0 release + - Review your [forwarded-allow-ips](reference/settings.md#forwarded_allow_ips) setting if you are still not seeing the SCRIPT_NAME transmitted + - Review your [forwarder-headers](reference/settings.md#forwarder_headers) setting if you are missing headers after upgrading from a version prior to 22.0.0 -- The SCRIPT_NAME change mitigates a regression that appeared first in the 22.0.0 release -- Review your :ref:`forwarded-allow-ips` setting if you are still not seeing the SCRIPT_NAME transmitted -- Review your :ref:`forwarder-headers` setting if you are missing headers after upgrading from a version prior to 22.0.0 -** Breaking changes ** +### Breaking changes -- refuse requests where the uri field is empty (:pr:`3255`) -- refuse requests with invalid CR/LR/NUL in heade field values (:pr:`3253`) -- remove temporary ``--tolerate-dangerous-framing`` switch from 22.0 (:pr:`3260`) +- refuse requests where the uri field is empty ([PR #3255](https://github.com/benoitc/gunicorn/pull/3255)) +- refuse requests with invalid CR/LR/NUL in heade field values ([PR #3253](https://github.com/benoitc/gunicorn/pull/3253)) +- remove temporary ``--tolerate-dangerous-framing`` switch from 22.0 ([PR #3260](https://github.com/benoitc/gunicorn/pull/3260)) - If any of the breaking changes affect you, be aware that now refused requests can post a security problem, especially so in setups involving request pipe-lining and/or proxies. -22.0.0 - 2024-04-17 -=================== +## 22.0.0 - 2024-04-17 - use `utime` to notify workers liveness - migrate setup to pyproject.toml @@ -41,13 +38,13 @@ Changelog - Trailer fields are no longer inspected for headers indicating secure scheme - support Python 3.12 -** Breaking changes ** +### Breaking changes - minimum version is Python 3.7 - the limitations on valid characters in the HTTP method have been bounded to Internet Standards -- requests specifying unsupported transfer coding (order) are refused by default (rare) +- requests specifying unsupported transfer coding (order.md) are refused by default (rare.md) - HTTP methods are no longer casefolded by default (IANA method registry contains none affected) -- HTTP methods containing the number sign (#) are no longer accepted by default (rare) +- HTTP methods containing the number sign (#) are no longer accepted by default (rare.md) - HTTP versions < 1.0 or >= 2.0 are no longer accepted by default (rare, only HTTP/1.1 is supported) - HTTP versions consisting of multiple digits or containing a prefix/suffix are no longer accepted - HTTP header field names Gunicorn cannot safely map to variables are silently dropped, as in other software @@ -56,28 +53,6 @@ Changelog - empty transfer codings are no longer permitted (reportedly seen with really old & broken proxies) -** SECURITY ** +### Security - fix CVE-2024-1135 - -History -======= - -.. toctree:: - :titlesonly: - - 2024-news - 2023-news - 2021-news - 2020-news - 2019-news - 2018-news - 2017-news - 2016-news - 2015-news - 2014-news - 2013-news - 2012-news - 2011-news - 2010-news - diff --git a/docs/content/assets/gunicorn.svg b/docs/content/assets/gunicorn.svg new file mode 100644 index 000000000..073f2029c --- /dev/null +++ b/docs/content/assets/gunicorn.svg @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + g + + + + + diff --git a/docs/content/community.md b/docs/content/community.md new file mode 100644 index 000000000..e9996b9d5 --- /dev/null +++ b/docs/content/community.md @@ -0,0 +1,40 @@ +# Community + +Connect with the project through these channels. + +## Project management & discussions + +Project maintenance guidelines live on the +[wiki](https://github.com/benoitc/gunicorn/wiki/Project-management). + +GitHub is used for: + +- [Bug reports](https://github.com/benoitc/gunicorn/issues) — search before + opening a new issue. +- [Discussions](https://github.com/benoitc/gunicorn/discussions) — Q&A and usage + tips. +- [Feature planning](https://github.com/benoitc/gunicorn/issues) — development + and project management topics. + +## IRC + +Join the Gunicorn channel on [Libera Chat](https://libera.chat/) at +[`#gunicorn`](https://web.libera.chat/?channels=#gunicorn). + +## Issue tracking + +File bugs, enhancements, and tasks in the +[GitHub issue tracker](https://github.com/benoitc/gunicorn/issues). + +## Security issues + +Report security vulnerabilities privately to +[`security@gunicorn.org`](mailto:security@gunicorn.org); only core developers +subscribe to this list. + +## Contributing + +Start with the +[contributing guide](https://github.com/benoitc/gunicorn/blob/master/CONTRIBUTING.md) +for development workflow, code style, and review expectations. New contributors +are welcome—open a draft pull request early to gather feedback. diff --git a/docs/content/configure.md b/docs/content/configure.md new file mode 100644 index 000000000..1698fba57 --- /dev/null +++ b/docs/content/configure.md @@ -0,0 +1,78 @@ + +# Configuration Overview + +Gunicorn reads configuration from five places, in increasing order of priority: + +1. Environment variables, for settings that support them. +2. Framework-specific configuration (currently Paste Deploy only). +3. A Python configuration file `gunicorn.conf.py` (default in the working directory). +4. The `GUNICORN_CMD_ARGS` environment variable. +5. Command-line arguments. + +If a configuration file is provided both via `GUNICORN_CMD_ARGS` and the CLI, +only the file specified on the command line is used. + +!!! note + Print the fully resolved configuration: + +bash +gunicorn --print-config APP_MODULE +``` + +Validate configuration and exit: + +```bash +gunicorn --check-config APP_MODULE +``` + +This is also a quick way to confirm that your application can start. +``` + +## Command line + +Options set on the command line override framework settings and values from the +configuration file. Not every setting has a command-line flag; run + +```bash +gunicorn -h +``` + +for the complete list. The CLI also exposes `--version`, which is not part of +the main [settings reference](reference/settings.md). + + +## Configuration file + +Provide a Python file (for example `gunicorn.conf.py`). Gunicorn executes the +file on every start or reload, so any valid Python is allowed: + +```python +import multiprocessing + +bind = "127.0.0.1:8000" +workers = multiprocessing.cpu_count() * 2 + 1 +``` + +Every configuration key is documented in the [settings reference](reference/settings.md). + +## Framework settings + +At present only Paste Deploy applications expose framework-specific settings. +If you have ideas for Django or other frameworks, open an +[issue](https://github.com/benoitc/gunicorn/issues). + +### Paste applications + +Reference Gunicorn as the server in your INI file: + +```ini +[server:main] +use = egg:gunicorn#main +host = 192.168.0.1 +port = 80 +workers = 2 +proc_name = brim +``` + +Gunicorn merges any recognised parameters into the base configuration. Values +from the configuration file and command line still override these defaults. diff --git a/docs/content/custom.md b/docs/content/custom.md new file mode 100644 index 000000000..f2bdfb736 --- /dev/null +++ b/docs/content/custom.md @@ -0,0 +1,62 @@ + +# Custom Application + +!!! info "Added in 19.0" + Use Gunicorn as part of your own WSGI application by subclassing + `gunicorn.app.base.BaseApplication`. + + + +Example: create a tiny WSGI app and load it with a custom application: + +```text +--8<-- "examples/standalone_app.py" +``` + + + +## Using server hooks + +Provide hooks through configuration, just like a standard Gunicorn deployment. +For example, a `pre_fork` hook: + +```python +def pre_fork(server, worker): + print(f"pre-fork server {server} worker {worker}", file=sys.stderr) + +if __name__ == "__main__": + options = { + "bind": "127.0.0.1:8080", + "workers": number_of_workers(), + "pre_fork": pre_fork, + } +``` + +## Direct usage of existing WSGI apps + +Run Gunicorn from Python to serve a WSGI application instance at runtime—useful +for rolling deploys or packaging with PEX. Gunicorn exposes +`gunicorn.app.wsgiapp`, which accepts any WSGI app (for example a Flask or +Django instance). Assuming your package is `exampleapi` and the application is +`app`: + +```bash +python -m gunicorn.app.wsgiapp exampleapi:app +``` + +All CLI flags and configuration files still apply: + +```bash +# Custom parameters +python -m gunicorn.app.wsgiapp exampleapi:app --bind=0.0.0.0:8081 --workers=4 +# Using a config file +python -m gunicorn.app.wsgiapp exampleapi:app -c config.py +``` + +For PEX builds use `-c gunicorn` at build time so the packaged app accepts the +entry point at runtime: + +```bash +pex . -v -c gunicorn -o compiledapp.pex +./compiledapp.pex exampleapi:app -c gunicorn_config.py +``` diff --git a/docs/content/deploy.md b/docs/content/deploy.md new file mode 100644 index 000000000..bb78674e4 --- /dev/null +++ b/docs/content/deploy.md @@ -0,0 +1,322 @@ +# Deploying Gunicorn + +We strongly recommend running Gunicorn behind a proxy server. + +## Nginx configuration + +Although many HTTP proxies exist, we recommend [Nginx](https://nginx.org/). +When using the default synchronous workers you must ensure the proxy buffers +slow clients; otherwise Gunicorn becomes vulnerable to denial-of-service +attacks. Use [Hey](https://github.com/rakyll/hey) to verify proxy behaviour. + +An example configuration for fast clients with Nginx +([source](https://github.com/benoitc/gunicorn/blob/master/examples/nginx.conf)): + +```nginx title="nginx.conf" +--8<-- "examples/nginx.conf" +``` + + + +To support streaming requests/responses or patterns such as Comet, long +polling, or WebSockets, disable proxy buffering and run Gunicorn with an async +worker class: + +```nginx +location @proxy_to_app { + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Host $http_host; + proxy_redirect off; + proxy_buffering off; + + proxy_pass http://app_server; +} +``` + +To ignore aborted requests (for example, health checks that close connections +prematurely) enable +[`proxy_ignore_client_abort`](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort): + +```nginx +proxy_ignore_client_abort on; +``` + +!!! note + The default value for `proxy_ignore_client_abort` is `off`. If it remains off + Nginx logs will report error 499 and Gunicorn may log `Ignoring EPIPE` when the + log level is `debug`. + + + +Pass protocol information to Gunicorn so applications can generate correct +URLs. Add this header to your `location` block: + +```nginx +proxy_set_header X-Forwarded-Proto $scheme; +``` + +If Nginx runs on a different host, tell Gunicorn which proxies are trusted so it +accepts the `X-Forwarded-*` headers: + +```bash +gunicorn -w 3 --forwarded-allow-ips="10.170.3.217,10.170.3.220" test:app +``` + +When all traffic comes from trusted proxies (for example Heroku) you can set +`--forwarded-allow-ips='*'`. This is **dangerous** if untrusted clients can +reach Gunicorn directly, because forged headers could make your application +serve secure content over plain HTTP. + +Gunicorn 19 changed the handling of `REMOTE_ADDR` to conform to +[RFC 3875](https://www.rfc-editor.org/rfc/rfc3875), meaning it now records the +proxy IP rather than the upstream client. To log the real client address, set +[`access_log_format`](reference/settings.md#access_log_format) to include `X-Forwarded-For`: + +```text +%({x-forwarded-for}i)s %(l.md)s %(u.md)s %(t.md)s "%(r.md)s" %(s.md)s %(b.md)s "%(f.md)s" "%(a.md)s" +``` + +When binding Gunicorn to a UNIX socket `REMOTE_ADDR` will be empty. + +## Using virtual environments + +Install Gunicorn inside your project +[virtual environment](https://pypi.python.org/pypi/virtualenv) to keep versions +isolated: + +```bash +mkdir ~/venvs/ +virtualenv ~/venvs/webapp +source ~/venvs/webapp/bin/activate +pip install gunicorn +deactivate +``` + +Force installation into the active virtual environment with `--ignore-installed`: + +```bash +source ~/venvs/webapp/bin/activate +pip install -I gunicorn +``` + +## Monitoring + +!!! note + Do not enable Gunicorn's daemon mode when using process monitors. These + supervisors expect to manage the direct child process. + + + +### Gaffer + +Use [Gaffer](https://gaffer.readthedocs.io/) with *gafferd* to manage Gunicorn: + +```ini +[process:gunicorn] +cmd = gunicorn -w 3 test:app +cwd = /path/to/project +``` + +Create a `Procfile` if you prefer: + +```procfile +gunicorn = gunicorn -w 3 test:app +``` + +Start Gunicorn via Gaffer: + +```bash +gaffer start +``` + +Or load it into a running *gafferd* instance: + +```bash +gaffer load +``` + +### runit + +[runit](http://smarden.org/runit/) is a popular supervisor. A sample service +script (see the +[full example](https://github.com/benoitc/gunicorn/blob/master/examples/gunicorn_rc)): + +```bash +#!/bin/sh + +GUNICORN=/usr/local/bin/gunicorn +ROOT=/path/to/project +PID=/var/run/gunicorn.pid + +APP=main:application + +if [ -f $PID ]; then rm $PID; fi + +cd $ROOT +exec $GUNICORN -c $ROOT/gunicorn.conf.py --pid=$PID $APP +``` + +Save as `/etc/sv//run`, make it executable, and symlink into +`/etc/service/`. runit will then supervise Gunicorn. + +### Supervisor + +[Supervisor](http://supervisord.org/) configuration example (adapted from +[examples/supervisor.conf](https://github.com/benoitc/gunicorn/blob/master/examples/supervisor.conf)): + +```ini +[program:gunicorn] +command=/path/to/gunicorn main:application -c /path/to/gunicorn.conf.py +directory=/path/to/project +user=nobody +autostart=true +autorestart=true +redirect_stderr=true +``` + +### Upstart + +Sample Upstart config (logs go to `/var/log/upstart/myapp.log`): + +```upstart +# /etc/init/myapp.conf + +description "myapp" + +start on (filesystem.md) +stop on runlevel [016] + +respawn +setuid nobody +setgid nogroup +chdir /path/to/app/directory + +exec /path/to/virtualenv/bin/gunicorn myapp:app +``` + +### systemd + +[systemd](https://www.freedesktop.org/wiki/Software/systemd/) can create a UNIX +socket and launch Gunicorn on demand. + +Service file: + +```ini +# /etc/systemd/system/gunicorn.service + +[Unit] +Description=gunicorn daemon +Requires=gunicorn.socket +After=network.target + +[Service] +Type=notify +NotifyAccess=main +User=someuser +Group=someuser +RuntimeDirectory=gunicorn +WorkingDirectory=/home/someuser/applicationroot +ExecStart=/usr/bin/gunicorn applicationname.wsgi +ExecReload=/bin/kill -s HUP $MAINPID +KillMode=mixed +TimeoutStopSec=5 +PrivateTmp=true + +[Install] +WantedBy=multi-user.target +``` + +`Type=notify` lets Gunicorn report readiness to systemd. If the service should +run under a transient user consider adding `DynamicUser=true`. Tighten +permissions further with `ProtectSystem=strict` if the app permits. + +Socket activation file: + +```ini +# /etc/systemd/system/gunicorn.socket + +[Unit] +Description=gunicorn socket + +[Socket] +ListenStream=/run/gunicorn.sock +SocketUser=www-data +SocketGroup=www-data +SocketMode=0660 + +[Install] +WantedBy=sockets.target +``` + +Enable and start the socket so it begins listening immediately and on reboot: + +```bash +systemctl enable --now gunicorn.socket +``` + +Test connectivity from the nginx user (Debian defaults to `www-data`): + +```bash +sudo -u www-data curl --unix-socket /run/gunicorn.sock http +``` + +!!! note + Use `systemctl show --value -p MainPID gunicorn.service` to retrieve the main + process ID or `systemctl kill -s HUP gunicorn.service` to send signals. + + + +Configure Nginx to proxy to the new socket: + +```nginx +user www-data; +... +http { + server { + listen 8000; + server_name 127.0.0.1; + location / { + proxy_pass http://unix:/run/gunicorn.sock; + } + } +} +... +``` + +!!! note + Adjust `listen` and `server_name` for production (typically port 80 and your + site's domain). + + + +Ensure nginx starts automatically: + +```bash +systemctl enable nginx.service +systemctl start nginx +``` + +Browse to to verify Gunicorn + Nginx + systemd. + +## Logging + +Configure logging through the CLI flags described in the +[settings documentation](reference/settings.md#logging) or via a +[logging configuration file](https://github.com/benoitc/gunicorn/blob/master/examples/logging.conf). +Rotate logs with `logrotate` by sending `SIGUSR1`: + +```bash +kill -USR1 $(cat /var/run/gunicorn.pid) +``` + +!!! note + If you override the `LOGGING` dictionary, set `disable_existing_loggers` to + `False` so Gunicorn's loggers remain active. + + + +!!! warning + Gunicorn's error log should capture Gunicorn-related messages only. Route your + application logs separately. + + diff --git a/docs/content/design.md b/docs/content/design.md new file mode 100644 index 000000000..eda92ebb5 --- /dev/null +++ b/docs/content/design.md @@ -0,0 +1,83 @@ + +# Design + +A brief look at Gunicorn's architecture. + +## Server model + +Gunicorn uses a pre-fork worker model: a master process manages worker +processes, while the workers handle requests and responses. The master never +touches individual client sockets. + +### Master + +The master process listens for signals (TTIN, TTOU, CHLD, etc.) and adjusts the +worker pool accordingly. `TTIN`/`TTOU` change the number of workers; `CHLD` +indicates a worker exited and must be restarted. + +### Sync workers + +The default `sync` worker handles one request at a time. Errors affect only the +current request. Because connections close after each response, persistent +connections are not supported even if you set `Keep-Alive` headers manually. + +### Async workers + +Async workers are powered by [greenlets](https://github.com/python-greenlet/greenlet) +through [Eventlet](http://eventlet.net/) or [Gevent](http://www.gevent.org/). +Most apps work without modification, though full compatibility may require +patches (for example installing [`psycogreen`](https://github.com/psycopg/psycogreen/) +when using [Psycopg](http://initd.org/psycopg/)). Some apps that depend on the +original blocking behaviour may not be compatible. + +### Gthread workers + +`gthread` is a threaded worker. The main loop accepts connections and places +them in a thread pool. Keep-alive connections return to the pool to await +further events; idle connections close after the keepalive timeout. + +### Tornado workers + +A Tornado worker class exists for Tornado-based applications. While it can +serve WSGI apps, this configuration is not recommended. + + +### AsyncIO workers + +Use third-party workers to pair Gunicorn with asyncio frameworks (see the +[aiohttp deployment guide](https://docs.aiohttp.org/en/stable/deployment.html#nginx-gunicorn) +or the [Flask aiohttp example](https://github.com/benoitc/gunicorn/blob/master/examples/frameworks/flaskapp_aiohttp_wsgi.py)). + +## Choosing a worker type + +Synchronous workers assume your app is CPU/network bound and avoids indefinite +operations. Any outbound HTTP calls or other blocking behaviour benefit from an +async worker. Because synchronous workers are vulnerable to slow clients, +Gunicorn requires a buffering proxy in front of the default configuration. Tools +like [Hey](https://github.com/rakyll/hey) can simulate slow responses to test +this scenario. + +Examples that need async workers: + +- Long blocking calls (outbound web services) +- Direct internet traffic (no buffering proxy) +- Streaming request/response bodies +- Long polling +- WebSockets / Comet + +## How many workers? + +Do **not** scale workers to match client count. Gunicorn usually needs only 4–12 +workers to handle heavy traffic. Start with `(2 * num_cores) + 1` and adjust +under load using `TTIN`/`TTOU`. + +Too many workers waste resources and can reduce throughput. + +## How many threads? + +Since Gunicorn 19 you can set `--threads` (with the `gthread` worker) to process +requests concurrently. Threads can extend request time beyond the worker +timeout while still notifying the master. The optimal mix of threads and worker +processes depends on the runtime (for example CPython vs. Jython). Threads share +memory, lowering footprint, and still allow reloads because application code is +loaded in worker processes. diff --git a/docs/content/faq.md b/docs/content/faq.md new file mode 100644 index 000000000..f26f1797c --- /dev/null +++ b/docs/content/faq.md @@ -0,0 +1,160 @@ + +# FAQ + +## WSGI bits + +### How do I set `SCRIPT_NAME`? + +By default `SCRIPT_NAME` is an empty string. Set it via an environment variable +or HTTP header. Because the header contains an underscore it is only accepted +from trusted forwarders listed in [`forwarded_allow_ips`](reference/settings.md#forwarded_allow_ips). + +!!! note + If your application should appear under a subfolder, `SCRIPT_NAME` typically + starts with a single leading slash and no trailing slash. + + + +## Server stuff + +### How do I reload my application in Gunicorn? + +Send `HUP` to the master process for a graceful reload: + +```bash +kill -HUP masterpid +``` + +### How might I test a proxy configuration? + +Use [Hey](https://github.com/rakyll/hey) to confirm that your proxy buffers +responses correctly for synchronous workers: + +```bash +hey -n 10000 -c 100 http://127.0.0.1:5000/ +``` + +That benchmark issues 10,000 requests with a concurrency of 100. + +### How can I name processes? + +Install [setproctitle](https://pypi.python.org/pypi/setproctitle) to give +Gunicorn processes meaningful names in tools such as `ps` and `top`. This helps +when running multiple Gunicorn instances. See the +[`proc_name`](reference/settings.md#proc_name) setting for details. + +### Why is there no HTTP keep-alive? + +The default sync workers target Nginx, which uses HTTP/1.0 for upstream +connections. If you need to serve unbuffered internet traffic directly, pick an +async worker instead. + +## Worker processes + +### How do I know which type of worker to use? + +Read the [design guide](design.md) for guidance on worker types. + +### What types of workers are available? + +See the [`worker_class`](reference/settings.md#worker_class) configuration reference. + +### How can I figure out the best number of worker processes? + +Follow the recommendations for tuning the [`number of workers`](design.md#how-many-workers). + +### How can I change the number of workers dynamically? + +Send `TTIN` or `TTOU` to the master process: + +```bash +kill -TTIN $masterpid # increment workers +kill -TTOU $masterpid # decrement workers +``` + +### Does Gunicorn suffer from the thundering herd problem? + +Potentially, when many sleeping handlers wake simultaneously but only one takes +the request. There is ongoing work to mitigate this +([issue #792](https://github.com/benoitc/gunicorn/issues/792)). Monitor load if +you use large numbers of workers or threads. + +### Why don't I see logs in the console? + +Gunicorn 19.0 disabled console logging by default. Use `--log-file=-` to stream +logs to stdout. Console logging returned in 19.2. + +## Kernel parameters + +High-concurrency deployments may need kernel tuning. These Linux-oriented tips +apply to any network service. + +### How can I increase the maximum number of file descriptors? + +Raise the per-process limit (remember sockets count as files). Running `sudo +ulimit` is ineffective—switch to root, adjust the limit, then launch Gunicorn. +Consider managing limits via systemd service units or init scripts. + +### How can I increase the maximum socket backlog? + +Increase the queue of pending connections: + +```bash +sudo sysctl -w net.core.somaxconn="2048" +``` + +### How can I disable the use of `sendfile()`? + +Pass `--no-sendfile` or set the `SENDFILE=0` environment variable. + +## Troubleshooting + +### Django reports `ImproperlyConfigured` + +Asynchronous workers may break `django.core.urlresolvers.reverse`. Use +`reverse_lazy` instead. + +### How do I avoid blocking in `os.fchmod`? + +Gunicorn's heartbeat touches temporary files. On disk-backed filesystems (for +example `/tmp` on some distributions) `os.fchmod` can block if I/O stalls or the +filesystem fills up. Mount a `tmpfs` and point `--worker-tmp-dir` to it. + +Check whether `/tmp` is RAM-backed: + +```bash +df /tmp +``` + +If not, create a new `tmpfs` mount: + +```bash +sudo cp /etc/fstab /etc/fstab.orig +sudo mkdir /mem +echo 'tmpfs /mem tmpfs defaults,size=64m,mode=1777,noatime,comment=for-gunicorn 0 0' | sudo tee -a /etc/fstab +sudo mount /mem +``` + +Verify the result: + +```bash +df /mem +``` + +Then start Gunicorn with `--worker-tmp-dir /mem`. + +### Why are workers silently killed? + +If a worker vanishes without logs, check for `SIGKILL`. Reverse proxies may show +`502` responses while Gunicorn logs only new worker startups (for example, +`[INFO] Booting worker`). A common culprit is the OOM killer in cgroups-limited +environments. + +Inspect kernel logs: + +```bash +dmesg | grep gunicorn +``` + +If you see messages similar to `Memory cgroup out of memory ... Killed process +(gunicorn.md)`, raise memory limits or adjust OOM behaviour. diff --git a/docs/content/index.md b/docs/content/index.md new file mode 100644 index 000000000..c9a7079a0 --- /dev/null +++ b/docs/content/index.md @@ -0,0 +1,68 @@ +# Gunicorn + +
+
+
+ +

Production-ready Python web services

+

Gunicorn is a dependable WSGI HTTP server for UNIX that keeps Python applications running fast and resilient in production. Built on a pre-fork worker model and trusted in countless deployments, it pairs clean configuration with flexible worker strategies so you can meet any traffic pattern.

+ +
+
+
$ pip install gunicorn
+$ gunicorn example:app --workers 3
+
Latest release: {{ release }}
+
+
+
+ +## Quickstart + +1. Install Gunicorn into your application environment. +2. Point Gunicorn at your WSGI app: `gunicorn myproject.wsgi`. +3. Tune worker type, concurrency, and hooks using the rich [settings](reference/settings.md). + +Need a longer walkthrough? Jump into the [install guide](install.md). + +## Why teams choose Gunicorn + +
+
+

Works with your framework

+

Django, Flask, FastAPI, Pyramid, you name it—Gunicorn speaks WSGI so your stack just runs.

+ Running Gunicorn → +
+
+

Flexible workers

+

Sync, async, gevent, eventlet—choose the concurrency model that fits.

+ Worker classes → +
+
+

Battle-tested hooks

+

Lifecycle hooks let you instrument, reload, and extend Gunicorn to match your deployment requirements.

+ Server hooks → +
+
+

Containers to bare metal

+

Deploy with systemd, Kubernetes, Heroku, or Docker—the configuration stays predictable everywhere.

+ Deployment patterns → +
+
+ +## Documentation map + +- [Install](install.md): Set up Gunicorn in a clean environment. +- [Run](run.md): CLI usage and integration with frameworks. +- [Configure](configure.md): Combine CLI flags and config files effectively. +- [Settings reference](reference/settings.md): Generated from the Gunicorn source of truth. +- [Signals](signals.md): Manage worker lifecycle in production. +- [Instrumentation](instrumentation.md): Monitor metrics and logs. + +## Community & support + +- Report bugs or request features on [GitHub Issues](https://github.com/benoitc/gunicorn/issues). +- Discuss strategies with maintainers in `#gunicorn` on [Libera Chat](https://libera.chat/). +- Contributions are welcome—see the [contributing guide](community.md#contributing) and say hi to the maintainers. diff --git a/docs/content/install.md b/docs/content/install.md new file mode 100644 index 000000000..df69e64fa --- /dev/null +++ b/docs/content/install.md @@ -0,0 +1,142 @@ +# Installation + +!!! note + Gunicorn requires **Python 3.12 or newer**. + + + +```bash +pip install gunicorn +``` + +## From source + +Install Gunicorn from GitHub if you want the latest development version: + +```bash +pip install git+https://github.com/benoitc/gunicorn.git +``` + +Stay current by upgrading in place: + +```bash +pip install -U git+https://github.com/benoitc/gunicorn.git +``` + +## Async workers + +Install Eventlet or Gevent if your application benefits from cooperative I/O. +Both rely on `greenlet`, so make sure the Python headers are available (for +example, install the `python-dev` package on Ubuntu). + +```bash +pip install greenlet # Required for both +pip install eventlet # For eventlet workers +pip install gunicorn[eventlet] # Or, using extra +pip install gevent # For gevent workers +pip install gunicorn[gevent] # Or, using extra +``` + +!!! note + Gevent also needs `libevent` 1.4.x or 2.0.4+. Install it from your package + manager or build it manually if the packaged version is too old. + + + +## Extra packages + +Some Gunicorn options require additional dependencies. Install them via +extras to pull everything in with one command. + +Most extras enable alternative worker types—see the +[design docs](design.md) for when each worker makes sense. + +- `gunicorn[eventlet]` — Eventlet-based greenlet workers +- `gunicorn[gevent]` — Gevent-based greenlet workers +- `gunicorn[gthread]` — Threaded workers +- `gunicorn[tornado]` — Tornado-based workers (not recommended) + +If you run more than one Gunicorn instance, the +[`proc_name`](reference/settings.md#proc_name) setting helps distinguish them in tools such +as `ps` and `top`. + +- `gunicorn[setproctitle]` — Enables setting the process name + +You can combine multiple extras, for example: + +```bash +pip install gunicorn[gevent,setproctitle] +``` + +## Debian GNU/Linux + +On Debian systems prefer the distribution packages unless you need per-project +virtual environments: + +- Zero-effort installation: automatically starts multiple instances based on + configs in `/etc/gunicorn.d`. +- Sensible log locations (`/var/log/gunicorn`) with `logrotate` support. +- Improved security: run each instance with a dedicated UNIX user/group. +- Safe upgrades: minimal downtime, reversible changes, and easy package purge. + +### stable ("buster") + +The Debian [stable](https://www.debian.org/releases/stable/) release ships +Gunicorn 19.9.0 (December 2020): + +```bash +sudo apt-get install gunicorn3 +``` + +Install Gunicorn 20.0.4 from [Debian Backports](https://backports.debian.org/) +by adding this line to `/etc/apt/sources.list`: + +```text +deb http://ftp.debian.org/debian buster-backports main +``` + +Refresh package metadata and install: + +```bash +sudo apt-get update +sudo apt-get -t buster-backports install gunicorn +``` + +### oldstable ("stretch") + +Stretch provides Gunicorn 19.6.0 (December 2020). Install the Python 3 version: + +```bash +sudo apt-get install gunicorn3 +``` + +To upgrade to 19.7.1 from backports, add: + +```text +deb http://ftp.debian.org/debian stretch-backports main +``` + +Then update and install: + +```bash +sudo apt-get update +sudo apt-get -t stretch-backports install gunicorn3 +``` + +### testing ("bullseye") and unstable ("sid") + +Both distributions include Gunicorn 20.0.4. Install it in the usual way: + +```bash +sudo apt-get install gunicorn +``` + +## Ubuntu + +Ubuntu 20.04 LTS (Focal Fossa) and newer include Gunicorn 20.0.4. Keep it +current through the package manager: + +```bash +sudo apt-get update +sudo apt-get install gunicorn +``` diff --git a/docs/content/instrumentation.md b/docs/content/instrumentation.md new file mode 100644 index 000000000..c4d3c2483 --- /dev/null +++ b/docs/content/instrumentation.md @@ -0,0 +1,32 @@ + +# Instrumentation + +!!! info "Added in 19.1" + Gunicorn exposes optional instrumentation for the arbiter and workers using the + statsD protocol over UDP. The `gunicorn.instrument.statsd` module turns + Gunicorn into a statsD client. + + + +UDP keeps Gunicorn isolated from slow statsD consumers, so metrics collection +does not impact request handling. + +Tell Gunicorn where the statsD server is located: + +```bash +gunicorn --statsd-host=localhost:8125 --statsd-prefix=service.app ... +``` + +The `Statsd` logger subclasses `gunicorn.glogging.Logger` and tracks: + +- `gunicorn.requests` — request rate per second +- `gunicorn.request.duration` — request duration histogram (milliseconds.md) +- `gunicorn.workers` — number of workers managed by the arbiter (gauge.md) +- `gunicorn.log.critical` — rate of critical log messages +- `gunicorn.log.error` — rate of error log messages +- `gunicorn.log.warning` — rate of warning log messages +- `gunicorn.log.exception` — rate of exceptional log messages + +See the [`statsd_host`](reference/settings.md#statsd_host) setting for additional options. + +[statsD](https://github.com/etsy/statsd) diff --git a/docs/content/news.md b/docs/content/news.md new file mode 100644 index 000000000..1b7f07229 --- /dev/null +++ b/docs/content/news.md @@ -0,0 +1,75 @@ + +# Changelog + +## 23.0.0 - 2024-08-10 + +- minor docs fixes ([PR #3217](https://github.com/benoitc/gunicorn/pull/3217), [PR #3089](https://github.com/benoitc/gunicorn/pull/3089), [PR #3167](https://github.com/benoitc/gunicorn/pull/3167)) +- worker_class parameter accepts a class ([PR #3079](https://github.com/benoitc/gunicorn/pull/3079)) +- fix deadlock if request terminated during chunked parsing ([PR #2688](https://github.com/benoitc/gunicorn/pull/2688)) +- permit receiving Transfer-Encodings: compress, deflate, gzip ([PR #3261](https://github.com/benoitc/gunicorn/pull/3261)) +- permit Transfer-Encoding headers specifying multiple encodings. note: no parameters, still ([PR #3261](https://github.com/benoitc/gunicorn/pull/3261)) +- sdist generation now explicitly excludes sphinx build folder ([PR #3257](https://github.com/benoitc/gunicorn/pull/3257)) +- decode bytes-typed status (as can be passed by gevent) as utf-8 instead of raising `TypeError` ([PR #2336](https://github.com/benoitc/gunicorn/pull/2336)) +- raise correct Exception when encounting invalid chunked requests ([PR #3258](https://github.com/benoitc/gunicorn/pull/3258)) +- the SCRIPT_NAME and PATH_INFO headers, when received from allowed forwarders, are no longer restricted for containing an underscore ([PR #3192](https://github.com/benoitc/gunicorn/pull/3192)) +- include IPv6 loopback address ``[::1]`` in default for [forwarded-allow-ips](reference/settings.md#forwarded_allow_ips) and [proxy-allow-ips](reference/settings.md#proxy_allow_ips) ([PR #3192](https://github.com/benoitc/gunicorn/pull/3192)) + +!!! note + - The SCRIPT_NAME change mitigates a regression that appeared first in the 22.0.0 release + - Review your [forwarded-allow-ips](reference/settings.md#forwarded_allow_ips) setting if you are still not seeing the SCRIPT_NAME transmitted + - Review your [forwarder-headers](reference/settings.md#forwarder_headers) setting if you are missing headers after upgrading from a version prior to 22.0.0 + + +### Breaking changes + +- refuse requests where the uri field is empty ([PR #3255](https://github.com/benoitc/gunicorn/pull/3255)) +- refuse requests with invalid CR/LR/NUL in heade field values ([PR #3253](https://github.com/benoitc/gunicorn/pull/3253)) +- remove temporary ``--tolerate-dangerous-framing`` switch from 22.0 ([PR #3260](https://github.com/benoitc/gunicorn/pull/3260)) +- If any of the breaking changes affect you, be aware that now refused requests can post a security problem, especially so in setups involving request pipe-lining and/or proxies. + +## 22.0.0 - 2024-04-17 + +- use `utime` to notify workers liveness +- migrate setup to pyproject.toml +- fix numerous security vulnerabilities in HTTP parser (closing some request smuggling vectors) +- parsing additional requests is no longer attempted past unsupported request framing +- on HTTP versions < 1.1 support for chunked transfer is refused (only used in exploits) +- requests conflicting configured or passed SCRIPT_NAME now produce a verbose error +- Trailer fields are no longer inspected for headers indicating secure scheme +- support Python 3.12 + +### Breaking changes + +- minimum version is Python 3.7 +- the limitations on valid characters in the HTTP method have been bounded to Internet Standards +- requests specifying unsupported transfer coding (order.md) are refused by default (rare.md) +- HTTP methods are no longer casefolded by default (IANA method registry contains none affected) +- HTTP methods containing the number sign (#) are no longer accepted by default (rare.md) +- HTTP versions < 1.0 or >= 2.0 are no longer accepted by default (rare, only HTTP/1.1 is supported) +- HTTP versions consisting of multiple digits or containing a prefix/suffix are no longer accepted +- HTTP header field names Gunicorn cannot safely map to variables are silently dropped, as in other software +- HTTP headers with empty field name are refused by default (no legitimate use cases, used in exploits) +- requests with both Transfer-Encoding and Content-Length are refused by default (such a message might indicate an attempt to perform request smuggling) +- empty transfer codings are no longer permitted (reportedly seen with really old & broken proxies) + + +### Security + +- fix CVE-2024-1135 + +## History + +- [2024](2024-news.md) +- [2023](2023-news.md) +- [2021](2021-news.md) +- [2020](2020-news.md) +- [2019](2019-news.md) +- [2018](2018-news.md) +- [2017](2017-news.md) +- [2016](2016-news.md) +- [2015](2015-news.md) +- [2014](2014-news.md) +- [2013](2013-news.md) +- [2012](2012-news.md) +- [2011](2011-news.md) +- [2010](2010-news.md) diff --git a/docs/source/settings.rst b/docs/content/reference/settings.md similarity index 61% rename from docs/source/settings.rst rename to docs/content/reference/settings.md index 046770616..edafe5337 100644 --- a/docs/source/settings.rst +++ b/docs/content/reference/settings.md @@ -1,38 +1,32 @@ -.. Please update gunicorn/config.py instead. +> **Generated file** — update `gunicorn/config.py` instead. -.. _settings: +# Settings -Settings -======== +This reference is built directly from `gunicorn.config.KNOWN_SETTINGS` and is +regenerated during every documentation build. -This is an exhaustive list of settings for Gunicorn. Some settings are only -able to be set from a configuration file. The setting name is what should be -used in the configuration file. The command line arguments are listed as well -for reference on setting at the command line. +!!! note + Settings can be provided through the `GUNICORN_CMD_ARGS` environment + variable. For example: -.. note:: + ```console + $ GUNICORN_CMD_ARGS="--bind=127.0.0.1 --workers=3" gunicorn app:app + ``` - Settings can be specified by using environment variable - ``GUNICORN_CMD_ARGS``. All available command line arguments can be used. - For example, to specify the bind address and number of workers:: + _Added in 19.7._ - $ GUNICORN_CMD_ARGS="--bind=127.0.0.1 --workers=3" gunicorn app:app - .. versionadded:: 19.7 + -Config File ------------ +# Config File -.. _config: +## `config` -``config`` -~~~~~~~~~~ +**Command line:** `-c CONFIG`, `--config CONFIG` -**Command line:** ``-c CONFIG`` or ``--config CONFIG`` +**Default:** `'./gunicorn.conf.py'` -**Default:** ``'./gunicorn.conf.py'`` - -:ref:`The Gunicorn config file`. +[The Gunicorn config file](../configure.md#configuration-file). A string of the form ``PATH``, ``file:PATH``, or ``python:MODULE_NAME``. @@ -42,32 +36,25 @@ application specific configuration. By default, a file named ``gunicorn.conf.py`` will be read from the same directory where gunicorn is being run. -.. versionchanged:: 19.4 - Loading the config from a Python module requires the ``python:`` - prefix. - -.. _wsgi-app: +!!! info "Changed in 19.4" + Loading the config from a Python module requires the ``python:`` + prefix. -``wsgi_app`` -~~~~~~~~~~~~ +## `wsgi_app` -**Default:** ``None`` +**Default:** `None` A WSGI application path in pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. -.. versionadded:: 20.1.0 +!!! info "Added in 20.1.0" -Debugging ---------- +# Debugging -.. _reload: +## `reload` -``reload`` -~~~~~~~~~~ +**Command line:** `--reload` -**Command line:** ``--reload`` - -**Default:** ``False`` +**Default:** `False` Restart workers when code changes. @@ -82,20 +69,17 @@ The default behavior is to attempt inotify with a fallback to file system polling. Generally, inotify should be preferred if available because it consumes less system resources. -.. note:: - In order to use the inotify reloader, you must have the ``inotify`` - package installed. - -.. _reload-engine: +!!! note + In order to use the inotify reloader, you must have the ``inotify`` + package installed. -``reload_engine`` -~~~~~~~~~~~~~~~~~ +## `reload_engine` -**Command line:** ``--reload-engine STRING`` +**Command line:** `--reload-engine STRING` -**Default:** ``'auto'`` +**Default:** `'auto'` -The implementation that should be used to power :ref:`reload`. +The implementation that should be used to power [reload](#reload). Valid engines are: @@ -103,95 +87,73 @@ Valid engines are: * ``'poll'`` * ``'inotify'`` (requires inotify) -.. versionadded:: 19.7 +!!! info "Added in 19.7" -.. _reload-extra-files: +## `reload_extra_files` -``reload_extra_files`` -~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--reload-extra-file FILES` -**Command line:** ``--reload-extra-file FILES`` +**Default:** `[]` -**Default:** ``[]`` - -Extends :ref:`reload` option to also watch and reload on additional files +Extends [reload](#reload) option to also watch and reload on additional files (e.g., templates, configurations, specifications, etc.). -.. versionadded:: 19.8 - -.. _spew: +!!! info "Added in 19.8" -``spew`` -~~~~~~~~ +## `spew` -**Command line:** ``--spew`` +**Command line:** `--spew` -**Default:** ``False`` +**Default:** `False` Install a trace function that spews every line executed by the server. This is the nuclear option. -.. _check-config: +## `check_config` -``check_config`` -~~~~~~~~~~~~~~~~ +**Command line:** `--check-config` -**Command line:** ``--check-config`` - -**Default:** ``False`` +**Default:** `False` Check the configuration and exit. The exit status is 0 if the configuration is correct, and 1 if the configuration is incorrect. -.. _print-config: - -``print_config`` -~~~~~~~~~~~~~~~~ +## `print_config` -**Command line:** ``--print-config`` +**Command line:** `--print-config` -**Default:** ``False`` +**Default:** `False` -Print the configuration settings as fully resolved. Implies :ref:`check-config`. +Print the configuration settings as fully resolved. Implies [check-config](#check_config). -Logging -------- +# Logging -.. _accesslog: +## `accesslog` -``accesslog`` -~~~~~~~~~~~~~ +**Command line:** `--access-logfile FILE` -**Command line:** ``--access-logfile FILE`` - -**Default:** ``None`` +**Default:** `None` The Access log file to write to. ``'-'`` means log to stdout. -.. _disable-redirect-access-to-syslog: - -``disable_redirect_access_to_syslog`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## `disable_redirect_access_to_syslog` -**Command line:** ``--disable-redirect-access-to-syslog`` +**Command line:** `--disable-redirect-access-to-syslog` -**Default:** ``False`` +**Default:** `False` Disable redirect access logs to syslog. -.. versionadded:: 19.8 +!!! info "Added in 19.8" -.. _access-log-format: +## `access_log_format` -``access_log_format`` -~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--access-logformat STRING` -**Command line:** ``--access-logformat STRING`` - -**Default:** ``'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'`` +**Default:** `'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'` The access log format. @@ -227,30 +189,24 @@ Use lowercase for header and environment variable names, and put %({x-forwarded-for}i)s -.. _errorlog: - -``errorlog`` -~~~~~~~~~~~~ +## `errorlog` -**Command line:** ``--error-logfile FILE`` or ``--log-file FILE`` +**Command line:** `--error-logfile FILE`, `--log-file FILE` -**Default:** ``'-'`` +**Default:** `'-'` The Error log file to write to. Using ``'-'`` for FILE makes gunicorn log to stderr. -.. versionchanged:: 19.2 - Log to stderr by default. +!!! info "Changed in 19.2" + Log to stderr by default. -.. _loglevel: +## `loglevel` -``loglevel`` -~~~~~~~~~~~~ +**Command line:** `--log-level LEVEL` -**Command line:** ``--log-level LEVEL`` - -**Default:** ``'info'`` +**Default:** `'info'` The granularity of Error log outputs. @@ -262,27 +218,21 @@ Valid level names are: * ``'error'`` * ``'critical'`` -.. _capture-output: - -``capture_output`` -~~~~~~~~~~~~~~~~~~ - -**Command line:** ``--capture-output`` +## `capture_output` -**Default:** ``False`` +**Command line:** `--capture-output` -Redirect stdout/stderr to specified file in :ref:`errorlog`. +**Default:** `False` -.. versionadded:: 19.6 +Redirect stdout/stderr to specified file in [errorlog](#errorlog). -.. _logger-class: +!!! info "Added in 19.6" -``logger_class`` -~~~~~~~~~~~~~~~~ +## `logger_class` -**Command line:** ``--logger-class STRING`` +**Command line:** `--logger-class STRING` -**Default:** ``'gunicorn.glogging.Logger'`` +**Default:** `'gunicorn.glogging.Logger'` The logger you want to use to log events in Gunicorn. @@ -292,29 +242,23 @@ normal usages in logging. It provides error and access logging. You can provide your own logger by giving Gunicorn a Python path to a class that quacks like ``gunicorn.glogging.Logger``. -.. _logconfig: +## `logconfig` -``logconfig`` -~~~~~~~~~~~~~ +**Command line:** `--log-config FILE` -**Command line:** ``--log-config FILE`` - -**Default:** ``None`` +**Default:** `None` The log config file to use. Gunicorn uses the standard Python logging module's Configuration file format. -.. _logconfig-dict: - -``logconfig_dict`` -~~~~~~~~~~~~~~~~~~ +## `logconfig_dict` -**Default:** ``{}`` +**Default:** `{}` The log config dictionary to use, using the standard Python logging module's dictionary configuration format. This option -takes precedence over the :ref:`logconfig` and :ref:`logconfig-json` options, +takes precedence over the [logconfig](#logconfig) and [logconfig-json](#logconfig_json) options, which uses the older file configuration format and JSON respectively. @@ -323,31 +267,25 @@ Format: https://docs.python.org/3/library/logging.config.html#logging.config.dic For more context you can look at the default configuration dictionary for logging, which can be found at ``gunicorn.glogging.CONFIG_DEFAULTS``. -.. versionadded:: 19.8 +!!! info "Added in 19.8" -.. _logconfig-json: +## `logconfig_json` -``logconfig_json`` -~~~~~~~~~~~~~~~~~~ +**Command line:** `--log-config-json FILE` -**Command line:** ``--log-config-json FILE`` - -**Default:** ``None`` +**Default:** `None` The log config to read config from a JSON file Format: https://docs.python.org/3/library/logging.config.html#logging.config.jsonConfig -.. versionadded:: 20.0 - -.. _syslog-addr: +!!! info "Added in 20.0" -``syslog_addr`` -~~~~~~~~~~~~~~~ +## `syslog_addr` -**Command line:** ``--log-syslog-to SYSLOG_ADDR`` +**Command line:** `--log-syslog-to SYSLOG_ADDR` -**Default:** ``'unix:///var/run/syslog'`` +**Default:** `'unix:///var/run/syslog'` Address to send syslog messages. @@ -359,54 +297,42 @@ Address is a string of the form: * ``udp://HOST:PORT`` : for UDP sockets * ``tcp://HOST:PORT`` : for TCP sockets -.. _syslog: +## `syslog` -``syslog`` -~~~~~~~~~~ +**Command line:** `--log-syslog` -**Command line:** ``--log-syslog`` - -**Default:** ``False`` +**Default:** `False` Send *Gunicorn* logs to syslog. -.. versionchanged:: 19.8 - You can now disable sending access logs by using the - :ref:`disable-redirect-access-to-syslog` setting. - -.. _syslog-prefix: +!!! info "Changed in 19.8" + You can now disable sending access logs by using the + disable-redirect-access-to-syslog setting. -``syslog_prefix`` -~~~~~~~~~~~~~~~~~ +## `syslog_prefix` -**Command line:** ``--log-syslog-prefix SYSLOG_PREFIX`` +**Command line:** `--log-syslog-prefix SYSLOG_PREFIX` -**Default:** ``None`` +**Default:** `None` Makes Gunicorn use the parameter as program-name in the syslog entries. All entries will be prefixed by ``gunicorn.``. By default the program name is the name of the process. -.. _syslog-facility: - -``syslog_facility`` -~~~~~~~~~~~~~~~~~~~ +## `syslog_facility` -**Command line:** ``--log-syslog-facility SYSLOG_FACILITY`` +**Command line:** `--log-syslog-facility SYSLOG_FACILITY` -**Default:** ``'user'`` +**Default:** `'user'` Syslog facility name -.. _enable-stdio-inheritance: +## `enable_stdio_inheritance` -``enable_stdio_inheritance`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `-R`, `--enable-stdio-inheritance` -**Command line:** ``-R`` or ``--enable-stdio-inheritance`` - -**Default:** ``False`` +**Default:** `False` Enable stdio inheritance. @@ -415,14 +341,11 @@ Enable inheritance for stdio file descriptors in daemon mode. Note: To disable the Python stdout buffering, you can to set the user environment variable ``PYTHONUNBUFFERED`` . -.. _statsd-host: - -``statsd_host`` -~~~~~~~~~~~~~~~ +## `statsd_host` -**Command line:** ``--statsd-host STATSD_ADDR`` +**Command line:** `--statsd-host STATSD_ADDR` -**Default:** ``None`` +**Default:** `None` The address of the StatsD server to log to. @@ -431,47 +354,37 @@ Address is a string of the form: * ``unix://PATH`` : for a unix domain socket. * ``HOST:PORT`` : for a network address -.. versionadded:: 19.1 +!!! info "Added in 19.1" -.. _dogstatsd-tags: +## `dogstatsd_tags` -``dogstatsd_tags`` -~~~~~~~~~~~~~~~~~~ +**Command line:** `--dogstatsd-tags DOGSTATSD_TAGS` -**Command line:** ``--dogstatsd-tags DOGSTATSD_TAGS`` - -**Default:** ``''`` +**Default:** `''` A comma-delimited list of datadog statsd (dogstatsd) tags to append to statsd metrics. -.. versionadded:: 20 - -.. _statsd-prefix: +!!! info "Added in 20" -``statsd_prefix`` -~~~~~~~~~~~~~~~~~ +## `statsd_prefix` -**Command line:** ``--statsd-prefix STATSD_PREFIX`` +**Command line:** `--statsd-prefix STATSD_PREFIX` -**Default:** ``''`` +**Default:** `''` Prefix to use when emitting statsd metrics (a trailing ``.`` is added, if not provided). -.. versionadded:: 19.2 +!!! info "Added in 19.2" -Process Naming --------------- +# Process Naming -.. _proc-name: +## `proc_name` -``proc_name`` -~~~~~~~~~~~~~ +**Command line:** `-n STRING`, `--name STRING` -**Command line:** ``-n STRING`` or ``--name STRING`` - -**Default:** ``None`` +**Default:** `None` A base to use with setproctitle for process naming. @@ -482,53 +395,40 @@ module. If not set, the *default_proc_name* setting will be used. -.. _default-proc-name: - -``default_proc_name`` -~~~~~~~~~~~~~~~~~~~~~ +## `default_proc_name` -**Default:** ``'gunicorn'`` +**Default:** `'gunicorn'` Internal setting that is adjusted for each type of application. -SSL ---- - -.. _keyfile: +# SSL -``keyfile`` -~~~~~~~~~~~ +## `keyfile` -**Command line:** ``--keyfile FILE`` +**Command line:** `--keyfile FILE` -**Default:** ``None`` +**Default:** `None` SSL key file -.. _certfile: +## `certfile` -``certfile`` -~~~~~~~~~~~~ +**Command line:** `--certfile FILE` -**Command line:** ``--certfile FILE`` - -**Default:** ``None`` +**Default:** `None` SSL certificate file -.. _ssl-version: - -``ssl_version`` -~~~~~~~~~~~~~~~ +## `ssl_version` -**Command line:** ``--ssl-version`` +**Command line:** `--ssl-version` -**Default:** ``<_SSLMethod.PROTOCOL_TLS: 2>`` +**Default:** `<_SSLMethod.PROTOCOL_TLS: 2>` SSL version to use (see stdlib ssl module's). -.. deprecated:: 21.0 - The option is deprecated and it is currently ignored. Use :ref:`ssl-context` instead. +!!! danger "Deprecated in 21.0" + The option is deprecated and it is currently ignored. Use [ssl-context](#ssl_context) instead. ============= ============ --ssl-version Description @@ -545,24 +445,23 @@ TLS_SERVER Auto-negotiate the highest protocol version like TLS, (Python 3.6+) ============= ============ -.. versionchanged:: 19.7 - The default value has been changed from ``ssl.PROTOCOL_TLSv1`` to - ``ssl.PROTOCOL_SSLv23``. -.. versionchanged:: 20.0 - This setting now accepts string names based on ``ssl.PROTOCOL_`` - constants. -.. versionchanged:: 20.0.1 - The default value has been changed from ``ssl.PROTOCOL_SSLv23`` to - ``ssl.PROTOCOL_TLS`` when Python >= 3.6 . +!!! info "Changed in 19.7" + The default value has been changed from ``ssl.PROTOCOL_TLSv1`` to + ``ssl.PROTOCOL_SSLv23``. -.. _cert-reqs: +!!! info "Changed in 20.0" + This setting now accepts string names based on ``ssl.PROTOCOL_`` + constants. -``cert_reqs`` -~~~~~~~~~~~~~ +!!! info "Changed in 20.0.1" + The default value has been changed from ``ssl.PROTOCOL_SSLv23`` to + ``ssl.PROTOCOL_TLS`` when Python >= 3.6 . -**Command line:** ``--cert-reqs`` +## `cert_reqs` -**Default:** ```` +**Command line:** `--cert-reqs` + +**Default:** `` Whether client certificate is required (see stdlib ssl module's) @@ -574,47 +473,35 @@ Whether client certificate is required (see stdlib ssl module's) `2` ssl.CERT_REQUIRED =========== =========================== -.. _ca-certs: - -``ca_certs`` -~~~~~~~~~~~~ +## `ca_certs` -**Command line:** ``--ca-certs FILE`` +**Command line:** `--ca-certs FILE` -**Default:** ``None`` +**Default:** `None` CA certificates file -.. _suppress-ragged-eofs: +## `suppress_ragged_eofs` -``suppress_ragged_eofs`` -~~~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--suppress-ragged-eofs` -**Command line:** ``--suppress-ragged-eofs`` - -**Default:** ``True`` +**Default:** `True` Suppress ragged EOFs (see stdlib ssl module's) -.. _do-handshake-on-connect: - -``do_handshake_on_connect`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## `do_handshake_on_connect` -**Command line:** ``--do-handshake-on-connect`` +**Command line:** `--do-handshake-on-connect` -**Default:** ``False`` +**Default:** `False` Whether to perform SSL handshake on socket connect (see stdlib ssl module's) -.. _ciphers: - -``ciphers`` -~~~~~~~~~~~ +## `ciphers` -**Command line:** ``--ciphers`` +**Command line:** `--ciphers` -**Default:** ``None`` +**Default:** `None` SSL Cipher suite to use, in the format of an OpenSSL cipher list. @@ -631,17 +518,13 @@ See the `OpenSSL Cipher List Format Documentation `_ for details on the format of an OpenSSL cipher list. -Security --------- +# Security -.. _limit-request-line: +## `limit_request_line` -``limit_request_line`` -~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--limit-request-line INT` -**Command line:** ``--limit-request-line INT`` - -**Default:** ``4094`` +**Default:** `4094` The maximum size of HTTP request line in bytes. @@ -656,14 +539,11 @@ from 0 (unlimited) to 8190. This parameter can be used to prevent any DDOS attack. -.. _limit-request-fields: - -``limit_request_fields`` -~~~~~~~~~~~~~~~~~~~~~~~~ +## `limit_request_fields` -**Command line:** ``--limit-request-fields INT`` +**Command line:** `--limit-request-fields INT` -**Default:** ``100`` +**Default:** `100` Limit the number of HTTP headers fields in a request. @@ -672,154 +552,126 @@ prevent DDOS attack. Used with the *limit_request_field_size* it allows more safety. By default this value is 100 and can't be larger than 32768. -.. _limit-request-field-size: +## `limit_request_field_size` -``limit_request_field_size`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--limit-request-field_size INT` -**Command line:** ``--limit-request-field_size INT`` - -**Default:** ``8190`` +**Default:** `8190` Limit the allowed size of an HTTP request header field. Value is a positive number or 0. Setting it to 0 will allow unlimited header field sizes. -.. warning:: - Setting this parameter to a very high or unlimited value can open - up for DDOS attacks. - -Server Hooks ------------- +!!! warning + Setting this parameter to a very high or unlimited value can open + up for DDOS attacks. -.. _on-starting: +# Server Hooks -``on_starting`` -~~~~~~~~~~~~~~~ +## `on_starting` -**Default:** +**Default:** -.. code-block:: python - - def on_starting(server): - pass +```python +def on_starting(server): + pass +``` Called just before the master process is initialized. The callable needs to accept a single instance variable for the Arbiter. -.. _on-reload: - -``on_reload`` -~~~~~~~~~~~~~ - -**Default:** +## `on_reload` -.. code-block:: python +**Default:** - def on_reload(server): - pass +```python +def on_reload(server): + pass +``` Called to recycle workers during a reload via SIGHUP. The callable needs to accept a single instance variable for the Arbiter. -.. _when-ready: +## `when_ready` -``when_ready`` -~~~~~~~~~~~~~~ +**Default:** -**Default:** - -.. code-block:: python - - def when_ready(server): - pass +```python +def when_ready(server): + pass +``` Called just after the server is started. The callable needs to accept a single instance variable for the Arbiter. -.. _pre-fork: - -``pre_fork`` -~~~~~~~~~~~~ - -**Default:** +## `pre_fork` -.. code-block:: python +**Default:** - def pre_fork(server, worker): - pass +```python +def pre_fork(server, worker): + pass +``` Called just before a worker is forked. The callable needs to accept two instance variables for the Arbiter and new Worker. -.. _post-fork: +## `post_fork` -``post_fork`` -~~~~~~~~~~~~~ +**Default:** -**Default:** - -.. code-block:: python - - def post_fork(server, worker): - pass +```python +def post_fork(server, worker): + pass +``` Called just after a worker has been forked. The callable needs to accept two instance variables for the Arbiter and new Worker. -.. _post-worker-init: - -``post_worker_init`` -~~~~~~~~~~~~~~~~~~~~ +## `post_worker_init` -**Default:** +**Default:** -.. code-block:: python - - def post_worker_init(worker): - pass +```python +def post_worker_init(worker): + pass +``` Called just after a worker has initialized the application. The callable needs to accept one instance variable for the initialized Worker. -.. _worker-int: - -``worker_int`` -~~~~~~~~~~~~~~ +## `worker_int` -**Default:** +**Default:** -.. code-block:: python - - def worker_int(worker): - pass +```python +def worker_int(worker): + pass +``` Called just after a worker exited on SIGINT or SIGQUIT. The callable needs to accept one instance variable for the initialized Worker. -.. _worker-abort: - -``worker_abort`` -~~~~~~~~~~~~~~~~ +## `worker_abort` -**Default:** +**Default:** -.. code-block:: python - - def worker_abort(worker): - pass +```python +def worker_abort(worker): + pass +``` Called when a worker received the SIGABRT signal. @@ -828,103 +680,85 @@ This call generally happens on timeout. The callable needs to accept one instance variable for the initialized Worker. -.. _pre-exec: - -``pre_exec`` -~~~~~~~~~~~~ - -**Default:** +## `pre_exec` -.. code-block:: python +**Default:** - def pre_exec(server): - pass +```python +def pre_exec(server): + pass +``` Called just before a new master process is forked. The callable needs to accept a single instance variable for the Arbiter. -.. _pre-request: +## `pre_request` -``pre_request`` -~~~~~~~~~~~~~~~ +**Default:** -**Default:** - -.. code-block:: python - - def pre_request(worker, req): - worker.log.debug("%s %s", req.method, req.path) +```python +def pre_request(worker, req): + worker.log.debug("%s %s", req.method, req.path) +``` Called just before a worker processes the request. The callable needs to accept two instance variables for the Worker and the Request. -.. _post-request: - -``post_request`` -~~~~~~~~~~~~~~~~ - -**Default:** +## `post_request` -.. code-block:: python +**Default:** - def post_request(worker, req, environ, resp): - pass +```python +def post_request(worker, req, environ, resp): + pass +``` Called after a worker processes the request. The callable needs to accept two instance variables for the Worker and the Request. -.. _child-exit: +## `child_exit` -``child_exit`` -~~~~~~~~~~~~~~ +**Default:** -**Default:** - -.. code-block:: python - - def child_exit(server, worker): - pass +```python +def child_exit(server, worker): + pass +``` Called just after a worker has been exited, in the master process. The callable needs to accept two instance variables for the Arbiter and the just-exited Worker. -.. versionadded:: 19.7 - -.. _worker-exit: - -``worker_exit`` -~~~~~~~~~~~~~~~ +!!! info "Added in 19.7" -**Default:** +## `worker_exit` -.. code-block:: python +**Default:** - def worker_exit(server, worker): - pass +```python +def worker_exit(server, worker): + pass +``` Called just after a worker has been exited, in the worker process. The callable needs to accept two instance variables for the Arbiter and the just-exited Worker. -.. _nworkers-changed: +## `nworkers_changed` -``nworkers_changed`` -~~~~~~~~~~~~~~~~~~~~ +**Default:** -**Default:** - -.. code-block:: python - - def nworkers_changed(server, new_value, old_value): - pass +```python +def nworkers_changed(server, new_value, old_value): + pass +``` Called just after *num_workers* has been changed. @@ -934,33 +768,27 @@ two integers of number of workers after and before change. If the number of workers is set for the first time, *old_value* would be ``None``. -.. _on-exit: - -``on_exit`` -~~~~~~~~~~~ - -**Default:** +## `on_exit` -.. code-block:: python +**Default:** - def on_exit(server): - pass +```python +def on_exit(server): + pass +``` Called just before exiting Gunicorn. The callable needs to accept a single instance variable for the Arbiter. -.. _ssl-context: +## `ssl_context` -``ssl_context`` -~~~~~~~~~~~~~~~ +**Default:** -**Default:** - -.. code-block:: python - - def ssl_context(config, default_ssl_context_factory): - return default_ssl_context_factory() +```python +def ssl_context(config, default_ssl_context_factory): + return default_ssl_context_factory() +``` Called when SSLContext is needed. @@ -974,27 +802,23 @@ The callable needs to return SSLContext object. Following example shows a configuration file that sets the minimum TLS version to 1.3: -.. code-block:: python - - def ssl_context(conf, default_ssl_context_factory): - import ssl - context = default_ssl_context_factory() - context.minimum_version = ssl.TLSVersion.TLSv1_3 - return context +```python +def ssl_context(conf, default_ssl_context_factory): + import ssl + context = default_ssl_context_factory() + context.minimum_version = ssl.TLSVersion.TLSv1_3 + return context +``` -.. versionadded:: 21.0 +!!! info "Added in 21.0" -Server Mechanics ----------------- +# Server Mechanics -.. _preload-app: +## `preload_app` -``preload_app`` -~~~~~~~~~~~~~~~ +**Command line:** `--preload` -**Command line:** ``--preload`` - -**Default:** ``False`` +**Default:** `False` Load application code before the worker processes are forked. @@ -1003,73 +827,62 @@ speed up server boot times. Although, if you defer application loading to each worker process, you can reload your application code easily by restarting workers. -.. _sendfile: - -``sendfile`` -~~~~~~~~~~~~ +## `sendfile` -**Command line:** ``--no-sendfile`` +**Command line:** `--no-sendfile` -**Default:** ``None`` +**Default:** `None` Disables the use of ``sendfile()``. If not set, the value of the ``SENDFILE`` environment variable is used to enable or disable its usage. -.. versionadded:: 19.2 -.. versionchanged:: 19.4 - Swapped ``--sendfile`` with ``--no-sendfile`` to actually allow - disabling. -.. versionchanged:: 19.6 - added support for the ``SENDFILE`` environment variable +!!! info "Added in 19.2" -.. _reuse-port: +!!! info "Changed in 19.4" + Swapped ``--sendfile`` with ``--no-sendfile`` to actually allow + disabling. -``reuse_port`` -~~~~~~~~~~~~~~ +!!! info "Changed in 19.6" + added support for the ``SENDFILE`` environment variable -**Command line:** ``--reuse-port`` +## `reuse_port` -**Default:** ``False`` +**Command line:** `--reuse-port` + +**Default:** `False` Set the ``SO_REUSEPORT`` flag on the listening socket. -.. versionadded:: 19.8 +!!! info "Added in 19.8" -.. _chdir: +## `chdir` -``chdir`` -~~~~~~~~~ +**Command line:** `--chdir` -**Command line:** ``--chdir`` +**Default:** -**Default:** ``'.'`` +``'.'`` Change directory to specified directory before loading apps. -.. _daemon: - -``daemon`` -~~~~~~~~~~ +## `daemon` -**Command line:** ``-D`` or ``--daemon`` +**Command line:** `-D`, `--daemon` -**Default:** ``False`` +**Default:** `False` Daemonize the Gunicorn process. Detaches the server from the controlling terminal and enters the background. -.. _raw-env: +## `raw_env` -``raw_env`` -~~~~~~~~~~~ +**Command line:** `-e ENV`, `--env ENV` -**Command line:** ``-e ENV`` or ``--env ENV`` - -**Default:** ``[]`` +**Default:** `[]` Set environment variables in the execution environment. @@ -1077,58 +890,51 @@ Should be a list of strings in the ``key=value`` format. For example on the command line: -.. code-block:: console - - $ gunicorn -b 127.0.0.1:8000 --env FOO=1 test:app +```console +$ gunicorn -b 127.0.0.1:8000 --env FOO=1 test:app +``` Or in the configuration file: -.. code-block:: python - - raw_env = ["FOO=1"] +```python +raw_env = ["FOO=1"] +``` -.. _pidfile: +## `pidfile` -``pidfile`` -~~~~~~~~~~~ +**Command line:** `-p FILE`, `--pid FILE` -**Command line:** ``-p FILE`` or ``--pid FILE`` - -**Default:** ``None`` +**Default:** `None` A filename to use for the PID file. If not set, no PID file will be written. -.. _worker-tmp-dir: - -``worker_tmp_dir`` -~~~~~~~~~~~~~~~~~~ +## `worker_tmp_dir` -**Command line:** ``--worker-tmp-dir DIR`` +**Command line:** `--worker-tmp-dir DIR` -**Default:** ``None`` +**Default:** `None` A directory to use for the worker heartbeat temporary file. If not set, the default temporary directory will be used. -.. note:: - The current heartbeat system involves calling ``os.fchmod`` on - temporary file handlers and may block a worker for arbitrary time - if the directory is on a disk-backed filesystem. +!!! note + The current heartbeat system involves calling ``os.fchmod`` on + temporary file handlers and may block a worker for arbitrary time + if the directory is on a disk-backed filesystem. - See :ref:`blocking-os-fchmod` for more detailed information - and a solution for avoiding this problem. + See [blocking-os-fchmod](#blocking_os_fchmod) for more detailed information + and a solution for avoiding this problem. -.. _user: +## `user` -``user`` -~~~~~~~~ +**Command line:** `-u USER`, `--user USER` -**Command line:** ``-u USER`` or ``--user USER`` +**Default:** -**Default:** ``os.geteuid()`` +``os.geteuid()`` Switch worker processes to run as this user. @@ -1136,14 +942,13 @@ A valid user id (as an integer) or the name of a user that can be retrieved with a call to ``pwd.getpwnam(value)`` or ``None`` to not change the worker process user. -.. _group: +## `group` -``group`` -~~~~~~~~~ +**Command line:** `-g GROUP`, `--group GROUP` -**Command line:** ``-g GROUP`` or ``--group GROUP`` +**Default:** -**Default:** ``os.getegid()`` +``os.getegid()`` Switch worker process to run as this group. @@ -1151,14 +956,11 @@ A valid group id (as an integer) or the name of a user that can be retrieved with a call to ``grp.getgrnam(value)`` or ``None`` to not change the worker processes group. -.. _umask: +## `umask` -``umask`` -~~~~~~~~~ +**Command line:** `-m INT`, `--umask INT` -**Command line:** ``-m INT`` or ``--umask INT`` - -**Default:** ``0`` +**Default:** `0` A bit mask for the file mode on files written by Gunicorn. @@ -1169,27 +971,21 @@ with ``int(value, 0)`` (``0`` means Python guesses the base, so values like ``0``, ``0xFF``, ``0022`` are valid for decimal, hex, and octal representations) -.. _initgroups: - -``initgroups`` -~~~~~~~~~~~~~~ +## `initgroups` -**Command line:** ``--initgroups`` +**Command line:** `--initgroups` -**Default:** ``False`` +**Default:** `False` If true, set the worker process's group access list with all of the groups of which the specified username is a member, plus the specified group id. -.. versionadded:: 19.7 +!!! info "Added in 19.7" -.. _tmp-upload-dir: +## `tmp_upload_dir` -``tmp_upload_dir`` -~~~~~~~~~~~~~~~~~~ - -**Default:** ``None`` +**Default:** `None` Directory to store temporary request data as they are read. @@ -1199,16 +995,13 @@ This path should be writable by the process permissions set for Gunicorn workers. If not specified, Gunicorn will choose a system generated temporary directory. -.. _secure-scheme-headers: - -``secure_scheme_headers`` -~~~~~~~~~~~~~~~~~~~~~~~~~ +## `secure_scheme_headers` -**Default:** ``{'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}`` +**Default:** `{'X-FORWARDED-PROTOCOL': 'ssl', 'X-FORWARDED-PROTO': 'https', 'X-FORWARDED-SSL': 'on'}` A dictionary containing headers and values that the front-end proxy uses to indicate HTTPS requests. If the source IP is permitted by -:ref:`forwarded-allow-ips` (below), *and* at least one request header matches +[forwarded-allow-ips](#forwarded_allow_ips) (below), *and* at least one request header matches a key-value pair listed in this dictionary, then Gunicorn will set ``wsgi.url_scheme`` to ``https``, so your application can tell that the request is secure. @@ -1225,14 +1018,11 @@ when handling HTTPS requests. It is important that your front-end proxy configuration ensures that the headers defined here can not be passed directly from the client. -.. _forwarded-allow-ips: - -``forwarded_allow_ips`` -~~~~~~~~~~~~~~~~~~~~~~~ +## `forwarded_allow_ips` -**Command line:** ``--forwarded-allow-ips STRING`` +**Command line:** `--forwarded-allow-ips STRING` -**Default:** ``'127.0.0.1,::1'`` +**Default:** `'127.0.0.1,::1'` Front-end's IPs from which allowed to handle set secure headers. (comma separated). @@ -1245,13 +1035,11 @@ authorized front-ends can access Gunicorn. By default, the value of the ``FORWARDED_ALLOW_IPS`` environment variable. If it is not defined, the default is ``"127.0.0.1,::1"``. -.. note:: - +!!! note This option does not affect UNIX socket connections. Connections not associated with an IP address are treated as allowed, unconditionally. -.. note:: - +!!! note The interplay between the request headers, the value of ``forwarded_allow_ips``, and the value of ``secure_scheme_headers`` is complex. Various scenarios are documented below to further elaborate. In each case, we have a request from the remote address 134.213.44.18, and the default value of @@ -1265,7 +1053,6 @@ variable. If it is not defined, the default is ``"127.0.0.1,::1"``. 'X-FORWARDED-SSL': 'on' } - .. list-table:: :header-rows: 1 :align: center @@ -1313,28 +1100,22 @@ variable. If it is not defined, the default is ``"127.0.0.1,::1"``. - ``InvalidSchemeHeaders()`` raised - IP address allowed, but the two secure headers disagreed on if HTTPS was used -.. _pythonpath: - -``pythonpath`` -~~~~~~~~~~~~~~ +## `pythonpath` -**Command line:** ``--pythonpath STRING`` +**Command line:** `--pythonpath STRING` -**Default:** ``None`` +**Default:** `None` A comma-separated list of directories to add to the Python path. e.g. ``'/home/djangoprojects/myproject,/home/python/mylibrary'``. -.. _paste: +## `paste` -``paste`` -~~~~~~~~~ +**Command line:** `--paste STRING`, `--paster STRING` -**Command line:** ``--paste STRING`` or ``--paster STRING`` - -**Default:** ``None`` +**Default:** `None` Load a PasteDeploy config file. The argument may contain a ``#`` symbol followed by the name of an app section from the config file, @@ -1343,14 +1124,11 @@ e.g. ``production.ini#admin``. At this time, using alternate server blocks is not supported. Use the command line arguments to control server configuration instead. -.. _proxy-protocol: - -``proxy_protocol`` -~~~~~~~~~~~~~~~~~~ +## `proxy_protocol` -**Command line:** ``--proxy-protocol`` +**Command line:** `--proxy-protocol` -**Default:** ``False`` +**Default:** `False` Enable detect PROXY protocol (PROXY mode). @@ -1368,14 +1146,11 @@ Example for stunnel config:: cert = /etc/ssl/certs/stunnel.pem key = /etc/ssl/certs/stunnel.key -.. _proxy-allow-ips: - -``proxy_allow_ips`` -~~~~~~~~~~~~~~~~~~~ +## `proxy_allow_ips` -**Command line:** ``--proxy-allow-from`` +**Command line:** `--proxy-allow-from` -**Default:** ``'127.0.0.1,::1'`` +**Default:** `'127.0.0.1,::1'` Front-end's IPs from which allowed accept proxy requests (comma separated). @@ -1384,19 +1159,15 @@ where you don't know in advance the IP address of front-end, but instead have ensured via other means that only your authorized front-ends can access Gunicorn. -.. note:: - +!!! note This option does not affect UNIX socket connections. Connections not associated with an IP address are treated as allowed, unconditionally. -.. _raw-paste-global-conf: - -``raw_paste_global_conf`` -~~~~~~~~~~~~~~~~~~~~~~~~~ +## `raw_paste_global_conf` -**Command line:** ``--paste-global CONF`` +**Command line:** `--paste-global CONF` -**Default:** ``[]`` +**Default:** `[]` Set a PasteDeploy global config variable in ``key=value`` form. @@ -1406,16 +1177,13 @@ The variables are passed to the PasteDeploy entrypoint. Example:: $ gunicorn -b 127.0.0.1:8000 --paste development.ini --paste-global FOO=1 --paste-global BAR=2 -.. versionadded:: 19.7 +!!! info "Added in 19.7" -.. _permit-obsolete-folding: +## `permit_obsolete_folding` -``permit_obsolete_folding`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--permit-obsolete-folding` -**Command line:** ``--permit-obsolete-folding`` - -**Default:** ``False`` +**Default:** `False` Permit requests employing obsolete HTTP line folding mechanism @@ -1426,16 +1194,13 @@ This option is provided to diagnose backwards-incompatible changes. Use with care and only if necessary. Temporary; the precise effect of this option may change in a future version, or it may be removed altogether. -.. versionadded:: 23.0.0 - -.. _strip-header-spaces: +!!! info "Added in 23.0.0" -``strip_header_spaces`` -~~~~~~~~~~~~~~~~~~~~~~~ +## `strip_header_spaces` -**Command line:** ``--strip-header-spaces`` +**Command line:** `--strip-header-spaces` -**Default:** ``False`` +**Default:** `False` Strip spaces present between the header name and the the ``:``. @@ -1444,16 +1209,13 @@ See https://portswigger.net/research/http-desync-attacks-request-smuggling-rebor Use with care and only if necessary. Deprecated; scheduled for removal in 25.0.0 -.. versionadded:: 20.0.1 +!!! info "Added in 20.0.1" -.. _permit-unconventional-http-method: +## `permit_unconventional_http_method` -``permit_unconventional_http_method`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--permit-unconventional-http-method` -**Command line:** ``--permit-unconventional-http-method`` - -**Default:** ``False`` +**Default:** `False` Permit HTTP methods not matching conventions, such as IANA registration guidelines @@ -1469,16 +1231,13 @@ changes around the incomplete application of those restrictions. Use with care and only if necessary. Temporary; scheduled for removal in 24.0.0 -.. versionadded:: 22.0.0 - -.. _permit-unconventional-http-version: +!!! info "Added in 22.0.0" -``permit_unconventional_http_version`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +## `permit_unconventional_http_version` -**Command line:** ``--permit-unconventional-http-version`` +**Command line:** `--permit-unconventional-http-version` -**Default:** ``False`` +**Default:** `False` Permit HTTP version not matching conventions of 2023 @@ -1489,16 +1248,13 @@ This option is provided to diagnose backwards-incompatible changes. Use with care and only if necessary. Temporary; the precise effect of this option may change in a future version, or it may be removed altogether. -.. versionadded:: 22.0.0 - -.. _casefold-http-method: +!!! info "Added in 22.0.0" -``casefold_http_method`` -~~~~~~~~~~~~~~~~~~~~~~~~ +## `casefold_http_method` -**Command line:** ``--casefold-http-method`` +**Command line:** `--casefold-http-method` -**Default:** ``False`` +**Default:** `False` Transform received HTTP methods to uppercase @@ -1508,19 +1264,16 @@ This option is provided because previous versions of gunicorn defaulted to this Use with care and only if necessary. Deprecated; scheduled for removal in 24.0.0 -.. versionadded:: 22.0.0 +!!! info "Added in 22.0.0" -.. _forwarder-headers: +## `forwarder_headers` -``forwarder_headers`` -~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--forwarder-headers` -**Command line:** ``--forwarder-headers`` - -**Default:** ``'SCRIPT_NAME,PATH_INFO'`` +**Default:** `'SCRIPT_NAME,PATH_INFO'` A list containing upper-case header field names that the front-end proxy -(see :ref:`forwarded-allow-ips`) sets, to be used in WSGI environment. +(see [forwarded-allow-ips](#forwarded_allow_ips)) sets, to be used in WSGI environment. This option has no effect for headers not present in the request. @@ -1530,14 +1283,11 @@ and ``REMOTE_USER``. It is important that your front-end proxy configuration ensures that the headers defined here can not be passed directly from the client. -.. _header-map: - -``header_map`` -~~~~~~~~~~~~~~ +## `header_map` -**Command line:** ``--header-map`` +**Command line:** `--header-map` -**Default:** ``'drop'`` +**Default:** `'drop'` Configure how header field names are mapped into environ @@ -1550,35 +1300,31 @@ The value ``refuse`` will return an error if a request contains *any* such heade The value ``dangerous`` matches the previous, not advisable, behaviour of mapping different header field names into the same environ name. -If the source is permitted as explained in :ref:`forwarded-allow-ips`, *and* the header name is -present in :ref:`forwarder-headers`, the header is mapped into environment regardless of +If the source is permitted as explained in [forwarded-allow-ips](#forwarded_allow_ips), *and* the header name is +present in [forwarder-headers](#forwarder_headers), the header is mapped into environment regardless of the state of this setting. Use with care and only if necessary and after considering if your problem could instead be solved by specifically renaming or rewriting only the intended headers on a proxy in front of Gunicorn. -.. versionadded:: 22.0.0 +!!! info "Added in 22.0.0" -Server Socket -------------- +# Server Socket -.. _bind: +## `bind` -``bind`` -~~~~~~~~ +**Command line:** `-b ADDRESS`, `--bind ADDRESS` -**Command line:** ``-b ADDRESS`` or ``--bind ADDRESS`` - -**Default:** ``['127.0.0.1:8000']`` +**Default:** `['127.0.0.1:8000']` The socket to bind. A string of the form: ``HOST``, ``HOST:PORT``, ``unix:PATH``, ``fd://FD``. An IP is a valid ``HOST``. -.. versionchanged:: 20.0 - Support for ``fd://FD`` got added. +!!! info "Changed in 20.0" + Support for ``fd://FD`` got added. Multiple addresses can be bound. ex.:: @@ -1591,14 +1337,11 @@ If the ``PORT`` environment variable is defined, the default is ``['0.0.0.0:$PORT']``. If it is not defined, the default is ``['127.0.0.1:8000']``. -.. _backlog: - -``backlog`` -~~~~~~~~~~~ +## `backlog` -**Command line:** ``--backlog INT`` +**Command line:** `--backlog INT` -**Default:** ``2048`` +**Default:** `2048` The maximum number of pending connections. @@ -1609,17 +1352,13 @@ load. Must be a positive integer. Generally set in the 64-2048 range. -Worker Processes ----------------- +# Worker Processes -.. _workers: +## `workers` -``workers`` -~~~~~~~~~~~ +**Command line:** `-w INT`, `--workers INT` -**Command line:** ``-w INT`` or ``--workers INT`` - -**Default:** ``1`` +**Default:** `1` The number of worker processes for handling requests. @@ -1631,14 +1370,11 @@ By default, the value of the ``WEB_CONCURRENCY`` environment variable, which is set by some Platform-as-a-Service providers such as Heroku. If it is not defined, the default is ``1``. -.. _worker-class: - -``worker_class`` -~~~~~~~~~~~~~~~~ +## `worker_class` -**Command line:** ``-k STRING`` or ``--worker-class STRING`` +**Command line:** `-k STRING`, `--worker-class STRING` -**Default:** ``'sync'`` +**Default:** `'sync'` The type of workers to use. @@ -1664,14 +1400,11 @@ Python path to a subclass of ``gunicorn.workers.base.Worker``. This alternative syntax will load the gevent class: ``gunicorn.workers.ggevent.GeventWorker``. -.. _threads: - -``threads`` -~~~~~~~~~~~ +## `threads` -**Command line:** ``--threads INT`` +**Command line:** `--threads INT` -**Default:** ``1`` +**Default:** `1` The number of worker threads for handling requests. @@ -1685,32 +1418,26 @@ If it is not defined, the default is ``1``. This setting only affects the Gthread worker type. -.. note:: - If you try to use the ``sync`` worker type and set the ``threads`` - setting to more than 1, the ``gthread`` worker type will be used - instead. +!!! note + If you try to use the ``sync`` worker type and set the ``threads`` + setting to more than 1, the ``gthread`` worker type will be used + instead. -.. _worker-connections: +## `worker_connections` -``worker_connections`` -~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--worker-connections INT` -**Command line:** ``--worker-connections INT`` - -**Default:** ``1000`` +**Default:** `1000` The maximum number of simultaneous clients. This setting only affects the ``gthread``, ``eventlet`` and ``gevent`` worker types. -.. _max-requests: - -``max_requests`` -~~~~~~~~~~~~~~~~ +## `max_requests` -**Command line:** ``--max-requests INT`` +**Command line:** `--max-requests INT` -**Default:** ``0`` +**Default:** `0` The maximum number of requests a worker will process before restarting. @@ -1721,14 +1448,11 @@ to help limit the damage of memory leaks. If this is set to zero (the default) then the automatic worker restarts are disabled. -.. _max-requests-jitter: +## `max_requests_jitter` -``max_requests_jitter`` -~~~~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--max-requests-jitter INT` -**Command line:** ``--max-requests-jitter INT`` - -**Default:** ``0`` +**Default:** `0` The maximum jitter to add to the *max_requests* setting. @@ -1736,16 +1460,13 @@ The jitter causes the restart per worker to be randomized by ``randint(0, max_requests_jitter)``. This is intended to stagger worker restarts to avoid all workers restarting at the same time. -.. versionadded:: 19.2 - -.. _timeout: +!!! info "Added in 19.2" -``timeout`` -~~~~~~~~~~~ +## `timeout` -**Command line:** ``-t INT`` or ``--timeout INT`` +**Command line:** `-t INT`, `--timeout INT` -**Default:** ``30`` +**Default:** `30` Workers silent for more than this many seconds are killed and restarted. @@ -1758,14 +1479,11 @@ For the non sync workers it just means that the worker process is still communicating and is not tied to the length of time required to handle a single request. -.. _graceful-timeout: +## `graceful_timeout` -``graceful_timeout`` -~~~~~~~~~~~~~~~~~~~~ +**Command line:** `--graceful-timeout INT` -**Command line:** ``--graceful-timeout INT`` - -**Default:** ``30`` +**Default:** `30` Timeout for graceful workers restart in seconds. @@ -1773,14 +1491,11 @@ After receiving a restart signal, workers have this much time to finish serving requests. Workers still alive after the timeout (starting from the receipt of the restart signal) are force killed. -.. _keepalive: - -``keepalive`` -~~~~~~~~~~~~~ +## `keepalive` -**Command line:** ``--keep-alive INT`` +**Command line:** `--keep-alive INT` -**Default:** ``2`` +**Default:** `2` The number of seconds to wait for requests on a Keep-Alive connection. @@ -1789,7 +1504,6 @@ to the client (e.g. when you don't have separate load balancer). When Gunicorn is deployed behind a load balancer, it often makes sense to set this to a higher value. -.. note:: - ``sync`` worker does not support persistent connections and will - ignore this option. - +!!! note + ``sync`` worker does not support persistent connections and will + ignore this option. diff --git a/docs/content/run.md b/docs/content/run.md new file mode 100644 index 000000000..a727c1c4b --- /dev/null +++ b/docs/content/run.md @@ -0,0 +1,154 @@ +# Running Gunicorn + +You can run Gunicorn directly from the command line or integrate it with +popular frameworks like Django, Pyramid, or TurboGears. For deployment +patterns see the [deployment guide](deploy.md). + +## Commands + +After installation you have access to the `gunicorn` executable. + + +### `gunicorn` + +Basic usage: + +```bash +gunicorn [OPTIONS] [WSGI_APP] +``` + +`WSGI_APP` follows the pattern `MODULE_NAME:VARIABLE_NAME`. The module can be a +full dotted path. The variable refers to a WSGI callable defined in that +module. + +!!! info "Changed in 20.1.0" + `WSGI_APP` can be omitted when defined in a [configuration file](configure.md). + + + +Example test application: + +```python +def app(environ, start_response): + """Simplest possible application object""" + data = b"Hello, World!\n" + status = "200 OK" + response_headers = [ + ("Content-type", "text/plain"), + ("Content-Length", str(len(data.md))) + ] + start_response(status, response_headers) + return iter([data]) +``` + +Run it with: + +```bash +gunicorn --workers=2 test:app +``` + +You can also expose a factory function that returns the application: + +```python +def create_app(): + app = FrameworkApp() + ... + return app +``` + +```bash +gunicorn --workers=2 'test:create_app()' +``` + +Passing positional and keyword arguments is supported but prefer +configuration files or environment variables for anything beyond quick tests. + +#### Commonly used arguments + +- `-c CONFIG`, `--config CONFIG` — configuration file (`PATH`, `file:PATH`, or + `python:MODULE_NAME`). +- `-b BIND`, `--bind BIND` — socket to bind (host, host:port, `fd://FD`, + or `unix:PATH`). +- `-w WORKERS`, `--workers WORKERS` — number of worker processes, typically + two to four per CPU core. See the [FAQ](faq.md) for tuning tips. +- `-k WORKERCLASS`, `--worker-class WORKERCLASS` — worker type (`sync`, + `eventlet`, `gevent`, `tornado`, `gthread`). Read the + [settings entry](reference/settings.md#worker_class) before switching classes. +- `-n APP_NAME`, `--name APP_NAME` — set the process name (requires + [`setproctitle`](https://pypi.python.org/pypi/setproctitle)). + +You can pass any setting via the environment variable +`GUNICORN_CMD_ARGS`. See the [configuration guide](configure.md) and +[settings reference](reference/settings.md) for details. + +## Integration + +Gunicorn integrates cleanly with Django and Paste Deploy applications. + +### Django + +Gunicorn looks for a WSGI callable named `application`. A typical invocation is: + +```bash +gunicorn myproject.wsgi +``` + +!!! note + Ensure your project is on `PYTHONPATH`. The easiest way is to run this command + from the directory containing `manage.py`. + + + +Set environment variables with `--env` and add your project to `PYTHONPATH` +if needed: + +```bash +gunicorn --env DJANGO_SETTINGS_MODULE=myproject.settings myproject.wsgi +``` + +See [`raw_env`](reference/settings.md#raw_env) and [`pythonpath`](reference/settings.md#pythonpath) for +more options. + +### Paste Deployment + +Frameworks such as Pyramid and TurboGears often rely on Paste Deployment +configuration. You can use Gunicorn in two ways. + +#### As a Paste server runner + +Let your framework command (for example `pserve` or `gearbox`) load Gunicorn by +configuring it as the server: + +```ini +[server:main] +use = egg:gunicorn#main +host = 127.0.0.1 +port = 8080 +workers = 3 +``` + +This approach is quick to set up but Gunicorn cannot control how the +application loads. Options like [`reload`](reference/settings.md#reload) will be ignored and +hot upgrades are unavailable. Features such as daemon mode may conflict with +what your framework already provides. Prefer running those features through the +framework (for example `pserve --reload`). Advanced configuration is still +possible by pointing the `config` key at a Gunicorn configuration file. + +#### Using Gunicorn's Paste support + +Use the [`paste`](reference/settings.md#paste) option to load a Paste configuration directly +with the Gunicorn CLI. This unlocks Gunicorn's reloader and hot code upgrades, +while still letting Paste define the application object. + +```bash +gunicorn --paste development.ini -b :8080 --chdir /path/to/project +``` + +Select a different application section by appending the name: + +```bash +gunicorn --paste development.ini#admin -b :8080 --chdir /path/to/project +``` + +In both modes Gunicorn will honor any Paste `loggers` configuration unless you +override it with Gunicorn-specific [logging settings](reference/settings.md#logging). diff --git a/docs/content/signals.md b/docs/content/signals.md new file mode 100644 index 000000000..ce08ca099 --- /dev/null +++ b/docs/content/signals.md @@ -0,0 +1,97 @@ + +# Signal Handling + +A quick reference to the signals handled by Gunicorn. This includes the signals +used internally to coordinate with worker processes. + +## Master process + +- `QUIT`, `INT` — quick shutdown. +- `TERM` — graceful shutdown; waits for workers to finish requests up to + [`graceful_timeout`](reference/settings.md#graceful_timeout). +- `HUP` — reload configuration, spawn new workers, and gracefully stop old + ones. If the app is not preloaded (see [`preload_app`](reference/settings.md#preload_app)) + the application code is reloaded too. +- `TTIN` — increase worker count by one. +- `TTOU` — decrease worker count by one. +- `USR1` — reopen log files. +- `USR2` — perform a binary upgrade. Send `TERM` to the old master afterwards + to stop it. This also reloads preloaded applications (see + [binary upgrades](#binary-upgrade)). +- `WINCH` — gracefully stop workers when Gunicorn runs as a daemon. + +## Worker process + +Workers rarely need direct signalling—if the master stays alive it will respawn +workers automatically. + +- `QUIT`, `INT` — quick shutdown. +- `TERM` — graceful shutdown. +- `USR1` — reopen log files. + +## Reload the configuration + +Use `HUP` to reload Gunicorn on the fly: + +```text +2013-06-29 06:26:55 [20682] [INFO] Handling signal: hup +2013-06-29 06:26:55 [20682] [INFO] Hang up: Master +2013-06-29 06:26:55 [20703] [INFO] Booting worker with pid: 20703 +2013-06-29 06:26:55 [20702] [INFO] Booting worker with pid: 20702 +2013-06-29 06:26:55 [20688] [INFO] Worker exiting (pid: 20688) +2013-06-29 06:26:55 [20687] [INFO] Worker exiting (pid: 20687) +2013-06-29 06:26:55 [20689] [INFO] Worker exiting (pid: 20689) +2013-06-29 06:26:55 [20704] [INFO] Booting worker with pid: 20704 +``` + +Gunicorn reloads its settings, starts new workers, and gracefully shuts down the +previous ones. If the app is not preloaded it reloads the application module as +well. + + +## Upgrading to a new binary on the fly + +!!! info "Changed in 19.6.0" + PID files now follow the pattern `.pid.2` instead of `.pid.oldbin`. + + + +You can replace the Gunicorn binary without downtime. Incoming requests remain +served and preloaded applications reload. + +1. Replace the old binary and send `USR2` to the master. Gunicorn starts a new + master whose PID file ends with `.2` and spawns new workers. + + ```text + PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND + 20844 benoitc 20 0 54808 11m 3352 S 0.0 0.1 0:00.36 gunicorn: master [test:app] + 20849 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app] + 20850 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] + 20851 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] + 20854 benoitc 20 0 55748 12m 3348 S 0.0 0.2 0:00.35 gunicorn: master [test:app] + 20859 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] + 20860 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.00 gunicorn: worker [test:app] + 20861 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] + ``` + +2. Send `WINCH` to the old master to gracefully stop its workers. + +You can still roll back while the old master keeps its listen sockets: + +1. Send `HUP` to the old master to restart its workers without reloading the + config file. +2. Send `TERM` to the new master to shut down its workers gracefully. +3. Send `QUIT` to the new master to force it to exit. + +If the new workers linger, send `KILL` after the new master quits. + +To complete the upgrade, send `TERM` to the old master so only the new server +continues running: + +```text +PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND +20854 benoitc 20 0 55748 12m 3348 S 0.0 0.2 0:00.45 gunicorn: master [test:app] +20859 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app] +20860 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app] +20861 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] +``` diff --git a/docs/content/styles/overrides.css b/docs/content/styles/overrides.css new file mode 100644 index 000000000..7cf82930d --- /dev/null +++ b/docs/content/styles/overrides.css @@ -0,0 +1,192 @@ +:root { + --gunicorn-green: #1d692d; + --gunicorn-green-dark: #14501f; + --gunicorn-green-light: #2a8729; + --gunicorn-cream: #f6f6f1; + --md-primary-fg-color: var(--gunicorn-green-light); + --md-primary-fg-color--light: #3da843; + --md-primary-fg-color--dark: var(--gunicorn-green-dark); + --md-accent-fg-color: var(--gunicorn-green); +} + +[data-md-color-scheme="slate"] { + --gunicorn-cream: #1d1f1d; + --md-primary-fg-color: var(--gunicorn-green); + --md-primary-fg-color--light: #3da843; + --md-primary-fg-color--dark: var(--gunicorn-green-dark); + --md-accent-fg-color: var(--gunicorn-green-light); +} + +.md-header__button.md-logo svg { + height: 1.8rem; +} + +.md-typeset .hero { + margin: 2rem 0 3rem; + padding: 3.5rem; + background: linear-gradient(135deg, rgba(29, 105, 45, 0.96), rgba(42, 135, 41, 0.85)); + color: #fff; + border-radius: 18px; + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.12); +} + +[data-md-color-scheme="slate"] .md-typeset .hero { + background: linear-gradient(135deg, rgba(20, 80, 31, 0.95), rgba(29, 105, 45, 0.88)); + box-shadow: 0 16px 48px rgba(0, 0, 0, 0.4); +} + +.md-typeset .hero__inner { + display: flex; + flex-wrap: wrap; + gap: 2.5rem; + align-items: center; + justify-content: space-between; +} + +.md-typeset .hero__copy { + flex: 1 1 320px; + max-width: 520px; + font-size: 1.05rem; + line-height: 1.6; +} + +.md-typeset .hero__copy h1 { + margin: 0 0 1rem; + font-size: 2.6rem; + font-weight: 700; + line-height: 1.2; +} + +.md-typeset .hero__cta { + margin-top: 1.75rem; + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.md-typeset .hero__code { + flex: 1 1 260px; + max-width: 420px; + background: rgba(255, 255, 255, 0.08); + border-radius: 14px; + padding: 1.5rem; + backdrop-filter: blur(4px); + font-size: 0.95rem; +} + +[data-md-color-scheme="slate"] .md-typeset .hero__code { + background: rgba(0, 0, 0, 0.35); +} + +.md-typeset .hero__code pre { + margin: 0 0 1rem; + border: none; + background: rgba(0, 0, 0, 0.35); + color: #e8f5ea; +} + +[data-md-color-scheme="slate"] .md-typeset .hero__code pre { + background: rgba(0, 0, 0, 0.55); +} + +.md-typeset .hero__version { + font-weight: 600; + letter-spacing: 0.01em; +} + +.md-typeset .feature-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 1.6rem; + margin: 2.5rem 0 3rem; +} + +.md-typeset .feature-card { + background: var(--gunicorn-cream); + border-radius: 14px; + padding: 1.5rem; + border: 1px solid rgba(0, 0, 0, 0.05); + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08); + transition: transform 0.2s ease, box-shadow 0.2s ease; +} + +[data-md-color-scheme="slate"] .md-typeset .feature-card { + background: rgba(45, 48, 45, 0.9); + border: 1px solid rgba(255, 255, 255, 0.05); + box-shadow: 0 18px 36px rgba(0, 0, 0, 0.35); +} + +.md-typeset .feature-card h3 { + margin-top: 0; + font-size: 1.3rem; + color: var(--gunicorn-green-dark); +} + +[data-md-color-scheme="slate"] .md-typeset .feature-card h3 { + color: var(--gunicorn-cream); +} + +.md-typeset .feature-card a { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-weight: 600; + color: var(--gunicorn-green); +} + +.md-typeset .feature-card:hover { + transform: translateY(-4px); + box-shadow: 0 18px 36px rgba(0, 0, 0, 0.12); +} + +.md-typeset .feature-card:hover a::after { + content: '\\2192'; + opacity: 1; + transform: translateX(4px); +} + +.md-typeset .feature-card a::after { + content: '\\2192'; + opacity: 0; + transition: opacity 0.2s ease, transform 0.2s ease; + transform: translateX(0); +} + +@media (max-width: 960px) { + .md-typeset .hero { + padding: 2.25rem; + } + + .md-typeset .hero__copy h1 { + font-size: 2.2rem; + } +} + +@media (max-width: 720px) { + .md-typeset .hero { + margin-top: 1.5rem; + padding: 1.75rem; + } + + .md-typeset .hero__cta { + flex-direction: column; + align-items: stretch; + } + + .md-typeset .hero__code { + width: 100%; + } +} + +.md-footer-meta__inner { + flex-wrap: wrap; +} + +.md-typeset .hero__logo { + height: 64px; + margin-bottom: 1.25rem; +} + +[data-md-color-scheme="slate"] .md-typeset .hero__logo { + filter: drop-shadow(0 0 8px rgba(0, 0, 0, 0.35)); +} diff --git a/docs/gunicorn_ext.py b/docs/gunicorn_ext.py deleted file mode 100755 index 4310162eb..000000000 --- a/docs/gunicorn_ext.py +++ /dev/null @@ -1,102 +0,0 @@ -import os -import inspect - -from docutils import nodes, utils - -import gunicorn.config as guncfg - -HEAD = """\ -.. Please update gunicorn/config.py instead. - -.. _settings: - -Settings -======== - -This is an exhaustive list of settings for Gunicorn. Some settings are only -able to be set from a configuration file. The setting name is what should be -used in the configuration file. The command line arguments are listed as well -for reference on setting at the command line. - -.. note:: - - Settings can be specified by using environment variable - ``GUNICORN_CMD_ARGS``. All available command line arguments can be used. - For example, to specify the bind address and number of workers:: - - $ GUNICORN_CMD_ARGS="--bind=127.0.0.1 --workers=3" gunicorn app:app - - .. versionadded:: 19.7 - -""" -ISSUE_URI = 'https://github.com/benoitc/gunicorn/issues/%s' -PULL_REQUEST_URI = 'https://github.com/benoitc/gunicorn/pull/%s' - - -def format_settings(app): - settings_file = os.path.join(app.srcdir, "settings.rst") - ret = [] - known_settings = sorted(guncfg.KNOWN_SETTINGS, key=lambda s: s.section) - for i, s in enumerate(known_settings): - if i == 0 or s.section != known_settings[i - 1].section: - ret.append("%s\n%s\n\n" % (s.section, "-" * len(s.section))) - ret.append(fmt_setting(s)) - - with open(settings_file, 'w') as settings: - settings.write(HEAD) - settings.write(''.join(ret)) - - -def fmt_setting(s): - if hasattr(s, "default_doc"): - val = s.default_doc - elif callable(s.default): - val = inspect.getsource(s.default) - val = "\n".join(" %s" % line for line in val.splitlines()) - val = "\n\n.. code-block:: python\n\n" + val - elif s.default == '': - val = "``''``" - else: - val = "``%r``" % s.default - - if s.cli and s.meta: - cli = " or ".join("``%s %s``" % (arg, s.meta) for arg in s.cli) - elif s.cli: - cli = " or ".join("``%s``" % arg for arg in s.cli) - else: - cli = "" - - out = [] - out.append(".. _%s:\n" % s.name.replace("_", "-")) - out.append("``%s``" % s.name) - out.append("~" * (len(s.name) + 4)) - out.append("") - if s.cli: - out.append("**Command line:** %s" % cli) - out.append("") - out.append("**Default:** %s" % val) - out.append("") - out.append(s.desc) - out.append("") - out.append("") - return "\n".join(out) - - -def issue_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): - issue = utils.unescape(text) - text = 'issue ' + issue - refnode = nodes.reference(text, text, refuri=ISSUE_URI % issue) - return [refnode], [] - - -def pull_request_role(typ, rawtext, text, lineno, inliner, options={}, content=[]): - issue = utils.unescape(text) - text = 'pull request ' + issue - refnode = nodes.reference(text, text, refuri=PULL_REQUEST_URI % issue) - return [refnode], [] - - -def setup(app): - app.connect('builder-inited', format_settings) - app.add_role('issue', issue_role) - app.add_role('pr', pull_request_role) diff --git a/docs/macros.py b/docs/macros.py new file mode 100644 index 000000000..093476ee7 --- /dev/null +++ b/docs/macros.py @@ -0,0 +1,11 @@ +from importlib import import_module + +def define_env(env): + """Register template variables for MkDocs macros.""" + gunicorn = import_module("gunicorn") + env.variables.update( + release=gunicorn.__version__, + version=gunicorn.__version__, + github_repo="https://github.com/benoitc/gunicorn", + pypi_url=f"https://pypi.org/project/gunicorn/{gunicorn.__version__}/", + ) diff --git a/docs/make.bat b/docs/make.bat deleted file mode 100644 index 705fcdcdf..000000000 --- a/docs/make.bat +++ /dev/null @@ -1,190 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -set I18NSPHINXOPTS=%SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% - set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. texinfo to make Texinfo files - echo. gettext to make PO message catalogs - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Gunicorn.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Gunicorn.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "texinfo" ( - %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. - goto end -) - -if "%1" == "gettext" ( - %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The message catalogs are in %BUILDDIR%/locale. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/docs/modernization-plan.md b/docs/modernization-plan.md new file mode 100644 index 000000000..6c04bb4d0 --- /dev/null +++ b/docs/modernization-plan.md @@ -0,0 +1,35 @@ +# Website Modernization Plan + +## Goals +- Serve a single, canonical domain backed by a static MkDocs build. +- Keep the documentation authoring experience entirely in Markdown. +- Modernize the marketing home page with a refreshed visual identity. +- Preserve the generated settings reference sourced from Python code. + +## Architecture Overview +- **Static site generator:** MkDocs with the Material theme. +- **Content layout:** Markdown files in `docs/content/`, grouped by guides, reference, and news archives. +- **Styling:** Lightweight CSS overrides in `docs/content/styles/overrides.css` for hero, feature cards, and color palette. +- **Dynamic data:** `docs/macros.py` exposes the Gunicorn version, while `scripts/build_settings_doc.py` renders the settings reference into Markdown during every build. +- **Assets:** SVG mascot and hero art live under `docs/content/assets/` so both the homepage and docs share the same branding. + +## Completed Work +- Removed Sphinx configuration, themes, and the legacy static snapshot under `docs/site/`. +- Converted the entire content library (guides, FAQ, design notes, yearly news) from MyST/RST to MkDocs-friendly Markdown. +- Rebuilt the homepage using Material’s layout primitives with responsive hero, CTAs, and feature cards. +- Added CSS overrides that mirror Gunicorn’s brand colors and support light/dark modes. +- Replaced the Sphinx extension with a standalone Markdown generator for the settings reference. +- Introduced an automated MkDocs workflow (`.github/workflows/docs.yml`) that builds on every push and deploys to `gh-pages` from the `main` branch. + +## Remaining Enhancements +1. **Visual polish:** produce updated screenshots/asciicasts for quickstart and deployment examples; add Open Graph imagery. +2. **Content review:** prune outdated news entries, tighten FAQs, and add framework-specific quickstarts (FastAPI, Flask, Django). +3. **Accessibility & internationalization:** run axe audits, ensure color contrast, and consider adding minimal localization support. +4. **Performance extras:** enable MkDocs search index minification and gzip the GitHub Pages output (served automatically once deployed). +5. **Contributor docs:** extend `CONTRIBUTING.md` with MkDocs authoring tips, link to preview artifacts, and describe the `mkdocs serve` workflow. + +## Deployment Checklist +- [x] Update DNS to point away from ReadTheDocs once `gh-pages` is published. +- [x] Verify `site_url` in `mkdocs.yml` for canonical URLs and sitemap generation. +- [x] Ensure `CNAME` (if required) is checked into `gh-pages` during deployment. +- [ ] Announce the migration to end-users and update links in READMEs and PyPI metadata. diff --git a/docs/site/.nojekyll b/docs/site/.nojekyll deleted file mode 100644 index e69de29bb..000000000 diff --git a/docs/site/CNAME b/docs/site/CNAME deleted file mode 100644 index b9f0ffbce..000000000 --- a/docs/site/CNAME +++ /dev/null @@ -1 +0,0 @@ -gunicorn.org diff --git a/docs/site/community.html b/docs/site/community.html deleted file mode 100644 index f6fae4d49..000000000 --- a/docs/site/community.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Community - - -

- Redirecting to here -

- - diff --git a/docs/site/configuration.html b/docs/site/configuration.html deleted file mode 100644 index 88bcf3026..000000000 --- a/docs/site/configuration.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Configuration - - -

- Redirecting to here -

- - diff --git a/docs/site/configure.html b/docs/site/configure.html deleted file mode 100644 index 3028eb9c2..000000000 --- a/docs/site/configure.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Configure - - -

- Redirecting to here -

- - diff --git a/docs/site/css/style.css b/docs/site/css/style.css deleted file mode 100644 index aec17c997..000000000 --- a/docs/site/css/style.css +++ /dev/null @@ -1,402 +0,0 @@ -html,body { - margin: 0; - padding: 0; -} - -h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,cite, -code,del,dfn,em,img,q,s,samp,small,strike,strong,sub,sup,tt,var, -dd,dl,dt,li,ol,ul,fieldset,form,label,legend,button,table,caption, -tbody,tfoot,thead,tr,th,td { - margin: 0; - padding: 0; - border: 0; - font: inherit; - vertical-align: baseline; -} - -ol,ul { - list-style: none; -} - -html { - overflow-y: scroll; - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -a:hover, a:active, a:focus { - outline: 0; -} - -img { - border: 0; - -ms-interpolation-mode: bicubic; -} - -body { - background: #F8F8F3; - margin: 0; - font: 14px/1.4 "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, "Lucida Grande", sans-serif; - color: #67686B; - height: auto; -} - -a, -a:hover { - text-decoration: none; -} - -.clearall { - clear: both; - display: block; - overflow: hidden; - visibility: hidden; - width: 0; - height: 0; -} - -.logo-wrapper { - border-bottom: 1px solid #2A8729; -} - -.latest { - width: 150px; - top: 0; - display: block; - float: right; - font-weight: bold; -} - - -.logo-div { - width: 1000px; - margin: 0 auto; - padding: 5px; - height: 72px; -} - -.logo { - width: 250px; - margin: 0 auto; - height: 119px; - background: url(../images/logo-bottom.png) no-repeat bottom center; - position: relative; - z-index: 99999; -} - -.banner-wrapper { - background: url(../images/banner-bg.jpg) repeat; - display: block; - width: 100%; - min-height: 365px; - margin-top: 1px; - margin-bottom: 1px; -} - -.banner { - width: 1000px; - margin: 0 auto; - padding: 15px; -} - -.title { - width: 250px; - margin: 0 auto; - margin-top: 32px; - text-align:center; -} - -.banner h1 { - font-size: 20px; - color: #FFF; - margin: 15px 10px 0; - padding: 5px 40px; - text-align: center; - line-height: 28px; -} - -.greenbutton { - background: url(../images/greenbutton.jpg) repeat-x; - height: 54px; - width: 224px; - line-height: 54px; - display: inline-block; - text-align: center; - border-radius: 3px; - border: solid 1px #1D692D; - color: #fff; - font-size: 22px; - letter-spacing: 1px; - text-shadow: 1px 1px 1px #000; -} - -.greenbutton:hover { - background: url(../images/greenbutton.jpg) repeat-x bottom; -} - -.redbutton { - background: url(../images/redbutton.jpg) repeat-x; - height: 54px; - width: 224px; - line-height: 54px; - display: inline-block; - text-align: center; - border-radius: 3px; - border: solid 1px #7D180A; - color: #fff; - font-size: 22px; - letter-spacing: 1px; - text-shadow: 1px 1px 1px #000; -} - -.redbutton:hover { - background: url(../images/redbutton.jpg) repeat-x bottom; -} - -.banner-button { - width: 460px; - margin: 0 auto; - margin-top: 30px; -} - -.banner-link { - width: 250px; - margin: 0 auto; - margin-top: 15px; - padding: 5px; - text-align: center; -} - -.banner-link a { - color: #fff; - font-weight: 700; - letter-spacing: 1px; -} - -.banner-link a:hover { - color: #000; -} - -.mid-wrapper { - width: 100%; - border-top: 1px solid #2A8729; - padding-top: 15px; -} - -.tabs { - width: 1000px; - margin: 0 auto; - padding: 3px; - margin-top: 5px; - margin-bottom: 25px; -} - -.tab-bar li { - width: 230px; - padding: 3px; - text-align: center; - float: left; - margin-right: 5px; - margin-left: 6px; -} - -.tab-bar li a { - display: inline-block; -} - -.tab-bar li a:hover > p, -.tab-bar li a:hover > h2 { - color: #1D692D; -} - -.tab-bar li a p, -.tab-bar li a h2 { - color: #404028; - margin-top: 8px; - line-height: 1.2; -} - -.tab-bar li a h2 { - font-weight: 700; - text-transform: uppercase; -} - -.withborder { - background: url(../images/separator.jpg) no-repeat; -} - -.gabout, .gcommunity, .gdownloads, .gdocuments { - height: 80px; - width: 230px; - padding-top: 118px; -} - -.gabout { - background: url(../images/about.jpg) no-repeat 50% 0; -} - -.gcommunity { - background: url(../images/community.jpg) no-repeat 50% 0; -} - -.gdocuments { - background: url(../images/documents.jpg) no-repeat 50% 0; -} - -.gdownloads { - background: url(../images/downloads.jpg) no-repeat 50% 0; -} - -.tabs li.active a, -.gabout:hover, -.gcommunity:hover, -.gdocuments:hover, -.gdownloads:hover { - background-position: 50% -220px; -} - -.tabs div { - display:none; -} - -.tabs div.active { - display: block; -} - -.tab-box { - color: #3F3F27; - border: 1px solid #DDDDD5; - padding: 25px 35px; - position: relative; - margin-top: 20px; - border-radius: 3px; -} - -.tab-box h1 { - font-size: 28px; - color: #2A8729; -} - -.tab-box p { - margin: 0 0 9px; -} - -.tab-box ul { - padding-left: 40px; -} - -.tab-box li { - list-style: disc; - margin: 0 0 9px; -} - -.tab-box a, -.latest a { - color: #3F3F27; - text-decoration: underline; -} - -.tab-box a:hover, -.latest a:hover { - color: #1D692D; -} - -.arrow { - background: url(../images/arrow.png) no-repeat; - position: absolute; - left: 115px; - top: -7px; - height: 10px; - width: 20px; -} - -pre { - font-family: Menlo, Monaco, Consolas, "Courier New", monospace; - font-size: 14px; - color: #333333; - display: block; - padding: 8.5px; - margin: 0 0 9px; - font-size: 14px; - line-height: 18px; - word-break: break-all; - word-wrap: break-word; - white-space: pre; - white-space: pre-wrap; - background-color: #EEFFCC; - border-top: 1px solid #A9CC99; - border-bottom: 1px solid #A9CC99; -} - -.user-wrapper { - background: url(../images/banner-bg.jpg) repeat; - height: 110px; -} - -.users { - width: 1000px; - padding: 20px 5px; - margin: 0 auto; - color: #fff; -} - -.users h3 { - font-size: 12px; - margin-left: 5px; - padding-top: 15px; -} - -.users h2 { - font-size: 26px; - margin-left: 5px; -} - -.users .left-details { - width: 120px; - float: left; - height: 66px; - background: url(../images/footer-arrow.png) no-repeat top right; - padding-right: 15px; - text-align: right; -} - -.users .company-logos { - float: left; - width: 820px; - height: 70px; - margin-left: 20px; -} - -.users .company-logos a img { - float: left; - border: solid 1px #004000; - margin: 0 6px; -} - -.users .company-logos a:hover img { - border: solid 1px #000; -} - -.footer { - background-color: #F8F8F3; - display: block; - height: 70px; -} - -.footer .footer-wp { - margin: 0 auto; - padding: 15px 5px; - width: 930px; - background: url(../images/footer-logo.jpg) no-repeat 0 50%; - padding-left: 70px; -} - -.footer-wp a { - color: #3F3F27; - text-decoration: underline; -} - -.footer-wp a:hover { - color: #1D692D; -} diff --git a/docs/site/deploy.html b/docs/site/deploy.html deleted file mode 100644 index 97568d2e0..000000000 --- a/docs/site/deploy.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Deployment - - -

- Redirecting to here -

- - diff --git a/docs/site/deployment.html b/docs/site/deployment.html deleted file mode 100644 index 2ccee4bbd..000000000 --- a/docs/site/deployment.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Deployment - - -

- Redirecting to here -

- - \ No newline at end of file diff --git a/docs/site/design.html b/docs/site/design.html deleted file mode 100644 index 38f04705f..000000000 --- a/docs/site/design.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Design - - -

- Redirecting to here -

- - diff --git a/docs/site/faq.html b/docs/site/faq.html deleted file mode 100644 index 5dbdc0b1b..000000000 --- a/docs/site/faq.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - FAQ - - -

- Redirecting to here -

- - diff --git a/docs/site/images/about.jpg b/docs/site/images/about.jpg deleted file mode 100644 index 4aab4d50f..000000000 Binary files a/docs/site/images/about.jpg and /dev/null differ diff --git a/docs/site/images/arrow.png b/docs/site/images/arrow.png deleted file mode 100644 index 754d30919..000000000 Binary files a/docs/site/images/arrow.png and /dev/null differ diff --git a/docs/site/images/banner-bg.jpg b/docs/site/images/banner-bg.jpg deleted file mode 100644 index 0ba44ffab..000000000 Binary files a/docs/site/images/banner-bg.jpg and /dev/null differ diff --git a/docs/site/images/community.jpg b/docs/site/images/community.jpg deleted file mode 100644 index 0cda8a88e..000000000 Binary files a/docs/site/images/community.jpg and /dev/null differ diff --git a/docs/site/images/documents.jpg b/docs/site/images/documents.jpg deleted file mode 100644 index d96d8ca90..000000000 Binary files a/docs/site/images/documents.jpg and /dev/null differ diff --git a/docs/site/images/downloads.jpg b/docs/site/images/downloads.jpg deleted file mode 100644 index 9c4f93734..000000000 Binary files a/docs/site/images/downloads.jpg and /dev/null differ diff --git a/docs/site/images/favicon.png b/docs/site/images/favicon.png deleted file mode 100644 index 63bef255b..000000000 Binary files a/docs/site/images/favicon.png and /dev/null differ diff --git a/docs/site/images/footer-arrow.png b/docs/site/images/footer-arrow.png deleted file mode 100644 index 483639f4f..000000000 Binary files a/docs/site/images/footer-arrow.png and /dev/null differ diff --git a/docs/site/images/footer-logo.jpg b/docs/site/images/footer-logo.jpg deleted file mode 100644 index cf6e5e399..000000000 Binary files a/docs/site/images/footer-logo.jpg and /dev/null differ diff --git a/docs/site/images/greenbutton.jpg b/docs/site/images/greenbutton.jpg deleted file mode 100644 index 0f8d7ac3b..000000000 Binary files a/docs/site/images/greenbutton.jpg and /dev/null differ diff --git a/docs/site/images/gunicorn.png b/docs/site/images/gunicorn.png deleted file mode 100644 index 98aaf382c..000000000 Binary files a/docs/site/images/gunicorn.png and /dev/null differ diff --git a/docs/site/images/large_gunicorn.png b/docs/site/images/large_gunicorn.png deleted file mode 100644 index 403301fc0..000000000 Binary files a/docs/site/images/large_gunicorn.png and /dev/null differ diff --git a/docs/site/images/logo-bottom.png b/docs/site/images/logo-bottom.png deleted file mode 100644 index 9264bed93..000000000 Binary files a/docs/site/images/logo-bottom.png and /dev/null differ diff --git a/docs/site/images/logo.jpg b/docs/site/images/logo.jpg deleted file mode 100644 index f96c50cf5..000000000 Binary files a/docs/site/images/logo.jpg and /dev/null differ diff --git a/docs/site/images/logo.png b/docs/site/images/logo.png deleted file mode 100644 index c162d6ae1..000000000 Binary files a/docs/site/images/logo.png and /dev/null differ diff --git a/docs/site/images/redbutton.jpg b/docs/site/images/redbutton.jpg deleted file mode 100644 index 735f73040..000000000 Binary files a/docs/site/images/redbutton.jpg and /dev/null differ diff --git a/docs/site/images/separator.jpg b/docs/site/images/separator.jpg deleted file mode 100644 index 6e6cbb8b4..000000000 Binary files a/docs/site/images/separator.jpg and /dev/null differ diff --git a/docs/site/images/title.png b/docs/site/images/title.png deleted file mode 100644 index e257bf206..000000000 Binary files a/docs/site/images/title.png and /dev/null differ diff --git a/docs/site/images/user1.jpg b/docs/site/images/user1.jpg deleted file mode 100644 index 6373b77f6..000000000 Binary files a/docs/site/images/user1.jpg and /dev/null differ diff --git a/docs/site/index.html b/docs/site/index.html deleted file mode 100644 index f8f811ca8..000000000 --- a/docs/site/index.html +++ /dev/null @@ -1,185 +0,0 @@ - - - - - Gunicorn - Python WSGI HTTP Server for UNIX - - - - - - - -
-
-
- Latest version: 23.0.0 -
- - -
-
- - -
-
- -
- -
-

Installation

-

- Here's a quick rundown on how to get started with Gunicorn. For more details read the documentation. -

-
-  $ pip install gunicorn
-  $ cat myapp.py
-    def app(environ, start_response):
-        data = b"Hello, World!\n"
-        start_response("200 OK", [
-            ("Content-Type", "text/plain"),
-            ("Content-Length", str(len(data)))
-        ])
-        return iter([data])
-  $ gunicorn -w 4 myapp:app
-  [2014-09-10 10:22:28 +0000] [30869] [INFO] Listening at: http://127.0.0.1:8000 (30869)
-  [2014-09-10 10:22:28 +0000] [30869] [INFO] Using worker: sync
-  [2014-09-10 10:22:28 +0000] [30874] [INFO] Booting worker with pid: 30874
-  [2014-09-10 10:22:28 +0000] [30875] [INFO] Booting worker with pid: 30875
-  [2014-09-10 10:22:28 +0000] [30876] [INFO] Booting worker with pid: 30876
-  [2014-09-10 10:22:28 +0000] [30877] [INFO] Booting worker with pid: 30877
-
-
-
-

Deployment

-

- Gunicorn is a WSGI HTTP server. It is best to use Gunicorn behind an HTTP proxy server. We strongly advise you to use nginx. -

-

Here's an example to help you get started with using nginx:

-
-  server {
-    listen 80;
-    server_name example.org;
-    access_log  /var/log/nginx/example.log;
-
-    location / {
-        proxy_pass http://127.0.0.1:8000;
-        proxy_set_header Host $host;
-        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
-    }
-  }
-
-

Nginx is set up as reverse proxy server to a Gunicorn server running on localhost port 8000.

-

Read the full documentation at docs.gunicorn.org

-
-
-

Project Management

-

Gunicorn uses GitHub for the project management. GitHub issues are used for 3 different purposes:

- -

Project maintenance guidelines are available on the wiki

- -

IRC

-

The Gunicorn channel is on the Libera Chat IRC - network. You can chat with the community on the #gunicorn channel.

- -

Issue Tracking

-

Bug reports, enhancement requests and tasks generally go in the Github - issue tracker.

- -

Security Issues

-

The security mailing list is a place to report security issues. Only - developers are subscribed to it. To post a message to the list use the - address security@gunicorn.org

- -
-
-

Documentation

-

You can read more comprehensive documentation at docs.gunicorn.org.

-

The contents are:

-
-
-
- - - - - - - - - diff --git a/docs/site/install.html b/docs/site/install.html deleted file mode 100644 index b3dfbd470..000000000 --- a/docs/site/install.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Install - - -

- Redirecting to here -

- - diff --git a/docs/site/installation.html b/docs/site/installation.html deleted file mode 100644 index b3dfbd470..000000000 --- a/docs/site/installation.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Install - - -

- Redirecting to here -

- - diff --git a/docs/site/js/main.js b/docs/site/js/main.js deleted file mode 100755 index c285c8fdd..000000000 --- a/docs/site/js/main.js +++ /dev/null @@ -1,46 +0,0 @@ -$(document).ready(function() { - Tabs.init(); -}); - -var Tabs = { - init: function(){ - var activateTab = function ($tab) { - var // this links tabs set - $tabs = $tab.parents('.tabs'), - // currently active tab - activeTab = { - 'tab' : $tabs.find('ul').children('li.active'), - 'content' : $tabs.find('div[data-tab].active') - }, - // newly clicked tab - newTab = { - 'tab' : $tab.parent('li'), - 'content' : $tabs.find('[data-tab=' + $tab.attr('href').replace('#', '') + ']') - }, - x, y; - - // remove active class from tab and content - for (x in activeTab) { - activeTab[x].removeClass('active'); - } - - // add active class to tab and content - for (y in newTab) { - newTab[y].addClass('active'); - } - }; - // hook up tab links - $(document).on('click', '.tabs ul li a', function(e) { - activateTab($(this)); - //alert($(this)); - }); - - // hook up initial load active tab - if (window.location.hash) { - var $activeTab = $('a[href="' + window.location.hash + '"]'); - if ($activeTab.length && $activeTab.parents('.tabs').length) { - activateTab($activeTab); - } - } - } -}; \ No newline at end of file diff --git a/docs/site/news.html b/docs/site/news.html deleted file mode 100644 index 318dcdf2e..000000000 --- a/docs/site/news.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - News - - -

- Redirecting to here -

- - diff --git a/docs/site/run.html b/docs/site/run.html deleted file mode 100644 index 236fc3e46..000000000 --- a/docs/site/run.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Run - - -

- Redirecting to here -

- - diff --git a/docs/site/sitemap.xml b/docs/site/sitemap.xml deleted file mode 100644 index 6411a24e3..000000000 --- a/docs/site/sitemap.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - http://gunicorn.org/ - 2019-11-27T00:02:48+01:00 - 1.0 - - - http://gunicorn.org/community.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/configuration.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/configure.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/deploy.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/deployment.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/design.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/faq.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/install.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/installation.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/news.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/run.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/tuning.html - 2012-10-04T00:43:15+05:45 - 0.5 - - - http://gunicorn.org/usage.html - 2012-10-04T00:43:15+05:45 - 0.5 - - diff --git a/docs/site/tuning.html b/docs/site/tuning.html deleted file mode 100644 index 5dbdc0b1b..000000000 --- a/docs/site/tuning.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - FAQ - - -

- Redirecting to here -

- - diff --git a/docs/site/usage.html b/docs/site/usage.html deleted file mode 100644 index 236fc3e46..000000000 --- a/docs/site/usage.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Green Unicorn - Run - - -

- Redirecting to here -

- - diff --git a/docs/sitemap_gen.py b/docs/sitemap_gen.py deleted file mode 100644 index 29c7ca028..000000000 --- a/docs/sitemap_gen.py +++ /dev/null @@ -1,41 +0,0 @@ -import os -import subprocess -from xml.etree import ElementTree - - -def main(): - generate( - site_path=os.path.join(os.path.dirname(__file__), 'site'), - special_priorities={'index.html': 1.0}) - - -def generate(site_path, special_priorities, directory_index='index.html'): - urlset = ElementTree.Element('urlset', xmlns='http://www.sitemaps.org/schemas/sitemap/0.9') - urlset.text = '\n ' - for root, dirs, filenames in os.walk(site_path): - for filename in filenames: - if filename.endswith('.html'): - absolute_filepath = os.path.join(root, filename) - relative_path = os.path.relpath(absolute_filepath, site_path) - relative_url = os.path.dirname(relative_path) if filename == directory_index else relative_path - last_modification = subprocess.check_output( - ['git', 'log', '-1', '--pretty="%cI"', absolute_filepath]).decode('ascii').strip('\n"') - url_element = ElementTree.SubElement(urlset, 'url') - loc_element = ElementTree.SubElement(url_element, 'loc') - loc_element.text = 'http://gunicorn.org/' + relative_url - lastmod_element = ElementTree.SubElement(url_element, 'lastmod') - lastmod_element.text = last_modification - priority_element = ElementTree.SubElement(url_element, 'priority') - priority_element.text = str(special_priorities.get(relative_path, 0.5)) - url_element.tail = priority_element.tail = '\n ' - url_element.text = loc_element.tail = lastmod_element.tail = '\n ' - # We sort the url nodes instead of the filenames because - # filenames might be altered by the directory_index option - urlset[:] = sorted([url for url in urlset], key=lambda url: url[0].text) - urlset.tail = urlset[-1].tail = '\n' - with open(os.path.join(site_path, 'sitemap.xml'), 'wb') as sitemap_file: - ElementTree.ElementTree(urlset).write(sitemap_file, encoding='UTF-8', xml_declaration=True) - - -if __name__ == '__main__': - main() diff --git a/docs/source/2015-news.rst b/docs/source/2015-news.rst deleted file mode 100644 index 61ea225b4..000000000 --- a/docs/source/2015-news.rst +++ /dev/null @@ -1,219 +0,0 @@ -================ -Changelog - 2015 -================ - -.. note:: - - Please see :doc:`news` for the latest changes. - -19.4.3 / 2015/12/30 -=================== - -- fix: don't check if a file is writable using os.stat with SELINUX (:issue:`1171`) - -19.4.2 / 2015/12/29 -=================== - -Core -++++ - -- improvement: handle HaltServer in manage_workers (:issue:`1095`) -- fix: Do not rely on sendfile sending requested count (:issue:`1155`) -- fix: claridy --no-sendfile default (:issue:`1156`) -- fix: LoggingCatch sendfile failure from no file descriptor (:issue:`1160`) - -Logging -+++++++ - -- fix: Always send access log to syslog if syslog is on -- fix: check auth before trying to own a file (:issue:`1157`) - - -Documentation -+++++++++++++ - -- fix: Fix Slowloris broken link. (:issue:`1142`) -- Tweak markup in faq.rst - -Testing -+++++++ - -- fix: gaiohttp test (:issue:`1164`) - -19.4.1 / 2015/11/25 -=================== - -- fix tornado worker (:issue:`1154`) - -19.4.0 / 2015/11/20 -=================== - -Core -++++ - -- fix: make sure that a user is able to access to the logs after dropping a - privilege (:issue:`1116`) -- improvement: inherit the `Exception` class where it needs to be (:issue:`997`) -- fix: make sure headers are always encoded as latin1 RFC 2616 (:issue:`1102`) -- improvement: reduce arbiter noise (:issue:`1078`) -- fix: don't close the unix socket when the worker exit (:issue:`1088`) -- improvement: Make last logged worker count an explicit instance var (:issue:`1078`) -- improvement: prefix config file with its type (:issue:`836`) -- improvement: pidfile handing (:issue:`1042`) -- fix: catch OSError as well as ValueError on race condition (:issue:`1052`) -- improve support of ipv6 by backporting urlparse.urlsplit from Python 2.7 to - Python 2.6. -- fix: raise InvalidRequestLine when the line contains malicious data - (:issue:`1023`) -- fix: fix argument to disable sendfile -- fix: add gthread to the list of supported workers (:issue:`1011`) -- improvement: retry socket binding up to five times upon EADDRNOTAVAIL - (:issue:`1004`) -- **breaking change**: only honor headers that can be encoded in ascii to comply to - the RFC 7230 (See :issue:`1151`). - -Logging -+++++++ - -- add new parameters to access log (:issue:`1132`) -- fix: make sure that files handles are correctly reopened on HUP - (:issue:`627`) -- include request URL in error message (:issue:`1071`) -- get username in access logs (:issue:`1069`) -- fix statsd logging support on Python 3 (:issue:`1010`) - -Testing -+++++++ - -- use last version of mock. -- many fixes in Travis CI support -- miscellaneous improvements in tests - -Thread worker -+++++++++++++ - -- fix: Fix self.nr usage in ThreadedWorker so that auto restart works as - expected (:issue:`1031`) - -Gevent worker -+++++++++++++ - -- fix quit signal handling (:issue:`1128`) -- add support for Python 3 (:issue:`1066`) -- fix: make graceful shutdown thread-safe (:issue:`1032`) - -Tornado worker -++++++++++++++ - -- fix ssl options (:issue:`1146`, :issue:`1135`) -- don't check timeout when stopping gracefully (:issue:`1106`) - -AIOHttp worker -++++++++++++++ - -- add SSL support (:issue:`1105`) - -Documentation -+++++++++++++ - -- fix link to proc name setting (:issue:`1144`) -- fix worker class documentation (:issue:`1141`, :issue:`1104`) -- clarify graceful timeout documentation (:issue:`1137`) -- don't duplicate NGINX config files examples (:issue:`1050`, :issue:`1048`) -- add `web.py` framework example (:issue:`1117`) -- update Debian/Ubuntu installations instructions (:issue:`1112`) -- clarify `pythonpath` setting description (:issue:`1080`) -- tweak some example for python3 -- clarify `sendfile` documentation -- miscellaneous typos in source code comments (thanks!) -- clarify why REMOTE_ADD may not be the user's IP address (:issue:`1037`) - - -Misc -++++ - -- fix: reloader should survive SyntaxError (:issue:`994`) -- fix: expose the reloader class to the worker. - - - -19.3.0 / 2015/03/06 -=================== - -Core -++++ - -- fix: :issue:`978` make sure a listener is inheritable -- add `check_config` class method to workers -- fix: :issue:`983` fix select timeout in sync worker with multiple - connections -- allows workers to access to the reloader. close :issue:`984` -- raise TypeError instead of AssertionError - -Logging -+++++++ - -- make Logger.loglevel a class attribute - -Documentation -+++++++++++++ - -- fix: :issue:`988` fix syntax errors in examples/gunicorn_rc - - -19.2.1 / 2015/02/4 -================== - -Logging -+++++++ - -- expose loglevel in the Logger class - -AsyncIO worker (gaiohttp) -+++++++++++++++++++++++++ - -- fix :issue:`977` fix initial crash - -Documentation -+++++++++++++ - -- document security mailing-list in the contributing page. - -19.2 / 2015/01/30 -================= - -Core -++++ - -- optimize the sync workers when listening on a single interface -- add `--sendfile` settings to enable/disable sendfile. fix :issue:`856` . -- add the selectors module to the code base. :issue:`886` -- add `--max-requests-jitter` setting to set the maximum jitter to add to the - max-requests setting. -- fix :issue:`899` propagate proxy_protocol_info to keep-alive requests -- fix :issue:`863` worker timeout: dynamic timeout has been removed -- fix: Avoid world writable file - -Logging -+++++++ - -- fix :issue:`941` set logconfig default to paster more trivially -- add statsd-prefix config setting: set the prefix to use when emitting statsd - metrics -- :issue:`832` log to console by default - -Thread Worker -+++++++++++++ - -- fix :issue:`908` make sure the worker can continue to accept requests - -Eventlet Worker -+++++++++++++++ - -- fix :issue:`867` Fix eventlet shutdown to actively shut down the workers. - -Documentation -+++++++++++++ - -Many improvements and fixes have been done, see the detailed changelog for -more information. diff --git a/docs/source/2016-news.rst b/docs/source/2016-news.rst deleted file mode 100644 index b7a4e66b8..000000000 --- a/docs/source/2016-news.rst +++ /dev/null @@ -1,91 +0,0 @@ -================ -Changelog - 2016 -================ - -.. note:: - - Please see :doc:`news` for the latest changes - -19.6.0 / 2016/05/21 -=================== - -Core & Logging -++++++++++++++ - -- improvement of the binary upgrade behaviour using USR2: remove file locking (:issue:`1270`) -- add the ``--capture-output`` setting to capture stdout/stderr tot the log - file (:issue:`1271`) -- Allow disabling ``sendfile()`` via the ``SENDFILE`` environment variable - (:issue:`1252`) -- fix reload under pycharm (:issue:`1129`) - -Workers -+++++++ - -- fix: make sure to remove the signal from the worker pipe (:issue:`1269`) -- fix: **gthread** worker, handle removed socket in the select loop - (:issue:`1258`) - -19.5.0 / 2016/05/10 -=================== - -Core -++++ - -- fix: Ensure response to HEAD request won't have message body -- fix: lock domain socket and remove on last arbiter exit (:issue:`1220`) -- improvement: use EnvironmentError instead of socket.error (:issue:`939`) -- add: new ``FORWARDED_ALLOW_IPS`` environment variable (:issue:`1205`) -- fix: infinite recursion when destroying sockets (:issue:`1219`) -- fix: close sockets on shutdown (:issue:`922`) -- fix: clean up sys.exc_info calls to drop circular refs (:issue:`1228`) -- fix: do post_worker_init after load_wsgi (:issue:`1248`) - -Workers -+++++++ - -- fix access logging in gaiohttp worker (:issue:`1193`) -- eventlet: handle QUIT in a new coroutine (:issue:`1217`) -- gevent: remove obsolete exception clauses in run (:issue:`1218`) -- tornado: fix extra "Server" response header (:issue:`1246`) -- fix: unblock the wait loop under python 3.5 in sync worker (:issue:`1256`) - -Logging -+++++++ - -- fix: log message for listener reloading (:issue:`1181`) -- Let logging module handle traceback printing (:issue:`1201`) -- improvement: Allow configuring logger_class with statsd_host (:issue:`1188`) -- fix: traceback formatting (:issue:`1235`) -- fix: print error logs on stderr and access logs on stdout (:issue:`1184`) - - -Documentation -+++++++++++++ - -- Simplify installation instructions in gunicorn.org (:issue:`1072`) -- Fix URL and default worker type in example_config (:issue:`1209`) -- update django doc url to 1.8 lts (:issue:`1213`) -- fix: miscellaneous wording corrections (:issue:`1216`) -- Add PSF License Agreement of selectors.py to NOTICE (:issue: `1226`) -- document LOGGING overriding (:issue:`1051`) -- put a note that error logs are only errors from Gunicorn (:issue:`1124`) -- add a note about the requirements of the threads workers under python 2.x (:issue:`1200`) -- add access_log_format to config example (:issue:`1251`) - -Tests -+++++ - -- Use more pytest.raises() in test_http.py - - -19.4.5 / 2016/01/05 -=================== - -- fix: NameError fileno in gunicorn.http.wsgi (:issue:`1178`) - -19.4.4 / 2016/01/04 -=================== - -- fix: check if a fileobject can be used with sendfile(2) (:issue:`1174`) -- doc: be more descriptive in errorlog option (:issue:`1173`) diff --git a/docs/source/2017-news.rst b/docs/source/2017-news.rst deleted file mode 100644 index 0fb201e61..000000000 --- a/docs/source/2017-news.rst +++ /dev/null @@ -1,46 +0,0 @@ -================ -Changelog - 2017 -================ - -.. note:: - - Please see :doc:`news` for the latest changes - -19.7.1 / 2017/03/21 -=================== - -- fix: continue if SO_REUSEPORT seems to be available but fails (:issue:`1480`) -- fix: support non-decimal values for the umask command line option (:issue:`1325`) - -19.7.0 / 2017/03/01 -=================== - -- The previously deprecated ``gunicorn_django`` command has been removed. - Use the :ref:`gunicorn-cmd` command-line interface instead. -- The previously deprecated ``django_settings`` setting has been removed. - Use the :ref:`raw-env` setting instead. -- The default value of :ref:`ssl-version` has been changed from - ``ssl.PROTOCOL_TLSv1`` to ``ssl.PROTOCOL_SSLv23``. -- fix: initialize the group access list when initgroups is set (:issue:`1297`) -- add environment variables to gunicorn access log format (:issue:`1291`) -- add --paste-global-conf option (:issue:`1304`) -- fix: print access logs to STDOUT (:issue:`1184`) -- remove upper limit on max header size config (:issue:`1313`) -- fix: print original exception on AppImportError (:issue:`1334`) -- use SO_REUSEPORT if available (:issue:`1344`) -- `fix leak `_ of duplicate file descriptor for bound sockets. -- add --reload-engine option, support inotify and other backends (:issue:`1368`, :issue:`1459`) -- fix: reject request with invalid HTTP versions -- add ``child_exit`` callback (:issue:`1394`) -- add support for eventlets _AlreadyHandled object (:issue:`1406`) -- format boot tracebacks properly with reloader (:issue:`1408`) -- refactor socket activation and fd inheritance for better support of SystemD (:issue:`1310`) -- fix: o fds are given by default in gunicorn (:issue:`1423`) -- add ability to pass settings to GUNICORN_CMD_ARGS environment variable which helps in container world (:issue:`1385`) -- fix: catch access denied to pid file (:issue:`1091`) -- many additions and improvements to the documentation - -Breaking Change -+++++++++++++++ - -- **Python 2.6.0** is the last supported version diff --git a/docs/source/2018-news.rst b/docs/source/2018-news.rst deleted file mode 100644 index 3b412cf5d..000000000 --- a/docs/source/2018-news.rst +++ /dev/null @@ -1,68 +0,0 @@ -================ -Changelog - 2018 -================ - -.. note:: - - Please see :doc:`news` for the latest changes - -19.9.0 / 2018/07/03 -=================== - -- fix: address a regression that prevented syslog support from working - (:issue:`1668`, :pr:`1773`) -- fix: correctly set `REMOTE_ADDR` on versions of Python 3 affected by - `Python Issue 30205 `_ - (:issue:`1755`, :pr:`1796`) -- fix: show zero response length correctly in access log (:pr:`1787`) -- fix: prevent raising :exc:`AttributeError` when ``--reload`` is not passed - in case of a :exc:`SyntaxError` raised from the WSGI application. - (:issue:`1805`, :pr:`1806`) -- The internal module ``gunicorn.workers.async`` was renamed to ``gunicorn.workers.base_async`` - since ``async`` is now a reserved word in Python 3.7. - (:pr:`1527`) - -19.8.1 / 2018/04/30 -=================== - -- fix: secure scheme headers when bound to a unix socket - (:issue:`1766`, :pr:`1767`) - -19.8.0 / 2018/04/28 -=================== - -- Eventlet 0.21.0 support (:issue:`1584`) -- Tornado 5 support (:issue:`1728`, :pr:`1752`) -- support watching additional files with ``--reload-extra-file`` - (:pr:`1527`) -- support configuring logging with a dictionary with ``--logging-config-dict`` - (:issue:`1087`, :pr:`1110`, :pr:`1602`) -- add support for the ``--config`` flag in the ``GUNICORN_CMD_ARGS`` environment - variable (:issue:`1576`, :pr:`1581`) -- disable ``SO_REUSEPORT`` by default and add the ``--reuse-port`` setting - (:issue:`1553`, :issue:`1603`, :pr:`1669`) -- fix: installing `inotify` on MacOS no longer breaks the reloader - (:issue:`1540`, :pr:`1541`) -- fix: do not throw ``TypeError`` when ``SO_REUSEPORT`` is not available - (:issue:`1501`, :pr:`1491`) -- fix: properly decode HTTP paths containing certain non-ASCII characters - (:issue:`1577`, :pr:`1578`) -- fix: remove whitespace when logging header values under gevent (:pr:`1607`) -- fix: close unlinked temporary files (:issue:`1327`, :pr:`1428`) -- fix: parse ``--umask=0`` correctly (:issue:`1622`, :pr:`1632`) -- fix: allow loading applications using relative file paths - (:issue:`1349`, :pr:`1481`) -- fix: force blocking mode on the gevent sockets (:issue:`880`, :pr:`1616`) -- fix: preserve leading `/` in request path (:issue:`1512`, :pr:`1511`) -- fix: forbid contradictory secure scheme headers -- fix: handle malformed basic authentication headers in access log - (:issue:`1683`, :pr:`1684`) -- fix: defer handling of ``USR1`` signal to a new greenlet under gevent - (:issue:`1645`, :pr:`1651`) -- fix: the threaded worker would sometimes close the wrong keep-alive - connection under Python 2 (:issue:`1698`, :pr:`1699`) -- fix: re-open log files on ``USR1`` signal using ``handler._open`` to - support subclasses of ``FileHandler`` (:issue:`1739`, :pr:`1742`) -- deprecation: the ``gaiohttp`` worker is deprecated, see the - :ref:`worker-class` documentation for more information - (:issue:`1338`, :pr:`1418`, :pr:`1569`) \ No newline at end of file diff --git a/docs/source/2020-news.rst b/docs/source/2020-news.rst deleted file mode 100644 index 1d91ef7e5..000000000 --- a/docs/source/2020-news.rst +++ /dev/null @@ -1,7 +0,0 @@ -================ -Changelog - 2020 -================ - -.. note:: - - Please see :doc:`news` for the latest changes diff --git a/docs/source/2024-news.rst b/docs/source/2024-news.rst deleted file mode 100644 index 376699b4d..000000000 --- a/docs/source/2024-news.rst +++ /dev/null @@ -1,61 +0,0 @@ -================ -Changelog - 2024 -================ - -23.0.0 - 2024-08-10 -=================== - -- minor docs fixes (:pr:`3217`, :pr:`3089`, :pr:`3167`) -- worker_class parameter accepts a class (:pr:`3079`) -- fix deadlock if request terminated during chunked parsing (:pr:`2688`) -- permit receiving Transfer-Encodings: compress, deflate, gzip (:pr:`3261`) -- permit Transfer-Encoding headers specifying multiple encodings. note: no parameters, still (:pr:`3261`) -- sdist generation now explicitly excludes sphinx build folder (:pr:`3257`) -- decode bytes-typed status (as can be passed by gevent) as utf-8 instead of raising `TypeError` (:pr:`2336`) -- raise correct Exception when encounting invalid chunked requests (:pr:`3258`) -- the SCRIPT_NAME and PATH_INFO headers, when received from allowed forwarders, are no longer restricted for containing an underscore (:pr:`3192`) -- include IPv6 loopback address ``[::1]`` in default for :ref:`forwarded-allow-ips` and :ref:`proxy-allow-ips` (:pr:`3192`) - -** NOTE ** - -- The SCRIPT_NAME change mitigates a regression that appeared first in the 22.0.0 release -- Review your :ref:`forwarded-allow-ips` setting if you are still not seeing the SCRIPT_NAME transmitted -- Review your :ref:`forwarder-headers` setting if you are missing headers after upgrading from a version prior to 22.0.0 - -** Breaking changes ** - -- refuse requests where the uri field is empty (:pr:`3255`) -- refuse requests with invalid CR/LR/NUL in heade field values (:pr:`3253`) -- remove temporary ``--tolerate-dangerous-framing`` switch from 22.0 (:pr:`3260`) -- If any of the breaking changes affect you, be aware that now refused requests can post a security problem, especially so in setups involving request pipe-lining and/or proxies. - -22.0.0 - 2024-04-17 -=================== - -- use `utime` to notify workers liveness -- migrate setup to pyproject.toml -- fix numerous security vulnerabilities in HTTP parser (closing some request smuggling vectors) -- parsing additional requests is no longer attempted past unsupported request framing -- on HTTP versions < 1.1 support for chunked transfer is refused (only used in exploits) -- requests conflicting configured or passed SCRIPT_NAME now produce a verbose error -- Trailer fields are no longer inspected for headers indicating secure scheme -- support Python 3.12 - -** Breaking changes ** - -- minimum version is Python 3.7 -- the limitations on valid characters in the HTTP method have been bounded to Internet Standards -- requests specifying unsupported transfer coding (order) are refused by default (rare) -- HTTP methods are no longer casefolded by default (IANA method registry contains none affected) -- HTTP methods containing the number sign (#) are no longer accepted by default (rare) -- HTTP versions < 1.0 or >= 2.0 are no longer accepted by default (rare, only HTTP/1.1 is supported) -- HTTP versions consisting of multiple digits or containing a prefix/suffix are no longer accepted -- HTTP header field names Gunicorn cannot safely map to variables are silently dropped, as in other software -- HTTP headers with empty field name are refused by default (no legitimate use cases, used in exploits) -- requests with both Transfer-Encoding and Content-Length are refused by default (such a message might indicate an attempt to perform request smuggling) -- empty transfer codings are no longer permitted (reportedly seen with really old & broken proxies) - - -** SECURITY ** - -- fix CVE-2024-1135 diff --git a/docs/source/_static/gunicorn.png b/docs/source/_static/gunicorn.png deleted file mode 100644 index a3a78e0e8..000000000 Binary files a/docs/source/_static/gunicorn.png and /dev/null differ diff --git a/docs/source/community.rst b/docs/source/community.rst deleted file mode 100644 index 5bfe51c08..000000000 --- a/docs/source/community.rst +++ /dev/null @@ -1,37 +0,0 @@ -========= -Community -========= - -Use these channels to communicate about the project: - -Project Management & Discussions -================================ - -Project maintenance guidelines are available on the `wiki `_ - -GitHub issues are used for 3 different purposes: - - * `Bug tracker `_ : To check for latest bugs. Tip: See existing issues before opening a new one! - * `Forum `_ : Stackoverflow-style questions about Gunicorn usage. - * `Other Issues `_ : Discussion of Gunicorn development, new features - and project management. - -IRC -=== - -The Gunicorn channel is on the `Libera Chat `_ IRC -network. You can chat with others on `#gunicorn channel -`_ - -Issue Tracking -============== - -Bug reports, enhancement requests and tasks generally go in the `Github -issue tracker `_ - -Security Issues -=============== - -The security mailing list is a place to report security issues. Only -developers are subscribed to it. To post a message to the list use the address -to `security@gunicorn.org `_ diff --git a/docs/source/conf.py b/docs/source/conf.py deleted file mode 100644 index f000c2dba..000000000 --- a/docs/source/conf.py +++ /dev/null @@ -1,72 +0,0 @@ -# -# Gunicorn documentation build configuration file -# - -import os -import sys -import time - -DOCS_DIR = os.path.abspath(os.path.dirname(__file__)) - -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' - -# for gunicorn_ext.py -sys.path.append(os.path.join(DOCS_DIR, os.pardir)) -sys.path.insert(0, os.path.join(DOCS_DIR, os.pardir, os.pardir)) - -extensions = ['gunicorn_ext'] -templates_path = ['_templates'] -source_suffix = '.rst' -master_doc = 'index' - -# General information about the project. -project = 'Gunicorn' -copyright = '2009-%s, Benoit Chesneau' % time.strftime('%Y') -# gunicorn version -import gunicorn -release = version = gunicorn.__version__ - -exclude_patterns = [] -pygments_style = 'sphinx' - - -# -- Options for HTML output --------------------------------------------------- - -if not on_rtd: # only import and set the theme if we're building docs locally - try: - import sphinx_rtd_theme - except ImportError: - html_theme = 'default' - else: - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] -else: - html_theme = 'default' - -html_static_path = ['_static'] -htmlhelp_basename = 'Gunicorndoc' - - -# -- Options for LaTeX output -------------------------------------------------- - -latex_elements = { - -} - -latex_documents = [ - ('index', 'Gunicorn.tex', 'Gunicorn Documentation', - 'Benoit Chesneau', 'manual'), -] - - -# -- Options for manual page output -------------------------------------------- -man_pages = [ - ('index', 'gunicorn', 'Gunicorn Documentation', - ['Benoit Chesneau'], 1) -] - -texinfo_documents = [ - ('index', 'Gunicorn', 'Gunicorn Documentation', - 'Benoit Chesneau', 'Gunicorn', 'One line description of project.', - 'Miscellaneous'), -] diff --git a/docs/source/configure.rst b/docs/source/configure.rst deleted file mode 100644 index dc9ba62da..000000000 --- a/docs/source/configure.rst +++ /dev/null @@ -1,118 +0,0 @@ -.. _configuration: - -====================== -Configuration Overview -====================== - -Gunicorn reads configuration information from five places. - -Gunicorn first reads environment variables for some configuration -:ref:`settings `. - -Gunicorn then reads configuration from a framework specific configuration -file. Currently this only affects Paster applications. - -The third source of configuration information is an optional configuration file -``gunicorn.conf.py`` searched in the current working directory or specified -using a command line argument. Anything specified in this configuration file -will override any framework specific settings. - -The fourth place of configuration information are command line arguments -stored in an environment variable named ``GUNICORN_CMD_ARGS``. - -Lastly, the command line arguments used to invoke Gunicorn are the final place -considered for configuration settings. If an option is specified on the command -line, this is the value that will be used. - -When a configuration file is specified in the command line arguments and in the -``GUNICORN_CMD_ARGS`` environment variable, only the configuration -file specified on the command line is used. - -Once again, in order of least to most authoritative: - 1. Environment Variables - 2. Framework Settings - 3. Configuration File - 4. ``GUNICORN_CMD_ARGS`` - 5. Command Line - - -.. note:: - - To print your resolved configuration when using the command line or the - configuration file you can run the following command:: - - $ gunicorn --print-config APP_MODULE - - To check your resolved configuration when using the command line or the - configuration file you can run the following command:: - - $ gunicorn --check-config APP_MODULE - - It also allows you to know if your application can be launched. - - -Command Line -============ - -If an option is specified on the command line, it overrides all other values -that may have been specified in the app specific settings, or in the optional -configuration file. Not all Gunicorn settings are available to be set from the -command line. To see the full list of command line settings you can do the -usual:: - - $ gunicorn -h - -There is also a ``--version`` flag available to the command line scripts that -isn't mentioned in the list of :ref:`settings `. - -.. _configuration_file: - -Configuration File -================== - -The configuration file should be a valid Python source file with a **python -extension** (e.g. `gunicorn.conf.py`). It only needs to be readable from the -file system. More specifically, it does not have to be on the module path -(sys.path, PYTHONPATH). Any Python is valid. Just consider that this will be -run every time you start Gunicorn (including when you signal Gunicorn to reload). - -To set a parameter, just assign to it. There's no special syntax. The values -you provide will be used for the configuration values. - -For instance:: - - import multiprocessing - - bind = "127.0.0.1:8000" - workers = multiprocessing.cpu_count() * 2 + 1 - -All the settings are mentioned in the :ref:`settings ` list. - - -Framework Settings -================== - -Currently, only Paster applications have access to framework specific -settings. If you have ideas for providing settings to WSGI applications or -pulling information from Django's settings.py feel free to open an issue_ to -let us know. - -.. _issue: https://github.com/benoitc/gunicorn/issues - -Paster Applications -------------------- - -In your INI file, you can specify to use Gunicorn as the server like such: - -.. code-block:: ini - - [server:main] - use = egg:gunicorn#main - host = 192.168.0.1 - port = 80 - workers = 2 - proc_name = brim - -Any parameters that Gunicorn knows about will automatically be inserted into -the base configuration. Remember that these will be overridden by the config -file and/or the command line. diff --git a/docs/source/custom.rst b/docs/source/custom.rst deleted file mode 100644 index 90f742094..000000000 --- a/docs/source/custom.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. _custom: - -================== -Custom Application -================== - -.. versionadded:: 19.0 - -Sometimes, you want to integrate Gunicorn with your WSGI application. In this -case, you can inherit from :class:`gunicorn.app.base.BaseApplication`. - -Here is a small example where we create a very small WSGI app and load it with -a custom Application: - -.. literalinclude:: ../../examples/standalone_app.py - :start-after: # See the NOTICE for more information - :lines: 2- - -Using server hooks ------------------- - -If you wish to include server hooks in your custom application, you can specify a function in the config options. Here is an example with the `pre_fork` hook: - -.. code-block:: python - - def pre_fork(server, worker): - print(f"pre-fork server {server} worker {worker}", file=sys.stderr) - - # ... - if __name__ == '__main__': - options = { - 'bind': '%s:%s' % ('127.0.0.1', '8080'), - 'workers': number_of_workers(), - 'pre_fork': pre_fork, - } - - -Direct Usage of Existing WSGI Apps ----------------------------------- - -If necessary, you can run Gunicorn straight from Python, allowing you to -specify a WSGI-compatible application at runtime. This can be handy for -rolling deploys or in the case of using PEX files to deploy your application, -as the app and Gunicorn can be bundled in the same PEX file. Gunicorn has -this functionality built-in as a first class citizen known as -:class:`gunicorn.app.wsgiapp`. This can be used to run WSGI-compatible app -instances such as those produced by Flask or Django. Assuming your WSGI API -package is *exampleapi*, and your application instance is *app*, this is all -you need to get going:: - - gunicorn.app.wsgiapp exampleapi:app - -This command will work with any Gunicorn CLI parameters or a config file - just -pass them along as if you're directly giving them to Gunicorn: - -.. code-block:: bash - - # Custom parameters - $ python gunicorn.app.wsgiapp exampleapi:app --bind=0.0.0.0:8081 --workers=4 - # Using a config file - $ python gunicorn.app.wsgiapp exampleapi:app -c config.py - -Note for those using PEX: use ``-c gunicorn`` as your entry at build -time, and your compiled app should work with the entry point passed to it at -run time. - -.. code-block:: bash - - # Generic pex build command via bash from root of exampleapi project - $ pex . -v -c gunicorn -o compiledapp.pex - # Running it - ./compiledapp.pex exampleapi:app -c gunicorn_config.py diff --git a/docs/source/deploy.rst b/docs/source/deploy.rst deleted file mode 100644 index 5f8689793..000000000 --- a/docs/source/deploy.rst +++ /dev/null @@ -1,380 +0,0 @@ -================== -Deploying Gunicorn -================== - -We strongly recommend using Gunicorn behind a proxy server. - -Nginx Configuration -=================== - -Although there are many HTTP proxies available, we strongly advise that you -use Nginx_. If you choose another proxy server you need to make sure that it -buffers slow clients when you use default Gunicorn workers. Without this -buffering Gunicorn will be easily susceptible to denial-of-service attacks. -You can use Hey_ to check if your proxy is behaving properly. - -An `example configuration`_ file for fast clients with Nginx_: - -.. literalinclude:: ../../examples/nginx.conf - :language: nginx - :caption: **nginx.conf** - -If you want to be able to handle streaming request/responses or other fancy -features like Comet, Long polling, or Web sockets, you need to turn off the -proxy buffering. **When you do this** you must run with one of the async worker -classes. - -To turn off buffering, you only need to add ``proxy_buffering off;`` to your -``location`` block:: - - ... - location @proxy_to_app { - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Host $http_host; - proxy_redirect off; - proxy_buffering off; - - proxy_pass http://app_server; - } - ... - -If you want to ignore aborted requests like health check of Load Balancer, some -of which close the connection without waiting for a response, you need to turn -on `ignoring client abort`_. - -To ignore aborted requests, you only need to add -``proxy_ignore_client_abort on;`` to your ``location`` block:: - - ... - proxy_ignore_client_abort on; - ... - -.. note:: - The default value of ``proxy_ignore_client_abort`` is ``off``. Error code - 499 may appear in Nginx log and ``Ignoring EPIPE`` may appear in Gunicorn - log if loglevel is set to ``debug``. - -It is recommended to pass protocol information to Gunicorn. Many web -frameworks use this information to generate URLs. Without this -information, the application may mistakenly generate 'http' URLs in -'https' responses, leading to mixed content warnings or broken -applications. To configure Nginx to pass an appropriate header, add -a ``proxy_set_header`` directive to your ``location`` block:: - - ... - proxy_set_header X-Forwarded-Proto $scheme; - ... - -If you are running Nginx on a different host than Gunicorn you need to tell -Gunicorn to trust the ``X-Forwarded-*`` headers sent by Nginx. By default, -Gunicorn will only trust these headers if the connection comes from localhost. -This is to prevent a malicious client from forging these headers:: - - $ gunicorn -w 3 --forwarded-allow-ips="10.170.3.217,10.170.3.220" test:app - -When the Gunicorn host is completely firewalled from the external network such -that all connections come from a trusted proxy (e.g. Heroku) this value can -be set to '*'. Using this value is **potentially dangerous** if connections to -Gunicorn may come from untrusted proxies or directly from clients since the -application may be tricked into serving SSL-only content over an insecure -connection. - -Gunicorn 19 introduced a breaking change concerning how ``REMOTE_ADDR`` is -handled. Previous to Gunicorn 19 this was set to the value of -``X-Forwarded-For`` if received from a trusted proxy. However, this was not in -compliance with :rfc:`3875` which is why the ``REMOTE_ADDR`` is now the IP -address of **the proxy** and **not the actual user**. - -To have access logs indicate **the actual user** IP when proxied, set -:ref:`access-log-format` with a format which includes ``X-Forwarded-For``. For -example, this format uses ``X-Forwarded-For`` in place of ``REMOTE_ADDR``:: - - %({x-forwarded-for}i)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" - -It is also worth noting that the ``REMOTE_ADDR`` will be completely empty if -you bind Gunicorn to a UNIX socket and not a TCP ``host:port`` tuple. - -Using Virtualenv -================ - -To serve an app from a Virtualenv_ it is generally easiest to just install -Gunicorn directly into the Virtualenv. This will create a set of Gunicorn -scripts for that Virtualenv which can be used to run applications normally. - -If you have Virtualenv installed, you should be able to do something like -this:: - - $ mkdir ~/venvs/ - $ virtualenv ~/venvs/webapp - $ source ~/venvs/webapp/bin/activate - $ pip install gunicorn - $ deactivate - -Then you just need to use one of the three Gunicorn scripts that was installed -into ``~/venvs/webapp/bin``. - -Note: You can force the installation of Gunicorn in your Virtualenv by -passing ``-I`` or ``--ignore-installed`` option to pip:: - - $ source ~/venvs/webapp/bin/activate - $ pip install -I gunicorn - -Monitoring -========== - -.. note:: - Make sure that when using either of these service monitors you do not - enable the Gunicorn's daemon mode. These monitors expect that the process - they launch will be the process they need to monitor. Daemonizing will - fork-exec which creates an unmonitored process and generally just - confuses the monitor services. - -Gaffer ------- - -Using Gafferd and gaffer -++++++++++++++++++++++++ - -Gaffer_ can be used to monitor Gunicorn. A simple configuration is:: - - [process:gunicorn] - cmd = gunicorn -w 3 test:app - cwd = /path/to/project - -Then you can easily manage Gunicorn using Gaffer_. - - -Using a Procfile -++++++++++++++++ - -Create a ``Procfile`` in your project:: - - gunicorn = gunicorn -w 3 test:app - -You can launch any other applications that should be launched at the same time. - -Then you can start your Gunicorn application using Gaffer_:: - - gaffer start - -If gafferd is launched you can also load your Procfile in it directly:: - - gaffer load - -All your applications will be then supervised by gafferd. - -Runit ------ - -A popular method for deploying Gunicorn is to have it monitored by runit_. -Here is an `example service`_ definition:: - - #!/bin/sh - - GUNICORN=/usr/local/bin/gunicorn - ROOT=/path/to/project - PID=/var/run/gunicorn.pid - - APP=main:application - - if [ -f $PID ]; then rm $PID; fi - - cd $ROOT - exec $GUNICORN -c $ROOT/gunicorn.conf.py --pid=$PID $APP - -Save this as ``/etc/sv/[app_name]/run``, and make it executable -(``chmod u+x /etc/sv/[app_name]/run``). -Then run ``ln -s /etc/sv/[app_name] /etc/service/[app_name]``. -If runit is installed, Gunicorn should start running automatically as soon -as you create the symlink. - -If it doesn't start automatically, run the script directly to troubleshoot. - -Supervisor ----------- - -Another useful tool to monitor and control Gunicorn is Supervisor_. A -`simple configuration`_ is:: - - [program:gunicorn] - command=/path/to/gunicorn main:application -c /path/to/gunicorn.conf.py - directory=/path/to/project - user=nobody - autostart=true - autorestart=true - redirect_stderr=true - -Upstart -------- - -Using Gunicorn with upstart is simple. In this example we will run the app -"myapp" from a virtualenv. All errors will go to -``/var/log/upstart/myapp.log``. - -**/etc/init/myapp.conf**:: - - description "myapp" - - start on (filesystem) - stop on runlevel [016] - - respawn - setuid nobody - setgid nogroup - chdir /path/to/app/directory - - exec /path/to/virtualenv/bin/gunicorn myapp:app - -Systemd -------- - -A tool that is starting to be common on linux systems is Systemd_. It is a -system services manager that allows for strict process management, resources -and permissions control. - -Below are configuration files and instructions for using systemd to create -a unix socket for incoming Gunicorn requests. Systemd will listen on this -socket and start gunicorn automatically in response to traffic. Later in -this section are instructions for configuring Nginx to forward web traffic -to the newly created unix socket: - -**/etc/systemd/system/gunicorn.service**:: - - [Unit] - Description=gunicorn daemon - Requires=gunicorn.socket - After=network.target - - [Service] - # gunicorn can let systemd know when it is ready - Type=notify - NotifyAccess=main - # the specific user that our service will run as - User=someuser - Group=someuser - # this user can be transiently created by systemd - # DynamicUser=true - RuntimeDirectory=gunicorn - WorkingDirectory=/home/someuser/applicationroot - ExecStart=/usr/bin/gunicorn applicationname.wsgi - ExecReload=/bin/kill -s HUP $MAINPID - KillMode=mixed - TimeoutStopSec=5 - PrivateTmp=true - # if your app does not need administrative capabilities, let systemd know - # ProtectSystem=strict - - [Install] - WantedBy=multi-user.target - -**/etc/systemd/system/gunicorn.socket**:: - - [Unit] - Description=gunicorn socket - - [Socket] - ListenStream=/run/gunicorn.sock - # Our service won't need permissions for the socket, since it - # inherits the file descriptor by socket activation. - # Only the nginx daemon will need access to the socket: - SocketUser=www-data - SocketGroup=www-data - # Once the user/group is correct, restrict the permissions: - SocketMode=0660 - - [Install] - WantedBy=sockets.target - - -Next enable and start the socket (it will autostart at boot too):: - - systemctl enable --now gunicorn.socket - - -Now let's see if the nginx daemon will be able to connect to the socket. -Running ``sudo -u www-data curl --unix-socket /run/gunicorn.sock http``, -our Gunicorn service will be automatically started and you should see some -HTML from your server in the terminal. - -.. note:: - - systemd employs cgroups to track the processes of a service, so it doesn't - need pid files. In the rare case that you need to find out the service main - pid, you can use ``systemctl show --value -p MainPID gunicorn.service``, but - if you only want to send a signal an even better option is - ``systemctl kill -s HUP gunicorn.service``. - -.. note:: - - ``www-data`` is the default nginx user in debian, other distributions use - different users (for example: ``http`` or ``nginx``). Check your distro to - know what to put for the socket user, and for the sudo command. - -You must now configure your web proxy to send traffic to the new Gunicorn -socket. Edit your ``nginx.conf`` to include the following: - -**/etc/nginx/nginx.conf**:: - - user www-data; - ... - http { - server { - listen 8000; - server_name 127.0.0.1; - location / { - proxy_pass http://unix:/run/gunicorn.sock; - } - } - } - ... - -.. note:: - - The listen and server_name used here are configured for a local machine. - In a production server you will most likely listen on port 80, - and use your URL as the server_name. - -Now make sure you enable the nginx service so it automatically starts at boot:: - - systemctl enable nginx.service - -Either reboot, or start Nginx with the following command:: - - systemctl start nginx - -Now you should be able to test Nginx with Gunicorn by visiting -http://127.0.0.1:8000/ in any web browser. Systemd is now set up. - - -Logging -======= - -Logging can be configured by using various flags detailed in the -`configuration documentation`_ or by creating a `logging configuration file`_. -Send the ``USR1`` signal to rotate logs if you are using the logrotate -utility:: - - kill -USR1 $(cat /var/run/gunicorn.pid) - -.. note:: - Overriding the ``LOGGING`` dictionary requires to set - ``disable_existing_loggers: False`` to not interfere with the Gunicorn - logging. - -.. warning:: - Gunicorn error log is here to log errors from Gunicorn, not from another - application. - -.. _Nginx: https://nginx.org/ -.. _Hey: https://github.com/rakyll/hey -.. _`example configuration`: https://github.com/benoitc/gunicorn/blob/master/examples/nginx.conf -.. _runit: http://smarden.org/runit/ -.. _`example service`: https://github.com/benoitc/gunicorn/blob/master/examples/gunicorn_rc -.. _Supervisor: http://supervisord.org/ -.. _`simple configuration`: https://github.com/benoitc/gunicorn/blob/master/examples/supervisor.conf -.. _`configuration documentation`: http://docs.gunicorn.org/en/latest/settings.html#logging -.. _`logging configuration file`: https://github.com/benoitc/gunicorn/blob/master/examples/logging.conf -.. _Virtualenv: https://pypi.python.org/pypi/virtualenv -.. _Systemd: https://www.freedesktop.org/wiki/Software/systemd/ -.. _Gaffer: https://gaffer.readthedocs.io/ -.. _`ignoring client abort`: http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_ignore_client_abort diff --git a/docs/source/design.rst b/docs/source/design.rst deleted file mode 100644 index 6796e9695..000000000 --- a/docs/source/design.rst +++ /dev/null @@ -1,150 +0,0 @@ - -.. _design: - -====== -Design -====== - -A brief description of the architecture of Gunicorn. - -Server Model -============ - -Gunicorn is based on the pre-fork worker model. This means that there is a -central master process that manages a set of worker processes. The master -never knows anything about individual clients. All requests and responses are -handled completely by worker processes. - -Master ------- - -The master process is a simple loop that listens for various process signals -and reacts accordingly. It manages the list of running workers by listening -for signals like TTIN, TTOU, and CHLD. TTIN and TTOU tell the master to -increase or decrease the number of running workers. CHLD indicates that a child -process has terminated, in this case the master process automatically restarts -the failed worker. - -Sync Workers ------------- - -The most basic and the default worker type is a synchronous worker class that -handles a single request at a time. This model is the simplest to reason about -as any errors will affect at most a single request. Though as we describe below -only processing a single request at a time requires some assumptions about how -applications are programmed. - -``sync`` worker does not support persistent connections - each connection is -closed after response has been sent (even if you manually add ``Keep-Alive`` -or ``Connection: keep-alive`` header in your application). - -Async Workers -------------- - -The asynchronous workers available are based on Greenlets_ (via Eventlet_ and -Gevent_). Greenlets are an implementation of cooperative multi-threading for -Python. In general, an application should be able to make use of these worker -classes with no changes. - -For full greenlet support applications might need to be adapted. -When using, e.g., Gevent_ and Psycopg_ it makes sense to ensure psycogreen_ is -installed and `setup `_. - -Other applications might not be compatible at all as they, e.g., rely on -the original unpatched behavior. - -Gthread Workers ---------------- - -The worker `gthread` is a threaded worker. It accepts connections in the -main loop. Accepted connections are added to the thread pool as a -connection job. On keepalive connections are put back in the loop -waiting for an event. If no event happens after the keepalive timeout, -the connection is closed. - -Tornado Workers ---------------- - -There's also a Tornado worker class. It can be used to write applications using -the Tornado framework. Although the Tornado workers are capable of serving a -WSGI application, this is not a recommended configuration. - - -.. _asyncio-workers: - -AsyncIO Workers ---------------- - -Third-party workers can be used to use Gunicorn with asyncio frameworks. - -Choosing a Worker Type -====================== - -The default synchronous workers assume that your application is resource-bound -in terms of CPU and network bandwidth. Generally this means that your -application shouldn't do anything that takes an undefined amount of time. An -example of something that takes an undefined amount of time is a request to the -internet. At some point the external network will fail in such a way that -clients will pile up on your servers. So, in this sense, any web application -which makes outgoing requests to APIs will benefit from an asynchronous worker. - -This resource bound assumption is why we require a buffering proxy in front of -a default configuration Gunicorn. If you exposed synchronous workers to the -internet, a DOS attack would be trivial by creating a load that trickles data to -the servers. For the curious, Hey_ is an example of this type of load. - - -Some examples of behavior requiring asynchronous workers: - - * Applications making long blocking calls (Ie, external web services) - * Serving requests directly to the internet - * Streaming requests and responses - * Long polling - * Web sockets - * Comet - -How Many Workers? -================= - -DO NOT scale the number of workers to the number of clients you expect to have. -Gunicorn should only need 4-12 worker processes to handle hundreds or thousands -of requests per second. - -Gunicorn relies on the operating system to provide all of the load balancing -when handling requests. Generally we recommend ``(2 x $num_cores) + 1`` as the -number of workers to start off with. While not overly scientific, the formula -is based on the assumption that for a given core, one worker will be reading -or writing from the socket while the other worker is processing a request. - -Obviously, your particular hardware and application are going to affect the -optimal number of workers. Our recommendation is to start with the above guess -and tune using TTIN and TTOU signals while the application is under load. - -Always remember, there is such a thing as too many workers. After a point your -worker processes will start thrashing system resources decreasing the -throughput of the entire system. - -How Many Threads? -=================== - -Since Gunicorn 19, a threads option can be used to process requests in multiple -threads. Using threads assumes use of the gthread worker. One benefit from threads -is that requests can take longer than the worker timeout while notifying the -master process that it is not frozen and should not be killed. Depending on the -system, using multiple threads, multiple worker processes, or some mixture, may -yield the best results. For example, CPython may not perform as well as Jython -when using threads, as threading is implemented differently by each. Using -threads instead of processes is a good way to reduce the memory footprint of -Gunicorn, while still allowing for application upgrades using the reload -signal, as the application code will be shared among workers but loaded only in -the worker processes (unlike when using the preload setting, which loads the -code in the master process). - -.. _Greenlets: https://github.com/python-greenlet/greenlet -.. _Eventlet: http://eventlet.net/ -.. _Gevent: http://www.gevent.org/ -.. _Hey: https://github.com/rakyll/hey -.. _aiohttp: https://docs.aiohttp.org/en/stable/deployment.html#nginx-gunicorn -.. _`example`: https://github.com/benoitc/gunicorn/blob/master/examples/frameworks/flaskapp_aiohttp_wsgi.py -.. _Psycopg: http://initd.org/psycopg/ -.. _psycogreen: https://github.com/psycopg/psycogreen/ diff --git a/docs/source/faq.rst b/docs/source/faq.rst deleted file mode 100644 index 8c52a4865..000000000 --- a/docs/source/faq.rst +++ /dev/null @@ -1,244 +0,0 @@ -.. _faq: - -=== -FAQ -=== - -WSGI Bits -========= - -How do I set SCRIPT_NAME? -------------------------- - -By default ``SCRIPT_NAME`` is an empty string. The value could be set by -setting ``SCRIPT_NAME`` in the environment or as an HTTP header. Note that -this headers contains and underscore, so it is only accepted from trusted -forwarders listed in the :ref:`forwarded-allow-ips` setting. - -.. note:: - - If your application should appear in a subfolder, your ``SCRIPT_NAME`` - would typically start with single slash but contain no trailing slash. - -Server Stuff -============ - -How do I reload my application in Gunicorn? -------------------------------------------- - -You can gracefully reload by sending HUP signal to gunicorn:: - - $ kill -HUP masterpid - -How might I test a proxy configuration? ---------------------------------------- - -The Hey_ program is a great way to test that your proxy is correctly -buffering responses for the synchronous workers:: - - $ hey -n 10000 -c 100 http://127.0.0.1:5000/ - -This runs a benchmark of 10000 requests with 100 running concurrently. - -How can I name processes? -------------------------- - -If you install the Python package setproctitle_ Gunicorn will set the process -names to something a bit more meaningful. This will affect the output you see -in tools like ``ps`` and ``top``. This helps for distinguishing the master -process as well as between masters when running more than one app on a single -machine. See the proc_name_ setting for more information. - -Why is there no HTTP Keep-Alive? --------------------------------- - -The default Sync workers are designed to run behind Nginx which only uses -HTTP/1.0 with its upstream servers. If you want to deploy Gunicorn to -handle unbuffered requests (ie, serving requests directly from the internet) -you should use one of the async workers. - -.. _Hey: https://github.com/rakyll/hey -.. _setproctitle: https://pypi.python.org/pypi/setproctitle -.. _proc_name: settings.html#proc-name - - -Worker Processes -================ - -How do I know which type of worker to use? ------------------------------------------- - -Read the :ref:`design` page for help on the various worker types. - -What types of workers are there? --------------------------------- - -Check out the configuration docs for worker_class_. - -How can I figure out the best number of worker processes? ---------------------------------------------------------- - -Here is our recommendation for tuning the `number of workers`_. - -How can I change the number of workers dynamically? ---------------------------------------------------- - -TTIN and TTOU signals can be sent to the master to increase or decrease -the number of workers. - -To increase the worker count by one:: - - $ kill -TTIN $masterpid - -To decrease the worker count by one:: - - $ kill -TTOU $masterpid - -Does Gunicorn suffer from the thundering herd problem? ------------------------------------------------------- - -The thundering herd problem occurs when many sleeping request handlers, which -may be either threads or processes, wake up at the same time to handle a new -request. Since only one handler will receive the request, the others will have -been awakened for no reason, wasting CPU cycles. At this time, Gunicorn does -not implement any IPC solution for coordinating between worker processes. You -may experience high load due to this problem when using many workers or -threads. However `a work has been started -`_ to remove this issue. - -.. _worker_class: settings.html#worker-class -.. _`number of workers`: design.html#how-many-workers - -Why I don't see any logs in the console? ----------------------------------------- - -In version 19.0, Gunicorn doesn't log by default in the console. -To watch the logs in the console you need to use the option ``--log-file=-``. -In version 19.2, Gunicorn logs to the console by default again. - -Kernel Parameters -================= - -When dealing with large numbers of concurrent connections there are a handful -of kernel parameters that you might need to adjust. Generally these should only -affect sites with a very large concurrent load. These parameters are not -specific to Gunicorn, they would apply to any sort of network server you may be -running. - -These commands are for Linux. Your particular OS may have slightly different -parameters. - -How can I increase the maximum number of file descriptors? ----------------------------------------------------------- - -One of the first settings that usually needs to be bumped is the maximum number -of open file descriptors for a given process. For the confused out there, -remember that Unices treat sockets as files. - -.. warning:: ``sudo ulimit`` may not work - -Considering non-privileged users are not able to relax the limit, you should -firstly switch to root user, increase the limit, then run gunicorn. Using ``sudo -ulimit`` would not take effect. - -Try systemd's service unit file, or an initscript which runs as root. - -How can I increase the maximum socket backlog? ----------------------------------------------- - -Listening sockets have an associated queue of incoming connections that are -waiting to be accepted. If you happen to have a stampede of clients that fill -up this queue new connections will eventually start getting dropped. - -:: - - $ sudo sysctl -w net.core.somaxconn="2048" - -How can I disable the use of ``sendfile()`` -------------------------------------------- - -Disabling the use ``sendfile()`` can be done by using the ``--no-sendfile`` -setting or by setting the environment variable ``SENDFILE`` to 0. - - - -Troubleshooting -=============== - -How do I fix Django reporting an ``ImproperlyConfigured`` error? ----------------------------------------------------------------- - -With asynchronous workers, creating URLs with the ``reverse`` function of -``django.core.urlresolvers`` may fail. Use ``reverse_lazy`` instead. - -.. _blocking-os-fchmod: - -How do I avoid Gunicorn excessively blocking in ``os.fchmod``? --------------------------------------------------------------- - -The current heartbeat system involves calling ``os.fchmod`` on temporary file -handlers and may block a worker for arbitrary time if the directory is on a -disk-backed filesystem. For example, by default ``/tmp`` is not mounted as -``tmpfs`` in Ubuntu; in AWS an EBS root instance volume may sometimes hang for -half a minute and during this time Gunicorn workers may completely block in -``os.fchmod``. ``os.fchmod`` may introduce extra delays if the disk gets full. -Also Gunicorn may refuse to start if it can't create the files when the disk is -full. - -Currently to avoid these problems you can use a ``tmpfs`` mount (for a new -directory or for ``/tmp``) and pass its path to ``--worker-tmp-dir``. First, -check whether your ``/tmp`` is disk-backed or RAM-backed:: - - $ df /tmp - Filesystem 1K-blocks Used Available Use% Mounted on - /dev/xvda1 ... ... ... ... / - -No luck. If you are using Fedora or Ubuntu, you should already have a ``tmpfs`` -mount at ``/dev/shm``:: - - $ df /dev/shm - Filesystem 1K-blocks Used Available Use% Mounted on - tmpfs ... ... ... ... /dev/shm - -In this case you can set ``--worker-tmp-dir /dev/shm``, otherwise you can -create a new ``tmpfs`` mount:: - - sudo cp /etc/fstab /etc/fstab.orig - sudo mkdir /mem - echo 'tmpfs /mem tmpfs defaults,size=64m,mode=1777,noatime,comment=for-gunicorn 0 0' | sudo tee -a /etc/fstab - sudo mount /mem - -Check the result:: - - $ df /mem - Filesystem 1K-blocks Used Available Use% Mounted on - tmpfs 65536 0 65536 0% /mem - -Now you can set ``--worker-tmp-dir /mem``. - -Why are Workers Silently Killed? --------------------------------------------------------------- - -A sometimes subtle problem to debug is when a worker process is killed and there -is little logging information about what happened. - -If you use a reverse proxy like NGINX you might see 502 returned to a client. - -In the gunicorn logs you might simply see ``[35] [INFO] Booting worker with pid: 35`` - -It's completely normal for workers to be stop and start, for example due to -max-requests setting. Ordinarily gunicorn will capture any signals and log something. - -This particular failure case is usually due to a SIGKILL being received, as it's -not possible to catch this signal silence is usually a common side effect! A common -cause of SIGKILL is when OOM killer terminates a process due to low memory condition. - -This is increasingly common in container deployments where memory limits are enforced -by cgroups, you'll usually see evidence of this from dmesg:: - - dmesg | grep gunicorn - Memory cgroup out of memory: Kill process 24534 (gunicorn) score 1506 or sacrifice child - Killed process 24534 (gunicorn) total-vm:1016648kB, anon-rss:550160kB, file-rss:25824kB, shmem-rss:0kB - -In these instances adjusting the memory limit is usually your best bet, it's also possible -to configure OOM not to send SIGKILL by default. diff --git a/docs/source/index.rst b/docs/source/index.rst deleted file mode 100644 index 3f89ce1eb..000000000 --- a/docs/source/index.rst +++ /dev/null @@ -1,46 +0,0 @@ -====================== -Gunicorn - WSGI server -====================== - -.. image:: _static/gunicorn.png - -:Website: http://gunicorn.org -:Source code: https://github.com/benoitc/gunicorn -:Issue tracker: https://github.com/benoitc/gunicorn/issues -:IRC: ``#gunicorn`` on Libera Chat -:Usage questions: https://github.com/benoitc/gunicorn/issues - -Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX. It's a pre-fork -worker model ported from Ruby's Unicorn project. The Gunicorn server is broadly -compatible with various web frameworks, simply implemented, light on server -resources, and fairly speedy. - -Features --------- - -* Natively supports WSGI, Django, and Paster -* Automatic worker process management -* Simple Python configuration -* Multiple worker configurations -* Various server hooks for extensibility -* Compatible with Python 3.x >= 3.7 - - -Contents --------- - -.. toctree:: - :maxdepth: 2 - - install - run - configure - settings - instrumentation - deploy - signals - custom - design - faq - community - news diff --git a/docs/source/install.rst b/docs/source/install.rst deleted file mode 100644 index a5f618a30..000000000 --- a/docs/source/install.rst +++ /dev/null @@ -1,172 +0,0 @@ -============ -Installation -============ - -.. highlight:: bash - -:Requirements: **Python 3.x >= 3.12** - -To install the latest released version of Gunicorn:: - - $ pip install gunicorn - -From Source -=========== - -You can install Gunicorn from source just as you would install any other -Python package:: - - $ pip install git+https://github.com/benoitc/gunicorn.git - -This will allow you to keep up to date with development on GitHub:: - - $ pip install -U git+https://github.com/benoitc/gunicorn.git - - -Async Workers -============= - -You may also want to install Eventlet_ or Gevent_ if you expect that your -application code may need to pause for extended periods of time during request -processing. Check out the `design docs`_ for more information on when you'll -want to consider one of the alternate worker types. - -:: - - $ pip install greenlet # Required for both - $ pip install eventlet # For eventlet workers - $ pip install gunicorn[eventlet] # Or, using extra - $ pip install gevent # For gevent workers - $ pip install gunicorn[gevent] # Or, using extra - -.. note:: - Both require ``greenlet``, which should get installed automatically. - If its installation fails, you probably need to install - the Python headers. These headers are available in most package - managers. On Ubuntu the package name for ``apt-get`` is - ``python-dev``. - - Gevent_ also requires that ``libevent`` 1.4.x or 2.0.4 is installed. - This could be a more recent version than what is available in your - package manager. If Gevent_ fails to build even with libevent_ - installed, this is the most likely reason. - - -Extra Packages -============== -Some Gunicorn options require additional packages. You can use the ``[extra]`` -syntax to install these at the same time as Gunicorn. - -Most extra packages are needed for alternate worker types. See the -`design docs`_ for more information on when you'll want to consider an -alternate worker type. - -* ``gunicorn[eventlet]`` - Eventlet-based greenlets workers -* ``gunicorn[gevent]`` - Gevent-based greenlets workers -* ``gunicorn[gthread]`` - Threaded workers -* ``gunicorn[tornado]`` - Tornado-based workers, not recommended - -If you are running more than one instance of Gunicorn, the :ref:`proc-name` -setting will help distinguish between them in tools like ``ps`` and ``top``. - -* ``gunicorn[setproctitle]`` - Enables setting the process name - -Multiple extras can be combined, like -``pip install gunicorn[gevent,setproctitle]``. - -Debian GNU/Linux -================ - -If you are using Debian GNU/Linux it is recommended that you use -system packages to install Gunicorn except maybe when you want to use -different versions of Gunicorn with virtualenv. This has a number of -advantages: - -* Zero-effort installation: Automatically starts multiple Gunicorn instances - based on configurations defined in ``/etc/gunicorn.d``. - -* Sensible default locations for logs (``/var/log/gunicorn``). Logs - can be automatically rotated and compressed using ``logrotate``. - -* Improved security: Can easily run each Gunicorn instance with a dedicated - UNIX user/group. - -* Sensible upgrade path: Upgrades to newer versions result in less downtime, - handle conflicting changes in configuration options, and can be quickly - rolled back in case of incompatibility. The package can also be purged - entirely from the system in seconds. - -stable ("buster") ------------------- - -The version of Gunicorn in the Debian_ "stable" distribution is 19.9.0 -(December 2020). You can install it using:: - - $ sudo apt-get install gunicorn3 - -You can also use the most recent version 20.0.4 (December 2020) by using -`Debian Backports`_. First, copy the following line to your -``/etc/apt/sources.list``:: - - deb http://ftp.debian.org/debian buster-backports main - -Then, update your local package lists:: - - $ sudo apt-get update - -You can then install the latest version using:: - - $ sudo apt-get -t buster-backports install gunicorn - -oldstable ("stretch") ---------------------- - -While Debian releases newer than Stretch will give you gunicorn with Python 3 -support no matter if you install the gunicorn or gunicorn3 package for Stretch -you specifically have to install gunicorn3 to get Python 3 support. - -The version of Gunicorn in the Debian_ "oldstable" distribution is 19.6.0 -(December 2020). You can install it using:: - - $ sudo apt-get install gunicorn3 - -You can also use the most recent version 19.7.1 (December 2020) by using -`Debian Backports`_. First, copy the following line to your -``/etc/apt/sources.list``:: - - deb http://ftp.debian.org/debian stretch-backports main - -Then, update your local package lists:: - - $ sudo apt-get update - -You can then install the latest version using:: - - $ sudo apt-get -t stretch-backports install gunicorn3 - -Testing ("bullseye") / Unstable ("sid") ---------------------------------------- - -"bullseye" and "sid" contain the latest released version of Gunicorn 20.0.4 -(December 2020). You can install it in the usual way:: - - $ sudo apt-get install gunicorn - - -Ubuntu -====== - -Ubuntu_ 20.04 LTS (Focal Fossa) or later contains the Gunicorn package by -default 20.0.4 (December 2020) so that you can install it in the usual way:: - - $ sudo apt-get update - $ sudo apt-get install gunicorn - - -.. _`design docs`: design.html -.. _Eventlet: http://eventlet.net -.. _Gevent: http://www.gevent.org/ -.. _libevent: http://libevent.org/ -.. _Debian: https://www.debian.org/ -.. _`Debian Backports`: https://backports.debian.org/ -.. _Ubuntu: https://www.ubuntu.com/ diff --git a/docs/source/instrumentation.rst b/docs/source/instrumentation.rst deleted file mode 100644 index 60cde4164..000000000 --- a/docs/source/instrumentation.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _instrumentation: - -=============== -Instrumentation -=============== - -.. versionadded:: 19.1 - -Gunicorn provides an optional instrumentation of the arbiter and -workers using the statsD_ protocol over UDP. Thanks to the -``gunicorn.instrument.statsd`` module, Gunicorn becomes a statsD client. -The use of UDP cleanly isolates Gunicorn from the receiving end of the statsD -metrics so that instrumentation does not cause Gunicorn to be held up by a slow -statsD consumer. - -To use statsD, just tell Gunicorn where the statsD server is: - -.. code-block:: bash - - $ gunicorn --statsd-host=localhost:8125 --statsd-prefix=service.app ... - -The ``Statsd`` logger overrides ``gunicorn.glogging.Logger`` to track -all requests. The following metrics are generated: - -* ``gunicorn.requests``: request rate per second -* ``gunicorn.request.duration``: histogram of request duration (in millisecond) -* ``gunicorn.workers``: number of workers managed by the arbiter (gauge) -* ``gunicorn.log.critical``: rate of critical log messages -* ``gunicorn.log.error``: rate of error log messages -* ``gunicorn.log.warning``: rate of warning log messages -* ``gunicorn.log.exception``: rate of exceptional log messages - -See the statsd-host_ setting for more information. - -.. _statsd-host: settings.html#statsd-host -.. _statsD: https://github.com/etsy/statsd diff --git a/docs/source/run.rst b/docs/source/run.rst deleted file mode 100644 index 108956b83..000000000 --- a/docs/source/run.rst +++ /dev/null @@ -1,184 +0,0 @@ -================ -Running Gunicorn -================ - -.. highlight:: bash - -You can run Gunicorn by using commands or integrate with popular frameworks -like Django, Pyramid, or TurboGears. For deploying Gunicorn in production see -:doc:`deploy`. - -Commands -======== - -After installing Gunicorn you will have access to the command line script -``gunicorn``. - -.. _gunicorn-cmd: - -gunicorn --------- - -Basic usage:: - - $ gunicorn [OPTIONS] [WSGI_APP] - -Where ``WSGI_APP`` is of the pattern ``$(MODULE_NAME):$(VARIABLE_NAME)``. The -module name can be a full dotted path. The variable name refers to a WSGI -callable that should be found in the specified module. - -.. versionchanged:: 20.1.0 - ``WSGI_APP`` is optional if it is defined in a :ref:`config` file. - -Example with the test app: - -.. code-block:: python - - def app(environ, start_response): - """Simplest possible application object""" - data = b'Hello, World!\n' - status = '200 OK' - response_headers = [ - ('Content-type', 'text/plain'), - ('Content-Length', str(len(data))) - ] - start_response(status, response_headers) - return iter([data]) - -You can now run the app with the following command: - -.. code-block:: text - - $ gunicorn --workers=2 test:app - -The variable name can also be a function call. In that case the name -will be imported from the module, then called to get the application -object. This is commonly referred to as the "application factory" -pattern. - -.. code-block:: python - - def create_app(): - app = FrameworkApp() - ... - return app - -.. code-block:: text - - $ gunicorn --workers=2 'test:create_app()' - -Positional and keyword arguments can also be passed, but it is -recommended to load configuration from environment variables rather than -the command line. - -Commonly Used Arguments -^^^^^^^^^^^^^^^^^^^^^^^ - -* ``-c CONFIG, --config=CONFIG`` - Specify a config file in the form - ``$(PATH)``, ``file:$(PATH)``, or ``python:$(MODULE_NAME)``. -* ``-b BIND, --bind=BIND`` - Specify a server socket to bind. Server sockets - can be any of ``$(HOST)``, ``$(HOST):$(PORT)``, ``fd://$(FD)``, or - ``unix:$(PATH)``. An IP is a valid ``$(HOST)``. -* ``-w WORKERS, --workers=WORKERS`` - The number of worker processes. This - number should generally be between 2-4 workers per core in the server. - Check the :ref:`faq` for ideas on tuning this parameter. -* ``-k WORKERCLASS, --worker-class=WORKERCLASS`` - The type of worker process - to run. You'll definitely want to read the production page for the - implications of this parameter. You can set this to ``$(NAME)`` - where ``$(NAME)`` is one of ``sync``, ``eventlet``, ``gevent``, - ``tornado``, ``gthread``. - ``sync`` is the default. See the :ref:`worker-class` documentation for more - information. -* ``-n APP_NAME, --name=APP_NAME`` - If setproctitle_ is installed you can - adjust the name of Gunicorn process as they appear in the process system - table (which affects tools like ``ps`` and ``top``). - -Settings can be specified by using environment variable -:ref:`GUNICORN_CMD_ARGS `. - -See :ref:`configuration` and :ref:`settings` for detailed usage. - -.. _setproctitle: https://pypi.python.org/pypi/setproctitle - -Integration -=========== - -Gunicorn also provides integration for Django and Paste Deploy applications. - -Django ------- - -Gunicorn will look for a WSGI callable named ``application`` if not specified. -So for a typical Django project, invoking Gunicorn would look like:: - - $ gunicorn myproject.wsgi - - -.. note:: - - This requires that your project be on the Python path; the simplest way to - ensure that is to run this command from the same directory as your - ``manage.py`` file. - -You can use the -`--env `_ option -to set the path to load the settings. In case you need it you can also -add your application path to ``PYTHONPATH`` using the -`--pythonpath `_ -option:: - - $ gunicorn --env DJANGO_SETTINGS_MODULE=myproject.settings myproject.wsgi - -Paste Deployment ----------------- - -Frameworks such as Pyramid and Turbogears are typically configured using Paste -Deployment configuration files. If you would like to use these files with -Gunicorn, there are two approaches. - -As a server runner, Gunicorn can serve your application using the commands from -your framework, such as ``pserve`` or ``gearbox``. To use Gunicorn with these -commands, specify it as a server in your configuration file: - -.. code-block:: ini - - [server:main] - use = egg:gunicorn#main - host = 127.0.0.1 - port = 8080 - workers = 3 - -This approach is the quickest way to get started with Gunicorn, but there are -some limitations. Gunicorn will have no control over how the application is -loaded, so settings such as reload_ will have no effect and Gunicorn will be -unable to hot upgrade a running application. Using the daemon_ option may -confuse your command line tool. Instead, use the built-in support for these -features provided by that tool. For example, run ``pserve --reload`` instead of -specifying ``reload = True`` in the server configuration block. For advanced -configuration of Gunicorn, such as `Server Hooks`_ specifying a Gunicorn -configuration file using the ``config`` key is supported. - -To use the full power of Gunicorn's reloading and hot code upgrades, use the -`paste option`_ to run your application instead. When used this way, Gunicorn -will use the application defined by the PasteDeploy configuration file, but -Gunicorn will not use any server configuration defined in the file. Instead, -`configure gunicorn`_. - -For example:: - - $ gunicorn --paste development.ini -b :8080 --chdir /path/to/project - -Or use a different application:: - - $ gunicorn --paste development.ini#admin -b :8080 --chdir /path/to/project - -With both approaches, Gunicorn will use any loggers section found in Paste -Deployment configuration file, unless instructed otherwise by specifying -additional `logging settings`_. - -.. _reload: http://docs.gunicorn.org/en/latest/settings.html#reload -.. _daemon: http://docs.gunicorn.org/en/latest/settings.html#daemon -.. _Server Hooks: http://docs.gunicorn.org/en/latest/settings.html#server-hooks -.. _paste option: http://docs.gunicorn.org/en/latest/settings.html#paste -.. _configure gunicorn: http://docs.gunicorn.org/en/latest/configure.html -.. _logging settings: http://docs.gunicorn.org/en/latest/settings.html#logging diff --git a/docs/source/signals.rst b/docs/source/signals.rst deleted file mode 100644 index c22ea0362..000000000 --- a/docs/source/signals.rst +++ /dev/null @@ -1,119 +0,0 @@ -.. _signals: - -=============== -Signal Handling -=============== - -A brief description of the signals handled by Gunicorn. We also document the -signals used internally by Gunicorn to communicate with the workers. - -Master process -============== - -- ``QUIT``, ``INT``: Quick shutdown -- ``TERM``: Graceful shutdown. Waits for workers to finish their - current requests up to the :ref:`graceful-timeout`. -- ``HUP``: Reload the configuration, start the new worker processes with a new - configuration and gracefully shutdown older workers. If the application is - not preloaded (using the :ref:`preload-app` option), Gunicorn will also load - the new version of it. -- ``TTIN``: Increment the number of processes by one -- ``TTOU``: Decrement the number of processes by one -- ``USR1``: Reopen the log files -- ``USR2``: Upgrade Gunicorn on the fly. A separate ``TERM`` signal should - be used to kill the old master process. This signal can also be used to use - the new versions of pre-loaded applications. See :ref:`binary-upgrade` for - more information. -- ``WINCH``: Gracefully shutdown the worker processes when Gunicorn is - daemonized. - -Worker process -============== - -Sending signals directly to the worker processes should not normally be -needed. If the master process is running, any exited worker will be -automatically respawned. - -- ``QUIT``, ``INT``: Quick shutdown -- ``TERM``: Graceful shutdown -- ``USR1``: Reopen the log files - -Reload the configuration -======================== - -The ``HUP`` signal can be used to reload the Gunicorn configuration on the -fly. - -:: - - 2013-06-29 06:26:55 [20682] [INFO] Handling signal: hup - 2013-06-29 06:26:55 [20682] [INFO] Hang up: Master - 2013-06-29 06:26:55 [20703] [INFO] Booting worker with pid: 20703 - 2013-06-29 06:26:55 [20702] [INFO] Booting worker with pid: 20702 - 2013-06-29 06:26:55 [20688] [INFO] Worker exiting (pid: 20688) - 2013-06-29 06:26:55 [20687] [INFO] Worker exiting (pid: 20687) - 2013-06-29 06:26:55 [20689] [INFO] Worker exiting (pid: 20689) - 2013-06-29 06:26:55 [20704] [INFO] Booting worker with pid: 20704 - - -Sending a ``HUP`` signal will reload the configuration, start the new -worker processes with a new configuration and gracefully shutdown older -workers. If the application is not preloaded (using the :ref:`preload-app` -option), Gunicorn will also load the new version of it. - -.. _binary-upgrade: - -Upgrading to a new binary on the fly -==================================== - -.. versionchanged:: 19.6.0 - PID file naming format has been changed from ``.pid.oldbin`` to - ``.pid.2``. - -If you need to replace the Gunicorn binary with a new one (when -upgrading to a new version or adding/removing server modules), you can -do it without any service downtime - no incoming requests will be -lost. Preloaded applications will also be reloaded. - -First, replace the old binary with a new one, then send a ``USR2`` signal to -the current master process. It executes a new binary whose PID file is -postfixed with ``.2`` (e.g. ``/var/run/gunicorn.pid.2``), -which in turn starts a new master process and new worker processes:: - - PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND - 20844 benoitc 20 0 54808 11m 3352 S 0.0 0.1 0:00.36 gunicorn: master [test:app] - 20849 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app] - 20850 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] - 20851 benoitc 20 0 54808 9.9m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] - 20854 benoitc 20 0 55748 12m 3348 S 0.0 0.2 0:00.35 gunicorn: master [test:app] - 20859 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] - 20860 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.00 gunicorn: worker [test:app] - 20861 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] - -At this point, two instances of Gunicorn are running, handling the -incoming requests together. To phase the old instance out, you have to -send a ``WINCH`` signal to the old master process, and its worker -processes will start to gracefully shut down. - -At this point you can still revert to the old process since it hasn't closed -its listen sockets yet, by following these steps: - -- Send a ``HUP`` signal to the old master process - it will start the worker - processes without reloading a configuration file -- Send a ``TERM`` signal to the new master process to gracefully shut down its - worker processes -- Send a ``QUIT`` signal to the new master process to force it quit - -If for some reason the new worker processes do not quit, send a ``KILL`` signal -to them after the new master process quits, and everything will back to exactly -as before the upgrade attempt. - -If the update is successful and you want to keep the new master process, send a -``TERM`` signal to the old master process to leave only the new server -running:: - - PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND - 20854 benoitc 20 0 55748 12m 3348 S 0.0 0.2 0:00.45 gunicorn: master [test:app] - 20859 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app] - 20860 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.02 gunicorn: worker [test:app] - 20861 benoitc 20 0 55748 11m 1500 S 0.0 0.1 0:00.01 gunicorn: worker [test:app] diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..d6945086c --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,94 @@ +site_name: Gunicorn +site_url: https://gunicorn.org +repo_url: https://github.com/benoitc/gunicorn +repo_name: benoitc/gunicorn +docs_dir: docs/content +use_directory_urls: true + +nav: + - Home: index.md + - Guides: + - Install: install.md + - Run: run.md + - Configure: configure.md + - Deploy: deploy.md + - Signals: signals.md + - Instrumentation: instrumentation.md + - Custom: custom.md + - Community: community.md + - FAQ: faq.md + - Design: design.md + - Reference: + - Settings: reference/settings.md + - News: + - Latest: news.md + - '2024': 2024-news.md + - '2023': 2023-news.md + - '2021': 2021-news.md + - '2020': 2020-news.md + - '2019': 2019-news.md + - '2018': 2018-news.md + - '2017': 2017-news.md + - '2016': 2016-news.md + - '2015': 2015-news.md + - '2014': 2014-news.md + - '2013': 2013-news.md + - '2012': 2012-news.md + - '2011': 2011-news.md + - '2010': 2010-news.md + +theme: + name: material + language: en + logo: assets/gunicorn.svg + favicon: assets/gunicorn.svg + features: + - content.code.copy + - navigation.instant + - navigation.tracking + - navigation.sections + - navigation.tabs + - navigation.top + - search.highlight + - search.suggest + - toc.follow + +plugins: + - search + - macros + - gen-files: + scripts: + - scripts/build_settings_doc.py + +markdown_extensions: + - admonition + - attr_list + - def_list + - footnotes + - md_in_html + - tables + - toc: + permalink: true + - pymdownx.details + - pymdownx.highlight + - pymdownx.inlinehilite + - pymdownx.magiclink + - pymdownx.superfences + - pymdownx.snippets: + base_path: + - . + check_paths: true + - pymdownx.tabbed: + alternate_style: true + - pymdownx.tasklist: + custom_checkbox: true + +extra_css: + - styles/overrides.css + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/benoitc/gunicorn + - icon: fontawesome/brands/python + link: https://pypi.org/project/gunicorn/ diff --git a/requirements_dev.txt b/requirements_dev.txt index 1d8c01291..40b6dae6b 100644 --- a/requirements_dev.txt +++ b/requirements_dev.txt @@ -5,5 +5,8 @@ # otherwise, oldest known-working version is 61.2 setuptools>=68.0 -sphinx -sphinx_rtd_theme +mkdocs>=1.6 +mkdocs-material>=9.5 +mkdocs-gen-files>=0.5 +mkdocs-macros-plugin>=1.0 +pymdown-extensions>=10.0 diff --git a/scripts/build_settings_doc.py b/scripts/build_settings_doc.py new file mode 100644 index 000000000..eb370f090 --- /dev/null +++ b/scripts/build_settings_doc.py @@ -0,0 +1,254 @@ +"""Generate the Markdown settings reference for MkDocs.""" +from __future__ import annotations + +import inspect +import textwrap +from pathlib import Path +from typing import List + +import re + +import gunicorn.config as guncfg + +HEAD = """\ +> **Generated file** — update `gunicorn/config.py` instead. + +# Settings + +This reference is built directly from `gunicorn.config.KNOWN_SETTINGS` and is +regenerated during every documentation build. + +!!! note + Settings can be provided through the `GUNICORN_CMD_ARGS` environment + variable. For example: + + ```console + $ GUNICORN_CMD_ARGS="--bind=127.0.0.1 --workers=3" gunicorn app:app + ``` + + _Added in 19.7._ + +""" + + +def _format_default(setting: guncfg.Setting) -> tuple[str, bool]: + if hasattr(setting, "default_doc"): + text = textwrap.dedent(setting.default_doc).strip("\n") + return text, True + default = setting.default + if callable(default): + source = textwrap.dedent(inspect.getsource(default)).strip("\n") + return f"```python\n{source}\n```", True + if default == "": + return "`''`", False + return f"`{default!r}`", False + + +def _format_cli(setting: guncfg.Setting) -> str | None: + if not setting.cli: + return None + if setting.meta: + variants = [f"`{opt} {setting.meta}`" for opt in setting.cli] + else: + variants = [f"`{opt}`" for opt in setting.cli] + return ", ".join(variants) + + +REF_MAP = { + "forwarded-allow-ips": ("reference/settings.md", "forwarded_allow_ips"), + "forwarder-headers": ("reference/settings.md", "forwarder_headers"), + "proxy-allow-ips": ("reference/settings.md", "proxy_allow_ips"), + "worker-class": ("reference/settings.md", "worker_class"), + "reload": ("reference/settings.md", "reload"), + "raw-env": ("reference/settings.md", "raw_env"), + "check-config": ("reference/settings.md", "check_config"), + "errorlog": ("reference/settings.md", "errorlog"), + "logconfig": ("reference/settings.md", "logconfig"), + "logconfig-json": ("reference/settings.md", "logconfig_json"), + "ssl-context": ("reference/settings.md", "ssl_context"), + "ssl-version": ("reference/settings.md", "ssl_version"), + "blocking-os-fchmod": ("reference/settings.md", "blocking_os_fchmod"), + "configuration_file": ("../configure.md", "configuration-file"), +} + +REF_PATTERN = re.compile(r":ref:`([^`]+)`") + + +def _convert_refs(text: str) -> str: + def repl(match: re.Match[str]) -> str: + raw = match.group(1) + if "<" in raw and raw.endswith(">"): + label, target = raw.split("<", 1) + target = target[:-1] + label = label.replace("\n", " ").strip() + else: + label, target = None, raw.strip() + info = REF_MAP.get(target) + if not info: + return (label or target).replace("\n", " ").strip() + path, anchor = info + if path.endswith(".md"): + if path == "reference/settings.md" and anchor: + href = f"#{anchor}" + else: + href = path + (f"#{anchor}" if anchor else "") + else: + href = path + (f"#{anchor}" if anchor else "") + text = (label or target).replace("\n", " ").strip() + return f"[{text}]({href})" + + return REF_PATTERN.sub(repl, text) + + +def _consume_indented(lines: List[str], start: int) -> tuple[str, int]: + body: List[str] = [] + i = start + while i < len(lines): + line = lines[i] + if line.startswith(" ") or not line.strip(): + body.append(line) + i += 1 + else: + break + text = textwrap.dedent("\n".join(body)).strip("\n") + return text, i + + +def _convert_desc(desc: str) -> str: + raw_lines = textwrap.dedent(desc).splitlines() + output: List[str] = [] + i = 0 + while i < len(raw_lines): + line = raw_lines[i] + stripped = line.strip() + if stripped.startswith(".. note::"): + body, i = _consume_indented(raw_lines, i + 1) + output.append("!!! note") + if body: + for body_line in body.splitlines(): + output.append(f" {body_line}" if body_line else "") + output.append("") + continue + if stripped.startswith(".. warning::"): + body, i = _consume_indented(raw_lines, i + 1) + output.append("!!! warning") + if body: + for body_line in body.splitlines(): + output.append(f" {body_line}" if body_line else "") + output.append("") + continue + if stripped.startswith(".. deprecated::"): + version = stripped.split("::", 1)[1].strip() + body, i = _consume_indented(raw_lines, i + 1) + title = f"Deprecated in {version}" if version else "Deprecated" + output.append(f"!!! danger \"{title}\"") + if body: + for body_line in body.splitlines(): + output.append(f" {body_line}" if body_line else "") + output.append("") + continue + if stripped.startswith(".. versionadded::"): + version = stripped.split("::", 1)[1].strip() + body, i = _consume_indented(raw_lines, i + 1) + title = f"Added in {version}" if version else "Added" + output.append(f"!!! info \"{title}\"") + if body: + for body_line in body.splitlines(): + output.append(f" {body_line}" if body_line else "") + output.append("") + continue + if stripped.startswith(".. versionchanged::"): + version = stripped.split("::", 1)[1].strip() + body, i = _consume_indented(raw_lines, i + 1) + title = f"Changed in {version}" if version else "Changed" + output.append(f"!!! info \"{title}\"") + if body: + for body_line in body.splitlines(): + output.append(f" {body_line}" if body_line else "") + output.append("") + continue + if stripped.startswith(".. code::") or stripped.startswith(".. code-block::"): + language = stripped.split("::", 1)[1].strip() + body, i = _consume_indented(raw_lines, i + 1) + fence = language or "text" + output.append(f"```{fence}") + if body: + output.append(body) + output.append("```") + output.append("") + continue + + output.append(line) + i += 1 + + text = "\n".join(output) + text = _convert_refs(text) + # Collapse excessive blank lines + text = re.sub(r"\n{3,}", "\n\n", text) + return text.strip("\n") + + +def _format_setting(setting: guncfg.Setting) -> str: + lines: list[str] = [f"## `{setting.name}`", ""] + + cli = _format_cli(setting) + if cli: + lines.extend((f"**Command line:** {cli}", "")) + + default_text, is_block = _format_default(setting) + if is_block: + lines.append("**Default:**") + lines.append("") + lines.append(default_text) + else: + lines.append(f"**Default:** {default_text}") + lines.append("") + + desc = _convert_desc(setting.desc) + if desc: + lines.append(desc) + lines.append("") + + return "\n".join(lines) + + +def render_settings() -> str: + sections: list[str] = [HEAD, '', ""] + known_settings = sorted(guncfg.KNOWN_SETTINGS, key=lambda s: s.section) + current_section: str | None = None + + for setting in known_settings: + if setting.section != current_section: + current_section = setting.section + sections.append(f"# {current_section}\n") + sections.append(_format_setting(setting)) + + return "\n".join(sections).strip() + "\n" + + +def _write_output(markdown: str) -> None: + try: + import mkdocs_gen_files # type: ignore + except ImportError: + mkdocs_gen_files = None + + if mkdocs_gen_files is not None: + try: + with mkdocs_gen_files.open("reference/settings.md", "w") as fh: + fh.write(markdown) + return + except Exception: + pass + + output = Path(__file__).resolve().parents[1] / "docs" / "content" / "reference" / "settings.md" + output.parent.mkdir(parents=True, exist_ok=True) + output.write_text(markdown, encoding="utf-8") + + +def main() -> None: + markdown = render_settings() + _write_output(markdown) + + +if __name__ == "__main__": + main()