Caddy is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go.
This plugin provides native support for Python apps.
It embeds the Python interpreter inside Caddy and serves requests directly without going through a reverse proxy.
Supports both WSGI and ASGI, which means you can run all types of frameworks like Flask, Django and FastAPI.
CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake
- Python >= 3.9 + dev files
- C compiler and build tools
- Go >= 1.21 and Xcaddy
Install requirements on Ubuntu 24.04:
$ sudo apt-get install python3-dev build-essential pkg-config golang
$ go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
You can also build with Docker.
main.py
from flask import Flask
app = Flask(__name__)
@app.route("/hello-world")
def hello():
return "Hello world!"
Caddyfile
http://localhost:9080 {
route {
python {
module_wsgi "main:app"
}
}
}
Run:
$ pip install Flask
$ CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake
$ ./caddy run --config Caddyfile
$ curl http://localhost:9080/hello-world
Hello world!
See how to setup Hot Reloading
main.py
from fastapi import FastAPI
@app.get("/hello-world")
def hello():
return "Hello world!"
Caddyfile
http://localhost:9080 {
route {
python {
module_asgi "main:app"
}
}
}
Run:
$ pip install fastapi
$ CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake
$ ./caddy run --config Caddyfile
$ curl http://localhost:9080/hello-world
Hello world!
NOTE: It's possible to enable/disable lifespan events by adding the
lifespan on|off
directive to your Caddy configuration. In the above case the lifespan events are disabled because the directive was omitted.
See how to setup Hot Reloading
There are docker images available with the following Python versions: 3.9
, 3.10
, 3.11
, 3.12
Example usage:
FROM ghcr.io/mliezun/caddy-snake:latest-py3.12
WORKDIR /app
# Copy your project into app
COPY . /app
# Caddy snake is already installed and has support for Python 3.12
CMD ["caddy", "run", "--config", "/app/Caddyfile"]
There's a template file in the project: builder.Dockerfile. It supports build arguments to configure which Python or Go version is desired for the build.
Make sure to use the same Python version as you have installed in your system.
You can copy the contents of the builder Dockerfile and execute the following commands to get your Caddy binary:
docker build -f builder.Dockerfile --build-arg PY_VERSION=3.9 -t caddy-snake .
docker run --rm -v $(pwd):/output caddy-snake
NOTE
It's also possible to provide virtual environments with the following syntax:
python {
module_wsgi "main:app"
venv "./venv"
}
What it does behind the scenes is to append venv/lib/python3.x/site-packages
to python sys.path
.
Disclaimer: Currently, when you provide a venv it gets added to the global
sys.path
, which in consequence means all apps have access to those packages.
Currently the Python app is not reloaded by the plugin if a file changes. But it is possible to setup using watchmedo to restart the Caddy process.
# Install on Debian and Ubuntu.
sudo apt-get install python3-watchdog
watchmedo auto-restart -d . -p "*.py" --recursive \
-- caddy run --config Caddyfile
Note that this will restart Caddy when new .py
files are created. If your venv is in the directory watched by watchmedo, installing packages in the venv will also restart Caddy by modifying .py
files.