Skip to main content

fastcaddy

Usage

Installation

Install from pypi

$ pip install fastcaddy

Installing Caddy

from fastcore.utils import *

This project is to help you use the caddy API, rather than a Caddyfile, to use caddy. To use the API, you need to install a plugin for your domain management service. We use Cloudflare, so we’ll document that here. For other domain services, see the Caddy docs for other plugins.

Cloudflare setup

You’ll need a token from Cloudflare with access to modify the necessary settings. Here’s the steps to create a token with the minimal privileges. You’ll need to install the cloudflare pip package, then import:

from cloudflare import Cloudflare

Then you’ll need create a Cloudflare API token for your user, which we’ll then use to create the less privileged token.

cf_token = os.environ['CLOUDFLARE_API_TOKEN']

We can now check that works OK:

cf = Cloudflare(api_token=cf_token)
zones = cf.zones.list()
len(zones.result)
8

Replace this with your domain name:

domain = 'answer.ai'
zones = cf.zones.list(name=domain)
assert len(zones.result)==1
zone_id = zones.result[0].id

Here’s the methods available for modifying DNS records:

  • client.dns.records.create(*, zone_id, **params) -> Optional
  • client.dns.records.update(dns_record_id, *, zone_id, **params) -> Optional
  • client.dns.records.list(*, zone_id, **params) -> SyncV4PagePaginationArray[Record]
  • client.dns.records.delete(dns_record_id, *, zone_id) -> Optional
  • client.dns.records.edit(dns_record_id, *, zone_id, **params) -> Optional
  • client.dns.records.export(*, zone_id) -> str
  • client.dns.records.get(dns_record_id, *, zone_id) -> Optional
  • client.dns.records.import\_(*, zone_id, **params) -> Optional
  • client.dns.records.scan(*, zone_id, **params) -> Optional

…and here’s the methods for tokens:

from cloudflare.types.user import (CIDRList, Policy, Token, TokenCreateResponse, TokenUpdateResponse, TokenListResponse,
                                   TokenDeleteResponse, TokenGetResponse, TokenVerifyResponse)
  • client.user.tokens.create(**params) -> Optional
  • client.user.tokens.update(token_id, **params) -> object
  • client.user.tokens.list(**params) -> SyncV4PagePaginationArray[object]
  • client.user.tokens.delete(token_id) -> Optional
  • client.user.tokens.get(token_id) -> object
  • client.user.tokens.verify() -> Optional
from cloudflare.types.user.tokens import PermissionGroupListResponse
  • client.user.tokens.permission_groups.list() -> SyncSinglePage[object]
from cloudflare.types.user.tokens import Value
  • client.user.tokens.value.update(token_id, **params) -> str

We need these two permissions in our token:

permission_groups = cf.user.tokens.permission_groups.list()

dns_write = next(group for group in permission_groups if group['name'] == 'DNS Write')
zone_read = next(group for group in permission_groups if group['name'] == 'Zone Read')

Now we can create it:

new_token = cf.user.tokens.create(
    name='caddy_dns',
    policies=[{
        "effect": "allow",
        "resources": { f"com.cloudflare.api.account.zone.{zone_id}": "*" },
        "permission_groups": [
            {"id": zone_read['id'], "name": "Zone Read"},
            {"id": dns_write['id'], "name": "DNS Write"}
        ]
    }]
)

print(new_token.value)

Make a copy of this value, which we’ll need for setting up caddy.

Installing caddy

To install caddy, we’ll use a tool called xcaddy. This is written in go. So first install go:

  • Mac: brew install go
  • Linux: sudo apt install golang

Note that if you are not on the latest Ubuntu, you’ll need to setup the backport repo before installing go:

sudo add-apt-repository -y ppa:longsleep/golang-backports
sudo apt update

Now we can install xcaddy:

go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

Alternatively, you can download the latest xcaddy directly, e.g:

# Change the OS and arch as needed, or remove them to view all options
wget -qO- https://latest.fast.ai/latest/caddyserver/xcaddy/linux_amd64.tar.gz

Then we use that to compile caddy with our desired domain plugin (cloudflare, in this case):

mkdir -p ~/go/bin
cd ~/go/bin
./xcaddy build --with github.com/caddy-dns/cloudflare

This gives us a ~/go/bin/caddy binary we can run:

./caddy version
./caddy run

Securely run caddy on start

If you’re using a server or running caddy a lot, you’ll want it to run on start. And if you’re making it publicly accessible, you’ll want it to be secure. This isn’t needed otherwise – you can just ~/go/bin/caddy run to run it manually (you may want to add ~/go/bin to your PATH env var).

To set this up, run from this repo root:

./setup_service.sh

