github.com/caddyserver/caddy/v2/cmd
No package summary is available.
Package
Files: 9. Third party imports: 7. Imports from organisation: 1. Tests: 0. Benchmarks: 0.
Constants
const downloadPath = "https://caddyserver.com/api/download"
const fullDocsFooter = `Full documentation is available at:
https://caddyserver.com/docs/command-line`
Vars
Interface guard
var _ flag.Value = (*StringSlice)(nil)
var commandNameRegex = regexp.MustCompile(`^[a-z0-9]$|^([a-z0-9]+-?[a-z0-9]*)+[a-z0-9]$`)
var commands = make(map[string]Command)
var defaultFactory = newRootCommandFactory(func() *cobra.Command {
return &cobra.Command{
Use: "caddy",
Long: `Caddy is an extensible server platform written in Go.
At its core, Caddy merely manages configuration. Modules are plugged
in statically at compile-time to provide useful functionality. Caddy's
standard distribution includes common modules to serve HTTP, TLS,
and PKI applications, including the automation of certificates.
To run Caddy, use:
- 'caddy run' to run Caddy in the foreground (recommended).
- 'caddy start' to start Caddy in the background; only do this
if you will be keeping the terminal window open until you run
'caddy stop' to close the server.
When Caddy is started, it opens a locally-bound administrative socket
to which configuration can be POSTed via a restful HTTP API (see
https://caddyserver.com/docs/api).
Caddy's native configuration format is JSON. However, config adapters
can be used to convert other config formats to JSON when Caddy receives
its configuration. The Caddyfile is a built-in config adapter that is
popular for hand-written configurations due to its straightforward
syntax (see https://caddyserver.com/docs/caddyfile). Many third-party
adapters are available (see https://caddyserver.com/docs/config-adapters).
Use 'caddy adapt' to see how a config translates to JSON.
For convenience, the CLI can act as an HTTP client to give Caddy its
initial configuration for you. If a file named Caddyfile is in the
current working directory, it will do this automatically. Otherwise,
you can use the --config flag to specify the path to a config file.
Some special-purpose subcommands build and load a configuration file
for you directly from command line input; for example:
- caddy file-server
- caddy reverse-proxy
- caddy respond
These commands disable the administration endpoint because their
configuration is specified solely on the command line.
In general, the most common way to run Caddy is simply:
$ caddy run
Or, with a configuration file:
$ caddy run --config caddy.json
If running interactively in a terminal, running Caddy in the
background may be more convenient:
$ caddy start
...
$ caddy stop
This allows you to run other commands while Caddy stays running.
Be sure to stop Caddy before you close the terminal!
Depending on the system, Caddy may need permission to bind to low
ports. One way to do this on Linux is to use setcap:
$ sudo setcap cap_net_bind_service=+ep $(which caddy)
Remember to run that command again after replacing the binary.
See the Caddy website for tutorials, configuration structure,
syntax, and module documentation: https://caddyserver.com/docs/
Custom Caddy builds are available on the Caddy download page at:
https://caddyserver.com/download
The xcaddy command can be used to build Caddy from source with or
without additional plugins: https://github.com/caddyserver/xcaddy
Where possible, Caddy should be installed using officially-supported
package installers: https://caddyserver.com/docs/install
Instructions for running Caddy in production are also available:
https://caddyserver.com/docs/running
`,
Example: ` $ caddy run
$ caddy run --config caddy.json
$ caddy reload --config caddy.json
$ caddy stop`,
// kind of annoying to have all the help text printed out if
// caddy has an error provisioning its modules, for instance...
SilenceUsage: true,
Version: onlyVersionText(),
}
})
Types
Command
Command represents a subcommand. Name, Func, and Short are required.
type Command struct {
// The name of the subcommand. Must conform to the
// format described by the RegisterCommand() godoc.
// Required.
Name string
// Usage is a brief message describing the syntax of
// the subcommand's flags and args. Use [] to indicate
// optional parameters and <> to enclose literal values
// intended to be replaced by the user. Do not prefix
// the string with "caddy" or the name of the command
// since these will be prepended for you; only include
// the actual parameters for this command.
Usage string
// Short is a one-line message explaining what the
// command does. Should not end with punctuation.
// Required.
Short string
// Long is the full help text shown to the user.
// Will be trimmed of whitespace on both ends before
// being printed.
Long string
// Flags is the flagset for command.
// This is ignored if CobraFunc is set.
Flags *flag.FlagSet
// Func is a function that executes a subcommand using
// the parsed flags. It returns an exit code and any
// associated error.
// Required if CobraFunc is not set.
Func CommandFunc
// CobraFunc allows further configuration of the command
// via cobra's APIs. If this is set, then Func and Flags
// are ignored, with the assumption that they are set in
// this function. A caddycmd.WrapCommandFuncForCobra helper
// exists to simplify porting CommandFunc to Cobra's RunE.
CobraFunc func(*cobra.Command)
}
CommandFunc
CommandFunc is a command's function. It runs the command and returns the proper exit code along with any error that occurred.
type CommandFunc func(Flags) (int, error)
Flags
Flags wraps a FlagSet so that typed values from flags can be easily retrieved.
type Flags struct {
*pflag.FlagSet
}
StringSlice
StringSlice is a flag.Value that enables repeated use of a string flag.
type StringSlice []string
exitError
exitError carries the exit code from CommandFunc to Main()
type exitError struct {
ExitCode int
Err error
}
moduleInfo
This type doesn't have documentation.
type moduleInfo struct {
caddyModuleID string
goModule *debug.Module
err error
}
pluginPackage
This type doesn't have documentation.
type pluginPackage struct {
Version string
Path string
}
rootCommandFactory
This type doesn't have documentation.
type rootCommandFactory struct {
constructor func() *cobra.Command
options []func(*cobra.Command)
}
storVal
This type doesn't have documentation.
type storVal struct {
StorageRaw json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`
}
Functions
func AdminAPIRequest
AdminAPIRequest makes an API request according to the CLI flags given, with the given HTTP method and request URI. If body is non-nil, it will be assumed to be Content-Type application/json. The caller should close the response body. Should only be used by Caddy CLI commands which need to interact with a running instance of Caddy via the admin API.
func AdminAPIRequest(adminAddr, method, uri string, headers http.Header, body io.Reader) (*http.Response, error) {
parsedAddr, err := caddy.ParseNetworkAddress(adminAddr)
if err != nil || parsedAddr.PortRangeSize() > 1 {
return nil, fmt.Errorf("invalid admin address %s: %v", adminAddr, err)
}
origin := "http://" + parsedAddr.JoinHostPort(0)
if parsedAddr.IsUnixNetwork() {
origin = "http://127.0.0.1" // bogus host is a hack so that http.NewRequest() is happy
// the unix address at this point might still contain the optional
// unix socket permissions, which are part of the address/host.
// those need to be removed first, as they aren't part of the
// resulting unix file path
addr, _, err := internal.SplitUnixSocketPermissionsBits(parsedAddr.Host)
if err != nil {
return nil, err
}
parsedAddr.Host = addr
} else if parsedAddr.IsFdNetwork() {
origin = "http://127.0.0.1"
}
// form the request
req, err := http.NewRequest(method, origin+uri, body)
if err != nil {
return nil, fmt.Errorf("making request: %v", err)
}
if parsedAddr.IsUnixNetwork() || parsedAddr.IsFdNetwork() {
// We used to conform to RFC 2616 Section 14.26 which requires
// an empty host header when there is no host, as is the case
// with unix sockets and socket fds. However, Go required a
// Host value so we used a hack of a space character as the host
// (it would see the Host was non-empty, then trim the space later).
// As of Go 1.20.6 (July 2023), this hack no longer works. See:
// https://github.com/golang/go/issues/60374
// See also the discussion here:
// https://github.com/golang/go/issues/61431
//
// After that, we now require a Host value of either 127.0.0.1
// or ::1 if one is set. Above I choose to use 127.0.0.1. Even
// though the value should be completely irrelevant (it could be
// "srldkjfsd"), if for some reason the Host *is* used, at least
// we can have some reasonable assurance it will stay on the local
// machine and that browsers, if they ever allow access to unix
// sockets, can still enforce CORS, ensuring it is still coming
// from the local machine.
} else {
req.Header.Set("Origin", origin)
}
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
for k, v := range headers {
req.Header[k] = v
}
// make an HTTP client that dials our network type, since admin
// endpoints aren't always TCP, which is what the default transport
// expects; reuse is not of particular concern here
client := http.Client{
Transport: &http.Transport{
DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
return net.Dial(parsedAddr.Network, parsedAddr.JoinHostPort(0))
},
},
}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("performing request: %v", err)
}
// if it didn't work, let the user know
if resp.StatusCode >= 400 {
respBody, err := io.ReadAll(io.LimitReader(resp.Body, 1024*1024*2))
if err != nil {
return nil, fmt.Errorf("HTTP %d: reading error message: %v", resp.StatusCode, err)
}
return nil, fmt.Errorf("caddy responded with error: HTTP %d: %s", resp.StatusCode, respBody)
}
return resp, nil
}
Cognitive complexity: 6
, Cyclomatic complexity: 5
func Commands
Commands returns a list of commands initialised by RegisterCommand
func Commands() map[string]Command {
return commands
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func DetermineAdminAPIAddress
DetermineAdminAPIAddress determines which admin API endpoint address should
be used based on the inputs. By priority: if address
is specified, then
it is returned; if config
is specified, then that config will be used for
finding the admin address; if configFile
(and configAdapter
) are specified,
then that config will be loaded to find the admin address; otherwise, the
default admin listen address will be returned.
func DetermineAdminAPIAddress(address string, config []byte, configFile, configAdapter string) (string, error) {
// Prefer the address if specified and non-empty
if address != "" {
return address, nil
}
// Try to load the config from file if specified, with the given adapter name
if configFile != "" {
var loadedConfigFile string
var err error
// use the provided loaded config if non-empty
// otherwise, load it from the specified file/adapter
loadedConfig := config
if len(loadedConfig) == 0 {
// get the config in caddy's native format
loadedConfig, loadedConfigFile, err = LoadConfig(configFile, configAdapter)
if err != nil {
return "", err
}
if loadedConfigFile == "" {
return "", fmt.Errorf("no config file to load; either use --config flag or ensure Caddyfile exists in current directory")
}
}
// get the address of the admin listener from the config
if len(loadedConfig) > 0 {
var tmpStruct struct {
Admin caddy.AdminConfig `json:"admin"`
}
err := json.Unmarshal(loadedConfig, &tmpStruct)
if err != nil {
return "", fmt.Errorf("unmarshaling admin listener address from config: %v", err)
}
if tmpStruct.Admin.Listen != "" {
return tmpStruct.Admin.Listen, nil
}
}
}
// Fallback to the default listen address otherwise
return caddy.DefaultAdminListen, nil
}
Cognitive complexity: 17
, Cyclomatic complexity: 9
func LoadConfig
LoadConfig loads the config from configFile and adapts it using adapterName. If adapterName is specified, configFile must be also. If no configFile is specified, it tries loading a default config file. The lack of a config file is not treated as an error, but false will be returned if there is no config available. It prints any warnings to stderr, and returns the resulting JSON config bytes along with the name of the loaded config file (if any).
func LoadConfig(configFile, adapterName string) ([]byte, string, error) {
return loadConfigWithLogger(caddy.Log(), configFile, adapterName)
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func Main
Main implements the main function of the caddy command. Call this if Caddy is to be the main() of your program.
func Main() {
if len(os.Args) == 0 {
fmt.Printf("[FATAL] no arguments provided by OS; args[0] must be command\n")
os.Exit(caddy.ExitCodeFailedStartup)
}
undo, err := maxprocs.Set()
defer undo()
if err != nil {
caddy.Log().Warn("failed to set GOMAXPROCS", zap.Error(err))
}
if err := defaultFactory.Build().Execute(); err != nil {
var exitError *exitError
if errors.As(err, &exitError) {
os.Exit(exitError.ExitCode)
}
os.Exit(1)
}
}
Cognitive complexity: 8
, Cyclomatic complexity: 5
func RegisterCommand
RegisterCommand registers the command cmd. cmd.Name must be unique and conform to the following format:
- lowercase
- alphanumeric and hyphen characters only
- cannot start or end with a hyphen
- hyphen cannot be adjacent to another hyphen
This function panics if the name is already registered, if the name does not meet the described format, or if any of the fields are missing from cmd.
This function should be used in init().
func RegisterCommand(cmd Command) {
if cmd.Name == "" {
panic("command name is required")
}
if cmd.Func == nil && cmd.CobraFunc == nil {
panic("command function missing")
}
if cmd.Short == "" {
panic("command short string is required")
}
if _, exists := commands[cmd.Name]; exists {
panic("command already registered: " + cmd.Name)
}
if !commandNameRegex.MatchString(cmd.Name) {
panic("invalid command name")
}
defaultFactory.Use(func(rootCmd *cobra.Command) {
rootCmd.AddCommand(caddyCmdToCobra(cmd))
})
}
Cognitive complexity: 11
, Cyclomatic complexity: 7
func WrapCommandFuncForCobra
WrapCommandFuncForCobra wraps a Caddy CommandFunc for use in a cobra command's RunE field.
func WrapCommandFuncForCobra(f CommandFunc) func(cmd *cobra.Command, _ []string) error {
return func(cmd *cobra.Command, _ []string) error {
status, err := f(Flags{cmd.Flags()})
if status > 1 {
cmd.SilenceErrors = true
return &exitError{ExitCode: status, Err: err}
}
return err
}
}
Cognitive complexity: 5
, Cyclomatic complexity: 2
func (*StringSlice) Set
func (ss *StringSlice) Set(value string) error {
*ss = append(*ss, value)
return nil
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (*exitError) Error
func (e *exitError) Error() string {
if e.Err == nil {
return fmt.Sprintf("exiting with status %d", e.ExitCode)
}
return e.Err.Error()
}
Cognitive complexity: 2
, Cyclomatic complexity: 2
func (*rootCommandFactory) Build
func (f *rootCommandFactory) Build() *cobra.Command {
o := f.constructor()
for _, v := range f.options {
v(o)
}
return o
}
Cognitive complexity: 3
, Cyclomatic complexity: 2
func (*rootCommandFactory) Use
func (f *rootCommandFactory) Use(fn func(cmd *cobra.Command)) {
f.options = append(f.options, fn)
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (Flags) Bool
Bool returns the boolean representation of the flag given by name. It returns false if the flag is not a boolean type. It panics if the flag is not in the flag set.
func (f Flags) Bool(name string) bool {
val, _ := strconv.ParseBool(f.String(name))
return val
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (Flags) Duration
Duration returns the duration representation of the flag given by name. It returns false if the flag is not a duration type. It panics if the flag is not in the flag set.
func (f Flags) Duration(name string) time.Duration {
val, _ := caddy.ParseDuration(f.String(name))
return val
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (Flags) Float64
Float64 returns the float64 representation of the flag given by name. It returns false if the flag is not a float64 type. It panics if the flag is not in the flag set.
func (f Flags) Float64(name string) float64 {
val, _ := strconv.ParseFloat(f.String(name), 64)
return val
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (Flags) Int
Int returns the integer representation of the flag given by name. It returns 0 if the flag is not an integer type. It panics if the flag is not in the flag set.
func (f Flags) Int(name string) int {
val, _ := strconv.ParseInt(f.String(name), 0, strconv.IntSize)
return int(val)
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (Flags) String
String returns the string representation of the flag given by name. It panics if the flag is not in the flag set.
func (f Flags) String(name string) string {
return f.FlagSet.Lookup(name).Value.String()
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
Private functions
func caddyCmdToCobra
caddyCmdToCobra (caddyCmd Command) *cobra.Command
References: cobra.Command.
func cmdAdaptConfig
cmdAdaptConfig (fl Flags) (int, error)
References: bytes.Buffer, caddyconfig.GetAdapter, fmt.Errorf, fmt.Println, fmt.Sprintf, json.Indent, os.ReadFile, zap.Int, zap.String.
func cmdAddPackage
cmdAddPackage (fl Flags) (int, error)
References: fmt.Errorf.
func cmdBuildInfo
cmdBuildInfo (_ Flags) (int, error)
References: debug.ReadBuildInfo, fmt.Errorf, fmt.Println.
func cmdEnviron
cmdEnviron (fl Flags) (int, error)
func cmdExportStorage
cmdExportStorage (fl Flags) (int, error)
References: certmagic.Storage, context.Background, errors.Is, errors.New, fmt.Errorf, fmt.Sprintf, fs.ErrNotExist, os.Create, os.File, os.Stdout, tar.Header, tar.NewWriter.
func cmdFmt
cmdFmt (fl Flags) (int, error)
References: caddyfile.Format, caddyfile.FormattingDifference, difflib.Common, difflib.Diff, difflib.LeftOnly, difflib.RightOnly, fmt.Errorf, fmt.Print, fmt.Printf, io.ReadAll, os.ReadFile, os.Stdin, os.WriteFile, strings.Join, strings.Split.
func cmdImportStorage
cmdImportStorage (fl Flags) (int, error)
References: certmagic.Storage, context.Background, errors.New, fmt.Errorf, fmt.Println, io.EOF, io.ReadAll, os.File, os.Open, os.Stdin, tar.NewReader.
func cmdListModules
cmdListModules (fl Flags) (int, error)
References: fmt.Print, fmt.Printf, fmt.Println.
func cmdReload
cmdReload (fl Flags) (int, error)
References: bytes.NewReader, fmt.Errorf, http.Header, http.MethodPost.
func cmdRemovePackage
cmdRemovePackage (fl Flags) (int, error)
References: fmt.Errorf.
func cmdRun
cmdRun (fl Flags) (int, error)
References: errors.Is, fmt.Errorf, fs.ErrNotExist, io.ReadAll, net.Dial, os.Getenv, os.ReadFile, os.Stdin, runtime.GOOS, zap.Error, zap.String.
func cmdStart
cmdStart (fl Flags) (int, error)
References: errors.Is, exec.Command, exec.ErrDot, fmt.Errorf, fmt.Printf, log.Println, net.ErrClosed, net.Listen, os.Args, os.Stderr, os.Stdout, rand.Read.
func cmdStop
cmdStop (fl Flags) (int, error)
References: fmt.Errorf, http.MethodPost, zap.Error.
func cmdUpgrade
cmdUpgrade (fl Flags) (int, error)
References: fmt.Errorf.
func cmdValidateConfig
cmdValidateConfig (fl Flags) (int, error)
References: fmt.Errorf, fmt.Println.
func cmdVersion
cmdVersion (_ Flags) (int, error)
References: fmt.Println.
func configFileWithRespectToDefault
configFileWithRespectToDefault returns the filename to use for loading the config, based on whether a config file is already specified and a supported default config file exists.
configFileWithRespectToDefault (logger *zap.Logger, configFile string) (string, error)
References: caddyconfig.GetAdapter, errors.Is, fmt.Errorf, fs.ErrNotExist, os.Stat.
func determineStorage
determineStorage returns the top-level storage module from the given config. It may return nil even if no error.
determineStorage (configFile string, configAdapter string) (*storVal, error)
References: errors.As, json.SyntaxError, json.Unmarshal, json.Valid.
func downloadBuild
downloadBuild (qs url.Values) (*http.Response, error)
References: fmt.Errorf, fmt.Sprintf, http.Get, json.NewDecoder, zap.String, zap.Strings.
func getModules
getModules () ([]moduleInfo, error)
References: debug.Module, debug.ReadBuildInfo, fmt.Errorf, reflect.New, reflect.Ptr, reflect.TypeOf, reflect.ValueOf, strings.HasPrefix.
func getPluginPackages
getPluginPackages (modules []moduleInfo) (map[string]pluginPackage, error)
References: fmt.Errorf.
func handleEnvFileFlag
handleEnvFileFlag loads the environment variables from the given --envfile flag if specified. This should be called as early in the command function.
handleEnvFileFlag (fl Flags) error
References: fmt.Errorf.
func handlePingbackConn
handlePingbackConn reads from conn and ensures it matches the bytes in expect, or returns an error if it doesn't.
handlePingbackConn (conn net.Conn, expect []byte) error
References: bytes.Equal, fmt.Errorf, io.LimitReader, io.ReadAll.
func init
init ()
References: cobra.Command.
func isCaddyfile
isCaddyfile (configFile,adapterName string) (bool, error)
References: filepath.Base, filepath.Ext, strings.HasPrefix, strings.HasSuffix, strings.ToLower.
func listModules
listModules (path string) error
References: exec.Command, os.Stderr, os.Stdout.
func loadConfigWithLogger
loadConfigWithLogger (logger *zap.Logger, configFile,adapterName string) ([]byte, string, error)
References: caddyconfig.Adapter, caddyconfig.GetAdapter, errors.Is, fmt.Errorf, fmt.Sprintf, fs.ErrNotExist, io.ReadAll, json.Unmarshal, os.ReadFile, os.Stdin, zap.Int, zap.NewNop, zap.String.
func loadEnvFromFile
loadEnvFromFile (envFile string) error
References: certmagic.FileStorage, filepath.Join, fmt.Errorf, os.LookupEnv, os.Open, os.Setenv.
func newRootCommandFactory
newRootCommandFactory (fn func() *cobra.Command) *rootCommandFactory
func onlyVersionText
onlyVersionText () string
func parseEnvFile
parseEnvFile parses an env file from KEY=VALUE format. It's pretty naive. Limited value quotation is supported, but variable and command expansions are not supported.
parseEnvFile (envInput io.Reader) (map[string]string, error)
References: bufio.NewScanner, fmt.Errorf, strings.Contains, strings.Cut, strings.HasPrefix, strings.HasSuffix, strings.ReplaceAll, strings.TrimPrefix, strings.TrimRight, strings.TrimSpace, strings.TrimSuffix.
func printEnvironment
printEnvironment ()
References: fmt.Printf, fmt.Println, fmt.Sprintf, os.Environ, os.Getwd, runtime.Compiler, runtime.GOARCH, runtime.GOMAXPROCS, runtime.GOOS, runtime.NumCPU, runtime.Version.
func removeCaddyBinary
removeCaddyBinary removes the Caddy binary at the given path.
On any non-Windows OS, this simply calls os.Remove, since they should probably not exhibit any issue with processes deleting themselves.
removeCaddyBinary (path string) error
References: os.Remove.
func showVersion
showVersion (path string) error
References: exec.Command, os.Stderr, os.Stdout.
func splitModule
splitModule (arg string) (string, error)
References: fmt.Errorf, strings.LastIndex.
func upgradeBuild
upgradeBuild (pluginPkgs map[string]pluginPackage, fl Flags) (int, error)
References: filepath.EvalSymlinks, fmt.Errorf, fmt.Print, fmt.Println, os.Executable, os.ModeSymlink, os.Rename, os.Stat, runtime.GOARCH, runtime.GOOS, url.Values, zap.Error, zap.String.
func watchConfigFile
watchConfigFile watches the config file at filename for changes and reloads the config if the file was updated. This function blocks indefinitely; it only quits if the poller has errors for long enough time. The filename passed in must be the actual config file used, not one to be discovered. Each second the config files is loaded and parsed into an object and is compared to the last config object that was loaded
watchConfigFile (filename,adapterName string)
References: bytes.Equal, debug.Stack, log.Printf, time.Second, time.Tick, zap.Error, zap.Logger, zap.String.
func writeCaddyBinary
writeCaddyBinary (path string, body *io.ReadCloser, fileInfo os.FileInfo) error
References: fmt.Errorf, io.Copy, os.O_CREATE, os.O_RDWR, os.O_TRUNC, os.OpenFile, zap.String.
Tests
Files: 1. Third party imports: 0. Imports from organisation: 0. Tests: 2. Benchmarks: 0.