Installation & Distribution
Caddy Snake is available in several forms, each suited to different use cases. This page covers how each distribution method works, where to get it, and when to use which.
PyPI Package (caddysnake)
The caddysnake package on PyPI is the easiest way to install and run Caddy Snake. It provides a caddysnake CLI command that serves your Python web app with a single command.
Install
pip install caddysnake
Requirements: Python >= 3.12, Linux (x86_64 or ARM64) or macOS (x86_64 or ARM64)
Available Python versions: 3.12, 3.13, 3.14
Usage
# Serve a WSGI app (Flask, Django, etc.)
caddysnake --server-type wsgi --app main:app
# Serve an ASGI app (FastAPI, Starlette, etc.)
caddysnake --server-type asgi --app main:app
# With HTTPS, workers, and static files
caddysnake \
--server-type asgi \
--app main:app \
--domain example.com \
--workers 4 \
--static-path ./static \
--access-logs
CLI Options
| Flag | Short | Description | Default |
|---|---|---|---|
--server-type | -t | Required. Type of Python app: wsgi or asgi | — |
--app | -a | Required. Python module and app variable (e.g. main:app) | — |
--domain | -d | Domain name for HTTPS with automatic certificates | — |
--listen | -l | Custom listen address | :9080 |
--workers | -w | Number of worker processes (0 = CPU count) | 0 |
--static-path | Path to a static files directory | — | |
--static-route | Route prefix for static files | /static | |
--debug | Enable debug logging | false | |
--access-logs | Enable access logs | false |
How it works
The PyPI package is built with maturin and distributed as platform-specific wheel files. Each wheel contains:
caddysnake-cli— a pre-compiled Caddy binary built with the caddy-snake plugin via xcaddycaddysnake_cli.py— a Python CLI wrapper (using click) that translates command-line flags intocaddy python-serverarguments and executes the bundled Caddy binary
When you run caddysnake --server-type wsgi --app main:app, the wrapper:
- Locates the bundled
caddysnake-clibinary in the package directory - Builds the equivalent
caddy python-servercommand with all the flags - Uses
os.execvto replace the current process with the Caddy binary
At runtime, the bundled Caddy binary spawns Python worker subprocesses using your system Python (or a venv interpreter). This is different from the pre-built standalone binaries, which bundle a full Python distribution and pass it via --python-path.
Build pipeline
The package is built and published automatically on tagged releases (v*.*.*) by the python-build.yml GitHub Actions workflow:
- Caddy is built with the caddy-snake plugin using
xcaddyinside a Docker container (builder.Dockerfile) - The resulting
caddybinary is moved into thecmd/cli/directory ascaddysnake-cli maturin build --releasepackages it into a Python wheel- The wheel is published to PyPI with
twine
This runs for each combination of Python version (3.12–3.14) and architecture (x86_64, ARM64), producing platform-specific wheels.
Pre-built Standalone Binaries
The standalone binaries are fully self-contained executables that bundle both Caddy (with the caddy-snake plugin) and a complete Python distribution. No system Python, no pip, no dependencies — just download and run.
Download
Pre-built binaries are available from the GitHub Releases page. The naming convention is:
caddy-standalone-{python-version}-{architecture}.tar.gz
For example:
caddy-standalone-3.13-x86_64_v2-unknown-linux-gnu.tar.gz— Python 3.13, Linux x86_64caddy-standalone-3.13-aarch64-unknown-linux-gnu.tar.gz— Python 3.13, Linux ARM64caddy-standalone-3.13-x86_64-apple-darwin.tar.gz— Python 3.13, macOS Intelcaddy-standalone-3.13-aarch64-apple-darwin.tar.gz— Python 3.13, macOS Apple Siliconcaddy-standalone-3.13-nogil-x86_64_v2-unknown-linux-gnu.tar.gz— Python 3.13 free-threadedcaddy-standalone-3.14-nogil-x86_64_v2-unknown-linux-gnu.tar.gz— Python 3.14 free-threaded
Available versions
| Python | Architectures | Notes |
|---|---|---|
| 3.12 | Linux x86_64, Linux ARM64, macOS x86_64, macOS ARM64 | |
| 3.13 | Linux x86_64, Linux ARM64, macOS x86_64, macOS ARM64 | |
| 3.13-nogil | Linux x86_64, Linux ARM64, macOS x86_64, macOS ARM64 | Free-threaded (PEP 703) |
| 3.14 | Linux x86_64, Linux ARM64, macOS x86_64, macOS ARM64 | |
| 3.14-nogil | Linux x86_64, Linux ARM64, macOS x86_64, macOS ARM64 | Free-threaded (PEP 703) |
Usage
# Download and extract
tar -xzf caddy-standalone-3.13-x86_64_v2-unknown-linux-gnu.tar.gz
# Use the CLI shorthand
./caddy python-server --server-type wsgi --app main:app
# Or use a Caddyfile for full configuration
./caddy run --config Caddyfile
Since the standalone binary comes with its own Python, you don't need to install Python on the host. However, your app's dependencies (e.g. Flask, FastAPI) need to be available. You can install them into a virtual environment and point to it with the venv directive:
# Create a venv using the embedded Python
./caddy python -m venv myenv
source myenv/bin/activate
pip install fastapi
# Run with the venv
./caddy python-server --server-type asgi --app main:app
Or in a Caddyfile:
python {
module_asgi "main:app"
venv "./myenv"
}
How it works
The standalone binary is a Go program (cmd/embed/main.go) that uses Go's //go:embed directive to bundle two files:
caddy— the Caddy binary built with the caddy-snake pluginpython-standalone.tar.gz— a python-build-standalone distribution (maintained by Astral)
When you run the standalone binary:
- It creates a temporary directory and extracts the embedded Python distribution into it
- It writes the embedded Caddy binary to another temporary directory
- It sets up the environment:
PYTHONHOME— points to the extracted Python distributionLD_LIBRARY_PATH— includes the Python shared libraries
- It executes the Caddy binary with the provided arguments, passing through stdin/stdout/stderr
- On exit, both temporary directories are cleaned up automatically
This means the binary is large (typically ~16 MB) because it contains a full Python interpreter, but it requires zero dependencies on the host system.
The pybs.py helper
The build process uses a helper script (cmd/embed/pybs.py) to download Python distributions from the python-build-standalone project. This script:
- Fetches release information from the GitHub API
- Selects the appropriate asset based on Python version, architecture, build config, and content type
- Supports all python-build-standalone architectures (Linux, macOS, Windows) and build configurations (pgo+lto, freethreaded, debug, etc.)
- Handles GitHub API rate limiting with exponential backoff
- Uses Levenshtein distance to suggest closest matches when an exact match isn't found
You can use pybs.py directly to download Python distributions:
# Download Python 3.13 for Linux x86_64 (default)
python3 cmd/embed/pybs.py latest
# Download Python 3.14 for macOS ARM
python3 cmd/embed/pybs.py latest \
--python-version 3.14 \
--architecture aarch64-apple-darwin
# List all available options
python3 cmd/embed/pybs.py latest --list-options
Build pipeline
The standalone binaries are built by the build-standalone.yml GitHub Actions workflow:
- Caddy is built with the caddy-snake plugin using
xcaddyin thecmd/embed/directory pybs.pydownloads the appropriate python-build-standalone distribution- The Python distribution is compressed as
python-standalone.tar.gz go build main.gocompiles the Go wrapper, which embeds both the Caddy binary and the Python distribution- The resulting self-contained binary is uploaded as a release artifact
For the 3.13-nogil and 3.14-nogil variants, a freethreaded python-build-standalone distribution is used instead.
Docker Images
Docker images come with Caddy Snake pre-installed and a specific Python version available.
Available images
# Docker Hub
docker pull mliezun/caddy-snake:latest-py3.13
# GitHub Container Registry
docker pull ghcr.io/mliezun/caddy-snake:latest-py3.13
Available Python versions: 3.12, 3.13, 3.14
Usage
FROM mliezun/caddy-snake:latest-py3.13
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["caddy", "run", "--config", "/app/Caddyfile"]
Registries
Building from Source
For maximum control, you can build Caddy with the caddy-snake plugin from source.
Requirements
- Python >= 3.12 (runtime — used by worker subprocesses)
- Go >= 1.26
- xcaddy
Build
# Install dependencies (Ubuntu 24.04)
sudo apt-get install python3 golang
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
# Build Caddy with caddy-snake
CGO_ENABLED=0 xcaddy build --with github.com/mliezun/caddy-snake
The resulting caddy binary uses your system Python and requires it at runtime.
Build with Docker
If you don't want to install Go and the build tools on your system, you can use Docker:
# Build the Docker image (uses builder.Dockerfile)
docker build -f builder.Dockerfile --build-arg PY_VERSION=3.13 -t caddy-snake-builder .
# Extract the caddy binary
docker run --rm -v $(pwd):/output caddy-snake-builder
Make sure the PY_VERSION matches the Python version on your target system.
Comparison
| Method | System Python required | Internet access needed | Caddyfile support | CLI shorthand | Best for |
|---|---|---|---|---|---|
PyPI (pip install caddysnake) | Yes | At install time | No (CLI only) | caddysnake | Quick start, development |
| Standalone binary | No (embedded) | No (self-contained) | Yes | ./caddy python-server | Production, air-gapped environments |
| Standalone app binary | No (embedded) | No (self-contained) | No (CLI) | ./myapp | Single-file distribution, edge deployments |
| Docker | No (in container) | At build time | Yes | caddy python-server | Containerized deployments |
| Build from source | Yes | At build time | Yes | ./caddy python-server | Custom builds, macOS, Windows |
See Apps as Standalone Binaries for packaging your app into a single executable.
- Use PyPI for the fastest way to get started or for development
- Use standalone binaries for production Linux deployments where you want zero dependencies
- Use standalone app binaries to distribute your app as a single executable (like FrankenPHP)
- Use Docker for containerized environments
- Build from source when you need macOS/Windows support or want to pin specific versions