caddy

package module
v1.0.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: AGPL-3.0 Imports: 19 Imported by: 0

README

Caddy storage module for Swytch

Share TLS certificates across Caddy instances without an external database.

Each instance runs an embedded Swytch node. Together, they replicate TLS certificates, ACME account state, and OCSP staples peer-to-peer and coordinate ACME issuance locks through Swytch's serializable transactions.

Discover peers through DNS, or use Swytch Cloud for peer discovery and durable storage.

Build a Caddy binary with this module

This repository is an independent Go module (github.com/swytchdb/caddy-storage) that depends on the released Swytch Engine. It does not require a Swytch repository checkout.

Build with xcaddy once this repository is published:

xcaddy build \
  --with github.com/swytchdb/caddy-storage

To build from a local checkout, use its absolute path:

xcaddy build \
  --with github.com/swytchdb/caddy-storage=/abs/path/to/caddy-storage

Development

Use Go 1.27 or newer. From this repository's root:

go test ./...
go vet ./...

Configure

Caddyfile
{
    storage swytch {
        cluster_passphrase <secret>     # empty = single-node (no replication)
        connection_secret <secret>      # Swytch Cloud durability; excludes cluster_passphrase + join
        join <dns-name>                 # peers resolve via DNS; optional
        cluster_port <num>              # QUIC port; default 7380/UDP
        cluster_advertise <addr:port>   # this node's reachable address; auto-detect if empty
        key_prefix __caddy:             # default; must live under __caddy:
        lock_ttl 30s                    # ACME issuance lock TTL; default 30s
    }
}

:80 {
    # ... your site config
}

Point your Caddy instances at the same join DNS name (which must resolve to at least one peer's cluster_advertise address), and they'll form a cluster. cluster_passphrase must match across every node.

JSON

The struct mapping follows Caddy's defaults — the field names below are JSON-encoded equivalents of the Caddyfile keywords:

{
  "storage": {
    "module": "swytch",
    "cluster_passphrase": "...",
    "connection_secret": "...",
    "join": "...",
    "cluster_port": 7380,
    "cluster_advertise": "10.0.0.1:7380",
    "key_prefix": "__caddy:",
    "lock_ttl": "30s"
  }
}

Lifecycle notes

  • The embedded engine is a process-wide singleton. Caddy reloads reuse it; changing cluster_passphrase, connection_secret, join, cluster_port, cluster_advertise, or key_prefix at reload time is rejected — these are all baked into the QUIC listener, TLS cert SAN, or peer-discovery state at startup and there is no live-update path. Restart the process instead.
  • connection_secret enables Swytch Cloud durability and is a self-contained cluster identity: the cluster passphrase derives from it and peers come from the cloud roster, so it is mutually exclusive with cluster_passphrase and join. TLS state still replicates peer-to-peer; Cloud is the backstop that rehydrates keys evicted from every live peer.
  • lock_ttl is per-storage and DOES take effect on the next reload.
  • Single-node mode (cluster_passphrase empty) is supported and useful for local development. No QUIC port is bound, no peer discovery runs.

Documentation

Overview

Package caddy provides Swytch storage for sharing TLS certificates across Caddy instances without an external database. An embedded Swytch node replicates TLS state peer-to-peer and coordinates ACME issuance locks.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type SwytchStorage

type SwytchStorage struct {
	// ClusterPassphrase enables cluster mode. Empty = single-node, no
	// replication. Must match across every peer.
	ClusterPassphrase string `json:"cluster_passphrase,omitempty"`

	// ConnectionSecret enables Swytch Cloud durability. It is a self-contained
	// cluster identity: the mTLS passphrase derives from it, so it is mutually
	// exclusive with ClusterPassphrase, and peer discovery uses the cloud
	// membership roster, so Join must be empty. When set, TLS state replicates
	// peer-to-peer as usual and is additionally backed by Swytch Cloud, so a key
	// evicted from every live peer is rehydrated from Cloud instead of lost.
	ConnectionSecret string `json:"connection_secret,omitempty"`

	// Join is the DNS name to discover peers.
	// Empty is fine for single-node deployments.
	Join string `json:"join,omitempty"`

	// ClusterPort is the QUIC port for cluster traffic.
	ClusterPort int `json:"cluster_port,omitempty"`

	// ClusterAdvertise is the <host>:<port> this node advertises.
	// Empty triggers auto-detection.
	ClusterAdvertise string `json:"cluster_advertise,omitempty"`

	// KeyPrefix scopes all keys this module reads/writes. Must live
	// under the reserved `__caddy:` namespace so the effect cache's
	// system-key pinning (which is __swytch:-only) does not pin
	// potentially large certificate/lock data and defeat the cache's
	// memory limit. Default `__caddy:`.
	KeyPrefix string `json:"key_prefix,omitempty"`

	// LockTTL is the duration after which a held lock is considered
	// stale and may be stolen by another acquirer.
	LockTTL caddycore.Duration `json:"lock_ttl,omitempty"`
}

SwytchStorage shares TLS certificates across Caddy instances without an external database.

Each instance runs an embedded Swytch node. Together, they replicate TLS certificates, ACME account state, and OCSP staples peer-to-peer and coordinate ACME issuance locks through Swytch's serializable transactions.

Point your Caddy instances at the same `join` DNS name and they'll form a cluster. `join` should resolve to reachable peer addresses: SRV records are preferred, otherwise A/AAAA records are used with `cluster_port`. `cluster_passphrase` must match across every node.

Alternatively, set `connection_secret` to use Swytch Cloud for peer discovery and durable storage. This replaces `cluster_passphrase` and `join`; TLS state still replicates peer-to-peer.

func (SwytchStorage) CaddyModule

func (SwytchStorage) CaddyModule() caddycore.ModuleInfo

CaddyModule implements caddy.Module.

func (*SwytchStorage) CertMagicStorage

func (s *SwytchStorage) CertMagicStorage() (certmagic.Storage, error)

CertMagicStorage implements caddy.StorageConverter — returns a certmagic.Storage backed by the singleton runtime that Provision claimed a reference to.

func (*SwytchStorage) Cleanup

func (s *SwytchStorage) Cleanup() error

Cleanup releases this module's reference on the runtime.

func (*SwytchStorage) Provision

func (s *SwytchStorage) Provision(ctx caddycore.Context) error

Provision is called once per Caddy reload. It claims a reference on the process-wide swytch runtime, starting it on the first call.

String fields (passphrase / join / advertise / prefix) are expanded through Caddy's Replacer so users can write `{env.SWYTCH_PASS}` or `{file./run/secrets/swytch}` in the Caddyfile.

func (*SwytchStorage) UnmarshalCaddyfile

func (s *SwytchStorage) UnmarshalCaddyfile(d *caddyfile.Dispenser) error

UnmarshalCaddyfile parses the storage block:

storage swytch {
    cluster_passphrase <pass>
    connection_secret <secret>
    join <dns>
    cluster_port <num>
    cluster_advertise <addr:port>
    key_prefix <str>
    lock_ttl <duration>
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL