Skip to content

Environment variables

Usage

To set environment variables when starting a Docker container:

docker run -d -p 80:80 \
  -e APP_MODULE="package.custom.module:api" \
  -e WORKERS_PER_CORE="2" \
  myimage

To set environment variables within a Dockerfile:

FROM ghcr.io/br3ndonland/inboard:fastapi
ENV APP_MODULE="package.custom.module:api" WORKERS_PER_CORE="2"

General

APP_MODULE

  • Python module with app instance.
  • Default: The appropriate app module from inboard.
  • Custom: For a module at /app/package/custom/module.py and app instance object api, APP_MODULE="package.custom.module:api"

    Example of a custom FastAPI app module

    # /app/package/custom/module.py
    from fastapi import FastAPI
    
    api = FastAPI()
    
    @api.get("/")
    def read_root():
        return {"message": "Hello World!"}
    

    Note

    The base Docker image sets the environment variable PYTHONPATH=/app, so the module name will be relative to /app unless you supply a custom PYTHONPATH.

PRE_START_PATH

  • Path to a pre-start script.
    • inboard optionally runs a pre-start script before starting the server. The path to a pre-start script can be specified with the environment variable PRE_START_PATH. If the environment variable is set to a nonzero value, inboard will run the script at the provided path, using the subprocess standard library package.
    • If the pre-start script exits with an error, inboard will not start the server.
  • Default: "/app/inboard/prestart.py" (provided with inboard)
  • Custom:

    • PRE_START_PATH="/app/package/custom_script.sh"
    • PRE_START_PATH= (set to an empty value) to disable

    Tip

    Add a file prestart.py or prestart.sh to the application directory, and copy the directory into the Docker image as described (for a project with the Python application in repo/package, COPY package /app/package). The container will automatically detect and run the prestart script before starting the web server.

PYTHONPATH

  • Python's search path for module files.
  • Default: PYTHONPATH="/app"
  • Custom: PYTHONPATH="/app/custom"

Gunicorn

Configuration file

GUNICORN_CONF

  • Path to a Gunicorn configuration file. Gunicorn accepts either file paths or module paths.
  • Default:
    • "python:inboard.gunicorn_conf" (provided with inboard)
  • Custom:
    • GUNICORN_CONF="/app/package/custom_gunicorn_conf.py" (file path)
    • GUNICORN_CONF="python:package.custom_gunicorn_conf" (module paths accepted with the python: prefix)

Process management

Info

As described in the Uvicorn docs, "Uvicorn includes a Gunicorn worker class allowing you to run ASGI applications, with all of Uvicorn's performance benefits, while also giving you Gunicorn's fully-featured process management."

PROCESS_MANAGER

  • Manager for Uvicorn worker processes.
  • Default: "gunicorn" (run Uvicorn with Gunicorn as the process manager)
  • Custom: "uvicorn" (run Uvicorn alone for local development)

