xcaddy

repository·master·Indexed 23 days ago

https://github.com/caddyserver/xcaddy

A command-line tool and Go package for building custom versions of the Caddy Web Server. It simplifies the process of adding specific plugins, embedding directories into the binary, and managing Caddy versions. xcaddy can be used as a CLI for rapid development and custom builds or as a Go library via the Builder struct for programmatic binary creation.

Tokens
3.6K
Snippets
7
Records
23
Agent score
81%

What's inside xcaddy

  1. Install xcaddy

    master

    You can install xcaddy using one of the following methods:

    Build from source

    Requires Go installed:

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

    Install via APT (Debian, Ubuntu, Raspbian)

    Use the Cloudsmith repository:

    sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-xcaddy-archive-keyring.gpg
    curl -1sLf 'https://dl.cloudsmith.io/public/caddy/xcaddy/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-xcaddy.list
    sudo apt update
    sudo apt install xcaddy

    Download binaries

    Pre-compiled binaries are available on the Release tab.

    go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
  2. Embed directories into Caddy using --embed

    master

    The --embed flag allows you to include local files directly inside the Caddy executable. To use them, you must declare a custom filesystem using the embedded module in your Caddyfile.

    Using unaliased directories

    If you use --embed ./dir, the contents are merged into the root of the embedded filesystem.

    $ xcaddy build --embed ./my-files --embed ./my-other-files

    Caddyfile usage:

    {
    	filesystem my_embeds embedded
    }
    
    localhost {
    	file_server {
    		fs my_embeds
    	}
    }

    Using aliased directories

    To serve multiple sites from different embedded directories, use an alias prefix (alias:path).

    $ xcaddy build --embed foo:./sites/foo --embed bar:./sites/bar

    Caddyfile usage:

    {
    	filesystem my_embeds embedded
    }
    
    foo.localhost {
    	root * /foo
    	file_server {
    		fs my_embeds
    	}
    }
    
    bar.localhost {
    	root * /bar
    	file_server {
    		fs my_embeds
    	}
    }
    xcaddy build --embed foo:./sites/foo --embed bar:./sites/bar
  3. Develop Caddy plugins with xcaddy

    master

    When developing a Caddy plugin, run xcaddy (without the build subcommand) from within your plugin's Go module directory.

    xcaddy will automatically build Caddy with your current module included and run it immediately. The binary is cleaned up after execution. This acts as a replacement for go run during development.

    Arguments passed to xcaddy are forwarded to the caddy command. For example:

    $ xcaddy run --config caddy.json
  4. Configure hermetic builds with Env and Secrets

    master

    To ensure reproducible and secure builds, Builder provides mechanisms to control the environment and redact sensitive information:

    • Env: If provided, this slice of KEY=value strings becomes the entire environment for the underlying Go commands. The process's ambient environment is not inherited. This is recommended for 'hermetic' builds to prevent leaking local credentials (like GOPROXY user info or .netrc) into build logs. You must include essential variables like PATH and HOME (or GOCACHE/GOMODCACHE).
    • Secrets: A list of strings that will be replaced with [REDACTED] in any step output processed via OnStep. Matching is exact and line-buffered.
    • RedactCredentials: When set to true, the builder attempts to mask common credential patterns (e.g., GitHub/AWS tokens, PEM private keys) in the output. This is a best-effort backstop and does not replace the need for a hermetic environment.
  5. Observe build progress with OnStep

    master

    The OnStep callback allows you to monitor and control the build process. It is called for each build phase (e.g., StepCompile, StepTidyModule). The callback runs in its own goroutine concurrently with the step, allowing you to read the step's Output (which includes stdout/stderr from Go commands) in real-time.

    Key behaviors:

    • Concurrency: The callback runs concurrently with the step. You can consume event.Output directly.
    • Sequentiality: Callbacks do not overlap; the next step starts only after the previous callback returns.
    • Error Handling: Returning a non-nil error from the callback aborts the build at the end of that step. To cancel a step mid-execution, cancel the context.Context passed to Build.
    • Lifecycle: Output reaches EOF when the step ends.
    builder.OnStep = func(e *xcaddy.StepEvent) error {
        scanner := bufio.NewScanner(e.Output)
        for scanner.Scan() {
            fmt.Printf("[%s] %s\n", e.Step, scanner.Text())
        }
        return scanner.Err()
    }
  6. Set Linux capabilities on the xcaddy output binary

    master

    If you need the resulting Caddy binary to bind to privileged ports (like port 80 or 443) without running as root, you can instruct xcaddy to set Linux capabilities on the output file.

    To enable this, set the XCADDY_SETCAP environment variable to 1. The tool will attempt to run setcap cap_net_bind_service=+ep on the generated binary. If sudo is available on your system, xcaddy will attempt to use it to perform this action.

  7. Use xcaddy as a Go library

    master

    You can use the xcaddy package programmatically to build Caddy binaries within your own Go applications.

    builder := xcaddy.Builder{
    	CaddyVersion: "v2.0.0",
    	Plugins: []xcaddy.Dependency{
    		{
    			ModulePath: "github.com/caddyserver/ntlm-transport",
    			Version:    "v0.1.1",
    		},
    	},
    }
    err := builder.Build(context.Background(), "./caddy")
    builder := xcaddy.Builder{
    	CaddyVersion: "v2.0.0",
    	Plugins: []xcaddy.Dependency{
    		{
    			ModulePath: "github.com/caddyserver/ntlm-transport",
    			Version:    "v0.1.1",
    		},
    	},
    }
    err := builder.Build(context.Background(), "./caddy")
  8. Configure xcaddy via environment variables

    master

    The following environment variables control xcaddy behavior:

    VariableDescription
    CADDY_VERSIONSets the version of Caddy to build.
    XCADDY_RACE_DETECTORSet to 1 to enable the Go race detector in the build.
    XCADDY_DEBUGSet to 1 to enable DWARF debug information.
    XCADDY_SETCAPSet to 1 to run sudo setcap cap_net_bind_service=+ep on the resulting binary. (Requires sudo unless XCADDY_SUDO=0 is set).
    XCADDY_SKIP_BUILDSet to 1 to skip compilation (useful for build tools like GoReleaser). Implies XCADDY_SKIP_CLEANUP=1.
    XCADDY_SKIP_CLEANUPSet to 1 to leave build artifacts on disk after exiting.
    XCADDY_WHICH_GOSets the go command to use.
    XCADDY_GO_BUILD_FLAGSOverrides default go build arguments (e.g., XCADDY_GO_BUILD_FLAGS="-ldflags '-w -s'").
    XCADDY_GO_MOD_FLAGSOverrides default go mod arguments.
  9. Build custom Caddy binaries with xcaddy build

    master

    Use the xcaddy build command to compile a custom Caddy binary with specific plugins, versions, or embedded files.

    Syntax

    $ xcaddy build [<caddy_version>]
        [--output <file>]
        [--with <module[@version][=replacement]>...]
        [--replace <module[@version]=replacement>...]
        [--embed <[alias]:path/to/dir>...]
        [--pgo <file>]

    Arguments

    • <caddy_version>: The core Caddy version to build. Defaults to the CADDY_VERSION env var or latest. Accepts tags (e.g., v2.0.1), branches (e.g., master), or commit hashes.
    • --output <file>: Specifies the output filename.
    • --with <module[@version][=replacement]>: Adds plugins. You can specify a version or a local replacement (e.g., --with github.com/user/repo=../local-repo).
    • --replace <module[@version]=replacement>: Writes a replace directive to go.mod without adding a blank import. Useful for developing Caddy's dependencies.
    • --embed <[alias]:path/to/dir>: Embeds a directory into the binary.
      • Without an alias: Files are placed in the root of the embedded filesystem.
      • With an alias (alias:path): Files are placed in a subdirectory named after the alias.
    • --pgo <file>: (Experimental) Specifies a profile for Profile Guided Optimization. If default.pgo exists in the current directory, it is used automatically.
  10. List all supported build platforms with SupportedPlatforms()

    master

    The SupportedPlatforms() function retrieves a list of all valid build targets by executing go tool dist list -json.

    It automatically handles the translation of Go's internal distribution list into xcaddy.Compile objects. For linux/arm targets, it explicitly includes specific ARM versions (5, 6, and 7) to ensure compatibility.

  11. Configure compilation targets with Compile and Platform

    master

    When programmatically controlling Caddy builds, use the Compile and Platform types to define build targets.

    • Platform defines the target operating system (OS), architecture (Arch), and specific ARM version (ARM).
    • Compile embeds a Platform and adds a Cgo boolean flag to indicate if Cgo should be enabled during the build process.
  12. Use the Builder to programmatically create custom Caddy builds

    master
    The Builder struct is the primary entrypoint for creating custom Caddy binaries with specific plugins and configurations. You can configure the Caddy version, plugins, module replacements, build flags, and environment variables. The Build method executes the build process and places the resulting binary at the specified outputFile path.