If all went well, you should see output like this:

 caddy.service - Caddy
     Loaded: loaded (/etc/systemd/system/caddy.service; enabled; preset: enabled)
     Active: active (running) since Sat 2024-11-09 05:06:47 UTC; 2 days ago
       Docs: https://caddyserver.com/docs/
   Main PID: 138140 (caddy)
      Tasks: 29 (limit: 154166)
     Memory: 19.3M (peak: 28.8M)
        CPU: 3min 37.216s
     CGroup: /system.slice/caddy.service
             └─138140 /usr/bin/caddy run --environ

How to use

We will now show how to set up caddy as a reverse proxy for hosts added dynamically.

fastcaddy talks to caddy’s admin API, and config set that way is ephemeral: it doesn’t survive a caddy restart. So the recommended pattern is a setup script that runs on every deploy (e.g. from systemd): call reset(), then the functions below for everything you host. Each function is safe to re-run – routes are tagged with predictable @ids (the hostname, or wildcard-{domain}), and re-adding one replaces it rather than duplicating it – so the script is the single source of truth for your routing config.

Initial setup

We’ll grab our token from the previous step (assuming here that it’s stored in an env var):

cf_token = os.environ.get('AAI_CF_TOKEN', 'XXX')

source

setup_caddy

setup_caddy (cf_token, srv_name='srv0')

Create SSL config and HTTP app skeleton

We can now setup the basic routes needed for caddy:

setup_caddy(cf_token)

source

gcfg

gcfg (path='/', method='get')

Gets the config at path

To view the configuration created, use gcfg:

# gcfg()

You can also view a sub-path of the configuration:

gcfg('/apps/http/servers')
{'srv0': {'listen': [':80', ':443'], 'routes': []}}

Reverse proxies


source

add_reverse_proxy

add_reverse_proxy (from_host, to_url)

Create a reverse proxy handler

To add a reverse proxy, use add_reverse_proxy:

host = 'jph.answer.ai'
add_reverse_proxy(host, 'localhost:5001')

source

gid

gid (path='/')

Gets the id at path

This is automatically added with an id matching the host, which you can view with gid:

gid('jph.answer.ai')
{ '@id': 'jph.answer.ai',
  'handle': [{'handler': 'reverse_proxy', 'upstreams': [{'dial': 'localhost:5001'}]}],
  'match': [{'host': ['jph.answer.ai']}],
  'terminal': True}

If you call this again with the same host, it will be replaced:

add_reverse_proxy(host, 'localhost:8000')
gid('jph.answer.ai').handle[1]
{'handler': 'reverse_proxy', 'upstreams': [{'dial': 'localhost:8000'}]}

source

del_id

del_id (id)

Delete route for id (e.g. a host)

To remove a host, delete its id:

del_id(host)

Wildcard subdomains

Caddy can create a wildcard SSL cert. To do so, add a wildcard route (a no-op if it already exists, so existing subdomains inside it are never destroyed):


source

add_wildcard_route

add_wildcard_route (domain)

Add a wildcard subdomain

add_wildcard_route('something.fast.ai')

Create reverse proxies in a wildcard domain requires using a special function:


source

add_sub_reverse_proxy

add_sub_reverse_proxy (domain, subdomain, port)

Add a reverse proxy to a wildcard subdomain

add_sub_reverse_proxy('something.fast.ai', 'foo', 5001)

These subdomains can be deleted in the usual way:

del_id('foo.something.fast.ai')

Release files for fastcaddy 0.0.11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastcaddy 0.0.11
File Size Uploaded
fastcaddy-0.0.11.tar.gz 119.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fastcaddy 0.0.11
File Interpreter ABI Platform
fastcaddy-0.0.11-py3-none-any.whl Python 3 none any Details

Total release size:236.3 kB

Release files / fastcaddy-0.0.11.tar.gz

Download URL fastcaddy-0.0.11.tar.gz
Size 119.1 kB
Tags Source
SHA-256 checksum
How to use checksums
720b23e2778f725edab6dfdaa4434a08af5c874df288fa77deabe30ce54eb250
BLAKE2b-256 checksum
How to use checksums
6a4a4064e51a1de984ee33514458f95f167db296c0e7d243ee0f879a917a765a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / fastcaddy-0.0.11-py3-none-any.whl

Download URL fastcaddy-0.0.11-py3-none-any.whl
Size 117.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
6051832f596304b5f3e3431981c53cce8e804f768f6a847ca75f21e85eaf02c1
BLAKE2b-256 checksum
How to use checksums
a59d94dd544a7edf4c548307a0224803b1e2f9758ef6d8fb7c0fa902f3b4516b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release history Release notifications | RSS feed

This release

0.0.11 This release

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page