WORKER_CLASS

  • Uvicorn worker class for Gunicorn to use.
  • Default: uvicorn.workers.UvicornWorker
  • Custom: For the alternate Uvicorn worker, WORKER_CLASS="uvicorn.workers.UvicornH11Worker" (the H11 worker is provided for PyPy and hasn't been tested)

Worker process calculation

Info

The number of Gunicorn worker processes to run is determined based on the MAX_WORKERS, WEB_CONCURRENCY, and WORKERS_PER_CORE environment variables, with a default of 1 worker per CPU core and a default minimum of 2. This is the "performance auto-tuning" feature described in tiangolo/uvicorn-gunicorn-docker.

MAX_WORKERS

  • Maximum number of workers, independent of number of CPU cores.
  • Default: not set (unlimited)
  • Custom: MAX_WORKERS="24"

WEB_CONCURRENCY

  • Total number of workers, independent of number of CPU cores.
  • Default: not set
  • Custom: WEB_CONCURRENCY="4"

WORKERS_PER_CORE

  • Number of Gunicorn workers per CPU core. Overridden if WEB_CONCURRENCY is set.
  • Default: 1
  • Custom:

    • WORKERS_PER_CORE="2": Run 2 worker processes per core (8 worker processes on a server with 4 cores).
    • WORKERS_PER_CORE="0.5" (floating point values permitted): Run 1 worker process for every 2 cores (2 worker processes on a server with 4 cores).

    Note

    • The default number of workers is the number of CPU cores multiplied by the value of the environment variable WORKERS_PER_CORE (which defaults to 1). On a machine with only 1 CPU core, the default minimum number of workers is 2 to avoid poor performance and blocking, as explained in the release notes for tiangolo/uvicorn-gunicorn-docker 0.3.0.
    • If both MAX_WORKERS and WEB_CONCURRENCY are set, the least of the two will be used as the total number of workers.
    • If either MAX_WORKERS or WEB_CONCURRENCY are set to 1, the total number of workers will be 1, overriding the default minimum of 2.

Worker timeouts

GRACEFUL_TIMEOUT

  • Number of seconds to wait for workers to finish serving requests before restart.
  • Default: "120"
  • Custom: GRACEFUL_TIMEOUT="20"

TIMEOUT

  • Workers silent for more than this many seconds are killed and restarted.
  • Default: "120"
  • Custom: TIMEOUT="20"

KEEP_ALIVE

  • Number of seconds to wait for workers to finish serving requests on a Keep-Alive connection.
  • Default: "5"
  • Custom: KEEP_ALIVE="20"

Host networking

HOST

  • Host IP address (inside of the container) where Gunicorn will listen for requests.
  • Default: "0.0.0.0"
  • Custom: n/a

PORT

  • Port the container should listen on.
  • Default: "80"
  • Custom: PORT="8080"

BIND

  • The actual host and port passed to Gunicorn.
  • Default: HOST:PORT ("0.0.0.0:80")
  • Custom: BIND="0.0.0.0:8080" (if custom BIND is set, overrides HOST and PORT)

Runtime configuration

GUNICORN_CMD_ARGS

  • Additional command-line arguments for Gunicorn. Gunicorn looks for the GUNICORN_CMD_ARGS environment variable automatically, and gives these settings precedence over other environment variables and Gunicorn config files.
  • Custom: To use a custom TLS certificate, copy or mount the certificate and private key into the Docker image, and set --keyfile and --certfile to the location of the files.

    CERTS="--keyfile=/secrets/key.pem --certfile=/secrets/cert.pem"
    docker run -d -p 443:443 \
      -e GUNICORN_CMD_ARGS="$CERTS" \
      -e PORT=443 myimage
    

Uvicorn

Info

These settings are mostly used for local development.

WITH_RELOAD

RELOAD_DIRS (new in inboard 0.7)

  • Directories and files to watch for changes, formatted as comma-separated string.
  • Default: watch all directories under project root.
  • Custom:

    • "inboard" (one directory)
    • "inboard, tests" (two directories)
    • "inboard, tests, Dockerfile" (two directories and a file) (watching non-Python files requires watchfiles, installed with the inboard[uvicorn-standard] extra)

    Note

    On the command-line, this Uvicorn setting is configured by passing --reload-dir, and can be passed multiple times, with one directory each.

    However, when running Uvicorn programmatically, uvicorn.run accepts a list of strings (uvicorn.run(reload_dirs=["dir1", "dir2"])), so inboard will parse the environment variable, send the list to Uvicorn, and Uvicorn will watch each directory or file specified.

RELOAD_DELAY (new in inboard 0.11)

  • Floating point value specifying the time, in seconds, to wait before reloading files.
  • Default: not set (the value is set by uvicorn.config.Config)
  • Custom: "0.5"

    Note

    • uvicorn.run equivalent: reload_delay
    • Uvicorn CLI equivalent: --reload-delay

RELOAD_EXCLUDES (new in inboard 0.11)

  • Glob pattern indicating files to exclude when watching for changes, formatted as comma-separated string.
  • Default: not set (the value is set by uvicorn.config.Config)
  • Custom: "*[Dd]ockerfile" (watching non-Python files requires watchfiles, installed with the inboard[uvicorn-standard] extra)

    Note

    • Parsed into a list of strings in the same manner as for RELOAD_DIRS.
    • uvicorn.run equivalent: reload_excludes
    • Uvicorn CLI equivalent: --reload-exclude

RELOAD_INCLUDES (new in inboard 0.11)

  • Glob pattern indicating files to include when watching for changes, formatted as comma-separated string.
  • Default: not set (the value is set by uvicorn.config.Config)
  • Custom: "*.py, *.md" (watching non-Python files requires watchfiles, installed with the inboard[uvicorn-standard] extra)

    Note

    • Parsed into a list of strings in the same manner as for RELOAD_DIRS.
    • uvicorn.run equivalent: reload_includes
    • Uvicorn CLI equivalent: --reload-include

UVICORN_CONFIG_OPTIONS (advanced usage, new in inboard 0.11)

  • JSON-formatted string containing arguments to pass directly to Uvicorn.
  • Default: not set
  • Custom: UVICORN_CONFIG_OPTIONS='{"reload": true, "reload_delay": null}'

The idea here is to allow a catch-all Uvicorn config variable in the spirit of GUNICORN_CMD_ARGS, so that advanced users can specify the full range of Uvicorn options even if inboard has not directly implemented them. The inboard.start module will run the UVICORN_CONFIG_OPTIONS environment variable value through json.loads(), and then pass the resultant dictionary through to Uvicorn. If the same option is set with an individual environment variable (such as WITH_RELOAD) and with a JSON value in UVICORN_CONFIG_OPTIONS, the JSON value will take precedence.

json.loads() converts data types from JSON to Python, and returns a Python dictionary. See the guide to understanding JSON schema for many helpful examples of how JSON data types correspond to Python data types. If the Uvicorn options are already available as a Python dictionary, dump them to a JSON-formatted string with json.dumps(), and set that as an environment variable.

Example of how to format UVICORN_CONFIG_OPTIONS as valid JSON

import json
import os
uvicorn_config_dict = dict(host="0.0.0.0", port=80, log_config=None, log_level="info", reload=False)
json.dumps(uvicorn_config_dict)
# '{"host": "0.0.0.0", "port": 80, "log_config": null, "log_level": "info", "reload": false}'
os.environ["UVICORN_CONFIG_OPTIONS"] = json.dumps(uvicorn_config_dict)
json.loads(os.environ["UVICORN_CONFIG_OPTIONS"]) == uvicorn_config_dict
# True

Warning

The UVICORN_CONFIG_OPTIONS environment variable is suggested for advanced usage because it requires some knowledge of uvicorn.config.Config. Other than the JSON -> Python dictionary conversion, no additional type conversions or validations are performed on UVICORN_CONFIG_OPTIONS. All options should be able to be passed directly to uvicorn.config.Config.

In the example below, reload will be passed through with the correct type (because it was formatted with the correct JSON type initially), but access_log will have an incorrect type (because it was formatted as a string instead of as a Boolean).

import json
import os
os.environ["UVICORN_CONFIG_OPTIONS_INCORRECT"] = '{"access_log": "false", "reload": true}'
json.loads(os.environ["UVICORN_CONFIG_OPTIONS_INCORRECT"])
# {'access_log': "false", 'reload': True}

Logging

LOGGING_CONF

  • Python module containing a logging configuration dictionary object named LOGGING_CONFIG. Can be either a module path (inboard.logging_conf) or a file path (/app/inboard/logging_conf.py). The LOGGING_CONFIG dictionary will be loaded and passed to logging.config.dictConfig().
  • Default: "inboard.logging_conf" (the default module provided with inboard)
  • Custom: For a logging config module at /app/package/custom_logging.py, LOGGING_CONF="package.custom_logging" or LOGGING_CONF="/app/package/custom_logging.py".

LOG_COLORS

  • Whether or not to color log messages. Currently only supported for LOG_FORMAT="uvicorn".
  • Default:
  • Custom:
    • LOG_COLORS="true"
    • LOG_COLORS="false"

LOG_FILTERS

LOG_FORMAT

  • Python logging format.
  • Default:
    • "simple": Simply the log level and message.
  • Custom:

    • "verbose": The most informative format, with the first 80 characters providing metadata, and the remainder supplying the log message.
    • "gunicorn": Gunicorn's default format.
    • "uvicorn": Uvicorn's default format, similar to simple, with support for LOG_COLORS. Note that Uvicorn's access formatter is not supported here, because it frequently throws errors related to ASGI scope.

    Example log message in different formats

    # simple
    INFO       Started server process [19012]
    
    # verbose
    2020-08-19 21:07:31 -0400      19012      uvicorn.error   main            INFO       Started server process [19012]
    
    # gunicorn
    [2020-08-19 21:07:31 -0400] [19012] [INFO] Started server process [19012]
    
    # uvicorn (can also be colored)
    INFO:     Started server process [19012]
    

LOG_LEVEL

  • Log level for Gunicorn or Uvicorn.
  • Default: "info"
  • Custom (organized from greatest to least amount of logging):
    • LOG_LEVEL="debug"
    • LOG_LEVEL="info"
    • LOG_LEVEL="warning"
    • LOG_LEVEL="error"
    • LOG_LEVEL="critical"

ACCESS_LOG

  • Access log file to which to write.
  • Default: "-" (stdout, print in Docker logs)
  • Custom:
    • ACCESS_LOG="./path/to/accesslogfile.txt"
    • ACCESS_LOG= (set to an empty value) to disable

ERROR_LOG

  • Error log file to which to write.
  • Default: "-" (stdout, print in Docker logs)
  • Custom:
    • ERROR_LOG="./path/to/errorlogfile.txt"
    • ERROR_LOG= (set to an empty value) to disable

See the logging reference for further info.

Authentication

BASIC_AUTH_USERNAME

  • Username for HTTP Basic auth.
  • Default: not set
  • Custom: BASIC_AUTH_USERNAME=test_user

BASIC_AUTH_PASSWORD

  • Password for HTTP Basic auth.
  • Default: not set
  • Custom: BASIC_AUTH_PASSWORD=r4ndom_bUt_memorable

See the authentication reference for further info.