Repository: phpple/caddy2-cn-doc Branch: master Commit: 554fac221e84 Files: 116 Total size: 608.3 KB Directory structure: gitextract_gisajt4l/ ├── .gitignore ├── Caddyfile ├── readme.md └── src/ ├── api/ │ ├── docs/ │ │ └── config.json │ └── modules/ │ └── index.json ├── docs/ │ ├── index.html │ ├── json/ │ │ └── index.html │ ├── markdown/ │ │ ├── api-tutorial.md │ │ ├── api.md │ │ ├── architecture.md │ │ ├── automatic-https.md │ │ ├── build.md │ │ ├── caddyfile/ │ │ │ ├── concepts.md │ │ │ ├── directives/ │ │ │ │ ├── abort.md │ │ │ │ ├── acme_server.md │ │ │ │ ├── basic_auth.md │ │ │ │ ├── bind.md │ │ │ │ ├── encode.md │ │ │ │ ├── error.md │ │ │ │ ├── file_server.md │ │ │ │ ├── forward_auth.md │ │ │ │ ├── fs.md │ │ │ │ ├── handle.md │ │ │ │ ├── handle_errors.md │ │ │ │ ├── handle_path.md │ │ │ │ ├── header.md │ │ │ │ ├── import.md │ │ │ │ ├── intercept.md │ │ │ │ ├── invoke.md │ │ │ │ ├── log.md │ │ │ │ ├── log_append.md │ │ │ │ ├── log_name.md │ │ │ │ ├── log_skip.md │ │ │ │ ├── map.md │ │ │ │ ├── method.md │ │ │ │ ├── metrics.md │ │ │ │ ├── php_fastcgi.md │ │ │ │ ├── push.md │ │ │ │ ├── redir.md │ │ │ │ ├── request_body.md │ │ │ │ ├── request_header.md │ │ │ │ ├── respond.md │ │ │ │ ├── reverse_proxy.md │ │ │ │ ├── rewrite.md │ │ │ │ ├── root.md │ │ │ │ ├── route.md │ │ │ │ ├── templates.md │ │ │ │ ├── tls.md │ │ │ │ ├── tracing.md │ │ │ │ ├── try_files.md │ │ │ │ ├── uri.md │ │ │ │ └── vars.md │ │ │ ├── directives.md │ │ │ ├── matchers.md │ │ │ ├── options.md │ │ │ ├── patterns.md │ │ │ ├── response-matchers.md │ │ │ └── spec.md │ │ ├── caddyfile-tutorial.md │ │ ├── caddyfile.md │ │ ├── command-line.md │ │ ├── config-adapters.md │ │ ├── conventions.md │ │ ├── examples.md │ │ ├── extending-caddy/ │ │ │ ├── caddyfile.md │ │ │ ├── config-adapters.md │ │ │ ├── namespaces.md │ │ │ └── placeholders.md │ │ ├── extending-caddy.md │ │ ├── faq.md │ │ ├── getting-started.md │ │ ├── index.md │ │ ├── install.md │ │ ├── json.md │ │ ├── logging.md │ │ ├── metrics.md │ │ ├── modules.md │ │ ├── profiling.md │ │ ├── quick-starts/ │ │ │ ├── api.md │ │ │ ├── caddyfile.md │ │ │ ├── https.md │ │ │ ├── railway.md │ │ │ ├── reverse-proxy.md │ │ │ └── static-files.md │ │ ├── quick-starts.md │ │ ├── running.md │ │ ├── signature-verification.md │ │ ├── troubleshooting.md │ │ └── v2-upgrade.md │ └── modules/ │ └── index.html ├── includes/ │ ├── docs/ │ │ ├── details.html │ │ ├── head.html │ │ ├── header.html │ │ ├── hovercard.html │ │ ├── nav.html │ │ └── renderbox.html │ ├── donate.html │ ├── footer.html │ └── head.html ├── index.html └── resources/ ├── 321140.cast ├── css/ │ ├── account/ │ │ ├── common.css │ │ └── dashboard.css │ ├── asciinema-player-2.6.1.css │ ├── chroma.css │ ├── common.css │ ├── docs-json.css │ ├── docs.css │ ├── download.css │ ├── home.css │ └── v2-landing.css └── js/ ├── common.js ├── docs-api.js ├── docs.js ├── json-docs.js └── module-docs.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ _book/ .* !.gitignore references agent/ ================================================ FILE: Caddyfile ================================================ http://127.0.0.1:22020 root * src file_server templates encode gzip try_files {path}.html {path} redir /docs/json /docs/json/ redir /docs/modules /docs/modules/ rewrite /docs/json/* /docs/json/index.html rewrite /docs/modules/* /docs/modules/index.html rewrite /docs/* /docs/index.html rewrite /api/modules /api/modules/index.json rewrite /api/modules/* {path}.json rewrite /api/docs/config/ /api/docs/config.json # redirect to /docs/ redir / /docs/ ================================================ FILE: readme.md ================================================ Caddy v2 中文文档 ================= 这是Caddy v2中文文档的网站, [https://caddy2.dengxiaolong.com/](https://caddy2.dengxiaolong.com/docs/). ## 要求 - 安装Caddy 2 (在PATH可直接运行`caddy`) ## 快速开始 1. `git clone https://github.com/phpple/caddy2-cn-doc/` 2. `cd caddy2-cn-doc` 3. `caddy run` 第一次,系统可能会提示你输入密码。这样Caddy就可以通过本地HTTPS为站点提供服务。如果无法绑定低端口,请更改[`Caddyfile`](Caddyfile)顶部的地址,例如`localhost:2015`。 然后你可以通过浏览器访问[http://127.0.0.1:22020/](http://127.0.0.1:22020/) (或者你配置的其他地址)。 ================================================ FILE: src/api/docs/config.json ================================================ { "status_code": 200, "result": { "structure": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.Config", "struct_fields": [ { "key": "admin", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.AdminConfig", "struct_fields": [ { "key": "disabled", "value": { "type": "bool", "doc": "If true, the admin endpoint will be completely disabled.\nNote that this makes any runtime changes to the config\nimpossible, since the interface to do so is through the\nadmin endpoint." }, "doc": "If true, the admin endpoint will be completely disabled.\nNote that this makes any runtime changes to the config\nimpossible, since the interface to do so is through the\nadmin endpoint." }, { "key": "listen", "value": { "type": "string", "doc": "The address to which the admin endpoint's listener should\nbind itself. Can be any single network address that can be\nparsed by Caddy. Default: localhost:2019" }, "doc": "The address to which the admin endpoint's listener should\nbind itself. Can be any single network address that can be\nparsed by Caddy. Default: localhost:2019" }, { "key": "enforce_origin", "value": { "type": "bool", "doc": "If true, CORS headers will be emitted, and requests to the\nAPI will be rejected if their `Host` and `Origin` headers\ndo not match the expected value(s). Use `origins` to\ncustomize which origins/hosts are allowed. If `origins` is\nnot set, the listen address is the only value allowed by\ndefault. Enforced only on local (plaintext) endpoint." }, "doc": "If true, CORS headers will be emitted, and requests to the\nAPI will be rejected if their `Host` and `Origin` headers\ndo not match the expected value(s). Use `origins` to\ncustomize which origins/hosts are allowed. If `origins` is\nnot set, the listen address is the only value allowed by\ndefault. Enforced only on local (plaintext) endpoint." }, { "key": "origins", "value": { "type": "array", "elems": { "type": "string", "doc": "The list of allowed origins/hosts for API requests. Only needed\nif accessing the admin endpoint from a host different from the\nsocket's network interface or if `enforce_origin` is true. If not\nset, the listener address will be the default value. If set but\nempty, no origins will be allowed. Enforced only on local\n(plaintext) endpoint." } }, "doc": "The list of allowed origins/hosts for API requests. Only needed\nif accessing the admin endpoint from a host different from the\nsocket's network interface or if `enforce_origin` is true. If not\nset, the listener address will be the default value. If set but\nempty, no origins will be allowed. Enforced only on local\n(plaintext) endpoint." }, { "key": "config", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.ConfigSettings", "struct_fields": [ { "key": "persist", "value": { "type": "bool", "doc": "Whether to keep a copy of the active config on disk. Default is true.\nNote that \"pulled\" dynamic configs (using the neighboring \"load\" module)\nare not persisted; only configs that are pushed to Caddy get persisted." }, "doc": "Whether to keep a copy of the active config on disk. Default is true.\nNote that \"pulled\" dynamic configs (using the neighboring \"load\" module)\nare not persisted; only configs that are pushed to Caddy get persisted." }, { "key": "load", "value": { "type": "module", "doc": "Loads a configuration to use. This is helpful if your configs are\nmanaged elsewhere, and you want Caddy to pull its config dynamically\nwhen it starts. The pulled config completely replaces the current\none, just like any other config load. It is an error if a pulled\nconfig is configured to pull another config.\n\nEXPERIMENTAL: Subject to change.", "module_namespace": "caddy.config_loaders", "module_inline_key": "module" }, "doc": "Loads a configuration to use. This is helpful if your configs are\nmanaged elsewhere, and you want Caddy to pull its config dynamically\nwhen it starts. The pulled config completely replaces the current\none, just like any other config load. It is an error if a pulled\nconfig is configured to pull another config.\n\nEXPERIMENTAL: Subject to change." } ], "doc": "Options pertaining to configuration management.\n\n\nConfigSettings configures the management of configuration." }, "doc": "Options pertaining to configuration management.\n\n\nConfigSettings configures the management of configuration." }, { "key": "identity", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.IdentityConfig", "struct_fields": [ { "key": "identifiers", "value": { "type": "array", "elems": { "type": "string", "doc": "List of names or IP addresses which refer to this server.\nCertificates will be obtained for these identifiers so\nsecure TLS connections can be made using them." } }, "doc": "List of names or IP addresses which refer to this server.\nCertificates will be obtained for these identifiers so\nsecure TLS connections can be made using them." }, { "key": "issuers", "value": { "type": "array", "elems": { "type": "module", "doc": "Issuers that can provide this admin endpoint its identity\ncertificate(s). Default: ACME issuers configured for\nZeroSSL and Let's Encrypt. Be sure to change this if you\nrequire credentials for private identifiers.", "module_namespace": "tls.issuance", "module_inline_key": "module" } }, "doc": "Issuers that can provide this admin endpoint its identity\ncertificate(s). Default: ACME issuers configured for\nZeroSSL and Let's Encrypt. Be sure to change this if you\nrequire credentials for private identifiers." } ], "doc": "Options that establish this server's identity. Identity refers to\ncredentials which can be used to uniquely identify and authenticate\nthis server instance. This is required if remote administration is\nenabled (but does not require remote administration to be enabled).\nDefault: no identity management.\n\n\nIdentityConfig configures management of this server's identity. An identity\nconsists of credentials that uniquely verify this instance; for example,\nTLS certificates (public + private key pairs)." }, "doc": "Options that establish this server's identity. Identity refers to\ncredentials which can be used to uniquely identify and authenticate\nthis server instance. This is required if remote administration is\nenabled (but does not require remote administration to be enabled).\nDefault: no identity management.\n\n\nIdentityConfig configures management of this server's identity. An identity\nconsists of credentials that uniquely verify this instance; for example,\nTLS certificates (public + private key pairs)." }, { "key": "remote", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.RemoteAdmin", "struct_fields": [ { "key": "listen", "value": { "type": "string", "doc": "The address on which to start the secure listener.\nDefault: :2021" }, "doc": "The address on which to start the secure listener.\nDefault: :2021" }, { "key": "access_control", "value": { "type": "array", "elems": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.AdminAccess", "struct_fields": [ { "key": "public_keys", "value": { "type": "array", "elems": { "type": "string", "doc": "Base64-encoded DER certificates containing public keys to accept.\n(The contents of PEM certificate blocks are base64-encoded DER.)\nAny of these public keys can appear in any part of a verified chain." } }, "doc": "Base64-encoded DER certificates containing public keys to accept.\n(The contents of PEM certificate blocks are base64-encoded DER.)\nAny of these public keys can appear in any part of a verified chain." }, { "key": "permissions", "value": { "type": "array", "elems": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.AdminPermissions", "struct_fields": [ { "key": "paths", "value": { "type": "array", "elems": { "type": "string", "doc": "The API paths allowed. Paths are simple prefix matches.\nAny subpath of the specified paths will be allowed." } }, "doc": "The API paths allowed. Paths are simple prefix matches.\nAny subpath of the specified paths will be allowed." }, { "key": "methods", "value": { "type": "array", "elems": { "type": "string", "doc": "The HTTP methods allowed for the given paths." } }, "doc": "The HTTP methods allowed for the given paths." } ], "doc": "Limits what the associated identities are allowed to do.\nIf unspecified, all permissions are granted.\n\n\nAdminPermissions specifies what kinds of requests are allowed\nto be made to the admin endpoint." } }, "doc": "Limits what the associated identities are allowed to do.\nIf unspecified, all permissions are granted.\n\n\nAdminPermissions specifies what kinds of requests are allowed\nto be made to the admin endpoint." } ], "doc": "List of access controls for this secure admin endpoint.\nThis configures TLS mutual authentication (i.e. authorized\nclient certificates), but also application-layer permissions\nlike which paths and methods each identity is authorized for.\n\n\nAdminAccess specifies what permissions an identity or group\nof identities are granted." } }, "doc": "List of access controls for this secure admin endpoint.\nThis configures TLS mutual authentication (i.e. authorized\nclient certificates), but also application-layer permissions\nlike which paths and methods each identity is authorized for.\n\n\nAdminAccess specifies what permissions an identity or group\nof identities are granted." } ], "doc": "Options pertaining to remote administration. By default, remote\nadministration is disabled. If enabled, identity management must\nalso be configured, as that is how the endpoint is secured.\nSee the neighboring \"identity\" object.\n\nEXPERIMENTAL: This feature is subject to change.\n\n\nRemoteAdmin enables and configures remote administration. If enabled,\na secure listener enforcing mutual TLS authentication will be started\non a different port from the standard plaintext admin server.\n\nThis endpoint is secured using identity management, which must be\nconfigured separately (because identity management does not depend\non remote administration). See the admin/identity config struct.\n\nEXPERIMENTAL: Subject to change." }, "doc": "Options pertaining to remote administration. By default, remote\nadministration is disabled. If enabled, identity management must\nalso be configured, as that is how the endpoint is secured.\nSee the neighboring \"identity\" object.\n\nEXPERIMENTAL: This feature is subject to change.\n\n\nRemoteAdmin enables and configures remote administration. If enabled,\na secure listener enforcing mutual TLS authentication will be started\non a different port from the standard plaintext admin server.\n\nThis endpoint is secured using identity management, which must be\nconfigured separately (because identity management does not depend\non remote administration). See the admin/identity config struct.\n\nEXPERIMENTAL: Subject to change." } ], "doc": "AdminConfig configures Caddy's API endpoint, which is used\nto manage Caddy while it is running.\n" }, "doc": "AdminConfig configures Caddy's API endpoint, which is used\nto manage Caddy while it is running.\n" }, { "key": "logging", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.Logging", "struct_fields": [ { "key": "sink", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.StandardLibLog", "struct_fields": [ { "key": "writer", "value": { "type": "module", "doc": "The module that writes out log entries for the sink.", "module_namespace": "caddy.logging.writers", "module_inline_key": "output" }, "doc": "The module that writes out log entries for the sink." } ], "doc": "Sink is the destination for all unstructured logs emitted\nfrom Go's standard library logger. These logs are common\nin dependencies that are not designed specifically for use\nin Caddy. Because it is global and unstructured, the sink\nlacks most advanced features and customizations.\n\n\nStandardLibLog configures the default Go standard library\nglobal logger in the log package. This is necessary because\nmodule dependencies which are not built specifically for\nCaddy will use the standard logger. This is also known as\nthe \"sink\" logger." }, "doc": "Sink is the destination for all unstructured logs emitted\nfrom Go's standard library logger. These logs are common\nin dependencies that are not designed specifically for use\nin Caddy. Because it is global and unstructured, the sink\nlacks most advanced features and customizations.\n\n\nStandardLibLog configures the default Go standard library\nglobal logger in the log package. This is necessary because\nmodule dependencies which are not built specifically for\nCaddy will use the standard logger. This is also known as\nthe \"sink\" logger." }, { "key": "logs", "value": { "type": "map", "map_keys": { "type": "string" }, "elems": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.CustomLog", "struct_fields": [ { "key": "writer", "value": { "type": "module", "doc": "The writer defines where log entries are emitted.", "module_namespace": "caddy.logging.writers", "module_inline_key": "output" }, "doc": "The writer defines where log entries are emitted." }, { "key": "encoder", "value": { "type": "module", "doc": "The encoder is how the log entries are formatted or encoded.", "module_namespace": "caddy.logging.encoders", "module_inline_key": "format" }, "doc": "The encoder is how the log entries are formatted or encoded." }, { "key": "level", "value": { "type": "string", "doc": "Level is the minimum level to emit, and is inclusive.\nPossible levels: DEBUG, INFO, WARN, ERROR, PANIC, and FATAL" }, "doc": "Level is the minimum level to emit, and is inclusive.\nPossible levels: DEBUG, INFO, WARN, ERROR, PANIC, and FATAL" }, { "key": "sampling", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.LogSampling", "struct_fields": [ { "key": "interval", "value": { "type": "int", "type_name": "time.Duration", "doc": "The window over which to conduct sampling.\n\n\nA Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years." }, "doc": "The window over which to conduct sampling.\n\n\nA Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years." }, { "key": "first", "value": { "type": "int", "doc": "Log this many entries within a given level and\nmessage for each interval." }, "doc": "Log this many entries within a given level and\nmessage for each interval." }, { "key": "thereafter", "value": { "type": "int", "doc": "If more entries with the same level and message\nare seen during the same interval, keep one in\nthis many entries until the end of the interval." }, "doc": "If more entries with the same level and message\nare seen during the same interval, keep one in\nthis many entries until the end of the interval." } ], "doc": "Sampling configures log entry sampling. If enabled,\nonly some log entries will be emitted. This is useful\nfor improving performance on extremely high-pressure\nservers.\n\n\nLogSampling configures log entry sampling." }, "doc": "Sampling configures log entry sampling. If enabled,\nonly some log entries will be emitted. This is useful\nfor improving performance on extremely high-pressure\nservers.\n\n\nLogSampling configures log entry sampling." }, { "key": "include", "value": { "type": "array", "elems": { "type": "string", "doc": "Include defines the names of loggers to emit in this\nlog. For example, to include only logs emitted by the\nadmin API, you would include \"admin.api\"." } }, "doc": "Include defines the names of loggers to emit in this\nlog. For example, to include only logs emitted by the\nadmin API, you would include \"admin.api\"." }, { "key": "exclude", "value": { "type": "array", "elems": { "type": "string", "doc": "Exclude defines the names of loggers that should be\nskipped by this log. For example, to exclude only\nHTTP access logs, you would exclude \"http.log.access\"." } }, "doc": "Exclude defines the names of loggers that should be\nskipped by this log. For example, to exclude only\nHTTP access logs, you would exclude \"http.log.access\"." } ], "doc": "Logs are your logs, keyed by an arbitrary name of your\nchoosing. The default log can be customized by defining\na log called \"default\". You can further define other logs\nand filter what kinds of entries they accept.\n\n\nCustomLog represents a custom logger configuration.\n\nBy default, a log will emit all log entries. Some entries\nwill be skipped if sampling is enabled. Further, the Include\nand Exclude parameters define which loggers (by name) are\nallowed or rejected from emitting in this log. If both Include\nand Exclude are populated, their values must be mutually\nexclusive, and longer namespaces have priority. If neither\nare populated, all logs are emitted." } }, "doc": "Logs are your logs, keyed by an arbitrary name of your\nchoosing. The default log can be customized by defining\na log called \"default\". You can further define other logs\nand filter what kinds of entries they accept.\n\n\nCustomLog represents a custom logger configuration.\n\nBy default, a log will emit all log entries. Some entries\nwill be skipped if sampling is enabled. Further, the Include\nand Exclude parameters define which loggers (by name) are\nallowed or rejected from emitting in this log. If both Include\nand Exclude are populated, their values must be mutually\nexclusive, and longer namespaces have priority. If neither\nare populated, all logs are emitted." } ], "doc": "Logging facilitates logging within Caddy. The default log is\ncalled \"default\" and you can customize it. You can also define\nadditional logs.\n\nBy default, all logs at INFO level and higher are written to\nstandard error (\"stderr\" writer) in a human-readable format\n(\"console\" encoder if stdout is an interactive terminal, \"json\"\nencoder otherwise).\n\nAll defined logs accept all log entries by default, but you\ncan filter by level and module/logger names. A logger's name\nis the same as the module's name, but a module may append to\nlogger names for more specificity. For example, you can\nfilter logs emitted only by HTTP handlers using the name\n\"http.handlers\", because all HTTP handler module names have\nthat prefix.\n\nCaddy logs (except the sink) are zero-allocation, so they are\nvery high-performing in terms of memory and CPU time. Enabling\nsampling can further increase throughput on extremely high-load\nservers.\n" }, "doc": "Logging facilitates logging within Caddy. The default log is\ncalled \"default\" and you can customize it. You can also define\nadditional logs.\n\nBy default, all logs at INFO level and higher are written to\nstandard error (\"stderr\" writer) in a human-readable format\n(\"console\" encoder if stdout is an interactive terminal, \"json\"\nencoder otherwise).\n\nAll defined logs accept all log entries by default, but you\ncan filter by level and module/logger names. A logger's name\nis the same as the module's name, but a module may append to\nlogger names for more specificity. For example, you can\nfilter logs emitted only by HTTP handlers using the name\n\"http.handlers\", because all HTTP handler module names have\nthat prefix.\n\nCaddy logs (except the sink) are zero-allocation, so they are\nvery high-performing in terms of memory and CPU time. Enabling\nsampling can further increase throughput on extremely high-load\nservers.\n" }, { "key": "storage", "value": { "type": "module", "doc": "StorageRaw is a storage module that defines how/where Caddy\nstores assets (such as TLS certificates). The default storage\nmodule is `caddy.storage.file_system` (the local file system),\nand the default path\n[depends on the OS and environment](/docs/conventions#data-directory).", "module_namespace": "caddy.storage", "module_inline_key": "module" }, "doc": "StorageRaw is a storage module that defines how/where Caddy\nstores assets (such as TLS certificates). The default storage\nmodule is `caddy.storage.file_system` (the local file system),\nand the default path\n[depends on the OS and environment](/docs/conventions#data-directory)." }, { "key": "apps", "value": { "type": "module_map", "type_name": "github.com/caddyserver/caddy/v2.ModuleMap", "doc": "AppsRaw are the apps that Caddy will load and run. The\napp module name is the key, and the app's config is the\nassociated value.\n\n\nModuleMap is a map that can contain multiple modules,\nwhere the map key is the module's name. (The namespace\nis usually read from an associated field's struct tag.)\nBecause the module's name is given as the key in a\nmodule map, the name does not have to be given in the\njson.RawMessage.", "module_namespace": "" }, "doc": "AppsRaw are the apps that Caddy will load and run. The\napp module name is the key, and the app's config is the\nassociated value.\n\n\nModuleMap is a map that can contain multiple modules,\nwhere the map key is the module's name. (The namespace\nis usually read from an associated field's struct tag.)\nBecause the module's name is given as the key in a\nmodule map, the name does not have to be given in the\njson.RawMessage." } ], "doc": "Config is the top (or beginning) of the Caddy configuration structure.\nCaddy config is expressed natively as a JSON document. If you prefer\nnot to work with JSON directly, there are [many config adapters](/docs/config-adapters)\navailable that can convert various inputs into Caddy JSON.\n\nMany parts of this config are extensible through the use of Caddy modules.\nFields which have a json.RawMessage type and which appear as dots (•••) in\nthe online docs can be fulfilled by modules in a certain module\nnamespace. The docs show which modules can be used in a given place.\n\nWhenever a module is used, its name must be given either inline as part of\nthe module, or as the key to the module's value. The docs will make it clear\nwhich to use.\n\nGenerally, all config settings are optional, as it is Caddy convention to\nhave good, documented default values. If a parameter is required, the docs\nshould say so.\n\nGo programs which are directly building a Config struct value should take\ncare to populate the JSON-encodable fields of the struct (i.e. the fields\nwith `json` struct tags) if employing the module lifecycle (e.g. Provision\nmethod calls).\n" }, "namespaces": { "": [ { "name": "exec", "docs": "exec is top level module that runs shell commands.", "package": "github.com/abiosoft/caddy-exec", "repo": "https://github.com/abiosoft/caddy-exec" }, { "name": "supervisor", "package": "github.com/baldinof/caddy-supervisor", "repo": "https://github.com/baldinof/caddy-supervisor" }, { "name": "http", "docs": "http is a robust, production-ready HTTP server.\n\nHTTPS is enabled by default if host matchers with qualifying names are used\nin any of routes; certificates are automatically provisioned and renewed.\nAdditionally, automatic HTTPS will also enable HTTPS for servers that listen\nonly on the HTTPS port but which do not have any TLS connection policies\ndefined by adding a good, default TLS connection policy.\n\nIn HTTP routes, additional placeholders are available (replace any `*`):\n\nPlaceholder | Description\n------------|---------------\n`{http.request.body}` | The request body (⚠️ inefficient; use only for debugging)\n`{http.request.cookie.*}` | HTTP request cookie\n`{http.request.duration}` | Time up to now spent handling the request (after decoding headers from client)\n`{http.request.header.*}` | Specific request header field\n`{http.request.host.labels.*}` | Request host labels (0-based from right); e.g. for foo.example.com: 0=com, 1=example, 2=foo\n`{http.request.host}` | The host part of the request's Host header\n`{http.request.hostport}` | The host and port from the request's Host header\n`{http.request.method}` | The request method\n`{http.request.orig_method}` | The request's original method\n`{http.request.orig_uri.path.dir}` | The request's original directory\n`{http.request.orig_uri.path.file}` | The request's original filename\n`{http.request.orig_uri.path}` | The request's original path\n`{http.request.orig_uri.query}` | The request's original query string (without `?`)\n`{http.request.orig_uri}` | The request's original URI\n`{http.request.port}` | The port part of the request's Host header\n`{http.request.proto}` | The protocol of the request\n`{http.request.remote.host}` | The host part of the remote client's address\n`{http.request.remote.port}` | The port part of the remote client's address\n`{http.request.remote}` | The address of the remote client\n`{http.request.scheme}` | The request scheme\n`{http.request.tls.version}` | The TLS version name\n`{http.request.tls.cipher_suite}` | The TLS cipher suite\n`{http.request.tls.resumed}` | The TLS connection resumed a previous connection\n`{http.request.tls.proto}` | The negotiated next protocol\n`{http.request.tls.proto_mutual}` | The negotiated next protocol was advertised by the server\n`{http.request.tls.server_name}` | The server name requested by the client, if any\n`{http.request.tls.client.fingerprint}` | The SHA256 checksum of the client certificate\n`{http.request.tls.client.public_key}` | The public key of the client certificate.\n`{http.request.tls.client.public_key_sha256}` | The SHA256 checksum of the client's public key.\n`{http.request.tls.client.certificate_pem}` | The PEM-encoded value of the certificate.\n`{http.request.tls.client.certificate_der_base64}` | The base64-encoded value of the certificate.\n`{http.request.tls.client.issuer}` | The issuer DN of the client certificate\n`{http.request.tls.client.serial}` | The serial number of the client certificate\n`{http.request.tls.client.subject}` | The subject DN of the client certificate\n`{http.request.tls.client.san.dns_names.*}` | SAN DNS names(index optional)\n`{http.request.tls.client.san.emails.*}` | SAN email addresses (index optional)\n`{http.request.tls.client.san.ips.*}` | SAN IP addresses (index optional)\n`{http.request.tls.client.san.uris.*}` | SAN URIs (index optional)\n`{http.request.uri.path.*}` | Parts of the path, split by `/` (0-based from left)\n`{http.request.uri.path.dir}` | The directory, excluding leaf filename\n`{http.request.uri.path.file}` | The filename of the path, excluding directory\n`{http.request.uri.path}` | The path component of the request URI\n`{http.request.uri.query.*}` | Individual query string value\n`{http.request.uri.query}` | The query string (without `?`)\n`{http.request.uri}` | The full request URI\n`{http.response.header.*}` | Specific response header field\n`{http.vars.*}` | Custom variables in the HTTP handler chain", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" }, { "name": "pki", "docs": "pki provides Public Key Infrastructure facilities for Caddy.\n\nThis app can define certificate authorities (CAs) which are capable\nof signing certificates. Other modules can be configured to use\nthe CAs defined by this app for issuing certificates or getting\nkey information needed for establishing trust.", "package": "github.com/caddyserver/caddy/v2/modules/caddypki", "repo": "https://github.com/caddyserver/caddy" }, { "name": "tls", "docs": "tls provides TLS facilities including certificate\nloading and management, client auth, and more.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" }, { "name": "security", "docs": "security implements security manager.", "package": "github.com/greenpau/caddy-security", "repo": "https://github.com/greenpau/caddy-security" }, { "name": "crowdsec", "docs": "crowdsec is a Caddy App that functions as a CrowdSec bouncer. It acts\nas a CrowdSec API client as well as a local cache for CrowdSec decisions,\nwhich can be used by the HTTP handler and Layer4 matcher to decide if\na request or connection is allowed or not.", "package": "github.com/hslatman/caddy-crowdsec-bouncer/crowdsec", "repo": "https://github.com/hslatman/caddy-crowdsec-bouncer" }, { "name": "dynamic_dns", "docs": "dynamic_dns is a Caddy app that keeps your DNS records updated with the public\nIP address of your instance. It updates A and AAAA records.", "package": "github.com/mholt/caddy-dynamicdns", "repo": "https://github.com/mholt/caddy-dynamicdns" }, { "name": "layer4", "docs": "layer4 is a Caddy app that operates closest to layer 4 of the OSI model.", "package": "github.com/mholt/caddy-l4/layer4", "repo": "https://github.com/mholt/caddy-l4" } ], "caddy.config_loaders": [ { "name": "http", "docs": "http can load Caddy configs over HTTP(S). It can adapt the config\nbased on the Content-Type header of the HTTP response.", "package": "github.com/caddyserver/caddy/v2/caddyconfig", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders": [ { "name": "console", "docs": "console encodes log entries that are mostly human-readable.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" }, { "name": "filter", "docs": "filter can filter (manipulate) fields on\nlog entries before they are actually encoded by\nan underlying encoder.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" }, { "name": "json", "docs": "json encodes entries as JSON.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" }, { "name": "logfmt", "docs": "logfmt encodes log entries as logfmt:\nhttps://www.brandur.org/logfmt\n\nNote that logfmt does not encode nested structures\nproperly, so it is not a good fit for most logs.\n\n⚠️ DEPRECATED. Do not use. It will eventually be removed\nfrom the standard Caddy modules. For more information,\nsee https://github.com/caddyserver/caddy/issues/3575.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" }, { "name": "single_field", "docs": "single_field writes a log entry that consists entirely\nof a single string field in the log entry. This is useful\nfor custom, self-encoded log entries that consist of a\nsingle field in the structured log entry.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" }, { "name": "formatted", "docs": "formatted allows the user to provide custom template for log prints. The\nencoder builds atop the json encoder, thus it follows its message structure. The placeholders\nare namespaced by the name of the app logging the message.", "package": "github.com/caddyserver/format-encoder", "repo": "https://github.com/caddyserver/format-encoder" } ], "caddy.logging.writers": [ { "name": "discard", "docs": "discard discards all writes.", "package": "github.com/caddyserver/caddy/v2", "repo": "https://github.com/caddyserver/caddy" }, { "name": "stderr", "docs": "stderr writes logs to standard error.", "package": "github.com/caddyserver/caddy/v2", "repo": "https://github.com/caddyserver/caddy" }, { "name": "stdout", "docs": "stdout writes logs to standard out.", "package": "github.com/caddyserver/caddy/v2", "repo": "https://github.com/caddyserver/caddy" }, { "name": "file", "docs": "file can write logs to files. By default, log files\nare rotated (\"rolled\") when they get large, and old log\nfiles get deleted, to ensure that the process does not\nexhaust disk space.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" }, { "name": "net", "docs": "net implements a log writer that outputs to a network socket. If\nthe socket goes down, it will dump logs to stderr while it attempts to\nreconnect.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.storage": [ { "name": "file_system", "docs": "file_system is a certmagic.Storage wrapper for certmagic.FileStorage.", "package": "github.com/caddyserver/caddy/v2/modules/filestorage", "repo": "https://github.com/caddyserver/caddy" }, { "name": "redis", "docs": "redis contain Redis client, and plugin option", "package": "github.com/gamalan/caddy-tlsredis", "repo": "https://github.com/gamalan/caddy-tlsredis" }, { "name": "consul", "docs": "consul allows to store certificates and other TLS resources\nin a shared cluster environment using Consul's key/value-store.\nIt uses distributed locks to ensure consistency.", "package": "github.com/pteich/caddy-tlsconsul", "repo": "https://github.com/pteich/caddy-tlsconsul" }, { "name": "consul", "docs": "consul holds all parameters for the Consul connection", "package": "github.com/pteich/caddy-tlsconsul", "repo": "https://github.com/pteich/caddy-tlsconsul" }, { "name": "dynamodb", "docs": "dynamodb implements certmagic.Storage to facilitate\nstorage of certificates in DynamoDB for a clustered environment.\nAlso implements certmagic.Locker to facilitate locking\nand unlocking of cert data during storage", "package": "github.com/silinternational/certmagic-storage-dynamodb/v2", "repo": "https://github.com/silinternational/certmagic-storage-dynamodb" }, { "name": "s3", "package": "github.com/ss098/certmagic-s3", "repo": "https://github.com/ss098/certmagic-s3" }, { "name": "s3", "package": "github.com/techknowlogick/certmagic-s3", "repo": "https://github.com/techknowlogick/certmagic-s3" } ], "tls.issuance": [ { "name": "acme", "docs": "acme manages certificates using the ACME protocol (RFC 8555).", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" }, { "name": "internal", "docs": "internal is a certificate issuer that generates\ncertificates internally using a locally-configured\nCA which can be customized using the `pki` app.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" }, { "name": "zerossl", "docs": "zerossl makes an ACME manager\nfor managing certificates using ACME.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ] }, "breadcrumb": { "": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.Config", "struct_fields": [ { "key": "admin", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.AdminConfig", "struct_fields": [ { "key": "disabled", "value": { "type": "bool", "doc": "If true, the admin endpoint will be completely disabled.\nNote that this makes any runtime changes to the config\nimpossible, since the interface to do so is through the\nadmin endpoint." }, "doc": "If true, the admin endpoint will be completely disabled.\nNote that this makes any runtime changes to the config\nimpossible, since the interface to do so is through the\nadmin endpoint." }, { "key": "listen", "value": { "type": "string", "doc": "The address to which the admin endpoint's listener should\nbind itself. Can be any single network address that can be\nparsed by Caddy. Default: localhost:2019" }, "doc": "The address to which the admin endpoint's listener should\nbind itself. Can be any single network address that can be\nparsed by Caddy. Default: localhost:2019" }, { "key": "enforce_origin", "value": { "type": "bool", "doc": "If true, CORS headers will be emitted, and requests to the\nAPI will be rejected if their `Host` and `Origin` headers\ndo not match the expected value(s). Use `origins` to\ncustomize which origins/hosts are allowed. If `origins` is\nnot set, the listen address is the only value allowed by\ndefault. Enforced only on local (plaintext) endpoint." }, "doc": "If true, CORS headers will be emitted, and requests to the\nAPI will be rejected if their `Host` and `Origin` headers\ndo not match the expected value(s). Use `origins` to\ncustomize which origins/hosts are allowed. If `origins` is\nnot set, the listen address is the only value allowed by\ndefault. Enforced only on local (plaintext) endpoint." }, { "key": "origins", "value": { "type": "array", "elems": { "type": "string", "doc": "The list of allowed origins/hosts for API requests. Only needed\nif accessing the admin endpoint from a host different from the\nsocket's network interface or if `enforce_origin` is true. If not\nset, the listener address will be the default value. If set but\nempty, no origins will be allowed. Enforced only on local\n(plaintext) endpoint." } }, "doc": "The list of allowed origins/hosts for API requests. Only needed\nif accessing the admin endpoint from a host different from the\nsocket's network interface or if `enforce_origin` is true. If not\nset, the listener address will be the default value. If set but\nempty, no origins will be allowed. Enforced only on local\n(plaintext) endpoint." }, { "key": "config", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.ConfigSettings", "struct_fields": [ { "key": "persist", "value": { "type": "bool", "doc": "Whether to keep a copy of the active config on disk. Default is true.\nNote that \"pulled\" dynamic configs (using the neighboring \"load\" module)\nare not persisted; only configs that are pushed to Caddy get persisted." }, "doc": "Whether to keep a copy of the active config on disk. Default is true.\nNote that \"pulled\" dynamic configs (using the neighboring \"load\" module)\nare not persisted; only configs that are pushed to Caddy get persisted." }, { "key": "load", "value": { "type": "module", "doc": "Loads a configuration to use. This is helpful if your configs are\nmanaged elsewhere, and you want Caddy to pull its config dynamically\nwhen it starts. The pulled config completely replaces the current\none, just like any other config load. It is an error if a pulled\nconfig is configured to pull another config.\n\nEXPERIMENTAL: Subject to change.", "module_namespace": "caddy.config_loaders", "module_inline_key": "module" }, "doc": "Loads a configuration to use. This is helpful if your configs are\nmanaged elsewhere, and you want Caddy to pull its config dynamically\nwhen it starts. The pulled config completely replaces the current\none, just like any other config load. It is an error if a pulled\nconfig is configured to pull another config.\n\nEXPERIMENTAL: Subject to change." } ], "doc": "Options pertaining to configuration management.\n\n\nConfigSettings configures the management of configuration." }, "doc": "Options pertaining to configuration management.\n\n\nConfigSettings configures the management of configuration." }, { "key": "identity", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.IdentityConfig", "struct_fields": [ { "key": "identifiers", "value": { "type": "array", "elems": { "type": "string", "doc": "List of names or IP addresses which refer to this server.\nCertificates will be obtained for these identifiers so\nsecure TLS connections can be made using them." } }, "doc": "List of names or IP addresses which refer to this server.\nCertificates will be obtained for these identifiers so\nsecure TLS connections can be made using them." }, { "key": "issuers", "value": { "type": "array", "elems": { "type": "module", "doc": "Issuers that can provide this admin endpoint its identity\ncertificate(s). Default: ACME issuers configured for\nZeroSSL and Let's Encrypt. Be sure to change this if you\nrequire credentials for private identifiers.", "module_namespace": "tls.issuance", "module_inline_key": "module" } }, "doc": "Issuers that can provide this admin endpoint its identity\ncertificate(s). Default: ACME issuers configured for\nZeroSSL and Let's Encrypt. Be sure to change this if you\nrequire credentials for private identifiers." } ], "doc": "Options that establish this server's identity. Identity refers to\ncredentials which can be used to uniquely identify and authenticate\nthis server instance. This is required if remote administration is\nenabled (but does not require remote administration to be enabled).\nDefault: no identity management.\n\n\nIdentityConfig configures management of this server's identity. An identity\nconsists of credentials that uniquely verify this instance; for example,\nTLS certificates (public + private key pairs)." }, "doc": "Options that establish this server's identity. Identity refers to\ncredentials which can be used to uniquely identify and authenticate\nthis server instance. This is required if remote administration is\nenabled (but does not require remote administration to be enabled).\nDefault: no identity management.\n\n\nIdentityConfig configures management of this server's identity. An identity\nconsists of credentials that uniquely verify this instance; for example,\nTLS certificates (public + private key pairs)." }, { "key": "remote", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.RemoteAdmin", "struct_fields": [ { "key": "listen", "value": { "type": "string", "doc": "The address on which to start the secure listener.\nDefault: :2021" }, "doc": "The address on which to start the secure listener.\nDefault: :2021" }, { "key": "access_control", "value": { "type": "array", "elems": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.AdminAccess", "struct_fields": [ { "key": "public_keys", "value": { "type": "array", "elems": { "type": "string", "doc": "Base64-encoded DER certificates containing public keys to accept.\n(The contents of PEM certificate blocks are base64-encoded DER.)\nAny of these public keys can appear in any part of a verified chain." } }, "doc": "Base64-encoded DER certificates containing public keys to accept.\n(The contents of PEM certificate blocks are base64-encoded DER.)\nAny of these public keys can appear in any part of a verified chain." }, { "key": "permissions", "value": { "type": "array", "elems": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.AdminPermissions", "struct_fields": [ { "key": "paths", "value": { "type": "array", "elems": { "type": "string", "doc": "The API paths allowed. Paths are simple prefix matches.\nAny subpath of the specified paths will be allowed." } }, "doc": "The API paths allowed. Paths are simple prefix matches.\nAny subpath of the specified paths will be allowed." }, { "key": "methods", "value": { "type": "array", "elems": { "type": "string", "doc": "The HTTP methods allowed for the given paths." } }, "doc": "The HTTP methods allowed for the given paths." } ], "doc": "Limits what the associated identities are allowed to do.\nIf unspecified, all permissions are granted.\n\n\nAdminPermissions specifies what kinds of requests are allowed\nto be made to the admin endpoint." } }, "doc": "Limits what the associated identities are allowed to do.\nIf unspecified, all permissions are granted.\n\n\nAdminPermissions specifies what kinds of requests are allowed\nto be made to the admin endpoint." } ], "doc": "List of access controls for this secure admin endpoint.\nThis configures TLS mutual authentication (i.e. authorized\nclient certificates), but also application-layer permissions\nlike which paths and methods each identity is authorized for.\n\n\nAdminAccess specifies what permissions an identity or group\nof identities are granted." } }, "doc": "List of access controls for this secure admin endpoint.\nThis configures TLS mutual authentication (i.e. authorized\nclient certificates), but also application-layer permissions\nlike which paths and methods each identity is authorized for.\n\n\nAdminAccess specifies what permissions an identity or group\nof identities are granted." } ], "doc": "Options pertaining to remote administration. By default, remote\nadministration is disabled. If enabled, identity management must\nalso be configured, as that is how the endpoint is secured.\nSee the neighboring \"identity\" object.\n\nEXPERIMENTAL: This feature is subject to change.\n\n\nRemoteAdmin enables and configures remote administration. If enabled,\na secure listener enforcing mutual TLS authentication will be started\non a different port from the standard plaintext admin server.\n\nThis endpoint is secured using identity management, which must be\nconfigured separately (because identity management does not depend\non remote administration). See the admin/identity config struct.\n\nEXPERIMENTAL: Subject to change." }, "doc": "Options pertaining to remote administration. By default, remote\nadministration is disabled. If enabled, identity management must\nalso be configured, as that is how the endpoint is secured.\nSee the neighboring \"identity\" object.\n\nEXPERIMENTAL: This feature is subject to change.\n\n\nRemoteAdmin enables and configures remote administration. If enabled,\na secure listener enforcing mutual TLS authentication will be started\non a different port from the standard plaintext admin server.\n\nThis endpoint is secured using identity management, which must be\nconfigured separately (because identity management does not depend\non remote administration). See the admin/identity config struct.\n\nEXPERIMENTAL: Subject to change." } ], "doc": "AdminConfig configures Caddy's API endpoint, which is used\nto manage Caddy while it is running.\n" }, "doc": "AdminConfig configures Caddy's API endpoint, which is used\nto manage Caddy while it is running.\n" }, { "key": "logging", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.Logging", "struct_fields": [ { "key": "sink", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.StandardLibLog", "struct_fields": [ { "key": "writer", "value": { "type": "module", "doc": "The module that writes out log entries for the sink.", "module_namespace": "caddy.logging.writers", "module_inline_key": "output" }, "doc": "The module that writes out log entries for the sink." } ], "doc": "Sink is the destination for all unstructured logs emitted\nfrom Go's standard library logger. These logs are common\nin dependencies that are not designed specifically for use\nin Caddy. Because it is global and unstructured, the sink\nlacks most advanced features and customizations.\n\n\nStandardLibLog configures the default Go standard library\nglobal logger in the log package. This is necessary because\nmodule dependencies which are not built specifically for\nCaddy will use the standard logger. This is also known as\nthe \"sink\" logger." }, "doc": "Sink is the destination for all unstructured logs emitted\nfrom Go's standard library logger. These logs are common\nin dependencies that are not designed specifically for use\nin Caddy. Because it is global and unstructured, the sink\nlacks most advanced features and customizations.\n\n\nStandardLibLog configures the default Go standard library\nglobal logger in the log package. This is necessary because\nmodule dependencies which are not built specifically for\nCaddy will use the standard logger. This is also known as\nthe \"sink\" logger." }, { "key": "logs", "value": { "type": "map", "map_keys": { "type": "string" }, "elems": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.CustomLog", "struct_fields": [ { "key": "writer", "value": { "type": "module", "doc": "The writer defines where log entries are emitted.", "module_namespace": "caddy.logging.writers", "module_inline_key": "output" }, "doc": "The writer defines where log entries are emitted." }, { "key": "encoder", "value": { "type": "module", "doc": "The encoder is how the log entries are formatted or encoded.", "module_namespace": "caddy.logging.encoders", "module_inline_key": "format" }, "doc": "The encoder is how the log entries are formatted or encoded." }, { "key": "level", "value": { "type": "string", "doc": "Level is the minimum level to emit, and is inclusive.\nPossible levels: DEBUG, INFO, WARN, ERROR, PANIC, and FATAL" }, "doc": "Level is the minimum level to emit, and is inclusive.\nPossible levels: DEBUG, INFO, WARN, ERROR, PANIC, and FATAL" }, { "key": "sampling", "value": { "type": "struct", "type_name": "github.com/caddyserver/caddy/v2.LogSampling", "struct_fields": [ { "key": "interval", "value": { "type": "int", "type_name": "time.Duration", "doc": "The window over which to conduct sampling.\n\n\nA Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years." }, "doc": "The window over which to conduct sampling.\n\n\nA Duration represents the elapsed time between two instants\nas an int64 nanosecond count. The representation limits the\nlargest representable duration to approximately 290 years." }, { "key": "first", "value": { "type": "int", "doc": "Log this many entries within a given level and\nmessage for each interval." }, "doc": "Log this many entries within a given level and\nmessage for each interval." }, { "key": "thereafter", "value": { "type": "int", "doc": "If more entries with the same level and message\nare seen during the same interval, keep one in\nthis many entries until the end of the interval." }, "doc": "If more entries with the same level and message\nare seen during the same interval, keep one in\nthis many entries until the end of the interval." } ], "doc": "Sampling configures log entry sampling. If enabled,\nonly some log entries will be emitted. This is useful\nfor improving performance on extremely high-pressure\nservers.\n\n\nLogSampling configures log entry sampling." }, "doc": "Sampling configures log entry sampling. If enabled,\nonly some log entries will be emitted. This is useful\nfor improving performance on extremely high-pressure\nservers.\n\n\nLogSampling configures log entry sampling." }, { "key": "include", "value": { "type": "array", "elems": { "type": "string", "doc": "Include defines the names of loggers to emit in this\nlog. For example, to include only logs emitted by the\nadmin API, you would include \"admin.api\"." } }, "doc": "Include defines the names of loggers to emit in this\nlog. For example, to include only logs emitted by the\nadmin API, you would include \"admin.api\"." }, { "key": "exclude", "value": { "type": "array", "elems": { "type": "string", "doc": "Exclude defines the names of loggers that should be\nskipped by this log. For example, to exclude only\nHTTP access logs, you would exclude \"http.log.access\"." } }, "doc": "Exclude defines the names of loggers that should be\nskipped by this log. For example, to exclude only\nHTTP access logs, you would exclude \"http.log.access\"." } ], "doc": "Logs are your logs, keyed by an arbitrary name of your\nchoosing. The default log can be customized by defining\na log called \"default\". You can further define other logs\nand filter what kinds of entries they accept.\n\n\nCustomLog represents a custom logger configuration.\n\nBy default, a log will emit all log entries. Some entries\nwill be skipped if sampling is enabled. Further, the Include\nand Exclude parameters define which loggers (by name) are\nallowed or rejected from emitting in this log. If both Include\nand Exclude are populated, their values must be mutually\nexclusive, and longer namespaces have priority. If neither\nare populated, all logs are emitted." } }, "doc": "Logs are your logs, keyed by an arbitrary name of your\nchoosing. The default log can be customized by defining\na log called \"default\". You can further define other logs\nand filter what kinds of entries they accept.\n\n\nCustomLog represents a custom logger configuration.\n\nBy default, a log will emit all log entries. Some entries\nwill be skipped if sampling is enabled. Further, the Include\nand Exclude parameters define which loggers (by name) are\nallowed or rejected from emitting in this log. If both Include\nand Exclude are populated, their values must be mutually\nexclusive, and longer namespaces have priority. If neither\nare populated, all logs are emitted." } ], "doc": "Logging facilitates logging within Caddy. The default log is\ncalled \"default\" and you can customize it. You can also define\nadditional logs.\n\nBy default, all logs at INFO level and higher are written to\nstandard error (\"stderr\" writer) in a human-readable format\n(\"console\" encoder if stdout is an interactive terminal, \"json\"\nencoder otherwise).\n\nAll defined logs accept all log entries by default, but you\ncan filter by level and module/logger names. A logger's name\nis the same as the module's name, but a module may append to\nlogger names for more specificity. For example, you can\nfilter logs emitted only by HTTP handlers using the name\n\"http.handlers\", because all HTTP handler module names have\nthat prefix.\n\nCaddy logs (except the sink) are zero-allocation, so they are\nvery high-performing in terms of memory and CPU time. Enabling\nsampling can further increase throughput on extremely high-load\nservers.\n" }, "doc": "Logging facilitates logging within Caddy. The default log is\ncalled \"default\" and you can customize it. You can also define\nadditional logs.\n\nBy default, all logs at INFO level and higher are written to\nstandard error (\"stderr\" writer) in a human-readable format\n(\"console\" encoder if stdout is an interactive terminal, \"json\"\nencoder otherwise).\n\nAll defined logs accept all log entries by default, but you\ncan filter by level and module/logger names. A logger's name\nis the same as the module's name, but a module may append to\nlogger names for more specificity. For example, you can\nfilter logs emitted only by HTTP handlers using the name\n\"http.handlers\", because all HTTP handler module names have\nthat prefix.\n\nCaddy logs (except the sink) are zero-allocation, so they are\nvery high-performing in terms of memory and CPU time. Enabling\nsampling can further increase throughput on extremely high-load\nservers.\n" }, { "key": "storage", "value": { "type": "module", "doc": "StorageRaw is a storage module that defines how/where Caddy\nstores assets (such as TLS certificates). The default storage\nmodule is `caddy.storage.file_system` (the local file system),\nand the default path\n[depends on the OS and environment](/docs/conventions#data-directory).", "module_namespace": "caddy.storage", "module_inline_key": "module" }, "doc": "StorageRaw is a storage module that defines how/where Caddy\nstores assets (such as TLS certificates). The default storage\nmodule is `caddy.storage.file_system` (the local file system),\nand the default path\n[depends on the OS and environment](/docs/conventions#data-directory)." }, { "key": "apps", "value": { "type": "module_map", "type_name": "github.com/caddyserver/caddy/v2.ModuleMap", "doc": "AppsRaw are the apps that Caddy will load and run. The\napp module name is the key, and the app's config is the\nassociated value.\n\n\nModuleMap is a map that can contain multiple modules,\nwhere the map key is the module's name. (The namespace\nis usually read from an associated field's struct tag.)\nBecause the module's name is given as the key in a\nmodule map, the name does not have to be given in the\njson.RawMessage.", "module_namespace": "" }, "doc": "AppsRaw are the apps that Caddy will load and run. The\napp module name is the key, and the app's config is the\nassociated value.\n\n\nModuleMap is a map that can contain multiple modules,\nwhere the map key is the module's name. (The namespace\nis usually read from an associated field's struct tag.)\nBecause the module's name is given as the key in a\nmodule map, the name does not have to be given in the\njson.RawMessage." } ], "doc": "Config is the top (or beginning) of the Caddy configuration structure.\nCaddy config is expressed natively as a JSON document. If you prefer\nnot to work with JSON directly, there are [many config adapters](/docs/config-adapters)\navailable that can convert various inputs into Caddy JSON.\n\nMany parts of this config are extensible through the use of Caddy modules.\nFields which have a json.RawMessage type and which appear as dots (•••) in\nthe online docs can be fulfilled by modules in a certain module\nnamespace. The docs show which modules can be used in a given place.\n\nWhenever a module is used, its name must be given either inline as part of\nthe module, or as the key to the module's value. The docs will make it clear\nwhich to use.\n\nGenerally, all config settings are optional, as it is Caddy convention to\nhave good, documented default values. If a parameter is required, the docs\nshould say so.\n\nGo programs which are directly building a Config struct value should take\ncare to populate the JSON-encodable fields of the struct (i.e. the fields\nwith `json` struct tags) if employing the module lifecycle (e.g. Provision\nmethod calls).\n" } }, "repo": "https://github.com/caddyserver/caddy" } } ================================================ FILE: src/api/modules/index.json ================================================ { "status_code": 200, "result": { "admin.api.load": [ { "name": "admin.api.load", "docs": "admin.api.load is a module that provides the /load endpoint\nfor the Caddy admin API. The only reason it's not baked\ninto the caddy package directly is because of the import\nof the caddyconfig package for its GetAdapter function.\nIf the caddy package depends on the caddyconfig package,\nthen the caddyconfig package will not be able to import\nthe caddy package, and it can more easily cause backward\nedges in the dependency tree (i.e. import cycle).\nFortunately, the admin API has first-class support for\nadding endpoints from modules.", "package": "github.com/caddyserver/caddy/v2/caddyconfig", "repo": "https://github.com/caddyserver/caddy" } ], "admin.api.metrics": [ { "name": "admin.api.metrics", "docs": "admin.api.metrics is a module that serves a metrics endpoint so that any gathered\nmetrics can be exposed for scraping. This module is not configurable, and\nis permanently mounted to the admin API endpoint at \"/metrics\".\nSee the Metrics module for a configurable endpoint that is usable if the\nAdmin API is disabled.", "package": "github.com/caddyserver/caddy/v2/modules/metrics", "repo": "https://github.com/caddyserver/caddy" } ], "admin.api.reverse_proxy": [ { "name": "admin.api.reverse_proxy", "docs": "admin.api.reverse_proxy is a module that provides the\n/reverse_proxy/upstreams endpoint for the Caddy admin\nAPI. This allows for checking the health of configured\nreverse proxy upstreams in the pool.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.config_loaders.http": [ { "name": "caddy.config_loaders.http", "docs": "caddy.config_loaders.http can load Caddy configs over HTTP(S). It can adapt the config\nbased on the Content-Type header of the HTTP response.", "package": "github.com/caddyserver/caddy/v2/caddyconfig", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.listeners.proxy_protocol": [ { "name": "caddy.listeners.proxy_protocol", "package": "github.com/mastercactapus/caddy2-proxyprotocol", "repo": "https://github.com/mastercactapus/caddy2-proxyprotocol" } ], "caddy.listeners.tls": [ { "name": "caddy.listeners.tls", "docs": "caddy.listeners.tls is a no-op listener wrapper that marks\nwhere the TLS listener should be in a chain of listener wrappers.\nIt should only be used if another listener wrapper must be placed\nin front of the TLS handshake.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders.console": [ { "name": "caddy.logging.encoders.console", "docs": "caddy.logging.encoders.console encodes log entries that are mostly human-readable.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders.filter": [ { "name": "caddy.logging.encoders.filter", "docs": "caddy.logging.encoders.filter can filter (manipulate) fields on\nlog entries before they are actually encoded by\nan underlying encoder.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders.filter.basic_auth_user": [ { "name": "caddy.logging.encoders.filter.basic_auth_user", "docs": "caddy.logging.encoders.filter.basic_auth_user is a Caddy log field filter that replaces the a base64 encoded authorization\nheader with just the user name.", "package": "github.com/ueffel/caddy-basic-auth-filter", "repo": "https://github.com/ueffel/caddy-basic-auth-filter" } ], "caddy.logging.encoders.filter.delete": [ { "name": "caddy.logging.encoders.filter.delete", "docs": "caddy.logging.encoders.filter.delete is a Caddy log field filter that\ndeletes the field.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders.filter.ip_mask": [ { "name": "caddy.logging.encoders.filter.ip_mask", "docs": "caddy.logging.encoders.filter.ip_mask is a Caddy log field filter that\nmasks IP addresses.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders.filter.replace": [ { "name": "caddy.logging.encoders.filter.replace", "docs": "caddy.logging.encoders.filter.replace is a Caddy log field filter that\nreplaces the field with the indicated string.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders.filter.tls_cipher": [ { "name": "caddy.logging.encoders.filter.tls_cipher", "docs": "caddy.logging.encoders.filter.tls_cipher is Caddy log field filter that replaces the numeric TLS cipher_suite value with\nthe string representation.", "package": "github.com/ueffel/caddy-tls-format", "repo": "https://github.com/ueffel/caddy-tls-format" } ], "caddy.logging.encoders.filter.tls_version": [ { "name": "caddy.logging.encoders.filter.tls_version", "docs": "caddy.logging.encoders.filter.tls_version is a Caddy log field filter that replaces the numeric TLS version with the\nstring version and optionally adds a prefix.", "package": "github.com/ueffel/caddy-tls-format", "repo": "https://github.com/ueffel/caddy-tls-format" } ], "caddy.logging.encoders.formatted": [ { "name": "caddy.logging.encoders.formatted", "docs": "caddy.logging.encoders.formatted allows the user to provide custom template for log prints. The\nencoder builds atop the json encoder, thus it follows its message structure. The placeholders\nare namespaced by the name of the app logging the message.", "package": "github.com/caddyserver/format-encoder", "repo": "https://github.com/caddyserver/format-encoder" } ], "caddy.logging.encoders.json": [ { "name": "caddy.logging.encoders.json", "docs": "caddy.logging.encoders.json encodes entries as JSON.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders.logfmt": [ { "name": "caddy.logging.encoders.logfmt", "docs": "caddy.logging.encoders.logfmt encodes log entries as logfmt:\nhttps://www.brandur.org/logfmt\n\nNote that logfmt does not encode nested structures\nproperly, so it is not a good fit for most logs.\n\n⚠️ DEPRECATED. Do not use. It will eventually be removed\nfrom the standard Caddy modules. For more information,\nsee https://github.com/caddyserver/caddy/issues/3575.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.encoders.single_field": [ { "name": "caddy.logging.encoders.single_field", "docs": "caddy.logging.encoders.single_field writes a log entry that consists entirely\nof a single string field in the log entry. This is useful\nfor custom, self-encoded log entries that consist of a\nsingle field in the structured log entry.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.writers.discard": [ { "name": "caddy.logging.writers.discard", "docs": "caddy.logging.writers.discard discards all writes.", "package": "github.com/caddyserver/caddy/v2", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.writers.file": [ { "name": "caddy.logging.writers.file", "docs": "caddy.logging.writers.file can write logs to files. By default, log files\nare rotated (\"rolled\") when they get large, and old log\nfiles get deleted, to ensure that the process does not\nexhaust disk space.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.writers.net": [ { "name": "caddy.logging.writers.net", "docs": "caddy.logging.writers.net implements a log writer that outputs to a network socket. If\nthe socket goes down, it will dump logs to stderr while it attempts to\nreconnect.", "package": "github.com/caddyserver/caddy/v2/modules/logging", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.writers.stderr": [ { "name": "caddy.logging.writers.stderr", "docs": "caddy.logging.writers.stderr writes logs to standard error.", "package": "github.com/caddyserver/caddy/v2", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.logging.writers.stdout": [ { "name": "caddy.logging.writers.stdout", "docs": "caddy.logging.writers.stdout writes logs to standard out.", "package": "github.com/caddyserver/caddy/v2", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.storage.consul": [ { "name": "caddy.storage.consul", "docs": "caddy.storage.consul allows to store certificates and other TLS resources\nin a shared cluster environment using Consul's key/value-store.\nIt uses distributed locks to ensure consistency.", "package": "github.com/pteich/caddy-tlsconsul", "repo": "https://github.com/pteich/caddy-tlsconsul" }, { "name": "caddy.storage.consul", "docs": "caddy.storage.consul holds all parameters for the Consul connection", "package": "github.com/pteich/caddy-tlsconsul", "repo": "https://github.com/pteich/caddy-tlsconsul" } ], "caddy.storage.dynamodb": [ { "name": "caddy.storage.dynamodb", "docs": "caddy.storage.dynamodb implements certmagic.Storage to facilitate\nstorage of certificates in DynamoDB for a clustered environment.\nAlso implements certmagic.Locker to facilitate locking\nand unlocking of cert data during storage", "package": "github.com/silinternational/certmagic-storage-dynamodb/v2", "repo": "https://github.com/silinternational/certmagic-storage-dynamodb" } ], "caddy.storage.file_system": [ { "name": "caddy.storage.file_system", "docs": "caddy.storage.file_system is a certmagic.Storage wrapper for certmagic.FileStorage.", "package": "github.com/caddyserver/caddy/v2/modules/filestorage", "repo": "https://github.com/caddyserver/caddy" } ], "caddy.storage.redis": [ { "name": "caddy.storage.redis", "docs": "caddy.storage.redis contain Redis client, and plugin option", "package": "github.com/gamalan/caddy-tlsredis", "repo": "https://github.com/gamalan/caddy-tlsredis" } ], "caddy.storage.s3": [ { "name": "caddy.storage.s3", "package": "github.com/ss098/certmagic-s3", "repo": "https://github.com/ss098/certmagic-s3" }, { "name": "caddy.storage.s3", "package": "github.com/techknowlogick/certmagic-s3", "repo": "https://github.com/techknowlogick/certmagic-s3" } ], "crowdsec": [ { "name": "crowdsec", "docs": "crowdsec is a Caddy App that functions as a CrowdSec bouncer. It acts\nas a CrowdSec API client as well as a local cache for CrowdSec decisions,\nwhich can be used by the HTTP handler and Layer4 matcher to decide if\na request or connection is allowed or not.", "package": "github.com/hslatman/caddy-crowdsec-bouncer/crowdsec", "repo": "https://github.com/hslatman/caddy-crowdsec-bouncer" } ], "dns.providers.alidns": [ { "name": "dns.providers.alidns", "docs": "dns.providers.alidns wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/alidns", "repo": "https://github.com/caddy-dns/alidns" } ], "dns.providers.azure": [ { "name": "dns.providers.azure", "docs": "dns.providers.azure wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/azure", "repo": "https://github.com/caddy-dns/azure" } ], "dns.providers.cloudflare": [ { "name": "dns.providers.cloudflare", "docs": "dns.providers.cloudflare wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/cloudflare", "repo": "https://github.com/caddy-dns/cloudflare" } ], "dns.providers.digitalocean": [ { "name": "dns.providers.digitalocean", "docs": "dns.providers.digitalocean wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/digitalocean", "repo": "https://github.com/caddy-dns/digitalocean" } ], "dns.providers.dnspod": [ { "name": "dns.providers.dnspod", "docs": "dns.providers.dnspod wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/dnspod", "repo": "https://github.com/caddy-dns/dnspod" } ], "dns.providers.duckdns": [ { "name": "dns.providers.duckdns", "docs": "dns.providers.duckdns wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/duckdns", "repo": "https://github.com/caddy-dns/duckdns" } ], "dns.providers.gandi": [ { "name": "dns.providers.gandi", "docs": "dns.providers.gandi wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/gandi", "repo": "https://github.com/caddy-dns/gandi" } ], "dns.providers.godaddy": [ { "name": "dns.providers.godaddy", "docs": "dns.providers.godaddy wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/godaddy", "repo": "https://github.com/caddy-dns/godaddy" } ], "dns.providers.googleclouddns": [ { "name": "dns.providers.googleclouddns", "docs": "dns.providers.googleclouddns lets Caddy read and manipulate DNS records hosted by this DNS provider.", "package": "github.com/caddy-dns/googleclouddns", "repo": "https://github.com/caddy-dns/googleclouddns" } ], "dns.providers.hetzner": [ { "name": "dns.providers.hetzner", "docs": "dns.providers.hetzner wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/hetzner", "repo": "https://github.com/caddy-dns/hetzner" } ], "dns.providers.lego_deprecated": [ { "name": "dns.providers.lego_deprecated", "docs": "dns.providers.lego_deprecated is a shim module that allows any and all of the\nDNS providers in go-acme/lego to be used with Caddy. They must\nbe configured via environment variables, they do not support\ncancellation in the case of frequent config changes.\n\nEven though this module is in the dns.providers namespace, it\nis only a special case for solving ACME challenges, intended to\nreplace the modules that used to be in the now-defunct tls.dns\nnamespace. Using it in other places of the Caddy config will\nresult in errors.\n\nThis module will eventually go away in favor of the modules that\nmake use of the libdns APIs: https://github.com/libdns", "package": "github.com/caddy-dns/lego-deprecated", "repo": "https://github.com/caddy-dns/lego-deprecated" } ], "dns.providers.netcup": [ { "name": "dns.providers.netcup", "docs": "dns.providers.netcup lets Caddy read and manipulate DNS records hosted by this DNS provider.", "package": "github.com/caddy-dns/netcup", "repo": "https://github.com/caddy-dns/netcup" } ], "dns.providers.openstack-designate": [ { "name": "dns.providers.openstack-designate", "docs": "dns.providers.openstack-designate wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/openstack-designate", "repo": "https://github.com/caddy-dns/openstack-designate" } ], "dns.providers.route53": [ { "name": "dns.providers.route53", "docs": "dns.providers.route53 wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/route53", "repo": "https://github.com/caddy-dns/route53" } ], "dns.providers.vultr": [ { "name": "dns.providers.vultr", "docs": "dns.providers.vultr wraps the provider implementation as a Caddy module.", "package": "github.com/caddy-dns/vultr", "repo": "https://github.com/caddy-dns/vultr" } ], "dynamic_dns": [ { "name": "dynamic_dns", "docs": "dynamic_dns is a Caddy app that keeps your DNS records updated with the public\nIP address of your instance. It updates A and AAAA records.", "package": "github.com/mholt/caddy-dynamicdns", "repo": "https://github.com/mholt/caddy-dynamicdns" } ], "dynamic_dns.ip_sources.simple_http": [ { "name": "dynamic_dns.ip_sources.simple_http", "docs": "dynamic_dns.ip_sources.simple_http is an IP source that looks up the public IP addresses by\nmaking HTTP(S) requests to the specified endpoints; it will try each\nendpoint with IPv4 and IPv6 until at least one returns a valid value.\nIt is OK if an endpoint doesn't support both IP versions; returning\na single valid IP address is sufficient.\n\nThe endpoints must return HTTP status 200 and the response body must\ncontain only the IP address in plain text.", "package": "github.com/mholt/caddy-dynamicdns", "repo": "https://github.com/mholt/caddy-dynamicdns" } ], "dynamic_dns.ip_sources.upnp": [ { "name": "dynamic_dns.ip_sources.upnp", "docs": "dynamic_dns.ip_sources.upnp gets the IP address from UPnP device.", "package": "github.com/mholt/caddy-dynamicdns", "repo": "https://github.com/mholt/caddy-dynamicdns" } ], "exec": [ { "name": "exec", "docs": "exec is top level module that runs shell commands.", "package": "github.com/abiosoft/caddy-exec", "repo": "https://github.com/abiosoft/caddy-exec" } ], "http": [ { "name": "http", "docs": "http is a robust, production-ready HTTP server.\n\nHTTPS is enabled by default if host matchers with qualifying names are used\nin any of routes; certificates are automatically provisioned and renewed.\nAdditionally, automatic HTTPS will also enable HTTPS for servers that listen\nonly on the HTTPS port but which do not have any TLS connection policies\ndefined by adding a good, default TLS connection policy.\n\nIn HTTP routes, additional placeholders are available (replace any `*`):\n\nPlaceholder | Description\n------------|---------------\n`{http.request.body}` | The request body (⚠️ inefficient; use only for debugging)\n`{http.request.cookie.*}` | HTTP request cookie\n`{http.request.duration}` | Time up to now spent handling the request (after decoding headers from client)\n`{http.request.header.*}` | Specific request header field\n`{http.request.host.labels.*}` | Request host labels (0-based from right); e.g. for foo.example.com: 0=com, 1=example, 2=foo\n`{http.request.host}` | The host part of the request's Host header\n`{http.request.hostport}` | The host and port from the request's Host header\n`{http.request.method}` | The request method\n`{http.request.orig_method}` | The request's original method\n`{http.request.orig_uri.path.dir}` | The request's original directory\n`{http.request.orig_uri.path.file}` | The request's original filename\n`{http.request.orig_uri.path}` | The request's original path\n`{http.request.orig_uri.query}` | The request's original query string (without `?`)\n`{http.request.orig_uri}` | The request's original URI\n`{http.request.port}` | The port part of the request's Host header\n`{http.request.proto}` | The protocol of the request\n`{http.request.remote.host}` | The host part of the remote client's address\n`{http.request.remote.port}` | The port part of the remote client's address\n`{http.request.remote}` | The address of the remote client\n`{http.request.scheme}` | The request scheme\n`{http.request.tls.version}` | The TLS version name\n`{http.request.tls.cipher_suite}` | The TLS cipher suite\n`{http.request.tls.resumed}` | The TLS connection resumed a previous connection\n`{http.request.tls.proto}` | The negotiated next protocol\n`{http.request.tls.proto_mutual}` | The negotiated next protocol was advertised by the server\n`{http.request.tls.server_name}` | The server name requested by the client, if any\n`{http.request.tls.client.fingerprint}` | The SHA256 checksum of the client certificate\n`{http.request.tls.client.public_key}` | The public key of the client certificate.\n`{http.request.tls.client.public_key_sha256}` | The SHA256 checksum of the client's public key.\n`{http.request.tls.client.certificate_pem}` | The PEM-encoded value of the certificate.\n`{http.request.tls.client.certificate_der_base64}` | The base64-encoded value of the certificate.\n`{http.request.tls.client.issuer}` | The issuer DN of the client certificate\n`{http.request.tls.client.serial}` | The serial number of the client certificate\n`{http.request.tls.client.subject}` | The subject DN of the client certificate\n`{http.request.tls.client.san.dns_names.*}` | SAN DNS names(index optional)\n`{http.request.tls.client.san.emails.*}` | SAN email addresses (index optional)\n`{http.request.tls.client.san.ips.*}` | SAN IP addresses (index optional)\n`{http.request.tls.client.san.uris.*}` | SAN URIs (index optional)\n`{http.request.uri.path.*}` | Parts of the path, split by `/` (0-based from left)\n`{http.request.uri.path.dir}` | The directory, excluding leaf filename\n`{http.request.uri.path.file}` | The filename of the path, excluding directory\n`{http.request.uri.path}` | The path component of the request URI\n`{http.request.uri.query.*}` | Individual query string value\n`{http.request.uri.query}` | The query string (without `?`)\n`{http.request.uri}` | The full request URI\n`{http.response.header.*}` | Specific response header field\n`{http.vars.*}` | Custom variables in the HTTP handler chain", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.authentication.hashes.bcrypt": [ { "name": "http.authentication.hashes.bcrypt", "docs": "http.authentication.hashes.bcrypt implements the bcrypt hash.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/caddyauth", "repo": "https://github.com/caddyserver/caddy" } ], "http.authentication.hashes.scrypt": [ { "name": "http.authentication.hashes.scrypt", "docs": "http.authentication.hashes.scrypt implements the scrypt KDF as a hash.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/caddyauth", "repo": "https://github.com/caddyserver/caddy" } ], "http.authentication.providers.authorize": [ { "name": "http.authentication.providers.authorize", "docs": "http.authentication.providers.authorize authorizes access to endpoints based on\nthe presense and content of JWT token.", "package": "github.com/greenpau/caddy-authorize", "repo": "https://github.com/greenpau/caddy-authorize" } ], "http.authentication.providers.authorizer": [ { "name": "http.authentication.providers.authorizer", "docs": "http.authentication.providers.authorizer authorizes access to endpoints based on\nthe presense and content of JWT token.", "package": "github.com/greenpau/caddy-security", "repo": "https://github.com/greenpau/caddy-security" } ], "http.authentication.providers.forms": [ { "name": "http.authentication.providers.forms", "docs": "http.authentication.providers.forms authorizes access to endpoints based on\nthe credentials provided in a request.", "package": "github.com/greenpau/caddy-auth-forms", "repo": "https://github.com/greenpau/caddy-auth-forms" } ], "http.authentication.providers.http_basic": [ { "name": "http.authentication.providers.http_basic", "docs": "http.authentication.providers.http_basic facilitates HTTP basic authentication.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/caddyauth", "repo": "https://github.com/caddyserver/caddy" } ], "http.authentication.providers.jwt": [ { "name": "http.authentication.providers.jwt", "docs": "http.authentication.providers.jwt facilitates JWT (JSON Web Token) authentication.", "package": "github.com/ggicci/caddy-jwt", "repo": "https://github.com/ggicci/caddy-jwt" }, { "name": "http.authentication.providers.jwt", "docs": "http.authentication.providers.jwt authorizes access to endpoints based on\nthe presense and content of JWT token.", "package": "github.com/greenpau/caddy-auth-jwt", "repo": "https://github.com/greenpau/caddy-auth-jwt" } ], "http.authentication.providers.saml": [ { "name": "http.authentication.providers.saml", "docs": "http.authentication.providers.saml authenticates requests the SAML Response to the SP Assertion\nConsumer Service using the HTTP-POST Binding.", "package": "github.com/greenpau/caddy-auth-saml", "repo": "https://github.com/greenpau/caddy-auth-saml" } ], "http.encoders.br": [ { "name": "http.encoders.br", "docs": "http.encoders.br can create brotli encoders.", "package": "github.com/ueffel/caddy-brotli", "repo": "https://github.com/ueffel/caddy-brotli" } ], "http.encoders.gzip": [ { "name": "http.encoders.gzip", "docs": "http.encoders.gzip can create gzip encoders.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/gzip", "repo": "https://github.com/caddyserver/caddy" } ], "http.encoders.zstd": [ { "name": "http.encoders.zstd", "docs": "http.encoders.zstd can create Zstandard encoders.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/zstd", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.acme_server": [ { "name": "http.handlers.acme_server", "docs": "http.handlers.acme_server is an ACME server handler.", "package": "github.com/caddyserver/caddy/v2/modules/caddypki/acmeserver", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.authelia": [ { "name": "http.handlers.authelia", "docs": "http.handlers.authelia implements a plugin for securing routes with authentication", "package": "github.com/HeavenVolkoff/caddy-authelia/plugin", "repo": "https://github.com/HeavenVolkoff/caddy-authelia" } ], "http.handlers.authentication": [ { "name": "http.handlers.authentication", "docs": "http.handlers.authentication is a middleware which provides user authentication.\nRejects requests with HTTP 401 if the request is not authenticated.\n\nAfter a successful authentication, the placeholder\n`{http.auth.user.id}` will be set to the username, and also\n`{http.auth.user.*}` placeholders may be set for any authentication\nmodules that provide user metadata.\n\nIts API is still experimental and may be subject to change.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/caddyauth", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.authenticator": [ { "name": "http.handlers.authenticator", "docs": "http.handlers.authenticator implements Form-Based, Basic, Local, LDAP,\nOpenID Connect, OAuth 2.0, SAML Authentication.", "package": "github.com/greenpau/caddy-security", "repo": "https://github.com/greenpau/caddy-security" } ], "http.handlers.authp": [ { "name": "http.handlers.authp", "docs": "http.handlers.authp implements Form-Based, Basic, Local, LDAP,\nOpenID Connect, OAuth 2.0, SAML Authentication.", "package": "github.com/greenpau/caddy-auth-portal", "repo": "https://github.com/greenpau/caddy-auth-portal" } ], "http.handlers.authz": [ { "name": "http.handlers.authz", "package": "github.com/casbin/caddy-authz/v2", "repo": "https://github.com/casbin/caddy-authz" } ], "http.handlers.cgi": [ { "name": "http.handlers.cgi", "package": "github.com/aksdb/caddy-cgi/v2", "repo": "https://github.com/aksdb/caddy-cgi" } ], "http.handlers.crowdsec": [ { "name": "http.handlers.crowdsec", "docs": "http.handlers.crowdsec matches request IPs to CrowdSec decisions to (dis)allow access", "package": "github.com/hslatman/caddy-crowdsec-bouncer/http", "repo": "https://github.com/hslatman/caddy-crowdsec-bouncer" } ], "http.handlers.ct": [ { "name": "http.handlers.ct", "docs": "http.handlers.ct allows to transpile YAML based configuration into a JSON ignition to be used with Flatcar or Fedora CoreOS.", "package": "github.com/cubic3d/caddy-ct", "repo": "https://github.com/cubic3d/caddy-ct" } ], "http.handlers.encode": [ { "name": "http.handlers.encode", "docs": "http.handlers.encode is a middleware which can encode responses.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.error": [ { "name": "http.handlers.error", "docs": "http.handlers.error implements a simple handler that returns an error.\nThis handler returns an error value, but does not write a response.\nThis is useful when you want the server to act as if an error\noccurred; for example, to invoke your custom error handling logic.\n\nSince this handler does not write a response, the error information\nis for use by the server to know how to handle the error.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.exec": [ { "name": "http.handlers.exec", "docs": "http.handlers.exec implements an HTTP handler that runs shell command.", "package": "github.com/abiosoft/caddy-exec", "repo": "https://github.com/abiosoft/caddy-exec" } ], "http.handlers.file_server": [ { "name": "http.handlers.file_server", "docs": "http.handlers.file_server implements a static file server responder for Caddy.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/fileserver", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.filter": [ { "name": "http.handlers.filter", "docs": "http.handlers.filter implements an HTTP handler that writes the\nvisitor's IP address to a file or stream.", "package": "github.com/sjtug/caddy2-filter", "repo": "https://github.com/sjtug/caddy2-filter" } ], "http.handlers.geofence": [ { "name": "http.handlers.geofence", "docs": "http.handlers.geofence implements IP geofencing functionality. https://github.com/circa10a/caddy-geofence", "package": "github.com/circa10a/caddy-geofence", "repo": "https://github.com/circa10a/caddy-geofence" } ], "http.handlers.git": [ { "name": "http.handlers.git", "docs": "http.handlers.git implements git repository manager.", "package": "github.com/greenpau/caddy-git", "repo": "https://github.com/greenpau/caddy-git" } ], "http.handlers.gopkg": [ { "name": "http.handlers.gopkg", "docs": "http.handlers.gopkg implements vanity go package import paths.\n\nVanity go package import paths give a cleaner appearance to go projects by separating the source code location from\nthe import path. It also gives flexibility to developers by allowing them to change a project's source code hosting\nplatform without requiring the project to be renamed. Finally, it allows projects hosted on various platforms to be\ngrouped under a common import path.", "package": "magnax.ca/caddy/gopkg", "repo": "https://github.com/MagnaXSoftware/gopkg" }, { "name": "http.handlers.gopkg", "docs": "http.handlers.gopkg represents the GoPkg Caddy module.", "package": "magnax.ca/caddy/gopkg", "repo": "https://github.com/MagnaXSoftware/gopkg" } ], "http.handlers.headers": [ { "name": "http.handlers.headers", "docs": "http.handlers.headers is a middleware which modifies request and response headers.\n\nChanges to headers are applied immediately, except for the response\nheaders when Deferred is true or when Required is set. In those cases,\nthe changes are applied when the headers are written to the response.\nNote that deferred changes do not take effect if an error occurs later\nin the middleware chain.\n\nProperties in this module accept placeholders.\n\nResponse header operations can be conditioned upon response status code\nand/or other header values.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/headers", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.hmac": [ { "name": "http.handlers.hmac", "docs": "http.handlers.hmac implements an HTTP handler that\nvalidates request body with hmac.", "package": "github.com/abiosoft/caddy-hmac", "repo": "https://github.com/abiosoft/caddy-hmac" } ], "http.handlers.image_filter": [ { "name": "http.handlers.image_filter", "docs": "http.handlers.image_filter is a caddy module that can apply image filters to images from the filesystem at\nruntime. It should be used together with a cache module, so filters don't have to be applied\nrepeatedly because it's an expensive operation.", "package": "github.com/ueffel/caddy-imagefilter", "repo": "https://github.com/ueffel/caddy-imagefilter" } ], "http.handlers.json_parse": [ { "name": "http.handlers.json_parse", "docs": "http.handlers.json_parse implements an HTTP handler that parses\njson body as placeholders.", "package": "github.com/abiosoft/caddy-json-parse", "repo": "https://github.com/abiosoft/caddy-json-parse" } ], "http.handlers.map": [ { "name": "http.handlers.map", "docs": "http.handlers.map implements a middleware that maps inputs to outputs. Specifically, it\ncompares a source value against the map inputs, and for one that matches, it\napplies the output values to each destination. Destinations become placeholder\nnames.\n\nMapped placeholders are not evaluated until they are used, so even for very\nlarge mappings, this handler is quite efficient.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/map", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.mercure": [ { "name": "http.handlers.mercure", "docs": "http.handlers.mercure implements a Mercure hub as a Caddy module. Mercure is a protocol allowing to push data updates to web browsers and other HTTP clients in a convenient, fast, reliable and battery-efficient way.", "package": "github.com/dunglas/mercure/caddy", "repo": "https://github.com/dunglas/mercure" } ], "http.handlers.metrics": [ { "name": "http.handlers.metrics", "docs": "http.handlers.metrics is a module that serves a /metrics endpoint so that any gathered\nmetrics can be exposed for scraping. This module is configurable by end-users\nunlike AdminMetrics.", "package": "github.com/caddyserver/caddy/v2/modules/metrics", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.openapi": [ { "name": "http.handlers.openapi", "package": "github.com/chukmunnlee/caddy-openapi", "repo": "https://github.com/chukmunnlee/caddy-openapi" } ], "http.handlers.openapi_validator": [ { "name": "http.handlers.openapi_validator", "docs": "http.handlers.openapi_validator is used to validate OpenAPI requests and responses against an OpenAPI specification", "package": "github.com/hslatman/caddy-openapi-validator", "repo": "https://github.com/hslatman/caddy-openapi-validator" } ], "http.handlers.pirsch": [ { "name": "http.handlers.pirsch", "package": "github.com/muety/caddy-pirsch-plugin", "repo": "https://github.com/muety/caddy-pirsch-plugin" } ], "http.handlers.prometheus": [ { "name": "http.handlers.prometheus", "docs": "http.handlers.prometheus -", "package": "github.com/hairyhenderson/caddyprom", "repo": "https://github.com/hairyhenderson/caddyprom" } ], "http.handlers.push": [ { "name": "http.handlers.push", "docs": "http.handlers.push is a middleware for manipulating the request body.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/push", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.quantity_limiter": [ { "name": "http.handlers.quantity_limiter", "docs": "http.handlers.quantity_limiter limits the number of successful requests for a token and allows the counter to be reset.", "package": "github.com/cubic3d/caddy-quantity-limiter", "repo": "https://github.com/cubic3d/caddy-quantity-limiter" } ], "http.handlers.rate_limit": [ { "name": "http.handlers.rate_limit", "docs": "http.handlers.rate_limit implements a handler for rate-limiting.\n\nIf a client exceeds the rate limit, an HTTP error with status `\u003creject_status\u003e` will\nbe returned. This error can be handled using the conventional error handlers.\nSee [handle_errors](https://caddyserver.com/docs/caddyfile/directives/handle_errors)\nfor how to set up error handlers.", "package": "github.com/RussellLuo/caddy-ext/ratelimit", "repo": "https://github.com/RussellLuo/caddy-ext" }, { "name": "http.handlers.rate_limit", "docs": "http.handlers.rate_limit implements rate limiting functionality.\n\nIf a rate limit is exceeded, an HTTP error with status 429 will be\nreturned. This error can be handled using the conventional error\nhandling routes in your config. An additional placeholder is made\navailable, called `{http.rate_limit.exceeded.name}`, which you can\nuse for logging or handling; it contains the name of the rate limit\nzone which limit was exceeded.", "package": "github.com/mholt/caddy-ratelimit", "repo": "https://github.com/mholt/caddy-ratelimit" } ], "http.handlers.realip": [ { "name": "http.handlers.realip", "package": "github.com/kirsch33/realip", "repo": "https://github.com/kirsch33/realip" } ], "http.handlers.replace_response": [ { "name": "http.handlers.replace_response", "docs": "http.handlers.replace_response manipulates response bodies by performing\nsubstring or regex replacements.", "package": "github.com/caddyserver/replace-response", "repo": "https://github.com/caddyserver/replace-response" } ], "http.handlers.request_body": [ { "name": "http.handlers.request_body", "docs": "http.handlers.request_body is a middleware for manipulating the request body.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/requestbody", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.request_debug": [ { "name": "http.handlers.request_debug", "docs": "http.handlers.request_debug is a middleware which displays the content of the request it\nhandles. It helps troubleshooting web requests by exposing headers\n(e.g. cookies), URL parameters, etc.", "package": "github.com/greenpau/caddy-request-debug", "repo": "https://github.com/greenpau/caddy-request-debug" } ], "http.handlers.request_id": [ { "name": "http.handlers.request_id", "docs": "http.handlers.request_id implements an HTTP handler that writes a\nunique request ID to response headers.", "package": "github.com/lolPants/caddy-requestid", "repo": "https://github.com/lolPants/caddy-requestid" } ], "http.handlers.reverse_proxy": [ { "name": "http.handlers.reverse_proxy", "docs": "http.handlers.reverse_proxy implements a highly configurable and production-ready reverse proxy.\n\nUpon proxying, this module sets the following placeholders (which can be used\nboth within and after this handler; for example, in response headers):\n\nPlaceholder | Description\n------------|-------------\n`{http.reverse_proxy.upstream.address}` | The full address to the upstream as given in the config\n`{http.reverse_proxy.upstream.hostport}` | The host:port of the upstream\n`{http.reverse_proxy.upstream.host}` | The host of the upstream\n`{http.reverse_proxy.upstream.port}` | The port of the upstream\n`{http.reverse_proxy.upstream.requests}` | The approximate current number of requests to the upstream\n`{http.reverse_proxy.upstream.max_requests}` | The maximum approximate number of requests allowed to the upstream\n`{http.reverse_proxy.upstream.fails}` | The number of recent failed requests to the upstream\n`{http.reverse_proxy.upstream.latency}` | How long it took the proxy upstream to write the response header.\n`{http.reverse_proxy.upstream.duration}` | Time spent proxying to the upstream, including writing response body to client.\n`{http.reverse_proxy.duration}` | Total time spent proxying, including selecting an upstream, retries, and writing response.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.rewrite": [ { "name": "http.handlers.rewrite", "docs": "http.handlers.rewrite is a middleware which can rewrite HTTP requests.\n\nThe Method and URI properties are \"setters\": the request URI\nwill be set to the given values. Other properties are \"modifiers\":\nthey modify existing files but do not explicitly specify what the\nresult will be. It is atypical to combine the use of setters and\nmodifiers in a single rewrite.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/rewrite", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.s3proxy": [ { "name": "http.handlers.s3proxy", "docs": "http.handlers.s3proxy implements a proxy to return, set, delete or browse objects from S3", "package": "github.com/lindenlab/caddy-s3-proxy", "repo": "https://github.com/lindenlab/caddy-s3-proxy" } ], "http.handlers.static_response": [ { "name": "http.handlers.static_response", "docs": "http.handlers.static_response implements a simple responder for static responses.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.subroute": [ { "name": "http.handlers.subroute", "docs": "http.handlers.subroute implements a handler that compiles and executes routes.\nThis is useful for a batch of routes that all inherit the same\nmatchers, or for multiple routes that should be treated as a\nsingle route.\n\nYou can also use subroutes to handle errors from its handlers.\nFirst the primary routes will be executed, and if they return an\nerror, the errors routes will be executed; in that case, an error\nis only returned to the entry point at the server if there is an\nadditional error returned from the errors routes.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.teapot": [ { "name": "http.handlers.teapot", "docs": "http.handlers.teapot implements a static \"418 I'm a teapot\" response to all requests on the route", "package": "github.com/hairyhenderson/caddy-teapot-module", "repo": "https://github.com/hairyhenderson/caddy-teapot-module" } ], "http.handlers.templates": [ { "name": "http.handlers.templates", "docs": "http.handlers.templates is a middleware which executes response bodies as Go templates.\nThe syntax is documented in the Go standard library's\n[text/template package](https://golang.org/pkg/text/template/).\n\n⚠️ Template functions/actions are still experimental, so they are subject to change.\n\n[All Sprig functions](https://masterminds.github.io/sprig/) are supported.\n\nIn addition to the standard functions and the Sprig library, Caddy adds\nextra functions and data that are available to a template:\n\n##### `.Args`\n\nAccess arguments passed to this page/context, for example as the result of a `include`.\n\n```\n{{.Args 0}} // first argument\n```\n\n##### `.Cookie`\n\nGets the value of a cookie by name.\n\n```\n{{.Cookie \"cookiename\"}}\n```\n\n##### `env`\n\nGets an environment variable.\n\n```\n{{env \"VAR_NAME\"}}\n```\n\n##### `placeholder`\n\nGets an [placeholder variable](/docs/conventions#placeholders).\nThe braces (`{}`) have to be omitted.\n\n```\n{{placeholder \"http.request.uri.path\"}}\n{{placeholder \"http.error.status_code\"}}\n```\n\n##### `.Host`\n\nReturns the hostname portion (no port) of the Host header of the HTTP request.\n\n```\n{{.Host}}\n```\n\n##### `httpInclude`\n\nIncludes the contents of another file by making a virtual HTTP request (also known as a sub-request). The URI path must exist on the same virtual server because the request does not use sockets; instead, the request is crafted in memory and the handler is invoked directly for increased efficiency.\n\n```\n{{httpInclude \"/foo/bar?q=val\"}}\n```\n\n##### `include`\n\nIncludes the contents of another file. Optionally can pass key-value pairs as arguments to be accessed by the included file.\n\n```\n{{include \"path/to/file.html\"}} // no arguments\n{{include \"path/to/file.html\" \"arg1\" 2 \"value 3\"}} // with arguments\n```\n\n##### `listFiles`\n\nReturns a list of the files in the given directory, which is relative to the template context's file root.\n\n```\n{{listFiles \"/mydir\"}}\n```\n\n##### `markdown`\n\nRenders the given Markdown text as HTML.\n\n```\n{{markdown \"My _markdown_ text\"}}\n```\n\n##### `.RemoteIP`\n\nReturns the client's IP address.\n\n```\n{{.RemoteIP}}\n```\n\n##### `.Req`\n\nAccesses the current HTTP request, which has various fields, including:\n\n - `.Method` - the method\n - `.URL` - the URL, which in turn has component fields (Scheme, Host, Path, etc.)\n - `.Header` - the header fields\n - `.Host` - the Host or :authority header of the request\n\n```\n{{.Req.Header.Get \"User-Agent\"}}\n```\n\n##### `.RespHeader.Add`\n\nAdds a header field to the HTTP response.\n\n```\n{{.RespHeader.Add \"Field-Name\" \"val\"}}\n```\n\n##### `.RespHeader.Del`\n\nDeletes a header field on the HTTP response.\n\n```\n{{.RespHeader.Del \"Field-Name\"}}\n```\n\n##### `.RespHeader.Set`\n\nSets a header field on the HTTP response, replacing any existing value.\n\n```\n{{.RespHeader.Set \"Field-Name\" \"val\"}}\n```\n\n##### `splitFrontMatter`\n\nSplits front matter out from the body. Front matter is metadata that appears at the very beginning of a file or string. Front matter can be in YAML, TOML, or JSON formats:\n\n**TOML** front matter starts and ends with `+++`:\n\n```\n+++\ntemplate = \"blog\"\ntitle = \"Blog Homepage\"\nsitename = \"A Caddy site\"\n+++\n```\n\n**YAML** is surrounded by `---`:\n\n```\n---\ntemplate: blog\ntitle: Blog Homepage\nsitename: A Caddy site\n---\n```\n\n**JSON** is simply `{` and `}`:\n\n```\n{\n\t\"template\": \"blog\",\n\t\"title\": \"Blog Homepage\",\n\t\"sitename\": \"A Caddy site\"\n}\n```\n\nThe resulting front matter will be made available like so:\n\n- `.Meta` to access the metadata fields, for example: `{{$parsed.Meta.title}}`\n- `.Body` to access the body after the front matter, for example: `{{markdown $parsed.Body}}`\n\n##### `stripHTML`\n\nRemoves HTML from a string.\n\n```\n{{stripHTML \"Shows \u003cb\u003eonly\u003c/b\u003e text content\"}}\n```", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/templates", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.trace": [ { "name": "http.handlers.trace", "docs": "http.handlers.trace is a middleware which displays the content of the request it\nhandles. It helps troubleshooting web requests by exposing headers\n(e.g. cookies), URL parameters, etc.", "package": "github.com/greenpau/caddy-trace", "repo": "https://github.com/greenpau/caddy-trace" } ], "http.handlers.vars": [ { "name": "http.handlers.vars", "docs": "http.handlers.vars is an HTTP middleware which sets variables to\nhave values that can be used in the HTTP request handler\nchain. The primary way to access variables is with placeholders,\nwhich have the form: `{http.vars.variable_name}`, or with\nthe `vars` and `vars_regexp` request matchers.\n\nThe key is the variable name, and the value is the value of the\nvariable. Both the name and value may use or contain placeholders.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.handlers.vulcain": [ { "name": "http.handlers.vulcain", "package": "github.com/dunglas/vulcain/caddy", "repo": "https://github.com/dunglas/vulcain" } ], "http.handlers.webdav": [ { "name": "http.handlers.webdav", "docs": "http.handlers.webdav implements an HTTP handler for responding to WebDAV clients.", "package": "github.com/mholt/caddy-webdav", "repo": "https://github.com/mholt/caddy-webdav" } ], "http.handlers.webhook": [ { "name": "http.handlers.webhook", "docs": "http.handlers.webhook is the module configuration.", "package": "github.com/WingLim/caddy-webhook", "repo": "https://github.com/WingLim/caddy-webhook" } ], "http.matchers.exec_noop": [ { "name": "http.matchers.exec_noop", "docs": "http.matchers.exec_noop is a matcher that blocks all requests.\nIt's primary purpose is to ensure the command is not\nexecuted when no route/matcher is specified.\nLimitation of Caddyfile config. JSON/API config do not need this.", "package": "github.com/abiosoft/caddy-exec", "repo": "https://github.com/abiosoft/caddy-exec" } ], "http.matchers.execnopmatch": [ { "name": "http.matchers.execnopmatch", "docs": "http.matchers.execnopmatch is a matcher that blocks all request.\nIt's primary purpose is to ensure the command is not\nexecuted when no route/matcher is specified.\nLimitation of Caddyfile config. JSON/API config do not need this.", "package": "github.com/abiosoft/caddy-exec", "repo": "https://github.com/abiosoft/caddy-exec" } ], "http.matchers.expression": [ { "name": "http.matchers.expression", "docs": "http.matchers.expression matches requests by evaluating a\n[CEL](https://github.com/google/cel-spec) expression.\nThis enables complex logic to be expressed using a comfortable,\nfamiliar syntax. Please refer to\n[the standard definitions of CEL functions and operators](https://github.com/google/cel-spec/blob/master/doc/langdef.md#standard-definitions).\n\nThis matcher's JSON interface is actually a string, not a struct.\nThe generated docs are not correct because this type has custom\nmarshaling logic.\n\nCOMPATIBILITY NOTE: This module is still experimental and is not\nsubject to Caddy's compatibility guarantee.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.file": [ { "name": "http.matchers.file", "docs": "http.matchers.file is an HTTP request matcher that can match\nrequests based upon file existence.\n\nUpon matching, three new placeholders will be made\navailable:\n\n- `{http.matchers.file.relative}` The root-relative\npath of the file. This is often useful when rewriting\nrequests.\n- `{http.matchers.file.absolute}` The absolute path\nof the matched file.\n- `{http.matchers.file.type}` Set to \"directory\" if\nthe matched file is a directory, \"file\" otherwise.\n- `{http.matchers.file.remainder}` Set to the remainder\nof the path if the path was split by `split_path`.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/fileserver", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.header": [ { "name": "http.matchers.header", "docs": "http.matchers.header matches requests by header fields. The key is the field\nname and the array is the list of field values. It performs fast,\nexact string comparisons of the field values. Fast prefix, suffix,\nand substring matches can also be done by suffixing, prefixing, or\nsurrounding the value with the wildcard `*` character, respectively.\nIf a list is null, the header must not exist. If the list is empty,\nthe field must simply exist, regardless of its value.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.header_regexp": [ { "name": "http.matchers.header_regexp", "docs": "http.matchers.header_regexp matches requests by a regular expression on header fields.\n\nUpon a match, it adds placeholders to the request: `{http.regexp.name.capture_group}`\nwhere `name` is the regular expression's name, and `capture_group` is either\nthe named or positional capture group from the expression itself. If no name\nis given, then the placeholder omits the name: `{http.regexp.capture_group}`\n(potentially leading to collisions).", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.host": [ { "name": "http.matchers.host", "docs": "http.matchers.host matches requests by the Host value (case-insensitive).\n\nWhen used in a top-level HTTP route,\n[qualifying domain names](/docs/automatic-https#hostname-requirements)\nmay trigger [automatic HTTPS](/docs/automatic-https), which automatically\nprovisions and renews certificates for you. Before doing this, you\nshould ensure that DNS records for these domains are properly configured,\nespecially A/AAAA pointed at your server.\n\nAutomatic HTTPS can be\n[customized or disabled](/docs/modules/http#servers/automatic_https).\n\nWildcards (`*`) may be used to represent exactly one label of the\nhostname, in accordance with RFC 1034 (because host matchers are also\nused for automatic HTTPS which influences TLS certificates). Thus,\na host of `*` matches hosts like `localhost` or `internal` but not\n`example.com`. To catch all hosts, omit the host matcher entirely.\n\nThe wildcard can be useful for matching all subdomains, for example:\n`*.example.com` matches `foo.example.com` but not `foo.bar.example.com`.\n\nDuplicate entries will return an error.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.maxmind_geolocation": [ { "name": "http.matchers.maxmind_geolocation", "docs": "Allows to filter requests based on source IP country.", "package": "github.com/porech/caddy-maxmind-geolocation", "repo": "https://github.com/porech/caddy-maxmind-geolocation" } ], "http.matchers.method": [ { "name": "http.matchers.method", "docs": "http.matchers.method matches requests by the method.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.not": [ { "name": "http.matchers.not", "docs": "http.matchers.not matches requests by negating the results of its matcher\nsets. A single \"not\" matcher takes one or more matcher sets. Each\nmatcher set is OR'ed; in other words, if any matcher set returns\ntrue, the final result of the \"not\" matcher is false. Individual\nmatchers within a set work the same (i.e. different matchers in\nthe same set are AND'ed).\n\nNOTE: The generated docs which describe the structure of this\nmodule are wrong because of how this type unmarshals JSON in a\ncustom way. The correct structure is:\n\n```json\n[\n\t{},\n\t{}\n]\n```\n\nwhere each of the array elements is a matcher set, i.e. an\nobject keyed by matcher name.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.path": [ { "name": "http.matchers.path", "docs": "http.matchers.path matches requests by the URI's path (case-insensitive). Path\nmatches are exact, but wildcards may be used:\n\n- At the end, for a prefix match (`/prefix/*`)\n- At the beginning, for a suffix match (`*.suffix`)\n- On both sides, for a substring match (`*/contains/*`)\n- In the middle, for a globular match (`/accounts/*/info`)\n\nThis matcher is fast, so it does not support regular expressions or\ncapture groups. For slower but more powerful matching, use the\npath_regexp matcher.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.path_regexp": [ { "name": "http.matchers.path_regexp", "docs": "http.matchers.path_regexp matches requests by a regular expression on the URI's path.\n\nUpon a match, it adds placeholders to the request: `{http.regexp.name.capture_group}`\nwhere `name` is the regular expression's name, and `capture_group` is either\nthe named or positional capture group from the expression itself. If no name\nis given, then the placeholder omits the name: `{http.regexp.capture_group}`\n(potentially leading to collisions).", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.protocol": [ { "name": "http.matchers.protocol", "docs": "http.matchers.protocol matches requests by protocol. Recognized values are\n\"http\", \"https\", and \"grpc\".", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.query": [ { "name": "http.matchers.query", "docs": "http.matchers.query matches requests by the URI's query string. It takes a JSON object\nkeyed by the query keys, with an array of string values to match for that key.\nQuery key matches are exact, but wildcards may be used for value matches. Both\nkeys and values may be placeholders.\nAn example of the structure to match `?key=value\u0026topic=api\u0026query=something` is:\n\n```json\n{\n\t\"key\": [\"value\"],\n\t\"topic\": [\"api\"],\n\t\"query\": [\"*\"]\n}\n```", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.remote_host": [ { "name": "http.matchers.remote_host", "docs": "http.matchers.remote_host matches based on the remote IP of the\nconnection. A host name can be specified, whose A and AAAA\nDNS records will be resolved to a corresponding IP for matching.\n\nNote that IPs can sometimes be spoofed, so do not rely\non this as a replacement for actual authentication.", "package": "github.com/muety/caddy-remote-host", "repo": "https://github.com/muety/caddy-remote-host" } ], "http.matchers.remote_ip": [ { "name": "http.matchers.remote_ip", "docs": "http.matchers.remote_ip matches requests by client IP (or CIDR range).", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.vars": [ { "name": "http.matchers.vars", "docs": "http.matchers.vars is an HTTP request matcher which can match\nrequests based on variables in the context.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.matchers.vars_regexp": [ { "name": "http.matchers.vars_regexp", "docs": "http.matchers.vars_regexp matches the value of the context variables by a given regular expression.\n\nUpon a match, it adds placeholders to the request: `{http.regexp.name.capture_group}`\nwhere `name` is the regular expression's name, and `capture_group` is either\nthe named or positional capture group from the expression itself. If no name\nis given, then the placeholder omits the name: `{http.regexp.capture_group}`\n(potentially leading to collisions).", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp", "repo": "https://github.com/caddyserver/caddy" } ], "http.precompressed.br": [ { "name": "http.precompressed.br", "docs": "http.precompressed.br provides the file extension for files precompressed with brotli encoding.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/brotli", "repo": "https://github.com/caddyserver/caddy" } ], "http.precompressed.gzip": [ { "name": "http.precompressed.gzip", "docs": "http.precompressed.gzip provides the file extension for files precompressed with gzip encoding.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/gzip", "repo": "https://github.com/caddyserver/caddy" } ], "http.precompressed.zstd": [ { "name": "http.precompressed.zstd", "docs": "http.precompressed.zstd provides the file extension for files precompressed with zstandard encoding.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/encode/zstd", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.cookie": [ { "name": "http.reverse_proxy.selection_policies.cookie", "docs": "http.reverse_proxy.selection_policies.cookie is a policy that selects\na host based on a given cookie name.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.first": [ { "name": "http.reverse_proxy.selection_policies.first", "docs": "http.reverse_proxy.selection_policies.first is a policy that selects\nthe first available host.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.header": [ { "name": "http.reverse_proxy.selection_policies.header", "docs": "http.reverse_proxy.selection_policies.header is a policy that selects\na host based on a given request header.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.ip_hash": [ { "name": "http.reverse_proxy.selection_policies.ip_hash", "docs": "http.reverse_proxy.selection_policies.ip_hash is a policy that selects a host\nbased on hashing the remote IP of the request.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.least_conn": [ { "name": "http.reverse_proxy.selection_policies.least_conn", "docs": "http.reverse_proxy.selection_policies.least_conn is a policy that selects the\nhost with the least active requests. If multiple\nhosts have the same fewest number, one is chosen\nrandomly. The term \"conn\" or \"connection\" is used\nin this policy name due to its similar meaning in\nother software, but our load balancer actually\ncounts active requests rather than connections,\nsince these days requests are multiplexed onto\nshared connections.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.random": [ { "name": "http.reverse_proxy.selection_policies.random", "docs": "http.reverse_proxy.selection_policies.random is a policy that selects\nan available host at random.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.random_choose": [ { "name": "http.reverse_proxy.selection_policies.random_choose", "docs": "http.reverse_proxy.selection_policies.random_choose is a policy that selects\ntwo or more available hosts at random, then\nchooses the one with the least load.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.round_robin": [ { "name": "http.reverse_proxy.selection_policies.round_robin", "docs": "http.reverse_proxy.selection_policies.round_robin is a policy that selects\na host based on round-robin ordering.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.selection_policies.uri_hash": [ { "name": "http.reverse_proxy.selection_policies.uri_hash", "docs": "http.reverse_proxy.selection_policies.uri_hash is a policy that selects a\nhost by hashing the request URI.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.transport.fastcgi": [ { "name": "http.reverse_proxy.transport.fastcgi", "docs": "http.reverse_proxy.transport.fastcgi facilitates FastCGI communication.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy/fastcgi", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.transport.http": [ { "name": "http.reverse_proxy.transport.http", "docs": "http.reverse_proxy.transport.http is essentially a configuration wrapper for http.Transport.\nIt defines a JSON structure useful when configuring the HTTP transport\nfor Caddy's reverse proxy. It builds its http.Transport at Provision.", "package": "github.com/caddyserver/caddy/v2/modules/caddyhttp/reverseproxy", "repo": "https://github.com/caddyserver/caddy" } ], "http.reverse_proxy.transport.http_ntlm": [ { "name": "http.reverse_proxy.transport.http_ntlm", "docs": "http.reverse_proxy.transport.http_ntlm proxies HTTP with NTLM authentication.\nIt basically wraps HTTPTransport so that it is compatible with\nNTLM's HTTP-hostile requirements. Specifically, it will use\nHTTPTransport's single, default *http.Transport for all requests\n(unless the client's connection is already mapped to a different\ntransport) until a request comes in with an Authorization header\nthat has \"NTLM\" or \"Negotiate\"; when that happens, NTLMTransport\nmaps the client's connection (by its address, req.RemoteAddr)\nto a new transport that is used only by that downstream conn.\nWhen the upstream connection is closed, the mapping is deleted.\nThis preserves NTLM authentication contexts by ensuring that\nclient connections use the same upstream connection. It does\nhurt performance a bit, but that's NTLM for you.\n\nThis transport also forces HTTP/1.1 and Keep-Alives in order\nfor NTLM to succeed.\n\nIt is basically the same thing as\n[nginx's paid ntlm directive](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ntlm)\n(but is free in Caddy!).", "package": "github.com/caddyserver/ntlm-transport", "repo": "https://github.com/caddyserver/ntlm-transport" } ], "layer4": [ { "name": "layer4", "docs": "layer4 is a Caddy app that operates closest to layer 4 of the OSI model.", "package": "github.com/mholt/caddy-l4/layer4", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.handlers.echo": [ { "name": "layer4.handlers.echo", "docs": "layer4.handlers.echo is a simple handler that writes what it reads.", "package": "github.com/mholt/caddy-l4/modules/l4echo", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.handlers.proxy": [ { "name": "layer4.handlers.proxy", "docs": "layer4.handlers.proxy is a handler that can proxy connections.", "package": "github.com/mholt/caddy-l4/modules/l4proxy", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.handlers.proxy_protocol": [ { "name": "layer4.handlers.proxy_protocol", "docs": "layer4.handlers.proxy_protocol is a connection handler that accepts the PROXY protocol.", "package": "github.com/mholt/caddy-l4/modules/l4proxyprotocol", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.handlers.tee": [ { "name": "layer4.handlers.tee", "docs": "layer4.handlers.tee is a layer4 handler that replicates a connection so\nthat a branch of handlers can concurrently handle it. Reads\nhappen in lock-step with all concurrent branches so as to\navoid buffering: if one of the branches (including the main\nhandler chain) stops reading from the connection, it will\nblock all branches.", "package": "github.com/mholt/caddy-l4/modules/l4tee", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.handlers.throttle": [ { "name": "layer4.handlers.throttle", "docs": "layer4.handlers.throttle throttles connections using leaky bucket rate limiting.", "package": "github.com/mholt/caddy-l4/modules/l4throttle", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.handlers.tls": [ { "name": "layer4.handlers.tls", "docs": "layer4.handlers.tls is a connection handler that terminates TLS.", "package": "github.com/mholt/caddy-l4/modules/l4tls", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.matchers.crowdsec": [ { "name": "layer4.matchers.crowdsec", "docs": "layer4.matchers.crowdsec matches IPs to CrowdSec decisions to (dis)allow access", "package": "github.com/hslatman/caddy-crowdsec-bouncer/layer4", "repo": "https://github.com/hslatman/caddy-crowdsec-bouncer" } ], "layer4.matchers.http": [ { "name": "layer4.matchers.http", "docs": "layer4.matchers.http is able to match HTTP connections. The auto-generated\ndocumentation for this type is wrong; instead of an object, it\nis an array of matcher set objects.", "package": "github.com/mholt/caddy-l4/modules/l4http", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.matchers.ip": [ { "name": "layer4.matchers.ip", "docs": "layer4.matchers.ip matches requests by remote IP (or CIDR range).", "package": "github.com/mholt/caddy-l4/layer4", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.matchers.proxy_protocol": [ { "name": "layer4.matchers.proxy_protocol", "package": "github.com/mholt/caddy-l4/modules/l4proxy", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.matchers.ssh": [ { "name": "layer4.matchers.ssh", "docs": "layer4.matchers.ssh is able to match SSH connections.", "package": "github.com/mholt/caddy-l4/modules/l4ssh", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.matchers.tls": [ { "name": "layer4.matchers.tls", "docs": "layer4.matchers.tls is able to match TLS connections. Its structure\nis different from the auto-generated documentation. This\nvalue should be a map of matcher names to their values.", "package": "github.com/mholt/caddy-l4/modules/l4tls", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.matchers.xmpp": [ { "name": "layer4.matchers.xmpp", "docs": "layer4.matchers.xmpp is able to match XMPP connections.", "package": "github.com/mholt/caddy-l4/modules/l4xmpp", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.proxy.selection_policies.first": [ { "name": "layer4.proxy.selection_policies.first", "docs": "layer4.proxy.selection_policies.first is a policy that selects\nthe first available host.", "package": "github.com/mholt/caddy-l4/modules/l4proxy", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.proxy.selection_policies.ip_hash": [ { "name": "layer4.proxy.selection_policies.ip_hash", "docs": "layer4.proxy.selection_policies.ip_hash is a policy that selects a host\nbased on hashing the remote IP of the connection.", "package": "github.com/mholt/caddy-l4/modules/l4proxy", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.proxy.selection_policies.least_conn": [ { "name": "layer4.proxy.selection_policies.least_conn", "docs": "layer4.proxy.selection_policies.least_conn is a policy that selects the upstream\nwith the least active connections. If multiple upstreams\nhave the same fewest number, one is chosen randomly.", "package": "github.com/mholt/caddy-l4/modules/l4proxy", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.proxy.selection_policies.random": [ { "name": "layer4.proxy.selection_policies.random", "docs": "layer4.proxy.selection_policies.random is a policy that selects\nan available host at random.", "package": "github.com/mholt/caddy-l4/modules/l4proxy", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.proxy.selection_policies.random_choose": [ { "name": "layer4.proxy.selection_policies.random_choose", "docs": "layer4.proxy.selection_policies.random_choose is a policy that selects\ntwo or more available hosts at random, then\nchooses the one with the least load.", "package": "github.com/mholt/caddy-l4/modules/l4proxy", "repo": "https://github.com/mholt/caddy-l4" } ], "layer4.proxy.selection_policies.round_robin": [ { "name": "layer4.proxy.selection_policies.round_robin", "docs": "layer4.proxy.selection_policies.round_robin is a policy that selects\na host based on round-robin ordering.", "package": "github.com/mholt/caddy-l4/modules/l4proxy", "repo": "https://github.com/mholt/caddy-l4" } ], "pki": [ { "name": "pki", "docs": "pki provides Public Key Infrastructure facilities for Caddy.\n\nThis app can define certificate authorities (CAs) which are capable\nof signing certificates. Other modules can be configured to use\nthe CAs defined by this app for issuing certificates or getting\nkey information needed for establishing trust.", "package": "github.com/caddyserver/caddy/v2/modules/caddypki", "repo": "https://github.com/caddyserver/caddy" } ], "security": [ { "name": "security", "docs": "security implements security manager.", "package": "github.com/greenpau/caddy-security", "repo": "https://github.com/greenpau/caddy-security" } ], "supervisor": [ { "name": "supervisor", "package": "github.com/baldinof/caddy-supervisor", "repo": "https://github.com/baldinof/caddy-supervisor" } ], "tls": [ { "name": "tls", "docs": "tls provides TLS facilities including certificate\nloading and management, client auth, and more.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.certificates.automate": [ { "name": "tls.certificates.automate", "docs": "tls.certificates.automate will automatically manage certificates for the names in the\nlist, including obtaining and renewing certificates. Automated certificates\nare managed according to their matching automation policy, configured\nelsewhere in this app.\n\nTechnically, this is a no-op certificate loader module that is treated as\na special case: it uses this app's automation features to load certificates\nfor the list of hostnames, rather than loading certificates manually.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.certificates.load_files": [ { "name": "tls.certificates.load_files", "docs": "tls.certificates.load_files loads certificates and their associated keys from disk.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.certificates.load_folders": [ { "name": "tls.certificates.load_folders", "docs": "tls.certificates.load_folders loads certificates and their associated keys from disk\nby recursively walking the specified directories, looking for PEM\nfiles which contain both a certificate and a key.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.certificates.load_pem": [ { "name": "tls.certificates.load_pem", "docs": "tls.certificates.load_pem loads certificates and their associated keys by\ndecoding their PEM blocks directly. This has the advantage\nof not needing to store them on disk at all.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.certificates.load_storage": [ { "name": "tls.certificates.load_storage", "docs": "tls.certificates.load_storage loads certificates and their associated keys\nfrom the globally configured storage module.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.handshake_match.alpn": [ { "name": "tls.handshake_match.alpn", "package": "github.com/mholt/caddy-l4/modules/l4tls", "repo": "https://github.com/mholt/caddy-l4" } ], "tls.handshake_match.remote_ip": [ { "name": "tls.handshake_match.remote_ip", "docs": "tls.handshake_match.remote_ip matches based on the remote IP of the\nconnection. Specific IPs or CIDR ranges can be specified.\n\nNote that IPs can sometimes be spoofed, so do not rely\non this as a replacement for actual authentication.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.handshake_match.sni": [ { "name": "tls.handshake_match.sni", "docs": "tls.handshake_match.sni matches based on SNI. Names in\nthis list may use left-most-label wildcards,\nsimilar to wildcard certificates.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.issuance.acme": [ { "name": "tls.issuance.acme", "docs": "tls.issuance.acme manages certificates using the ACME protocol (RFC 8555).", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.issuance.internal": [ { "name": "tls.issuance.internal", "docs": "tls.issuance.internal is a certificate issuer that generates\ncertificates internally using a locally-configured\nCA which can be customized using the `pki` app.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.issuance.zerossl": [ { "name": "tls.issuance.zerossl", "docs": "tls.issuance.zerossl makes an ACME manager\nfor managing certificates using ACME.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls", "repo": "https://github.com/caddyserver/caddy" } ], "tls.stek.distributed": [ { "name": "tls.stek.distributed", "docs": "tls.stek.distributed implements a distributed STEK provider. This\nmodule will obtain STEKs from a storage module instead\nof generating STEKs internally. This allows STEKs to be\ncoordinated, improving TLS session resumption in a cluster.", "package": "github.com/caddyserver/caddy/v2/modules/caddytls/distributedstek", "repo": "https://github.com/caddyserver/caddy" } ], "tls.stek.standard": [ { "name": "tls.stek.standard", "package": "github.com/caddyserver/caddy/v2/modules/caddytls/standardstek", "repo": "https://github.com/caddyserver/caddy" } ] } } ================================================ FILE: src/docs/index.html ================================================ {{$pathParts := splitList "/" .OriginalReq.URL.Path}} {{$markdownFilename := default "index" (slice $pathParts 2 | join "/")}} {{$markdownFilePath := printf "/docs/markdown/%s.md" $markdownFilename}} {{if not (fileExists $markdownFilePath)}}{{httpError 404}}{{end}} {{$markdownFile := (include $markdownFilePath | splitFrontMatter)}} {{$title := default $markdownFilename $markdownFile.Meta.title}} {{$title}} — Caddy v2中文文档 {{include "/includes/docs/head.html"}} {{include "/includes/docs/header.html"}}
{{include "/includes/docs/nav.html"}}
{{markdown $markdownFile.Body}}
{{include "/includes/donate.html"}}
{{include "/includes/footer.html"}} ================================================ FILE: src/docs/json/index.html ================================================ JSON配置结构 - Caddy V2中文文档 {{include "/includes/docs/head.html"}} {{include "/includes/docs/header.html"}}
{{include "/includes/docs/nav.html"}}
{{include "/includes/docs/renderbox.html"}} {{include "/includes/docs/details.html"}}
{{include "/includes/docs/hovercard.html"}} {{include "/includes/footer.html"}} ================================================ FILE: src/docs/markdown/api-tutorial.md ================================================ --- title: "API教程" --- # API教程 本教程将向你展示如何使用Caddy的[管理API](/docs/api),这使得以可编程方式实现自动化成为可能。 **目标:** - 🔲 运行守护程序 - 🔲 给 Caddy 一个配置 - 🔲 测试配置 - 🔲 替换活动配置 - 🔲 遍历配置 - 🔲 使用`@id`标签 **必备:** - 基本的终端/命令行技能 - 基本的JSON经验 - PATH支持`caddy`和`curl` --- 要启动 Caddy 守护程序,请使用`run`子命令:
caddy run
这永远阻塞,但它在做什么?此刻……什么都没有。默认情况下,Caddy的配置(“config”)为空白。我们可以使用另一个终端中的[管理API](/docs/api)来验证这一点:
curl localhost:2019/config/
我们可以通过给它一个配置来使Caddy变得有用。一种方法是向 [/load](/docs/api#post-load)端点发出 POST 请求。就像任何 HTTP 请求一样,有很多方法可以做到这一点,但在本教程中,我们将使用`curl`。 ## 你的第一个配置 为了能发起请求,我们需要进行配置。Caddy的配置只是一个[JSON文档](/docs/json/) (或[任何能转换为JSON](/docs/config-adapters)的文件)。 将下面的内容保存到JSON文件: ```json { "apps": { "http": { "servers": { "example": { "listen": [":2015"], "routes": [ { "handle": [{ "handler": "static_response", "body": "Hello, world!" }] } ] } } } } } ``` 然后上传:
curl localhost:2019/load \
	-H "Content-Type: application/json" \
	-d @caddy.json
我们可以验证 Caddy 是否通过另一个 GET 请求应用了我们的新配置:
curl localhost:2019/config/
通过在浏览器中访问[localhost:2015](http://localhost:2015)或使用`curl`命令来测试它是否有效:
curl localhost:2015
Hello, world!
如果你看到_Hello, world!_,就恭喜啦——它已经工作了!确保你的配置按预期工作始终是一个好主意,尤其是在部署到生产环境之前。 ```json { "handler": "static_response", "body": "I can do hard things." } ``` 保存配置文件,然后通过再次运行相同的POST请求来更新Caddy的活动配置:
curl localhost:2019/load \
	-H "Content-Type: application/json" \
	-d @caddy.json
为了更好地衡量,请验证配置是否已更新:
curl localhost:2019/config/
通过在浏览器中刷新页面(或再次运行`curl`)来测试它,你将看到一条鼓舞人心的消息! ## 遍历配置 让我们使用 Caddy API 的强大功能来进行更改,而不需要修改我们的配置文件,而不是上传整个配置文件。 通过像我们上面所做的那样替换整个配置来对生产服务器进行少量更改可能是危险的;这就像拥有对文件系统的root访问权限。Caddy的API允许你限制更改的范围,以确保配置的其他部分不会被意外更改。 使用请求URI的路径,我们可以遍历配置结构并仅更新消息字符串(如果被遮挡,请确保向右滚动): 使用请求 URI 的路径,我们可以遍历配置结构并仅更新消息字符串(如果被遮挡,请确保向右滚动):
curl \
	localhost:2019/config/apps/http/servers/example/routes/0/handle/0/body \
	-H "Content-Type: application/json" \
	-d '"Work smarter, not harder."'
你可以验证它是否适用于类似的GET请求,例如:
curl localhost:2019/config/apps/http/servers/example/routes
你应该看到: ```json [{"handle":[{"body":"Work smarter, not harder.","handler":"static_response"}]}] ``` **重要提示:** 显而易见,一旦你使用API进行配置,原始配置文件并不会被修改,这样你的配置文件就过时了。有几种方法可以处理这个问题: - 使用`--resume`作为[caddy run](/docs/command-line#caddy-run)命令的最后一个参数。 - 不要混合使用配置文件和API两种方式进行更改; 始终使用同一种方式。 - 使用GET请求[导出Caddy的新配置](/docs/api#get-configpath) (不如前两个选项推荐)。 ## 在JSON中使用`@id` 配置遍历当然有用,但是路径有点长,你不觉得吗? 我们可以给我们的处理对象一个[`@id`标签](/docs/api#using-id-in-json),使它更容易访问:
curl \
	localhost:2019/config/apps/http/servers/example/routes/0/handle/0/@id \
	-H "Content-Type: application/json" \
	-d '"msg"'
这给我们的处理对象添加了一个属性:"@id": "msg",所以它现在看起来像这样: ```json { "@id": "msg", "body": "Work smarter, not harder.", "handler": "static_response" } ``` 然后我们可以直接访问它:
curl localhost:2019/id/msg
现在我们也通过更短的路径更改消息:
curl \
	localhost:2019/id/msg/body \
	-H "Content-Type: application/json" \
	-d '"Some shortcuts are good."'
并再次检查:
curl localhost:2019/id/msg/body
================================================ FILE: src/docs/markdown/api.md ================================================ --- title: "API" --- # API Caddy是通过管理端点进行配置的,该端点可以使用[REST](https://en.wikipedia.org/wiki/Representational_state_transfer)API通过HTTP访问。你可以在Caddy配置中[配置此端点](/docs/json/admin/)。 **默认地址:`localhost:2019`** 默认地址可以通过设置`CADDY_ADMIN`环境变量来更改。某些安装方法可能会将其设置为其他值。Caddy配置中的地址始终优先于默认设置。 最新的配置将在任何更改后保存到磁盘(除非[禁用](/docs/json/admin/config/))在重启后恢复上一个工作配置,这可以保证在电源循环或类似情况下配置的持久性。 要开始使用 API,请尝试我们的[API教程](/docs/api-tutorial)或者,如果你只有一分钟时间,请尝试我们的[API快速入门指南](/docs/quick-starts/api)。 --- - **[POST /load](#post-load)** 设置或替换当前配置 - **[POST /stop](#post-stop)** 停止当前配置并退出进程 - **[GET /config/[path]](#get-configpath)** 导出指定路径的配置 - **[POST /config/[path]](#post-configpath)** 设置或替换对象;追加到数组 - **[PUT /config/[path]](#put-configpath)** 创建新对象;插入数组 - **[PATCH /config/[path]](#patch-configpath)** 替换现有对象或数组元素 - **[DELETE /config/[path]](#delete-configpath)** 删除指定路径的值 - **[在JSON中使用`@id`](#using-id-in-json)** 轻松遍历配置结构 - **[并发配置修改](#concurrent-config-changes)** 在对配置进行非同步修改时避免冲突。 - **[POST /adapt](#post-adapt)** 将配置适配为JSON格式,而不实际运行它 - **[GET /pki/ca/<id>](#get-pkicaltidgt)** 返回有关特定[PKI应用](/docs/json/apps/pki/)的CA的信息 - **[GET /pki/ca/<id>/certificates](#get-pkicaltidgtcertificates)** 返回特定[PKI应用](/docs/json/apps/pki/) CA的证书链 - **[GET /reverse_proxy/upstreams](#get-reverse-proxyupstreams)** 返回配置的代理上游的当前状态 ## POST /load 设置 Caddy 的配置,覆盖任何以前的配置。它会一直阻塞,直到重新加载完成或失败。配置更改是轻量级、高效的,并且会导致零停机。如果新配置因任何原因失败,则旧配置将回滚到原位而不会停机。 该端点使用配置适配器支持不同的配置格式。请求的`Content-Type`标头指示请求正文中使用的配置格式。通常这个值应该是`application/json`,代表Caddy的原生配置格式。对于其他配置格式,请指定适当的`Content-Type`,正斜杠`/`之后的值是要使用的配置适配器的名称。例如,在提交Caddyfile时,使用类似于`text/caddyfile`的值;或者对于JSON 5,使用类似于`application/json5`的值; 等等。 如果新配置与当前配置相同,则不会发生重新加载。要强制重新加载,请在请求标头中设置`Cache-Control: must-revalidate`。 ### 示例 设置新的活动配置:
curl "http://localhost:2019/load" \
	-H "Content-Type: application/json" \
	-d @caddy.json
注意:`curl`的`-d`标志会删除换行符,因此如果你的配置格式对换行符敏感(例如 Caddyfile),请改用`--data-binary`:
curl "http://localhost:2019/load" \
	-H "Content-Type: text/caddyfile" \
	--data-binary @Caddyfile
## POST /stop 优雅地关闭服务器并退出进程。要仅停止正在运行的配置而不退出进程,请使用[DELETE /config/](#delete-configpath)。 ### 示例 停止进程:
curl -X POST "http://localhost:2019/stop"
## GET /config/[path] 在命名路径中导出 Caddy 的当前配置。返回 JSON 正文。 ### 示例 导出整个配置并漂亮地打印它:
curl "http://localhost:2019/config/" | jq
{
	"apps": {
		"http": {
			"servers": {
				"myserver": {
					"listen": [
						":443"
					],
					"routes": [
						{
							"match": [
								{
									"host": [
										"example.com"
									]
								}
							],
							"handle": [
								{
									"handler": "file_server"
								}
							]
						}
					]
				}
			}
		}
	}
}
仅导出侦听器地址:
curl "http://localhost:2019/config/apps/http/servers/myserver/listen"
[":443"]
## POST /config/[path] 将 Caddy 的配置更改为请求的 JSON 正文的命名路径。如果目标值是一个数组,则追加 POST;如果是一个对象,则会进行创建或替换。 作为一种特殊情况,如果满足以下条件,可以将许多项目添加到数组中: 1. 路径结束于`/...` 2. `/...`之前的路径元素指的是一个数组 3. 有效载荷是一个数组 在这种情况下,有效载荷数组中的元素将被扩展,并且每个元素都将附加到目标数组中。在 Go 术语中,这将具有与以下相同的效果: ```go baseSlice = append(baseSlice, newElems...) ``` ### 示例 添加监听地址:
curl \
	-H "Content-Type: application/json" \
	-d '":8080"' \
	"http://localhost:2019/config/apps/http/servers/myserver/listen"
添加多个监听地址:
curl \
	-H "Content-Type: application/json" \
	-d '[":8080", ":5133"]' \
	"http://localhost:2019/config/apps/http/servers/myserver/listen/..."
## PUT /config/[path] 将 Caddy 的配置更改为请求的 JSON 正文的命名路径。如果目标值是数组中的位置(索引),则 PUT 插入;如果是一个对象,它会严格创建一个新值。 ### 示例 在第一个槽中添加监听地址:
curl -X PUT \
	-H "Content-Type: application/json" \
	-d '":8080"' \
	"http://localhost:2019/config/apps/http/servers/myserver/listen/0"
## PATCH /config/[path] 将 Caddy 的配置更改为请求的 JSON 正文的命名路径。PATCH 严格替换现有值或数组元素。 ### 示例 替换监听地址:
curl -X PATCH \
	-H "Content-Type: application/json" \
	-d '[":8081", ":8082"]' \
	"http://localhost:2019/config/apps/http/servers/myserver/listen"
## DELETE /config/[path] 在命名路径中删除 Caddy 的配置。DELETE 删除目标值。 ### 示例 要卸载整个当前配置但保持进程运行:
curl -X DELETE "http://localhost:2019/config/"
只停止一个 HTTP 服务器:
curl -X DELETE "http://localhost:2019/config/apps/http/servers/myserver"

在JSON中使用`@id`

你可以在 JSON 文档中嵌入 ID,以便更轻松地直接访问 JSON 的这些部分。 只需添加一个称为`"@id"`对象的字段并为其指定一个唯一名称。例如,如果你有一个想要经常访问的反向代理处理程序:
{
	"@id": "my_proxy",
	"handler": "reverse_proxy"
}
要使用它,只需以与`/config/`相应端点相同的方式向`/id/`API端点发出请求,但无需完整路径。ID 将请求直接带入你的配置范围。 例如,要在没有 ID 的情况下访问反向代理的上游,路径将类似于:
/config/apps/http/servers/myserver/routes/1/handle/0/upstreams
但是有了ID,路径就变成了:
/id/my_proxy/upstreams
这更容易记忆和手写。

并发配置更改

Caddy的配置API为单个请求提供[ACID保证](https://en.wikipedia.org/wiki/ACID),但涉及多个请求的更改如果没有适当同步,可能会导致冲突或数据丢失。 例如,两个客户端可能同时使用`GET /config/foo`,在该范围内进行编辑(配置路径),然后同时调用`POST|PUT|PATCH|DELETE /config/foo/...`来应用更改,导致冲突:要么一个会覆盖另一个,要么第二个可能会将配置留在意外状态,因为它是针对不同版本的配置应用的,而不是针对准备好的版本。这是因为更改彼此不知道。 Caddy的API不支持跨多个请求的事务,并且HTTP是一种无状态协议。但是,您可以使用`Etag`标头和`If-Match`标头来检测和防止所有更改的冲突,作为一种乐观并发控制。如果有任何可能同时使用Caddy的`/config/...`端点而没有同步,则对`GET /config/...`请求的所有响应都有一个名为`Etag`的HTTP尾部,其中包含该范围内内容的路径和哈希(例如`Etag: "/config/apps/http/servers 65760b8e"`)。只需在具有更改性质的请求上设置`If-Match`标头,以前一个`GET`请求的Etag尾部的值为依据。 这个基本算法如下: 1. 对配置的任何范围`S`执行`GET`请求。保存响应的`Etag`尾部。 2. 对返回的配置进行所需的更改。 3. 在范围`S`内执行`POST|PUT|PATCH|DELETE`请求,将`If-Match`标头设置为最近的`Etag`值。 4. 如果响应是HTTP 412(前提条件失败),则从步骤1重新开始,或者在尝试次数过多后放弃。 该算法可以安全地允许对Caddy的配置进行多个重叠更改,而无需显式同步。它的设计使得对配置不同部分的同时更改不需要重试:只有重叠到配置相同范围的更改才可能导致冲突,因此需要重试。 ## POST /adapt 将配置适配为Caddy JSON格式,而不加载或运行它。如果成功,生成的JSON文档将在响应正文中返回。 Content-Type标头用于指定配置格式,方式与[/load](#post-load)相同。例如,要适配Caddyfile,请设置`Content-Type: text/caddyfile`。 只要关联的[配置适配器](/docs/config-adapters)已插入到您的Caddy构建中,此端点将适应任何配置格式。 ### 示例 将Caddyfile适配为JSON: ```bash curl "http://localhost:2019/adapt" \ -H "Content-Type: text/caddyfile" \ --data-binary @Caddyfile ``` ## GET /pki/ca/<id> 通过其ID返回有关特定[PKI应用](/docs/json/apps/pki/) CA的信息。如果请求的CA ID是默认值(`local`),则如果尚未创建CA,则将会创建该CA。如果其他CA ID尚未创建,则将返回错误。 ```bash curl "http://localhost:2019/pki/ca/local" | jq { "id": "local", "name": "Caddy Local Authority", "root_common_name": "Caddy Local Authority - 2022 ECC Root", "intermediate_common_name": "Caddy Local Authority - ECC Intermediate", "root_certificate": "-----BEGIN CERTIFICATE-----\nMIIB ... gRw==\n-----END CERTIFICATE-----\n", "intermediate_certificate": "-----BEGIN CERTIFICATE-----\nMIIB ... FzQ==\n-----END CERTIFICATE-----\n" } ``` ## GET /pki/ca/<id>/certificates 通过其ID返回特定[PKI应用](/docs/json/apps/pki/) CA的证书链。如果请求的CA ID是默认值(`local`),则如果尚未创建CA,则将会创建该CA。如果其他CA ID尚未创建,则将返回错误。 此端点由[`caddy trust`](/docs/command-line#caddy-trust)命令在内部使用,以允许将CA的根证书安装到系统的信任存储中。 ```bash curl "http://localhost:2019/pki/ca/local/certificates" -----BEGIN CERTIFICATE----- MIIByDCCAW2gAwIBAgIQViS12trTXBS/nyxy7Zg9JDAKBggqhkjOPQQDAjAwMS4w ... By75JkP6C14OfU733oElfDUMa5ctbMY53rWFzQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBpDCCAUmgAwIBAgIQTS5a+3LUKNxC6qN3ZDR8bDAKBggqhkjOPQQDAjAwMS4w ... 9M9t0FwCIQCAlUr4ZlFzHE/3K6dARYKusR1ck4A3MtucSSyar6lgRw== -----END CERTIFICATE----- ``` ## GET /reverse_proxy/upstreams 将配置的反向代理上游(后端)的当前状态作为 JSON 文档返回。
curl "http://localhost:2019/reverse_proxy/upstreams" | jq
[
	{"address": "10.0.1.1:80", "num_requests": 4, "fails": 2},
	{"address": "10.0.1.2:80", "num_requests": 5, "fails": 4},
	{"address": "10.0.1.3:80", "num_requests": 3, "fails": 3}
]
JSON 数组中的每个条目都是存储在全局上游池中的已配置[upstream](/docs/json/apps/http/servers/routes/handle/reverse_proxy/upstreams/)。 - **address** 上游的拨号地址。对于SRV上游,这是`lookup_srv`的DNS名称。 - **healthy** 反映了Caddy是否认为上游是健康的。请注意,“健康”是与“可用性”不同的概念。不健康的后端将始终不可用,但健康的后端可能不可用。无论特定的反向代理处理程序配置如何,运行状况都是一个全局特性,而可用性由特定的反向代理处理程序的配置决定。例如,如果处理程序被配置为一次只允许N个请求并且它当前有N个活动请求,那么健康的后端将不可用。“健康”属性不反映可用性。 - **num_requests** 是上游当前正在处理的活动请求的数量。 - **fails** 当前记录的失败请求数,由被动运行状况检查配置。 如果你的目标是确定后端的可用性,则需要根据你正在使用的处理程序配置交叉检查上游的相关属性。例如,如果你为代理启用了[被动健康检查](/docs/json/apps/http/servers/routes/handle/reverse_proxy/health_checks/passive/),那么你还需要考虑`fails`和`num_requests`值来确定上游是否可用:检查`fails`数量是否小于为你的代理配置的最大故障数量代理(即[`max_fails`](/docs/json/apps/http/servers/routes/handle/reverse_proxy/health_checks/passive/max_fails)),并且`num_requests`小于或等于你配置的每个上游的最大请求量(即对于整个代理的[`unhealthy_request_count`](/docs/json/apps/http/servers/routes/handle/reverse_proxy/health_checks/passive/unhealthy_request_count),或对于单个上游的[`max_requests`](/docs/json/apps/http/servers/routes/handle/reverse_proxy/upstreams/max_requests))。 ================================================ FILE: src/docs/markdown/architecture.md ================================================ --- title: 架构 --- 架构 ============ Caddy 是一个单一的、自包含的、静态的二进制文件,外部依赖项为零,因为它是用 Go 编写的。这些价值观构成了项目愿景的重要组成部分,因为它们简化了部署并减少了生产环境中繁琐的故障排除。 如果没有动态链接,那么如何扩展呢?Caddy 采用了一种新颖的插件架构,其功能远远超出任何其他 Web 服务器,即使是那些具有外部(动态链接)依赖项的服务器。 我们“更少的活动部件”的理念最终会导致更可靠、更易于管理、更便宜的站点——尤其是在规模上。这份半技术文档描述了我们如何通过软件工程实现这一目标。 ## 概述 CCaddy 由命令、核心库和模块组成。 **命令**提供了你更熟悉的[命令行界面](/docs/command-line)。这是你从操作系统启动进程的方式。这里的代码和逻辑数量相当少,并且仅具有以用户所需方式引导核心所需的内容。我们有意避免使用标记和环境变量进行配置,除非它们与引导配置有关。 **[核心库](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc)**,或者叫 Caddy的“核心”,主要作用是管理配置。它可以[`Run()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Run) 一个新配置或[`Stop()`](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Stop) 正在运行的配置。它还为要使用的模块提供各种实用程序、类型和值。 **模块**做其他所有事情。许多模块内置在 Caddy 中,称为 _标准模块_。这是是对大多数用户而言最有用的。 ## Caddy核心 Caddy的核心只是加载一个初始配置("config"),或者,在没有配置的情况下,随后打开一个套接字以接受新配置。 [Caddy配置](/docs/json/) 就是一个JSON文档,在其顶层包含一些字段: ```json { "admin": {}, "logging": {}, "apps": {•••}, ... } ``` Caddy 的核心知道如何在本地使用其中一些字段: - [`admin`](/docs/json/admin/) 通过它能设置[管理API](/docs/api)并管理流程 - [`logging`](/docs/json/logging/) 通过它可以[记录logs](/docs/logging) 但是其他顶级字段([`apps`](/docs/json/apps/))对于 Caddy 的核心是不透明的。事实上,Caddy 所知道的如何处理`apps`中的字节,是将它们反序列化为一个接口类型,它可以调用两个方法: 1. `Start()` 2. `Stop()` ……就是这样,它在每个应用的配置载入时调用`Start()`,且在它们的配置被卸载时调用`Stop()`。 启动应用的模块时,它会初始化应用模块的生命周期。 ## 模块生命周期 有两种模块:_主机模块_ 和 _访客模块_。 **主机模块**(或“父”模块)是加载其他模块的模块。 **访客模块**(或“子”模块)是那些被加载的模块。所有模块都是访客模块——甚至是应用程序模块。 模块被加载,被配置和验证,被使用,然后被清理,按以下顺序: 1. 被载入 2. 被配置和验证 3. 被使用 4. 被清理 当首先加载配置时,Caddy 通过初始化所有已配置的应用模块来启动模块生命周期。之后,它被每个应用程序模块带着它走完剩下的路。 ### 加载阶段 加载模块涉及将其 JSON 字节反序列化为内存中的类型值。就是……基本上就是这,它只是将 JSON 解码为一个值。 ### 供应阶段 这个阶段是大部分设置工作的地方。所有模块在加载后都有机会自行配置。 由于 JSON 编码中的任何属性都已经被解码,因此这里只需要进行额外的设置。配置期间最常见的任务是设置访客模块。换句话说,供应主机模块也会导致供应其客户模块,一直向下。 您可以通过在我们的文档[遍历 Caddy 的 JSON 结构](/docs/json/)来了解这一点。你看到`{•••}` 的任何地方都是可以使用访客模块的地方;当你单击其中一个时,你可以一直向下探索,直到没有更多的访客模块。 其他常见的配置任务是设置将在模块生命周期内使用的内部值,或标准化输入。例如,[http.matchers.remote_ip](/docs/modules/http.matchers.remote_ip) 模块使用配置阶段从它从 JSON 接收的字符串输入中解析 CIDR 值。这样,它就不必在每个 HTTP 请求期间都这样做,因此效率更高。 验证也可以在供应阶段进行。如果模块的结果配置无效,则会在此处返回错误,从而中止整个配置加载过程。 ### 使用阶段 一旦客户模块被配置和验证,它就可以被它的主机模块使用。这究竟意味着什么取决于每个主机模块。 每个模块都有一个 ID,它由一个命名空间和该命名空间中的名称组成。例如,[`http.handlers.reverse_proxy`](/docs/modules/http.handlers.reverse_proxy) 是一个 HTTP 处理程序,因为它在`http.handlers` 命名空间中,并且它的名称是`reverse_proxy`。命名空间中的所有模块都`http.handlers` 满足主机模块已知的相同接口。因此,`http` 应用程序知道如何加载和使用这些类型的模块。 ### 清理阶段 当需要停止配置时,所有模块都会被卸载。如果一个模块分配了任何应该被释放的资源,它就有机会在清理阶段这样做。 ## 插入 一个模块——或任何 Caddy 插件——通过`import`为模块的包添加一个“插入”到 Caddy。通过导入包,[模块将自己注册](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#RegisterModule) 到 Caddy 核心,因此当 Caddy 进程启动时,它通过名称知道每个模块。它甚至可以在模块值和名称之间关联,反之亦然。 ## 管理配置 由于服务器需要的高并发性和数千个参数,更改正在运行的服务器的活动配置(通常称为“重新加载”)可能会很棘手。Caddy 使用具有许多优点的设计优雅地解决了这个问题: - 不中断运行服务 - 可以进行粒度配置更改 - 只需要一把锁(在后台) - 所有的重载都是原子的、一致的、隔离的,并且大多是持久的(“ACID”) - 最小的全局状态 您可以[在此处观看有关 Caddy 2 设计的视频](https://www.youtube.com/watch?v=EhJO8giOqQs)。 配置重新加载通过配置新模块来工作,如果全部成功,则清理旧模块。在短时间内,两个配置同时运行。 每个配置都与一个包含所有模块状态的[上下文](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Context)相关联,因此大多数状态永远不会逃脱配置的范围。这对于正确性、性能和简单性来说是个好消息! 然而,有时真正的全局状态是必要的。例如,反向代理可能会跟踪其上游的健康状况;由于全局每个上游只有一个,因此如果每次进行小的配置更改时都忘记它们,那将是很糟糕的。幸运的是,Caddy[提供了](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#UsagePool)类似于语言运行时的垃圾收集器的工具来保持全局状态的整洁。 一种明显的在线配置更新方法是同步对每个配置参数的访问,即使在热路径中也是如此。这在性能和复杂性方面非常糟糕———尤其—是在规模上——因此 Caddy 不使用这种方法。 相反,配置被视为不可变的原子单元:要么整个东西被替换,要么什么都没有改变。[管理API端点](/docs/api)——允许通过遍历结构进行精细更改——仅改变配置的内存表示,从中生成并加载一个全新的配置文档。这种方法在简单性、性能和一致性方面具有巨大的优势。由于只有一把锁,Caddy 很容易处理快速重新加载。 ================================================ FILE: src/docs/markdown/automatic-https.md ================================================ --- title: "自动HTTPS" --- # 自动HTTPS **Caddy是第一个也是唯一一个_默认_自动使用HTTPS的Web服务器。** 自动HTTPS为你的所有站点提供TLS证书并保持更新。它还为你将HTTP重定向到HTTPS!Caddy使用安全且现代的默认设置——无需停机、额外配置或单独的工具。 这是一个28秒的视频,展示了它的工作原理: **菜单:** - [概览(overview)](#overview) - [激活(Activation)](#activation) - [效果(Effects)](#effects) - [主机名要求(Hostname requirements)](#hostname-requirements) - [本地(Local)HTTPS](#local-https) - [测试(Testing)](#testing) - [ACME质询(Challenges)](#acme-challenges) - [按需(On-Demand)TLS](#on-demand-tls) - [错误(Errors)](#errors) - [存储(Storage)](#storage) - [通配符证书(Wildcard certificates)](#wildcard-certificates) ## 概览(Overview) **默认情况下,Caddy通过HTTPS为所有站点提供服务。** - Caddy 使用本地自动信任的自签名证书(如果允许)通过 HTTPS 提供 IP 地址和本地/内部主机名。 - 例子:`localhost`、`127.0.0.1` - Caddy使用来自公开的ACME CA的证书,通过HTTPS提供公共DNS名称,例如[Let's Encrypt](https://letsencrypt.org)或者[ZeroSSL](https://zerossl.com). - 例子:`example.com`、`sub.example.com`、`*.example.com` Caddy 会自动更新所有托管证书并将 HTTP(默认端口 80)重定向到 HTTPS(默认端口 443)。 **对于本地 HTTPS:** - Caddy 可能会提示输入密码以将其唯一的根证书安装到你的信任库中。每个根只发生一次;你可以随时删除它。 - 任何在不信任Caddy根目录的情况下访问该站点的客户端都会显示安全错误。 **对于公共域名:** - 如果你的域的A/AAAA记录指向你的服务器, - 端口80和443对外开放, - Caddy 可以绑定到那些端口( _或者_ 这些端口被转发到 Caddy), - 你的[data目录](/docs/conventions#data-directory)是可写且持久的, - 并且你的域名出现在配置中的相关位置, 然后网站将自动通过 HTTPS 提供服务。你无需为此做任何其他事情。它就是管用! 由于HTTPS使用共享的公共基础架构,因此作为服务器管理员,你应该了解此页面上的其余信息,以便避免不必要的问题,在问题发生时进行故障排除,并正确配置高级部署。 ## 激活(Activation) 当Caddy知道它所服务的域名(即主机名)或IP地址时,它会隐式激活自动HTTPS。有多种方法可以告诉Caddy你的域名或IP,具体取决于你运行或配置Caddy的方式: - [Caddyfile](/docs/caddyfile)的[站点地址](/docs/caddyfile/concepts#addresses) - [路由](/docs/modules/http#servers/routes)中的[域名匹配器](/docs/json/apps/http/servers/routes/match/host/) - 命令行标志,如[--domain](/docs/command-line#caddy-file-server)或[--from](/docs/command-line#caddy-reverse-proxy) - [自动化](/docs/json/apps/tls/certificates/automate/)证书加载器 以下任何一项都将阻止全部或部分激活自动HTTPS: - [明确禁用它](/docs/json/apps/http/servers/automatic_https/) - 在配置中不提供任何域名或IP - 仅监听HTTP端口 - 手动加载证书(除非[这个配置属性](/docs/json/apps/http/servers/automatic_https/ignore_loaded_certificates/)为`true`) ## 效果(Effects) 激活自动HTTPS后,会发生以下情况: - [所有域名](#hostname-requirements)的证书会被获取和更新 - 默认端口(如果有)会被更改为[HTTPS端口](/docs/modules/http#https_port)`443` - HTTP(使用[HTTP端口](/docs/modules/http#http_port)`80`)会被重定向到HTTPS 自动HTTPS永远不会覆盖显式配置。 如有必要,你可以[自定义或禁用HTTPS](/docs/json/apps/http/servers/automatic_https/);例如,你可以跳过某些域名或禁用重定向(对于 Caddyfile,请使用[全局选项](/docs/caddyfile/options)执行该操作)。 ## 主机名要求(Hostname requirements) 如果所有主机名(域名)符合以下条件,则它们都有资格获得完全托管的证书: - 非空 - 仅由字母数字、连字符、点和通配符(`*`)组成 - 不要以点开头或结尾([RFC 1034](https://tools.ietf.org/html/rfc1034#section-3.5)) 此外,如果主机名符合以下条件,则它们有资格获得公开信任的证书: - 不是本地主机(包括`.localhost`和`.local`TLD) - 不是IP地址 - 只有一个通配符`*`作为最左边的标签 ## 本地(Local) HTTPS 为了通过 HTTPS 为非公共站点提供服务,Caddy 生成自己的证书颁发机构 (CA) 并使用它来签署证书。信任链由根证书和中间证书组成。叶证书由中间人签名。它们存储在[Caddy的数据目录](/docs/conventions#data-directory)中的`pki/authorities/local`。 Caddy 的本地CA由[Smallstep库](https://smallstep.com/certificates/)提供支持。 本地HTTPS不使用ACME,也不执行任何DNS验证。它仅在本地机器上工作,并且仅在安装了CA的根证书的地方才受信任。 ### CA根(Root) 根的私钥是使用加密安全的伪随机源唯一生成的,并以有限的权限保存到存储中。它仅被加载到内存中以执行签名任务,之后它留下了垃圾收集的范围。 虽然可以将Caddy配置为直接使用root签名(以支持不兼容的客户端),但默认情况此功能被禁用,且root密钥仅用于签署中间体。 第一次使用根密钥时,Caddy将尝试将其安装到系统的本地信任库中。如果它没有权限这样做,它会提示输入密码。如果不需要,可以在配置中禁用此行为。 安装 Caddy 的根 CA 后,你将在本地信任存储中看到它作为“Caddy Local Authority”(除非你配置了不同的名称)。如果你愿意,你可以随时卸载它(该[`caddy untrust`](/docs/command-line#caddy-untrust)命令使这很容易)。 请注意,自动将证书安装到本地信任存储中只是为了方便,不能保证能正常工作,尤其是在使用容器或Caddy作为非特权系统服务运行的情况下。最后,如果你依赖内部PKI,系统管理员有责任确保将Caddy的根CA正确添加到必要的信任存储中(这超出了Web服务器的范围)。 ### CA中间体(Intermediates) 中间证书和密钥也将被生成,用于签署叶(leaf)(单个站点)证书。 与根证书不同,中间证书的生命周期要短得多,并且会根据需要自动更新。 ## 测试(Testing) 要测试或试验你的 Caddy 配置,请确保[将ACME端点更改](/docs/modules/tls.issuance.acme#ca)为暂存或开发URL,否则你可能会达到速率限制,这可能会阻止你访问HTTPS长达一周,具体取决于你遇到的速率限制。 Caddy的默认CA 之一是[Let's Encrypt](https://letsencrypt.org/),它有一个[暂存端点](https://letsencrypt.org/docs/staging-environment/)不被相同的[速率限制](https://letsencrypt.org/docs/rate-limits/)影响: ``` https://acme-staging-v02.api.letsencrypt.org/directory ``` ## ACME质询(challenges) 获取公众信任的 TLS 证书需要来自公众信任的第三方机构的验证。如今,此验证过程通过[ACME协议](https://tools.ietf.org/html/rfc8555)自动执行,并且可以执行以下三种方式之一(“质询类型”),如下所述。 前两种质询类型默认启用。如果启用了多种质询,Caddy会随机选择一种,以避免依赖特定质询带来的意外。随着时间的推移,它会了解哪种质询类型最成功,并会开始倾向于选取它,但如果有必要,它还是会重新选取其他可用的质询类型。 ### HTTP质询(challenge) HTTP质询对候选主机名的A/AAAA记录执行权威DNS查找,然后使用HTTP通过端口80请求临时加密资源。如果CA看到预期的资源,则会颁发证书。 此质询要求端口80可从外部访问。如果Caddy无法监听80端口,则必须将来自80端口的数据包转发到Caddy的[HTTP端口](/docs/json/apps/http/http_port/)。 默认情况下启用此质询,不需要显式配置。 ### TLS-ALPN质询(challenge) TLS-ALPN 质询对候选主机名的A/AAAA记录执行权威DNS查找,然后使用包含特殊ServerName和ALPN值的TLS握手通过端口443请求临时加密资源。如果CA看到预期的资源,则会颁发证书。 此种质询要求端口443可从外部访问。如果Caddy无法监听443端口,则必须将来自443端口的数据包转发到Caddy的[HTTPS端口](/docs/json/apps/http/https_port/)。 默认情况下启用此质询,不需要显式配置。 ### DNS质询(challenge) DNS质询对候选主机名的TX 记录执行权威DNS查找,并查找具有特定值的特殊TXT记录。如果CA看到预期值,则颁发证书。 此质询不需要任何开放端口,并且请求证书的服务器不需要可从外部访问。但是,DNS 质询需要配置。Caddy 需要知道访问你域的 DNS 提供商的凭据,以便它可以设置(和清除)特殊的 TXT 记录。如果启用 DNS 质询,则默认禁用其他质询。 DNS提供商支持是一项社区工作。[在我们的wiki上了解如何为你的提供商启用DNS质询](https://caddy.community/t/how-to-use-dns-provider-modules-in-caddy-2/8148)。 ## 按需(On-Demand) TLS Caddy开创了一种我们称为**按需(On-Demand) TLS**的新技术,它在需要它的第一次TLS握手期间动态获取新证书,而不是在配置加载时。至关重要的是,这不需要提前在配置中指定域名。 许多企业依靠这一独特的功能以更低的成本扩展他们的 TLS 部署,并且在为数万个站点提供服务时不会遇到运营难题。 按需 TLS 在以下情况下很有用: - 当你启动或重新加载服务器时,你并不知道所有域名, - 域名可能未立即正确配置(尚未设置 DNS 记录), - 你无法控制域名(例如,它们是客户的域名)。 启用按需 TLS 后,你无需在配置中指定域名即可为其获取证书。相反,当收到 Caddy 尚未获得证书的服务器名称 (SNI) 的 TLS 握手时,会在 Caddy 获得用于完成握手的证书时保持握手。延迟通常只有几秒钟,只有最初的握手很慢。所有未来的握手都很快,因为证书被缓存和重用,并且更新发生在后台。未来的握手可能会触发对证书的维护以使其保持更新,但如果证书尚未过期,则此维护将在后台进行。 ### 使用按需(Using On-Demand) TLS **在生产环境中,必须同时启用和限制按需TLS。在不限制的情况下启用会使你的服务器受到攻击。** 如果使用 JSON 配置,则在[TLS自动化策略](/docs/json/apps/tls/automation/policies/)中启用按需TLS,如果使用Caddyfile,则在带有[带有`tls`指令的站点块](/docs/caddyfile/directives/tls)中启用它。 为防止滥用此功能,你必须配置限制。这是在[`automation`JSON配置对象](/docs/json/apps/tls/automation/on_demand/)或Caddyfile的[`on_demand_tls`全局选项](/docs/caddyfile/options#on-demand-tls)中完成的。限制是“全局的”,不能按站点或按域进行配置。主要限制是“询问”端点,Caddy 将向其发送 HTTP 请求以询问它是否有权在握手中获取和管理域的证书。这意味着你将需要一些内部后端,例如,可以查询数据库的帐户表并查看客户是否已使用该域名注册。 你还可以将速率限制配置为限制,但仅速率限制不足以提供保护。 请注意你的 CA 能够以多快的速度颁发证书。如果花费的时间超过几秒钟,这将对用户体验产生负面影响(仅适用于第一个客户端)。 由于它的延迟性质和滥用的可能性(如果没有通过适当的配置来缓解),我们建议仅在你的实际用例在上面描述时才启用按需 TLS。 [有关有效使用按需TLS的更多信息,请参阅我们的wiki文章](https://caddy.community/t/serving-tens-of-thousands-of-domains-over-https-with-caddy/11179)。 ## 错误(Errors) 如果证书管理出现错误,Caddy会尽力继续。 默认情况下,证书管理在后台执行。这意味着它不会阻止启动或减慢你的网站。但是,这也意味着服务器将在所有证书可用之前运行。在后台运行允许Caddy在很长一段时间内以指数退避重试。 如果在获取或更新证书时出错,会发生以下情况: 1. Caddy在短暂暂停后重试一次,以防万一这是偶然事件 2. Caddy短暂停顿,然后切换到下一个启用的质询类型 3. 在尝试了所有启用的质询类型后,[它会尝试下一个配置的颁发者](#issuer-fallback) - Let's Encrypt - ZeroSSL 4. 在尝试了所有发行人之后,它会以指数方式回退 - 尝试之间最多间隔 1 天 - 长达30天 在使用Let's Encrypt重试期间,Caddy 切换到他们的[暂存环境](https://letsencrypt.org/docs/staging-environment/)以避免速率限制问题。这不是一个完美的策略,但总的来说它很有帮助。 ACME质询至少需要几秒钟才能完成,内部速率限制有助于减少意外滥用。除了你或CA配置的内容之外,Caddy还使用内部速率限制,这样你就可以给Caddy一个包含一百万个域名的配置(platter),它会逐渐(但尽可能快地)获得所有域名的证书。Caddy的内部速率限制目前是每个ACME帐户每10秒尝试10次。 为避免资源泄漏,Caddy会在配置更改时中止正在进行的任务(包括ACME事务)。虽然Caddy能够处理频繁的配置重新加载,但请注意诸如此类的操作注意事项,并考虑批量配置更改以减少重新加载并让Caddy有机会在后台实际完成获取证书。 ### 发行人后备(Issuer fallback) Caddy 是第一个(也是迄今为止唯一一个)在无法成功获得证书时支持完全冗余、自动故障转移到其他CA的服务器。 默认情况下,Caddy启用两个与ACME兼容的CA:[**Let's Encrypt**](https://letsencrypt.org)和[**ZeroSSL**](https://zerossl.com)。如果Caddy无法从Let's Encrypt获得证书,它将尝试使用ZeroSSL;如果两者都失败,它将退避并稍后重试。在你的配置中,你可以自定义Caddy使用哪些颁发者来获取证书,可以是通用的,也可以是特定名称的。 ## 存储(Storage) Caddy 将在其[配置的存储设施](/docs/json/storage/)中存储公共证书、私钥和其他资产(或默认存储设施,如果未配置 - 请参阅链接了解详细信息)。 **使用默认配置需要了解的主要内容是该`$HOME`文件夹必须是可写且持久的。`--environ`的作用是帮助你排除故障,如果指定了标志,Caddy会在启动时打印该环境变量。 任何配置为使用相同存储的Caddy实例都将自动共享这些资源并作为集群协调证书管理。 在尝试任何 ACME 事务之前,Caddy 将测试配置的存储以确保它是可写的并且有足够的容量。这有助于减少不必要的锁争用。 ## 通配符证书(Wildcard certificates) 当 Caddy 配置为使用合格的通配符名称为站点提供服务时,它可以获取和管理通配符证书。如果只有最左边的域标签是通配符,则站点名称有资格使用通配符。例如,`*.example.com`符合条件,但这些不符合条件:`sub.*.example.com`、`foo*.example.com`、`*bar.example.com`和`*.*.example.com`。 如果使用 Caddyfile,Caddy 会根据证书主题名称获取站点名称。换句话说,定义为的站点`sub.example.com`将导致 Caddy管理`sub.example.com`的证书, ,定义为的站点`*.example.com`将导致Caddy管理`*.example.com`的通配符证书。你可以在我们的[常用Caddyfile模式](/docs/caddyfile/patterns#wildcard-certificates)页面上看到这一点。如果你需要不同的行为,JSON 配置可以让你更精确地控制证书主题和站点名称(“主机匹配器”)。 通配符证书代表了广泛的权限,并且仅应在你拥有如此多的子域以致为它们管理单个证书会使 PKI 紧张或导致你达到 CA 强制的速率限制时使用。 **注意:** [Let's Encrypt](https://letsencrypt.org/docs/challenge-types/)需要使用[DNS质询](#dns-challenge)才能获得通配符证书。 ## 加密的ClientHello(ECH) 通常在TLS握手时,ClientHello(包含SNI,即目标域名)会以明文传输。ECH通过“外层”ClientHello包裹真实的“内层”ClientHello,从而保护真实域名不在链路上明文暴露。 Caddy可以自动生成、发布并提供ECH配置。要让ECH真正产生隐私收益,还需要DNS发布、客户端支持与安全DNS查询(如DoH/DoT)等条件共同满足。 ### 部署注意事项 ECH是一个系统性能力,部署时应重点关注以下几点: - DNS中需要有对应域名记录,Caddy才会为其发布HTTPS类型记录中的ECH配置。 - 客户端即使看到`encrypted_client_hello`扩展,也不代表已成功使用ECH,排障时应结合SNI值判断。 - ECH密钥需要轮换,并在一段时间内兼容旧配置,避免客户端缓存导致连接失败。 - 建议统一使用一个public name来增大匿名集,但也要评估集中化带来的运维与信任边界问题。 - 若要保护子域名隐私,应同时评估通配符证书、DNSSEC配置与客户端能力。 #### 发布(Publication) Caddy仅会为已有DNS记录的域名发布HTTPS类型记录中的ECH配置;若只有通配符记录,请确保配置中也包含对应通配符域名。 #### ECH GREASE 现代浏览器常会发送带`encrypted_client_hello`扩展的握手以增加不可区分性。排障时请不要仅凭扩展存在与否判断是否启用ECH。 #### 密钥轮换(Key rotation) ECH密钥应定期轮换,并在一段时间内继续兼容旧配置,以覆盖DNS缓存传播周期,减少握手失败或明文回退风险。 #### Public name outer SNI中的public name必须由你的服务器可权威响应,且建议使用统一、通用的名称,以便在配置更新时为客户端提供带内更新路径。 #### 匿名集(Anonymity set) 匿名集越大,旁路观察者越难推断真实目标。实践中建议同一组织尽量收敛到较少public name。 #### 集中化(Centralization) ECH通常与DoH/DoT联动,可能在提升隐私的同时带来流量与依赖集中化。部署时应结合自身威胁模型权衡。 #### 子域名隐私(Subdomain privacy) 如需降低子域名泄露风险,可结合通配符证书、合理DNSSEC策略与ECH一并部署;同时避免在域名中放置敏感信息。 ### 启用ECH ECH依赖将配置发布到DNS,因此你需要使用包含对应DNS提供商模块(`caddy-dns`)的Caddy构建。 在Caddyfile中,可在全局选项中配置DNS提供商与ECH public name: ```caddy { dns ech example.com } ``` 若使用JSON,可在`tls`应用中配置: ```json "encrypted_client_hello": { "configs": [ { "public_name": "example.com" } ] }, "dns": { "name": "" } ``` ### 验证ECH 可通过抓包(如Wireshark)确认SNI字段是否显示public name而非真实站点域名;这通常是验证ECH是否生效的关键指标。 部署检查建议: - 启动后确认日志中出现ECH配置发布成功信息。 - 确认浏览器已启用ECH,并在必要时启用DoH/DoT。 - 清理DNS缓存并建立新连接后再抓包验证,避免复用旧连接影响判断。 ### 存储中的ECH ECH配置会存放在[数据目录](/docs/conventions#data-directory)的存储模块中(默认文件系统),位于`ech/configs`路径下。元数据文件用于记录发布时间,避免每次重载都重复向DNS提供商发布。必要时可删除元数据触发重建,但应注意这也可能影响轮换时间点。 ================================================ FILE: src/docs/markdown/build.md ================================================ --- title: 从源码构建 --- # 从源码构建 如果你需要自定义构建(例如带插件),构建Caddy有多种方式: - [Git](#git):从Git仓库构建 - [`xcaddy`](#xcaddy):使用`xcaddy`构建 - [Docker](#docker):构建自定义Docker镜像 要求: - [Go](https://golang.org/doc/install) 1.20或更高版本 [Package Support Files](#package-support-files-for-custom-builds-for-debianubunturaspbian)一节包含给这类用户的说明:已在Debian衍生系统上通过APT安装Caddy,但仍需要自定义构建可执行文件用于生产运维。 ## Git 要求: - 已安装Go(见上文) 克隆仓库:
git clone "https://github.com/caddyserver/caddy.git"
如果你没有git,也可以[从GitHub](https://github.com/caddyserver/caddy)下载源码压缩包。每个[发布版本](https://github.com/caddyserver/caddy/releases)也提供源码快照。 构建:
cd caddy/cmd/caddy/
go build
Go程序很容易交叉编译到其他平台。只需设置不同的`GOOS`、`GOARCH`和/或`GOARM`环境变量。(详见[go文档](https://golang.org/doc/install/source#environment)) 例如,当你当前不在Windows上时,编译Windows版Caddy:
GOOS=windows go build
类似地,当你当前不在Linux或ARMv6上时,编译Linux ARMv6版:
GOOS=linux GOARCH=arm GOARM=6 go build
## xcaddy [`xcaddy`命令](https://github.com/caddyserver/xcaddy)是构建带版本信息和/或插件Caddy的最简单方式。 要求: - 已安装Go(见上文) - 确保[`xcaddy`](https://github.com/caddyserver/xcaddy/releases)在你的`PATH`中 你**不需要**下载Caddy源码(它会自动完成)。 然后,构建Caddy(包含版本信息)只需:
xcaddy build
若要携带插件构建,使用`--with`:
xcaddy build \
    --with github.com/caddyserver/nginx-adapter
	--with github.com/caddyserver/ntlm-transport@v0.1.1
如你所见,可以通过`@`语法指定插件版本。版本可以是tag名、commit SHA或分支。 使用`xcaddy`的跨平台编译方式与`go`命令一致。例如,为macOS交叉编译:
GOOS=darwin xcaddy build
## Docker 你可以使用`:builder`镜像,快速构建带自定义模块的新Caddy二进制: ```Dockerfile FROM caddy:-builder AS builder RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ xcaddy build \ --with github.com/caddyserver/nginx-adapter \ --with github.com/hairyhenderson/caddy-teapot-module@v0.0.3-0 FROM caddy: COPY --from=builder /usr/bin/caddy /usr/bin/caddy ``` 请将``替换为当前最新Caddy版本作为起点。 注意第二个`FROM`指令:它只是把新构建的二进制覆盖到常规`caddy`镜像上,因此产物镜像会小很多。 构建阶段用`xcaddy`构建并注入指定模块,过程与[上文](#xcaddy)一致。`--mount=type=cache,target=/go/pkg/mod`和`--mount=type=cache,target=/root/.cache/go-build`分别用于缓存Go模块依赖和构建产物,可显著加速后续构建。该参数是[Docker特性](https://docs.docker.com/build/cache/optimize/#use-cache-mounts),不是`xcaddy`特性。 若使用Docker Compose,请参见我们推荐的[`compose.yml`](/docs/running#docker-compose)及使用说明。 ## Package support files for custom builds for Debian/Ubuntu/Raspbian 该流程旨在:运行自定义`caddy`二进制的同时,保留`caddy`软件包中的支持文件。 该流程让用户可以继续利用官方包中的默认配置、systemd服务文件和bash补全。 要求: - 按[这些说明](/docs/install#debian-ubuntu-raspbian)安装`caddy`软件包 - 构建你的自定义`caddy`二进制(见上文),或从[下载页](/download)下载自定义构建 - 你的自定义`caddy`二进制应位于当前目录 流程:
sudo dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy
sudo mv ./caddy /usr/bin/caddy.custom
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10
sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50
sudo systemctl restart caddy
说明: - `dpkg-divert`会把`/usr/bin/caddy`二进制移动到`/usr/bin/caddy.default`,并设置diversion,以防后续软件包再向该路径安装文件。 - `update-alternatives`会创建到`/usr/bin/caddy`的符号链接,指向你期望的caddy二进制。 - `systemctl restart caddy`会停止默认版本Caddy服务并启动自定义版本。 你可以执行下面命令并按屏幕提示,在默认/自定义`caddy`二进制之间切换;完成后重启Caddy服务。
update-alternatives --config caddy
完成上述配置后,你可运行[`caddy upgrade`](/docs/command-line#caddy-upgrade)来升级Caddy。它会尝试按你当前构建中的同款插件组合,下载带最新Caddy版本的新构建,然后替换当前二进制。 ================================================ FILE: src/docs/markdown/caddyfile/concepts.md ================================================ --- title: Caddyfile概念 --- # Caddyfile概念 本文档将帮助你详细了解HTTP Caddyfile。 1. [结构](#structure) 2. [地址](#addresses) 3. [匹配器](#matchers) 4. [占位符](#placeholders) 5. [片段](#snippets) 6. [注释](#comments) 7. [环境变量](#environment-variables) 8. [全局选项](#global-options)

结构

下面的图片可以直观地描述Caddyfile的结构: ![Caddyfile的结构](/resources/images/caddyfile-visual.png) 关键点: - 可选的**全局选项块**可以放在文件的头部 - 否则, Caddyfile的首行**总是**要提供服务的网站地址。 - 所有指令和匹配器都**必须**放在站点块中。跨站点块没有全局范围或继承。 - 如果**只有一个站点块**,则其花括号`{ }`是可选的。 一个Caddyfile至少包含一个或多个站点块,这些块总是以站点的一个或多个[地址](#addresses)开始。出现在地址之前的任何指令都会使扰乱解析器。 ### 块 打开和关闭一个**块**是用花括号完成的: ``` ... { ... } ``` - 打开的花括号`{`必须位于行尾。 - 大括号`}`必须独占一行。 当只有一个站点块时,花括号(和缩进)是可选的。这是为了方便快速定义单个站点,例如: ```caddy localhost reverse_proxy /api/* localhost:9001 file_server ``` 相当于: ```caddy localhost { reverse_proxy /api/* localhost:9001 file_server } ``` 当你只有一个站点块时;这是一个偏好问题。 要使用相同的Caddyfile配置多个站点,你必须在每个站点周围使用花括号来分隔它们的配置: ```caddy example1.com { root * /www/example.com file_server } example2.com { reverse_proxy localhost:9000 } ``` 如果一个请求匹配多个站点块,则选择具有最具体匹配地址的站点块。请求不会级联到其他站点块。 ### 指令 [**指令**](/docs/caddyfile/directives)是自定义网站服务方式的关键字。例如,完整的文件服务器配置可能如下所示: ```caddy localhost file_server ``` 或反向代理: ```caddy localhost reverse_proxy localhost:9000 ``` 在这些示例中,[`file_server`](/docs/caddyfile/directives/file_server)和[`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy)是指令。指令是站点块中一行的第一个单词。 在第二个示例中,`localhost:9000`是一个**参数**,因为它出现在指令之后的同一行。 请注意,当调整 Caddyfile 时,指令会根据特定的默认[指令顺序](/docs/caddyfile/directives#directive-order)进行排序。 **子指令**可以出现在指令块中: ```caddy localhost reverse_proxy localhost:9000 localhost:9001 { lb_policy first } ``` 这里,`lb_policy`是[`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy)的子指令(它用于设置后端之间使用的负载平衡策略)。 ### 标记和引号 Caddyfile在被解析之前被词法解析成标记。空格在Caddyfile中很重要,因为标记就是由它进行分隔。 通常,指令需要一定数量的参数。如果单个参数有一个带有空格的值,它会被作为两个单独的标记进行词法分析: ```caddy-d directive abc def ``` 这可能会出现问题并返回错误或意外行为。 如果`abc def`应该是单个参数的值,则需要使用引号: ```caddy-d directive "abc def" ``` 如果你也需要在带引号的标记中使用引号,则可以转义引号: ```caddy-d directive "\"abc def\"" ``` 在带引号的标记内,所有其他字符都按字面意思处理,包括空格、制表符和换行符。 你还可以使用反引号`来引用标记: ```caddy-d directive `"foo bar"` ``` 当标记包含引号文字时,反引号字符串很方便,例如JSON文本。

地址

地址总是出现在站点块的顶部,并且通常出现在Caddyfile中的第一行。 这些是有效地址的示例: - `localhost` - `example.com` - `:443` - `http://example.com` - `localhost:8080` - `127.0.0.1` - `[::1]:2015` - `example.com/foo/*` - `*.example.com` - `http://` 从地址中,Caddy可以潜在地推断出你站点的方案、主机、端口和路径。 如果你指定主机名,则只会处理具有匹配Host标头的请求。换句话说,如果站点地址是`localhost`,那么Caddy将不会匹配到`127.0.0.1`的请求。 可以使用通配符(`*`),但仅代表主机名的一个标签。例如,`*.example.com`匹配`foo.example.com`,但不匹配`foo.bar.example.com`,`*`匹配`localhost`,但不匹配`example.com`。要捕获所有主机,请省略地址的主机部分。 如果多个站点共享相同的定义,你可以将所有站点一起列出: ```caddy localhost:8080, example.com, www.example.com ``` 或者 ```caddy localhost:8080, example.com, www.example.com ``` 请注意逗号如何表示地址的延续。 地址必须是唯一的;你不能多次指定同一个地址。

匹配器

默认情况下,注入HTTP处理程序的指令适用于所有请求(除非另有说明)。 请求匹配器可用于按给定标准对请求进行分类。这个概念源于[底层的JSON结构](/docs/json/apps/http/servers/routes/match/),知道如何在Caddyfile中使用它们很重要。使用匹配器,你可以准确指定某个指令适用于哪些请求。 对于支持匹配器的指令,指令后的第一个参数是**匹配器标记**。这里有些例子: ```caddy-d root * /var/www # matcher token: * root /index.html /var/www # matcher token: /index.html root @post /var/www # matcher token: @post ``` 完全省略匹配器标记,则可以匹配所有的请求;例如,如果下一个参数看起来不像路径匹配器,则不需要给出`*`。 **[阅读有关请求匹配器的页面](/docs/caddyfile/matchers),了解更多信息。**

占位符

你可以在Caddyfile中使用任何[Caddy占位符](/docs/conventions#placeholders),但为方便起见,你还可以使用一些等效的速记符: | 简写 | 替换 | |---------------------------------------|----------------------------------------------------| | `{dir}` | `{http.request.uri.path.dir}` | | `{file}` | `{http.request.uri.path.file}` | | `{header.*}` | `{http.request.header.*}` | | `{host}` | `{http.request.host}` | | `{labels.*}` | `{http.request.host.labels.*}` | | `{hostport}` | `{http.request.hostport}` | | `{port}` | `{http.request.port}` | | `{method}` | `{http.request.method}` | | `{path}` | `{http.request.uri.path}` | | `{path.*}` | `{http.request.uri.path.*}` | | `{query}` | `{http.request.uri.query}` | | `{query.*}` | `{http.request.uri.query.*}` | | `{re.*.*}` | `{http.regexp.*.*}` | | `{remote}` | `{http.request.remote}` | | `{remote_host}` | `{http.request.remote.host}` | | `{remote_port}` | `{http.request.remote.port}` | | `{scheme}` | `{http.request.scheme}` | | `{uri}` | `{http.request.uri}` | | `{tls_cipher}` | `{http.request.tls.cipher_suite}` | | `{tls_version}` | `{http.request.tls.version}` | | `{tls_client_fingerprint}` | `{http.request.tls.client.fingerprint}` | | `{tls_client_issuer}` | `{http.request.tls.client.issuer}` | | `{tls_client_serial}` | `{http.request.tls.client.serial}` | | `{tls_client_subject}` | `{http.request.tls.client.subject}` | | `{tls_client_certificate_pem}` | `{http.request.tls.client.certificate_pem}` | | `{tls_client_certificate_der_base64}` | `{http.request.tls.client.certificate_der_base64}` | | `{upstream_hostport}` | `{http.reverse_proxy.upstream.hostport}` |

片段

你可以定义称为片段的特殊块,方法是给它们一个用括号括起来的名称: ```caddy (redirect) { @http { protocol http } redir @http https://{host}{uri} } ``` 然后你可以在任何你需要的地方重复使用它: ```caddy-d import redirect ``` [`import`](/docs/caddyfile/directives/import) 指令还可用于在其位置包含其他文件。作为一种特殊情况,它几乎可以出现在Caddyfile中的任何位置。 你可以将参数传递给导入的配置并像这样使用它们: ```caddy (snippet) { respond "Yahaha! You found {args.0}!" } a.example.com { import snippet "Example A" } b.example.com { import snippet "Example B" } ```

注释

注释从行首的`#`开始并一直持续到行尾: ```caddy-d # Comments can start a line directive # or go at the end ``` 哈希字符`#`不能出现在标记的中间(即它必须以空格开头或出现在行首)。这允许在URI或其他值中使用它而不需要引号。

环境变量

如果你的配置依赖于环境变量,你可以在Caddyfile中使用它们: ```caddy {$SITE_ADDRESS} ``` 这种形式的环境变量在解析开始之前被替换,因此它们可以扩展为空值、部分标记、完整标记,甚至是多个标记和行。 当未找到环境变量时,可以指定默认值,方法是使用`:`变量名和默认值之间的分隔符: ```caddy {$DOMAIN:localhost} ``` 如果你想将环境变量的替换推迟到运行时,你可以使用[标准`{env.*}`占位符](/docs/conventions#placeholders)。

全局选项

Caddyfile可以选择以没有键的特殊块开始,称为[全局选项块](/docs/caddyfile/options): ```caddy { ... } ``` 如果存在,它必须是配置中的第一个块。 它用于设置全局适用的选项,或不适用于任何特定站点。在里面,只能设置全局选项;你不能在其中使用常规站点指令。 点击[了解](/docs/caddyfile/options)有关全局选项块的更多信息。 ================================================ FILE: src/docs/markdown/caddyfile/directives/abort.md ================================================ --- title: abort (Caddyfile指令) --- # abort 通过立即中止HTTP处理链和关闭连接,阻止对客户端的任何响应。同一连接上的任何并发的、活动的HTTP流都会被中断。 ## 语法 ```caddy-d abort [] ``` ## 示例 当使用通配符证书时,强行关闭收到的未定义域名的连接。 ```caddy *.example.com { @foo host foo.example.com handle @foo { respond "This is foo!" 200 } # 未定义的域名会落到这里,但我们不想接收它们的请求 handle { 中止 } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/acme_server.md ================================================ --- title: acme_server (Caddyfile指令) --- # acme_server 一个嵌入式[ACME协议](https://tools.ietf.org/html/rfc8555)服务器处理程序。这允许一个Caddy实例为任何其他兼容ACME的软件(包括其他Caddy实例)签发证书。 启用后,匹配路径`/acme/*`的请求将由ACME服务器处理。 ## 客户端配置 使用ACME服务器的默认值时,ACME客户端只需配置为使用`https://localhost/acme/local/directory`作为它们的ACME端点。(`local`是Caddy默认CA的ID。) ## 语法 ```caddy-d acme_server [] { ca lifetime resolvers challenges allow_wildcard_names allow { domains ip_ranges } deny { domains ip_ranges } } ``` - **ca** 指定用于签署证书的证书颁发机构ID。默认值是`local`,也就是Caddy的默认CA,用于本地使用的自签名证书,这在开发环境中最常见。若用于更广泛的场景,建议指定不同的CA以避免混淆。如果给定ID的CA尚不存在,它将被创建。参见[PKI应用全局选项](/docs/caddyfile/options#pki-options)来配置其他CA。 - **lifetime**(默认:`12h`)是一个[持续时间](/docs/conventions#durations),指定已签发证书的有效期。该值必须小于用于签名的[中间证书](/docs/caddyfile/options#intermediate-lifetime)的有效期。除非绝对必要,否则不建议更改。 - **resolvers** 是用于查找TXT记录以完成ACME DNS质询的DNS解析器地址。接受[网络地址](/docs/conventions#network-addresses),未指定时默认使用UDP和53端口。如果主机是IP地址,将直接拨号到该地址解析上游服务器。如果主机不是IP地址,则使用Go标准库的[名称解析约定](https://golang.org/pkg/net/#hdr-Name_Resolution)解析地址。如果指定了多个解析器,将随机选择一个。 - **challenges** 设置启用的质询类型。如果未设置,或该指令未带值使用,则启用所有质询类型。可接受的值为:`http-01`、`tls-alpn-01`、`dns-01`。 - **allow_wildcard_names** 启用签发带有通配符SAN(Subject Alternative Name)的证书。 - **allow**、**deny** 配置`acme_server`的运行策略。策略评估遵循Step-CA [这里](https://smallstep.com/docs/step-ca/policies/#policy-evaluation)描述的规则。 - **domains** 根据策略评估规则设置允许或拒绝的主体域名。 - **ip_ranges** 根据策略评估规则设置允许或拒绝的主体IP范围。 ## 示例 在域名`acme.example.com`上提供ID为`home`的ACME服务器,通过[`pki`全局选项](/docs/caddyfile/options#pki-options)自定义CA,并使用`internal`签发者签发自己的证书: ```caddy { pki { ca home { name "My Home CA" } } } acme.example.com { tls { issuer internal { ca home } } acme_server { ca home } } ``` 如果你有另一台Caddy服务器,它可以使用上面的ACME服务器来签发自己的证书: ```caddy { acme_ca https://acme.example.com/acme/home/directory acme_ca_root /path/to/home_ca_root.crt } example.com { respond "Hello, world!" } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/basic_auth.md ================================================ --- title: basic_auth (Caddyfile指令) --- # basic_auth 启用 HTTP 基本身份验证,可用于使用用户名和散列密码保护目录和文件。 **请注意,基本身份验证在普通 HTTP 上并不安全。** 在决定使用 HTTP 基本身份验证保护什么时,请谨慎使用。 当用户请求受保护的资源时,如果尚未提供用户名和密码,浏览器会提示用户输入。如果 `Authorization` 标头中存在正确的凭据,服务器会授予访问权限;如果标头缺失或凭据不正确,服务器会响应 HTTP 401 Unauthorized。 Caddy 配置不接受明文密码;在将密码放入配置之前,必须先对其进行哈希处理。[`caddy hash-password`](/docs/command-line#caddy-hash-password) 命令可以帮助完成这一步。 认证成功后,`{http.auth.user.id}` 占位符将可用,其中包含已认证的用户名。 在 v2.8.0 之前,此指令名为 `basicauth`;后来为与其他指令保持一致而重命名为 `basic_auth`。 ## 语法 ```caddy-d basic_auth [] [ []] { ... } ``` - **<hash_algorithm>** 指定此配置中用于哈希的密码哈希算法(或密钥派生函数)。可用选项包括 `argon2id`,默认值是 `bcrypt`。 - **<realm>** 是自定义 realm 名称。 - **<username>** 是用户名或用户 ID。 - **<hashed_password>** 是密码哈希。 ## 示例 要求对 `example.com` 的所有请求进行认证: ```caddy example.com { basic_auth { # 用户名 "Bob",密码 "hiccup" Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG } respond "Welcome, {http.auth.user.id}" 200 } ``` 保护 `/secret/` 中的文件,使只有 `Bob` 可以访问(其他路径仍可被任何人访问): ```caddy example.com { root /srv basic_auth /secret/* { # 用户名 "Bob",密码 "hiccup" Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG } file_server } ``` `argon2id` 示例: ```caddy example.com { root /srv basic_auth /secret/* argon2id { # 用户名 "Bob",密码 "hiccup" Bob $argon2id$v=19$m=47104,t=1,p=1$zJPvVe48N64JUa9MFlVhiw$b5Tznu0PxnA4TciY6qYe2BFPxncF1ePQaeNukHhH1cU } file_server } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/bind.md ================================================ --- title: bind (Caddyfile指令) --- # bind 指定服务器的套接字绑定的接口。通常情况下,监听器会绑定到空(通配符)接口。然而,你可以强制监听器绑定到另一个主机名或IP。(这个指令只接受一个主机,而不能是端口)。 通常,监听器会绑定到空(通配符)接口。不过,你可以强制监听器改为绑定到其他主机名或IP。此指令只接受主机,不接受端口。端口由[站点地址](/docs/caddyfile/concepts#addresses)决定(默认为`443`)。 请注意,站点绑定方式不一致可能会导致意外后果。例如,如果同一端口上的两个站点都解析到`127.0.0.1`,而只有其中一个站点配置了`bind 127.0.0.1`,那么只有一个站点可访问,因为另一个站点会在没有指定具体主机的情况下绑定到该端口;操作系统会选择更具体匹配的套接字。(虚拟主机不会在不同监听器之间共享。) `bind`接受[网络地址](/docs/conventions#network-addresses),但不能包含端口。 ## 语法 ```caddy-d bind ``` - **<hosts...>** 是要绑定监听器的主机接口列表。 ## 示例 要使套接字只能从当前机器访问,请绑定到回环接口(localhost): ```caddy example.com { bind 127.0.0.1 } ``` 要包含IPv6: ```caddy example.com { bind 127.0.0.1 [::1] } ``` 要绑定到`10.0.0.1:8080`: ```caddy example.com:8080 { bind 10.0.0.1 } ``` 要绑定到`/run/caddy`处的Unix域套接字: ```caddy example.com { bind unix//run/caddy } ``` 要将文件权限改为所有用户可写([默认](/docs/conventions#network-addresses)为`0200`,即只有所有者可写): ```caddy example.com { bind unix//run/caddy|0222 } ``` 要把一个域名绑定到两个不同接口,并返回不同响应: ```caddy example.com { bind 10.0.0.1 respond "One" } example.com { bind 10.0.0.2 respond "Two" } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/encode.md ================================================ --- title: encode (Caddyfile指令) --- # encode 使用指定的编码对响应进行编码。其典型用途就是压缩。 ## 语法 ```caddy-d encode [] [] { # 编码格式 gzip [] zstd [] minimum_length match } ``` - **<formats...>** 是要启用的编码格式列表。如果启用了多种编码,则会根据请求的`Accept-Encoding`头选择编码;如果客户端没有强偏好(q-factor),则使用第一个受支持的编码。如果省略,默认启用`zstd`(优先)和`gzip`。 - **gzip** 启用Gzip压缩,可选择指定级别。 - **zstd** 启用Zstandard压缩,可选择指定级别(可能的值为default、fastest、better、best)。默认压缩级别大致等同于Zstandard的默认模式(级别3)。 - **minimum_length** 是响应应达到多少字节才进行编码的最小值(默认:512)。 - **match** 是一个[响应匹配器](/docs/caddyfile/response-matchers)。只有匹配的响应会被编码。默认如下: ```caddy-d match { header Content-Type application/atom+xml* header Content-Type application/eot* header Content-Type application/font* header Content-Type application/geo+json* header Content-Type application/graphql+json* header Content-Type application/javascript* header Content-Type application/json* header Content-Type application/ld+json* header Content-Type application/manifest+json* header Content-Type application/opentype* header Content-Type application/otf* header Content-Type application/rss+xml* header Content-Type application/truetype* header Content-Type application/ttf* header Content-Type application/vnd.api+json* header Content-Type application/vnd.ms-fontobject* header Content-Type application/wasm* header Content-Type application/x-httpd-cgi* header Content-Type application/x-javascript* header Content-Type application/x-opentype* header Content-Type application/x-otf* header Content-Type application/x-perl* header Content-Type application/x-protobuf* header Content-Type application/x-ttf* header Content-Type application/xhtml+xml* header Content-Type application/xml* header Content-Type font/* header Content-Type image/svg+xml* header Content-Type image/vnd.microsoft.icon* header Content-Type image/x-icon* header Content-Type multipart/bag* header Content-Type multipart/mixed* header Content-Type text/* } ``` ## 示例 启用Gzip压缩: ```caddy-d encode gzip ``` 启用Zstandard和Gzip压缩(Zstandard隐式优先,因为它排在前面): ```caddy-d encode zstd gzip ``` 由于这是默认值,前一个配置与下面的配置完全等价: ```caddy-d encode ``` 完整站点示例,压缩由[`file_server`](file_server)提供的静态文件: ```caddy example.com { root /srv encode file_server } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/error.md ================================================ --- title: error (Caddyfile 指令) --- # error 触发HTTP处理链中的一个错误,有一个可选的消息和推荐的HTTP状态码。 这个处理程序并不会输出响应。相反,它应该与[`handle_errors`](handle_errors)指令搭配使用,以调用你的自定义错误处理逻辑。 ## 语法 ``caddy-d error [] | [] { message } ``` - **<status>**是要输出的HTTP状态代码。默认是`500`。 - **<message>**是错误信息。默认是没有错误信息。 - **message**是提供错误信息的另一种方式;多行的时候使用起来非常方便。 澄清一下,第一个非匹配器参数可以是一个3位数的状态代码,或者一个错误信息字符串。如果是一个错误信息,下一个参数可以是状态代码。 ## 示例 在某些请求路径上触发一个错误, 并使用[`handle_errors`](handle_errors)来输出一个响应。 ``caddy example.com { root * /srv # 对某些路径触发错误 error /private* "Unauthorized" 403 error /hidden* "Not found" 404 # 通过提供一个HTML页面来处理这个错误 handle_errors { rewrite * /{err.status_code}.html file_server } file_server } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/file_server.md ================================================ --- title: file_server(Caddyfile指令) --- # file_server 一个静态文件服务器,支持真实和虚拟文件系统。它通过将请求的URI路径附加到[站点的根路径](/docs/caddyfile/directives/root)来形成文件路径。 默认情况下,它会强制执行规范URI;这意味着对于不以尾部斜线结尾的目录请求,会发出HTTP重定向来添加尾部斜线;对于带有尾部斜线的文件请求,会发出HTTP重定向来移除尾部斜线。不过,如果内部重写修改了路径的最后一个元素(文件名),则不会发出重定向。 最常见的是,`file_server`指令会与[`root`](root)指令配对使用,为整个站点设置文件根目录。此指令也有一个`root`子指令(见下文),可仅为这个处理器设置根目录(不推荐)。注意,站点根目录不提供沙盒保证:文件服务器确实会防止路径组件中的目录遍历,但根目录中的符号链接仍可能允许访问根目录之外的内容。 发生错误时(例如文件未找到`404`、权限被拒绝`403`),会调用错误路由。使用[`handle_errors`](handle_errors)指令可以定义错误路由并显示自定义错误页面。 使用`browse`时,默认输出由HTML模板生成。客户端也可以分别通过`Accept: application/json`或`Accept: text/plain`请求JSON或纯文本形式的目录列表。JSON输出适合脚本使用,纯文本输出适合人在终端中查看。 ## 语法 ```caddy-d file_server [] [browse] { fs root hide index browse [] { reveal_symlinks sort [] file_limit } precompressed [] status disable_canonical_uris pass_thru } ``` - **fs** 指定要使用的备用(也许是虚拟的)文件系统。可以使用`caddy.fs`命名空间中的任何Caddy模块。任何根路径/前缀仍会应用到备用文件系统模块。默认情况下使用本地磁盘。 [`xcaddy`](/docs/build#xcaddy) v0.4.0引入了[`--embed`标志](https://github.com/caddyserver/xcaddy#custom-builds),可将文件系统树嵌入到自定义Caddy构建中,并注册名为`embedded`的`fs`模块,让你的静态站点可以作为Caddy可执行文件分发。 - **root** 设置站点根路径。它类似于[`root`](root)指令,但只应用于这个文件服务器实例,并会覆盖任何可能已经定义的其他站点根。默认值:`{http.vars.root}`或当前工作目录。注意:这个子指令只改变此处理器的根目录。对于其他指令(例如[`try_files`](try_files)或[`templates`](templates)),如果需要知道相同的站点根目录,应使用[`root`](root)指令。 - **hide** 是要隐藏的文件或文件夹列表;如果请求这些文件,文件服务器会假装它们不存在。它接受占位符和glob模式。注意,这些是 _文件系统_ 路径,**不是**请求路径。换句话说,相对路径以当前工作目录为基准,而不是站点根目录;并且所有路径在比较前都会尽可能转换为绝对形式。指定不带路径分隔符的文件名或模式时,会隐藏任何位置中所有名称匹配的文件;否则,会先尝试路径前缀匹配,然后再尝试glob匹配。由于这是Caddyfile配置,默认会加入活动配置文件。隐藏比较区分大小写;在大小写不敏感的文件系统上,大小写不同的请求路径仍可能解析到同一个磁盘路径,因此不应把`hide`视为保护敏感路径的安全边界。 - **index** 是要查找作为索引文件的文件名列表。默认值:`index.html index.txt` - **browse** 对没有索引文件的目录请求启用文件列表。 - **** 是可选的自定义模板文件,用于目录列表。默认模板可通过`caddy file-server export-template`命令导出,该命令会将默认模板打印到标准输出。嵌入模板也可以在[源代码中找到](https://github.com/caddyserver/caddy/blob/master/modules/caddyhttp/fileserver/browse.html)。目录列表模板也可以使用[标准templates模块](/docs/modules/http.handlers.templates#docs)中的动作。 - **reveal_symlinks** 在目录列表中显示符号链接的目标。默认情况下,符号链接目标会被隐藏,只显示链接文件本身。 - **sort** 更改目录列表的默认排序。第一个参数是排序字段/列:`name`、`namedirfirst`、`size`或`time`。第二个参数是可选方向:`asc`或`desc`。例如,`sort name desc`会按名称降序排序。 - **file_limit** 设置目录列表中最多显示的文件数。默认值:`10000`。如果文件数量超过此限制,只会显示前N个文件,其中N是指定的限制值。 - **precompressed** 是用于搜索预压缩sidecar文件的编码格式列表。参数是一个有序的编码格式列表,用于搜索预压缩的[sidecar文件](https://en.wikipedia.org/wiki/Sidecar_file)。支持的格式有`gzip`(`.gz`)、`zstd`(`.zst`)和`br`(`.br`)。如果省略格式,则默认使用`br zstd gzip`(按此顺序)。 所有文件查找都会先查找未压缩文件是否存在。一旦找到,Caddy会查找每种启用格式对应文件扩展名的sidecar文件。如果找到预压缩的sidecar文件,Caddy会用预压缩文件响应,并适当地设置`Content-Encoding`响应头。否则,Caddy会正常响应未压缩文件。如果启用了[`encode`](encode)指令,那么在没有预压缩文件时,它可能会即时压缩响应。 - **status** 是写入响应时使用的可选状态码覆盖。用[自定义错误页面](handle_errors)响应请求时特别有用。可以是3位状态码,例如:`404`。支持占位符。默认情况下,写入的状态码通常是`200`,部分内容则是`206`。 - **disable_canonical_uris** 禁用默认重定向行为(如果请求路径是目录则添加尾部斜线,如果请求路径是文件则移除尾部斜线)。注意,默认情况下,如果请求路径的最后一个元素(文件名)经历了内部重写,则不会执行规范化,以避免用隐式行为破坏显式重写。 - **pass_thru** 启用pass-thru模式:如果找不到请求的文件,则继续执行路由中的下一个HTTP处理器,而不是触发`404`错误(调用[`handle_errors`](handle_errors)路由)。实际上,这通常只在后面还有其他处理器指令的[`route`](route)块中有用,因为此指令实际上会[排序在最后](/docs/caddyfile/directives#directive-order)。 ## 示例 从当前目录提供静态文件: ```caddy-d file_server ``` 启用文件列表: ```caddy-d file_server browse ``` 只提供`/static`文件夹中的静态文件: ```caddy-d file_server /static/* ``` `file_server`指令通常与[`root`指令](root)配对,以设置提供文件的根路径: ```caddy example.com { root /srv file_server } ``` 隐藏所有`.git`文件夹及其内容: ```caddy-d file_server { hide .git } ``` 如果客户端支持(`Accept-Encoding`头),则在请求文件旁边检查预压缩文件是否存在。因此,如果请求`/path/to/file`,它会按顺序检查`/path/to/file.br`、`/path/to/file.zst`和`/path/to/file.gz`,并提供第一个可用文件,同时设置对应的`Content-Encoding`: ```caddy-d file_server { precompressed } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/forward_auth.md ================================================ --- title: forward_auth (Caddyfile指令) --- # forward_auth 一个专用的(opinionated)指令,它会把请求复制给认证网关,认证网关可以决定是否应该继续处理,或者需要跳转到一个登录页面。 - [语法](#syntax) - [扩展形式](#expanded-form) - [示例](#examples) - [Authelia](#authelia) - [Tailscale](#tailscale) Caddy的[`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy)能够向外部服务执行“预检查请求”,但此指令专门针对认证用例定制。它实际上只是使用一个更长、更常见配置(如下)的便捷方式。 此指令会把`uri`重写后,向配置的上游发出`GET`请求: - 如果上游响应`2xx`状态码,则允许访问,`copy_headers`中的头字段会被复制到原始请求,并继续处理。 - 否则,如果上游响应任何其他状态码,则上游响应会被复制回客户端。这个响应通常应包含重定向到认证网关登录页面的内容。 如果这并不完全是你想要的行为,可以以下面的[扩展形式](#expanded-form)为基础,按需自定义。 支持[`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy)的所有子指令,并将它们传递给底层的`reverse_proxy`处理器。 ## 语法 ```caddy-d forward_auth [] [] { uri copy_headers { } } ``` - **<upstreams...>** 是要向其发送认证请求的上游(后端)列表。 - **uri** 是在发送给上游的请求上设置的URI(路径和查询)。这通常是认证网关的验证端点。 - **copy_headers** 是在请求获得成功状态码时,要从响应复制到原始请求的HTTP头字段列表。 可通过`>`后接新名称来重命名字段,例如`Before>After`。 如果你更喜欢可读性,也可以使用块来逐行列出所有字段。 由于此指令是反向代理上带有预设行为的包装器,你可以使用[`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy#syntax)的任何子指令来自定义它。 ## 扩展形式 `forward_auth`指令等同于以下配置。像[Authelia](https://www.authelia.com/)这样的认证网关适合这个预设。如果你的网关不适合,可以借用下面的配置并按需自定义,而不是使用`forward_auth`快捷方式。 ```caddy-d reverse_proxy { # 始终使用 GET,避免消耗传入请求的 # 请求体 method GET # 将 URI 改为认证网关的 # 验证端点 rewrite # 转发原始方法和 URI, # 因为它们会在上面被重写;这 # 是对 reverse_proxy 已设置的其他 # X-Forwarded-* 头的补充 header_up X-Forwarded-Method {method} header_up X-Forwarded-Uri {uri} # 成功响应时,复制响应头 @good status 2xx handle_response @good { # 例如,对每个 copy_headers 字段…… request_header Remote-User {rp.header.Remote-User} request_header Remote-Email {rp.header.Remote-Email} } } ``` ## 示例 ### Authelia 在通过反向代理提供你的应用之前,将认证委托给[Authelia](https://www.authelia.com/): ```caddy # 提供认证网关本身 auth.example.com { reverse_proxy authelia:9091 } # 提供你的应用 app1.example.com { forward_auth authelia:9091 { uri /api/authz/forward-auth copy_headers Remote-User Remote-Groups Remote-Name Remote-Email } reverse_proxy app1:8080 } ``` 更多信息,请参阅[Authelia文档](https://www.authelia.com/integration/proxies/caddy/)中与Caddy集成的说明。 ### Tailscale 将认证委托给[Tailscale](https://tailscale.com/)(目前名为[`nginx-auth`](https://tailscale.com/blog/tailscale-auth-nginx/),但它仍可与Caddy一起使用),并使用`copy_headers`的替代语法来*重命名*复制的头(注意每个头中的`>`): ```caddy-d forward_auth unix//run/tailscale.nginx-auth.sock { uri /auth header_up Remote-Addr {remote_host} header_up Remote-Port {remote_port} header_up Original-URI {uri} copy_headers { Tailscale-User>X-Webauth-User Tailscale-Name>X-Webauth-Name Tailscale-Login>X-Webauth-Login Tailscale-Tailnet>X-Webauth-Tailnet Tailscale-Profile-Picture>X-Webauth-Profile-Picture } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/fs.md ================================================ --- title: fs (Caddyfile指令) --- # fs 设置执行文件 I/O 时应使用哪个文件系统。 这可以让你连接到云端运行的远程文件系统、具有类文件接口的数据库,甚至读取嵌入到 Caddy 二进制文件中的文件。 首先,你必须使用 [`filesystem` 全局选项](/docs/caddyfile/options#filesystem)声明一个文件系统名称,然后可以使用此指令指定要使用哪个文件系统。 此指令通常会与 [`file_server` 指令](file_server)一起使用以提供静态文件,或与 [`try_files` 指令](try_files)一起使用以根据文件是否存在执行重写。通常也会与 [`root` 指令](root)一起使用,以设置文件系统内的根路径。 ## 语法 ```caddy-d fs [] ``` ## 示例 使用名为 `foo` 的文件系统,并假设有一个名为 `custom`、可能需要认证的模块: ```caddy { filesystem foo custom { api_key abc123 } } example.com { fs foo root /srv file_server } ``` 仅从 `foo` 文件系统提供图片,其余内容仍使用默认文件系统: ```caddy example.com { fs /images* foo root /srv file_server } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/handle.md ================================================ --- title: handle (Caddyfile指令) --- # handle 评估一组指令,这些指令与同级嵌套的其他`handle`块相互排斥。 换句话说,当多个`handle`指令连续出现时,只会评估第一个_匹配_的`handle`块。没有匹配器的`handle`会作为_后备_路由。 `handle`指令会根据其匹配器,按照[指令排序算法](/docs/caddyfile/directives#sorting-algorithm)排序。[`handle_path`](handle_path)指令是一个特殊情况,它与带路径匹配器的`handle`具有相同排序优先级。 如果需要,handle块可以嵌套。只有HTTP处理器指令可以在handle块内使用。 ## 语法 ```caddy-d handle [] { } ``` - **** 是HTTP处理器指令或指令块的列表,每行一个,写法与在handle块外部使用时相同。 ## 类似指令 还有其他一些指令也可以包装HTTP处理器指令,但每个指令都有自己的用途,取决于你想表达的行为: - [`handle_path`](handle_path)的作用与`handle`相同,但它会在运行处理器之前从请求中剥离一个前缀。 - [`handle_errors`](handle_errors)类似于`handle`,但只会在Caddy处理请求时遇到错误时调用。 - [`route`](route)像`handle`一样包装其他指令,但有两个区别: 1. route块之间不互斥; 2. route内的指令不会被[重新排序](/docs/caddyfile/directives#directive-order),在需要时能给你更多控制。 ## 示例 用静态文件服务器处理`/foo/`中的请求,并用反向代理处理其他请求: ```caddy example.com { handle /foo/* { file_server } handle { reverse_proxy 127.0.0.1:8080 } } ``` 你可以在同一个站点中混合使用`handle`和[`handle_path`](handle_path),它们之间仍然是互斥的: ```caddy example.com { handle_path /foo/* { # 路径中的 "/foo" 前缀会被剥离 } handle /bar/* { # 路径仍保留 "/bar" } } ``` 你可以嵌套`handle`块来创建更复杂的路由逻辑: ```caddy example.com { handle /foo* { handle /foo/bar* { # 此块只匹配 /foo/bar 下的路径 } handle { # 此块匹配 /foo/ 下的其他所有内容 } } handle { # 此块匹配其他所有内容(作为后备) } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/handle_errors.md ================================================ --- title: handle_errors (Caddyfile指令) --- # handle_errors 设置错误处理程序。 当正常的HTTP请求处理程序返回错误时,正常处理会停止,错误处理程序会被调用。错误处理程序形成一条路由,就像普通路由一样,它们可以做普通路由能做的任何事情。这让你在处理HTTP请求期间发生的错误时有很大的控制力和灵活性。例如,你可以提供静态错误页面、模板化错误页面,或者反向代理到另一个后端来处理错误。 该指令可以使用不同状态码重复多次,以便用不同方式处理不同错误。如果未指定状态码,则匹配任何错误;如果其他错误处理程序都不匹配,它会作为后备处理程序。 请求的上下文会带入错误路由,因此在请求上下文中设置的任何值,例如[站点根目录](root)或[vars](vars),也会在错误处理程序中保留。此外,处理错误时还可以使用[新的占位符](#placeholders)。 请注意,某些指令(例如[`reverse_proxy`](reverse_proxy))可能会写入被归类为错误的HTTP状态响应,但这_不会_触发错误路由。 你可以使用[`error`](error)指令,根据自己的路由决策显式触发错误。 ## 语法 ```caddy-d handle_errors [] { } ``` - **** 是一个或多个HTTP状态码,用于匹配正在处理的错误。状态码可以是3位数字,也可以是特殊的`4xx`或`5xx`,分别匹配400-499或500-599范围内的所有状态码。如果未指定状态码,则匹配任何错误;如果其他错误处理程序都不匹配,它会作为后备处理程序。 - **** 是HTTP处理器[指令](/docs/caddyfile/directives)和[匹配器](/docs/caddyfile/matchers)的列表,每行一个。 ## 占位符 处理错误时可以使用以下占位符。它们是完整占位符的[Caddyfile简写](/docs/caddyfile/concepts#placeholders),完整占位符可在[HTTP服务器错误路由的JSON文档](/docs/json/apps/http/servers/errors/#routes)中找到。 | 占位符 | 描述 | |---|---| | `{err.status_code}` | 推荐的HTTP状态码 | | `{err.status_text}` | 与推荐状态码关联的状态文本 | | `{err.message}` | 错误消息 | | `{err.trace}` | 错误来源 | | `{err.id}` | 本次错误发生的标识符 | ## 示例 基于状态码的自定义错误页面(即`404`错误对应名为`404.html`的页面)。注意,当[`file_server`](file_server)在`handle_errors`中运行时,会保留错误的HTTP状态码(假设你事先在站点中设置了[站点根目录](root)): ```caddy-d handle_errors { rewrite /{err.status_code}.html file_server } ``` 使用[`templates`](templates)写入自定义错误消息的单一错误页面: ```caddy-d handle_errors { rewrite /error.html templates file_server } ``` 如果只想为部分错误代码提供自定义错误页面,可以先用[`file`](/docs/caddyfile/matchers#file)匹配器检查自定义错误文件是否存在: ```caddy-d handle_errors { @custom_err file /err-{err.status_code}.html /err.html handle @custom_err { rewrite {file_match.relative} file_server } respond "{err.status_code} {err.status_text}" } ``` 反向代理到一台非常擅长处理HTTP错误并改善你心情的专业服务器😸: ```caddy-d handle_errors { rewrite /{err.status_code} reverse_proxy https://http.cat { replace_status {err.status_code} } } ``` 只需使用[`respond`](respond)即可返回错误代码和名称 ```caddy-d handle_errors { respond "{err.status_code} {err.status_text}" } ``` 要用不同方式处理特定错误代码: ```caddy-d handle_errors 404 410 { respond "It's a 404 or 410 error!" } handle_errors 5xx { respond "It's a 5xx error." } handle_errors { respond "It's another error" } ``` 上面的行为与下面相同;下面使用[`expression`](/docs/caddyfile/matchers#expression)匹配器匹配状态码,并使用[`handle`](handle)实现互斥: ```caddy-d handle_errors { @404-410 `{err.status_code} in [404, 410]` handle @404-410 { respond "It's a 404 or 410 error!" } @5xx `{err.status_code} >= 500 && {err.status_code} < 600` handle @5xx { respond "It's a 5xx error." } handle { respond "It's another error" } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/handle_path.md ================================================ --- title: handle_path (Caddyfile指令) --- # handle_path 与[`handle`指令](/docs/caddyfile/directives/handle)相同,但会隐式剥离匹配到的路径前缀。 处理匹配某个路径的请求(同时从请求URI中剥离该路径)是一种足够常见的用例,因此提供了这个专门的便捷指令。 ## 语法 ```caddy-d handle_path { } ``` - **** 是HTTP处理器指令或指令块的列表,每行一个,写法与在`handle_path`块外部使用时相同。 只接受且必须提供一个[路径匹配器](/docs/caddyfile/matchers#path-matchers);不能在`handle_path`中使用命名匹配器。 ## 示例 这个配置: ```caddy-d handle_path /prefix/* { ... } ``` 👆 实际上等同于下面这个配置 👇,但 👆 的`handle_path`形式稍微更简洁 ```caddy-d handle /prefix/* { uri strip_prefix /prefix ... } ``` 一个完整的Caddyfile示例,其中`handle_path`和`handle`相互排斥;但请注意[子文件夹问题 ](https://caddy.community/t/the-subfolder-problem-or-why-cant-i-reverse-proxy-my-app-into-a-subfolder/8575) ```caddy example.com { # 提供 API,并剥离 /api 前缀 handle_path /api/* { reverse_proxy localhost:9000 } # 提供静态站点 handle { root /srv file_server } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/header.md ================================================ --- title: header (Caddyfile directive) --- # header 操作 HTTP 响应标头字段。它可以设置、添加和删除标头值,或使用正则表达式执行替换。 默认情况下,除非删除任何标头(`-`前缀)或设置默认值(`?`前缀),否则立即执行标头操作。在这些情况下,标头操作会自动推迟,直到将它们写入客户端为止。 要操作 HTTP 请求标头,您可以使用[`request_header`](request_header)指令。 ## 语法 ```caddy-d header [] [[+|-|?|>] [|] []] { # Add + # Set # Set with defer > # Delete - # Replace # Replace with defer > # Default ? [defer] match } ``` - **<field>** 是头字段的名称。 如果没有前缀,该字段将被设置(覆盖)。 以`+`为前缀来添加该字段,而不是覆盖(设置)该字段(如果该字段已存在);标头字段可以在响应中出现多次。 前缀为`-`即可删除该字段。该字段可以使用前缀或后缀`*`通配符来删除所有匹配的字段。 以`?`为前缀来设置该字段的默认值。仅当该字段尚不存在时才会写入。 以`>`为前缀设置该字段,并启用`defer`作为快捷方式。 - **<value>** 是添加或设置字段时的标头字段值。 - **<find>** 是要搜索的正则表达式。占位符可用于动态输入搜索模式。使用的正则表达式语言是 RE2,包含在 Go 中。请参阅[RE2 语法参考](https://github.com/google/re2/wiki/Syntax)和[Go regexp 语法概述](https://pkg.go.dev/regexp/syntax)。 - **<replace>** 为重置值;如果执行搜索和替换,则需要。使用`$1`或`$2`等从搜索模式引用捕获组。如果替换值为`""`,则将从该值中删除匹配的文本。详情请见[Go documentation](https://golang.org/pkg/regexp/#Regexp.Expand)。 - **defer** 推迟标头操作的执行,直到响应发送到客户端。该选项在以下条件下自动启用: - 使用`-`删除任何标头字段时。 - 使用`?`设置默认值时。 - 在设置或替换操作中使用`>`前缀时。 - 当存在一个或多个`match`条件时。 - **match**是内联[响应匹配器](/docs/caddyfile/response-matchers)。标头操作仅适用于满足指定条件的响应。 对于多个标头操作,您可以打开一个块并以相同的方式为每行指定一个操作。 当使用`?`前缀设置默认标头值时,如果它位于具有多个标头操作的`header`块中,它会自动分离到自己的`header`处理程序中。[在底层](/docs/modules/http.handlers.headers#response/require),使用`?`配置一个[响应匹配器](/docs/caddyfile/response-matchers),它应用于指令的整个处理程序,它仅应用标头操作(如`defer`),但前提是该字段尚未设置。 ## 示例 在所有响应上设置自定义标头字段: ```caddy-d header Custom-Header "My value" ``` 删除“隐藏”标头字段: ```caddy-d header -Hidden ``` 在任何 Location 标头中将`http://`替换为`https://`: ```caddy-d header Location http:// https:// ``` 在所有页面上设置安全和隐私标题:(**WARNING:**仅在您了解其含义时使用!) ```caddy-d header { # disable FLoC tracking Permissions-Policy interest-cohort=() # enable HSTS Strict-Transport-Security max-age=31536000; # disable clients from sniffing the media type X-Content-Type-Options nosniff # clickjacking protection X-Frame-Options DENY } ``` 旨在互斥的多个标头指令: ```caddy-d route { header Cache-Control max-age=3600 header /static/* Cache-Control max-age=31536000 } ``` 如果上游未定义缓存过期时间,则设置默认缓存过期时间: ```caddy-d header ?Cache-Control "max-age=3600" reverse_proxy upstream:443 ``` 将所有对 GET 请求的成功响应标记为可缓存长达一个小时: ```caddy-d @GET method GET header @GET Cache-Control "max-age=3600" { match status 2xx } reverse_proxy upstream:443 ``` 防止在上游服务器发生异常时缓存错误响应: ```caddy-d header { -Cache-Control -CDN-Cache-Control match status 500 } reverse_proxy upstream:443 ``` 如果上游服务器支持客户端提示,则将浅色模式响应标记为可与深色模式响应单独缓存: ```caddy-d header { Cache-Control "max-age=3600" Vary "Sec-CH-Prefers-Color-Scheme" match { header Accept-CH "*Sec-CH-Prefers-Color-Scheme*" header Critical-CH "Sec-CH-Prefers-Color-Scheme" } } reverse_proxy upstream:443 ``` 通过用特定域替换通配符值来防止过度宽松的 CORS 标头: ```caddy-d header >Access-Control-Allow-Origin "\*" "allowed-partner.com" reverse_proxy upstream:443 ``` **Note**:在替换操作中,``值被解释为正则表达式。要匹配`*`字符,必须使用反斜杠对其进行转义,如上例所示。 或者,您可以使用[响应匹配器](/docs/caddyfile/response-matchers)逐字匹配标头值: ```caddy-d header Access-Control-Allow-Origin "allowed-partner.com" { match header Access-Control-Allow-Origin * } reverse_proxy upstream:443 ``` 覆盖代理上游为以`/no-cache`开头的路径设置的缓存过期时间;启用`defer`是必要的,以确保在代理写入其标头之后设置标头: ```caddy-d header /no-cache* >Cache-Control no-cache reverse_proxy upstream:443 ``` 执行`Set-Cookie`标头的延迟更新以添加`SameSite=None`;正则表达式捕获用于获取现有值,`$1`在开头重新插入它并附加附加选项: ```caddy-d header >Set-Cookie (.*) "$1; SameSite=None;" ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/import.md ================================================ --- title: import (Caddyfile directive) --- # import 包含[snippet](/docs/caddyfile/concepts#snippets)或文件,将此指令替换为代码片段或文件的内容。 该指令是一种特殊情况:它在解析结构之前进行评估,并且可以出现在 Caddyfile 中的任何位置。 ## 语法 ```caddy-d import [] [{block}] ``` - **<pattern>** 是要包含的文件名、glob 模式或[snippet](/docs/caddyfile/concepts#snippets)的名称。它的内容将替换该行,就像该文件的内容一开始就出现在此处一样。 如果找不到特定文件,则为错误,但空 glob 模式不是错误。 如果导入特定文件,如果文件为空,将会发出警告。 如果模式是文件名或 glob,则它始终与`import`出现的文件相关。 如果使用 glob 模式`*`作为最终路径段,则隐藏文件(即以`.`开头的文件)将被忽略。要导入隐藏文件,请使用`.*`作为最后一段。 - **<args...>** 是传递给导入令牌的可选参数列表。此占位符是一种特殊情况,在 Caddyfile 解析时而不是在运行时进行评估。它们可以以多种形式使用,类似于[Go 的切片语法](https://gobyexample.com/slices): -`{args[n]}`,其中`n`是参数的从 0 开始的位置索引 -`{args[:]}`插入所有参数 -`{args[:m]}`插入`m`之前的参数 -`{args[n:]}`插入以`n`开头的参数 -`{args[n:m]}`插入`n`和`m`之间的参数 对于插入许多令牌的表单,占位符**must**是[词法单元](/docs/caddyfile/concepts#tokens-and-quotes)本身,它不能是另一个令牌的一部分。换句话说,它周围必须有空格,并且不能用引号引起来。 请注意,在 v2.7.0 之前,语法为`{args.N}`,但这种形式已被弃用,取而代之的是上面更灵活的语法。 ⚠️实验版|v2.9.x+ - **{block}** 是传递给导入令牌的可选块。此占位符是一种特殊情况,在 Caddyfile 解析时(而不是运行时)递归求值。它们可以以两种形式使用: -`{block}`,其中整个提供的块的内容将替换占位符 -`{blocks.key}`,其中`key`是所提供块中参数的第一个标记 ## 示例 导入相邻启用站点的文件夹中的所有文件(隐藏文件除外): ```caddy-d import sites-enabled/* ``` 导入使用导入参数设置 CORS 标头的代码片段: ```caddy (cors) { @origin header Origin {args[0]} header @origin Access-Control-Allow-Origin "{args[0]}" header @origin Access-Control-Allow-Methods "OPTIONS,HEAD,GET,POST,PUT,PATCH,DELETE" } example.com { import cors example.com } ``` 导入一个片段,它将代理上游列表作为参数: ```caddy (https-proxy) { reverse_proxy {args[:]} { transport http { tls } } } example.com { import https-proxy 10.0.0.1 10.0.0.2 10.0.0.3 } ``` 导入一个片段,该片段创建一个代理,并将前缀重写规则作为第一个参数: ```caddy (proxy-rewrite) { rewrite {args[0]}{uri} reverse_proxy {args[1:]} } example.com { import proxy-rewrite /api 10.0.0.1 10.0.0.2 10.0.0.3 } ``` ⚠️实验版|v2.9.x+ 导入一个片段,该片段以可配置的“hello world”消息和内容类型进行响应: ```caddy (hello-world) { header { Cache-Control max-age=3600 X-Foo bar {blocks.content_type} } respond /hello-world 200 { {blocks.body} } } example.com { import hello-world { content_type { Content-Type text/html } body { body "

hello world

" } } } ``` 导入为反向代理提供可扩展选项的代码片段: ```caddy (extendable-proxy) { reverse_proxy { {blocks.proxy_target} {blocks.proxy_options} } } example.com { import extendable-proxy { proxy_target { to 10.0.0.1 } proxy_options { transport http { tls } } } } ``` 导入一个提供任何指令集的代码片段,但带有预加载的中间件: ```caddy (instrumented-route) { header { Alt-Svc `h3="0.0.0.0:443"; ma=2592000` } tracing { span args[0] } {block} } example.com { import instrumented-route example-com { respond "OK" } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/intercept.md ================================================ --- title: intercept (Caddyfile指令) --- # intercept 这是从 [`reverse_proxy` 指令](reverse_proxy)的[响应拦截](reverse_proxy#intercepting-responses)功能抽象出来的通用形式。它可以与任何会产生响应的处理器一起使用,包括来自插件的处理器,例如 [FrankenPHP](https://frankenphp.dev/) 的 `php_server`。 此指令允许你[匹配响应](/docs/caddyfile/response-matchers),并调用第一个匹配的 `handle_response` 路由或 `replace_status`。调用时,原始响应体会被暂缓写出,从而让该路由有机会写出不同的响应体、新的状态码,或执行必要的响应头操作。如果该路由**没有**写出新的响应体,则会改为写出原始响应体。 ## 语法 ```caddy-d intercept [] { @name { status header [] } replace_status [] handle_response [] { } } ``` - **@name** 是一个命名的[响应匹配器](/docs/caddyfile/response-matchers)块。只要每个响应匹配器都有唯一名称,就可以定义多个匹配器。响应可以按状态码以及响应头是否存在或其值进行匹配。 - **replace_status** 会在给定匹配器匹配响应时,直接更改响应状态码。 - **handle_response** 定义原始响应被给定响应匹配器匹配时要执行的路由。如果省略匹配器,则拦截所有响应。定义多个 `handle_response` 块时,将应用第一个匹配的块。在该块内部,可以使用所有其他[指令](/docs/caddyfile/directives)。 在 `handle_response` 路由中,可以使用以下占位符从原始响应中提取信息: - `{resp.status_code}` 原始响应的状态码。 - `{resp.header.*}` 原始响应的响应头。 ## 示例 使用 [FrankenPHP](https://frankenphp.dev/) 的 `php_server` 时,可以用 `intercept` 实现 `X-Accel-Redirect` 支持,按 PHP 应用的请求提供静态文件: ```caddy localhost { root /srv intercept { @accel header X-Accel-Redirect * handle_response @accel { root /path/to/private/files rewrite {resp.header.X-Accel-Redirect} method GET file_server } } php_server } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/invoke.md ================================================ --- title: invoke (Caddyfile指令) --- # invoke ⚠️ 实验性 调用一个[命名路由](/docs/caddyfile/concepts#named-routes)。 当与拥有自身内存状态的 HTTP 处理器指令配合使用时,或者这些处理器在加载时创建成本较高时,此指令很有用。如果你有数百个甚至更多站点,调用命名路由可以帮助减少内存使用。 ## 语法 ```caddy-d invoke [] ``` - **<route-name>** 是要调用的、此前已定义的路由名称。如果找不到该路由,则会触发错误。 ## 示例 定义一个带有 [`reverse_proxy`](/docs/caddyfile/directives/reverse_proxy) 的[命名路由](/docs/caddyfile/concepts#named-routes),可在多个站点中复用,并为每个站点复用相同的内存中负载均衡状态。 ```caddy &(app-proxy) { reverse_proxy app-01:8080 app-02:8080 app-03:8080 { lb_policy least_conn health_uri /healthz health_interval 5s } } # 根域名允许通过 /app 子路径访问应用, # 其他路径访问主站点。 example.com { handle_path /app* { invoke app-proxy } handle { root /srv file_server } } # 该应用也可通过子域名访问。 app.example.com { invoke app-proxy } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/log.md ================================================ --- title: log (Caddyfile directive) --- # log 启用和配置 HTTP 请求日志记录(也称为访问日志)。 `log`指令适用于它出现的站点块的主机名,除非被`hostnames`子指令覆盖。 配置后,默认情况下将记录对该站点的所有请求。要有条件地跳过日志记录中的某些请求,请使用[`log_skip` 指令](log_skip)。 要将自定义字段添加到日志条目,请使用[`log_append` 指令](log_append)。 - [语法](#syntax) - [输出模块](#output-modules) - [stderr](#stderr) - [stdout](#stdout) - [discard](#discard) - [file](#file) - [net](#net) - [格式模块](#format-modules) - [console](#console) - [json](#json) - [filter](#filter) - [delete](#delete) - [rename](#rename) - [replace](#replace) - [ip_mask](#ip-mask) - [query](#query) - [cookie](#cookie) - [regexp](#regexp) - [hash](#hash) - [append](#append) - [示例](#examples) 默认情况下,具有潜在敏感信息的标头(`Cookie`、`Set-Cookie`、`Authorization`和`Proxy-Authorization`)将在访问日志中记录为`REDACTED`。可以使用[`log_credentials`](/docs/caddyfile/options#log-credentials)全局服务器选项禁用此行为。 ## 语法 ```caddy-d log [] { hostnames no_hostname output ... format ... level sampling { interval first thereafter } } ``` - **logger_name**是此站点记录器名称的可选覆盖。 默认情况下,记录器名称是自动生成的,例如`log0`、`log1`等,具体取决于 Caddyfile 中站点的顺序。仅当您希望从全局选项中定义的另一个记录器可靠地引用此记录器的输出时,这才有用。见下面的[示例](#multiple-outputs)。 - **hostnames**是此记录器适用的主机名的可选覆盖。 默认情况下,记录器适用于它出现的站点块的主机名,即站点地址。如果您希望在[wildcard site block](/docs/caddyfile/patterns#wildcard-certificates)中的每个子域定义不同的记录器,这非常有用。见下面的[示例](#wildcard-logs)。 - **no_hostname**阻止记录器与任何站点块的主机名关联。默认情况下,记录器与`log`指令出现的[site address](/docs/caddyfile/concepts#addresses)关联。 当您想要根据某些条件(例如请求路径或方法)使用[`log_name` 指令](/docs/caddyfile/directives/log_name)将请求记录到不同的文件时,这非常有用。 - **output**配置日志写入位置。见下面的[`output` 模块](#output-modules)。 默认:`stderr`。 - **format**描述如何对日志进行编码或格式化。见下面的[`format` 模块](#format-modules)。 默认:如果检测到`stderr`是终端,则为`console`,否则为`json`。 - **level**是登录的最低入门级别。默认:`INFO`。 请注意,访问日志目前仅发出`INFO`和`ERROR`级别的日志。 - **sampling**配置日志采样以减少日志量。如果指定了采样,则启用采样,并且以下默认值生效。省略此项将禁用采样。 - **interval**是进行采样的[持续时间窗口](/docs/conventions#durations)。默认:`1s`(禁用)。 - **first** 是在给定级别和每个时间间隔的消息中保留多少日志。默认:`100`。 - **thereafter**是在第一个保留日志之后的每个间隔中要跳过的日志数。默认:`100`。 例如,对于`interval 1s`、`first 5`和`thereafter 10`,在每 10 秒间隔内,将保留前 5 个日志条目,然后将允许在该秒内通过具有相同级别和消息的每 10 个日志条目。 ### 输出模块 **output** 子指令允许您自定义日志写入位置。 #### 标准错误 标准错误(控制台,是默认值)。 ```caddy-d output stderr ``` #### 标准输出 标准输出(控制台)。 ```caddy-d output stdout ``` #### 丢弃 无输出。 ```caddy-d output discard ``` #### 文件 一个文件。默认情况下,日志文件根据大小进行轮换(“滚动”),以防止磁盘空间耗尽。 日志滚动由[timberjack ](https://github.com/DeRuina/timberjack)提供 ```caddy-d output file { mode roll_disabled roll_size roll_interval roll_minutes roll_at roll_uncompressed roll_local_time roll_keep roll_keep_for backup_time_format } ``` - **<filename>** 是日志文件的路径。 滚动时,文件将使用模板`--.log`重命名。时间戳根据[`backup_time_format`](#backup_time_format)选项进行格式化。原因是`size`或`time`,具体取决于哪个触发了轮换。如果文件被压缩,`.gz`会附加到文件名中。 例如,如果文件名为`access.log`,则滚动文件如果因大小而滚动,则可能命名为`access-2026-01-30T22-15-42.123-size.log`;如果因时间滚动,则滚动文件可能命名为`access-2025-01-30T00-00-00.000-time.log`。 - **mode**是用于日志文件的 Unix 文件模式/权限。该模式由 1 到 4 个八进制数字组成(与 Unix[chmod ](https://en.wikipedia.org/wiki/Chmod)命令接受的数字格式相同,除了全零模式被解释为默认模式`600`)。 例如:`0600`会将模式设置为`rw-,---,---`(日志文件所有者有读/写权限,其他任何人都没有权限);`0640`将模式设置为`rw-,r--,---`(对文件所有者具有读/写权限,对组仅具有读权限);`644`将模式设置为`rw-,r--,r--`向日志文件所有者提供读/写权限,但仅向群组所有者和其他用户提供读权限。 - **roll_disabled**禁用日志滚动。这可能会导致磁盘空间耗尽,因此仅当您的日志文件以其他方式维护时才使用此选项。 - **roll_size**是滚动日志文件的大小。当前的实现支持兆字节分辨率;小数值向上舍入到下一个整数兆字节。例如,`1.1MiB`向上舍入为`2MiB`。 该功能始终处于启用状态。如果写入日志导致文件超过指定大小,则日志将立即轮转。备份文件名将包含`size`作为原因。 默认:`100MiB` - **roll_interval**是日志轮转之间的最大持续时间。该值为[持续时间字符串](/docs/conventions#durations),之后滚动日志文件。 启用后,自上次轮换后经过此持续时间后,文件将在下次写入日志时轮换。备份文件名将包含`time`作为原因。 请注意,如果设置为`24h`,则不一定在午夜滚动,而是在自上次旋转以来的 24 小时标记处滚动。如果由于尺寸而发生滚动,则下一次旋转的时间将比上一次旋转的时间有所偏移。您可以使用`roll_at`或`roll_minutes`选项在特定时间进行滚动。 默认值:禁用 - **roll_minutes**是滚动日志文件的分钟值 (0-59) 列表。例如,`10 40`每 30 分钟滚动一次日志文件,`xx:10`和`xx:40`每小时滚动一次日志文件。旋转与时钟分钟(秒 0)对齐。 启用此功能会生成一个 goroutine 计时器,该计时器会在指定的分钟值处触发日志轮换(即引入少量后台处理)。除了`roll_interval`和`roll_size`之外,还可以进行此操作。备份文件名将包含`time`作为原因。 默认值:禁用 - **roll_at**是滚动日志文件的时间值列表(采用 24 小时格式)。例如,`00:00 12:00`每天会在午夜和中午滚动日志文件两次。旋转与时钟分钟(秒 0)对齐。 启用此功能会生成一个 goroutine 计时器,该计时器会在指定时间触发日志轮换(即引入少量后台处理)。除了`roll_interval`和`roll_size`之外,还可以进行此操作。备份文件名将包含`time`作为原因。 默认值:禁用 - **roll_uncompressed**关闭 gzip 日志压缩。 默认:`gzip`压缩已启用。 - **roll_local_time**设置滚动以在文件名中使用本地时间戳。 默认:使用 UTC 时间。 - **roll_keep**是在删除最旧的日志文件之前保留多少个日志文件。创建新日志文件时触发。 默认:`10` - **roll_keep_for**是将滚动文件保留为[持续时间字符串](/docs/conventions#durations)的时间。创建新日志文件时触发。 当前的实现支持日分辨率;小数值向上舍入到下一个整天。例如,`36h`(1.5 天)向上舍入为`48h`(2 天)。 默认:`2160h`(90 天) - **backup_time_format**是备份文件名中使用的时间格式。必须是有效的时间布局字符串;详情请参见[Go documentation](https://pkg.go.dev/time#pkg-constants)。 默认:`2006-01-02T15-04-05` #### 网 一个网络套接字。如果套接字出现故障,它会在尝试重新连接时将日志转储到 stderr。 ```caddy-d output net
{ dial_timeout soft_start } ``` - **<address>** 是要写入日志的[address](/docs/conventions#network-addresses)。 - **dial_timeout**是等待成功连接到日志套接字的时间。如果套接字出现故障,日志发送可能会被阻止长达这么长时间。 - **soft_start**在连接到套接字时将忽略错误,即使远程日志服务关闭,也允许您加载配置。日志将被发送到 stderr。 ### 格式化模块 **format** 子指令允许您自定义日志的编码(格式化)方式。它出现在`log`块内。 除了每个单独编码器的语法之外,还可以在大多数编码器上设置这些通用属性: ```caddy-d format { message_key level_key time_key name_key caller_key stacktrace_key line_ending time_format time_local duration_format level_format } ``` - **message_key**日志条目的消息字段的键。默认:`msg` - **level_key**日志条目的级别字段的键。默认:`level` - **time_key**日志条目的时间字段的键。默认:`ts` - **name_key**日志条目的名称字段的键。默认:`name` - **caller_key**日志条目的呼叫者字段的键。 - **stacktrace_key**日志条目的 stacktrace 字段的键。 - **line_ending**要使用的行结尾。 - **time_format**时间戳的格式。 默认:如果格式默认为`console`则为`wall_milli`,否则为`unix_seconds_float`。 可能是以下之一: -`unix_seconds_float`自 Unix 纪元以来的浮点数秒数。 -`unix_milli_float`自 Unix 纪元以来的浮点数毫秒数。 -`unix_nano`自 Unix 纪元以来的纳秒整数。 -`iso8601`示例:`2006-01-02T15:04:05.000Z0700` -`rfc3339`示例:`2006-01-02T15:04:05Z07:00` -`rfc3339_nano`示例:`2006-01-02T15:04:05.999999999Z07:00` -`wall`示例:`2006/01/02 15:04:05` -`wall_milli`示例:`2006/01/02 15:04:05.000` -`wall_nano`示例:`2006/01/02 15:04:05.000000000` -`common_log`示例:`02/Jan/2006:15:04:05 -0700` - 或者,任何兼容的时间布局字符串;详情请参见[Go documentation](https://pkg.go.dev/time#pkg-constants)。 请注意,格式字符串的部分是布局的特殊常量;所以`2006`是年份,`01`是月份,`Jan`是字符串形式的月份,`02`是日期。不要在格式字符串中使用实际的当前日期数字。 - **time_local**使用本地系统时间而不是默认的 UTC 时间进行日志记录。 - **duration_format**持续时间的格式。 默认:`seconds`。 可能是以下之一: -`s`、`second`或`seconds`浮点数经过的秒数。 -`ms`、`milli`或`millis`浮点数经过的毫秒数。 -`ns`、`nano`或`nanos`已过去的纳秒整数。 -`string`使用 Go 内置的字符串格式,例如`1m32.05s`或`6.31ms`。 - **level_format**级别的格式。 默认:如果格式默认为`console`则为`color`,否则为`lower`。 可能是以下之一: -`lower`小写。 -`upper`大写。 -`color`大写,采用 ANSI 颜色。 #### 安慰 控制台编码器格式化日志条目以供人类可读,同时保留一些结构。 ```caddy-d format console ``` #### json 将每个日志条目格式化为 JSON 对象。 ```caddy-d format json ``` #### 筛选 允许按字段过滤。 ```caddy-d format filter { fields { ... } ... wrap ... } ``` 可以通过用`>`表示嵌套层来引用嵌套字段。换句话说,对于像`{"a":{"b":0}}`这样的对象,内部字段可以被引用为`a>b`。 以下字段是日志的基础字段,无法过滤,因为它们是由底层日志库作为特殊情况添加的:`ts`、`level`、`logger`和`msg`。 指定`wrap`是可选的;如果省略,则根据当前输出模块是[`stderr`](#stderr)还是[`stdout`](#stdout)来选择默认值,并且是交互式终端,在这种情况下选择[`console`](#console),否则选择[`json`](#json)。 作为快捷方式,可以省略`fields`块,并且可以直接在`filter`块内指定过滤器。 这些是可用的过滤器: ##### 删除 标记要跳过编码的字段。 ```caddy-d delete ``` ##### 重命名 重命名日志字段的键。 ```caddy-d rename ``` ##### 代替 标记要在编码时用提供的字符串替换的字段。 ```caddy-d replace ``` ##### IP掩码 使用 CIDR 掩码(即 IP 中要保留的位数,从左侧开始)屏蔽字段中的 IP 地址。如果该字段是字符串数组(例如 HTTP 标头),则数组中的每个值都会被屏蔽。该值可以是逗号分隔的 IP 地址字符串。 IPv4 和 IPv6 地址有单独的配置,因为它们具有不同的总位数。 最常见的是,要过滤的字段是: -`request>remote_ip`为直连客户端 - 配置[`trusted_proxies`](/docs/caddyfile/options#trusted-proxies)时解析的“真实客户端”为`request>client_ip` -`request>headers>X-Forwarded-For`(如果位于反向代理后面) ```caddy-d ip_mask [ []] { ipv4 ipv6 } ``` ##### 询问 将字段标记为执行一项或多项操作,以操作 URL 字段的查询部分。最常见的是,要过滤的字段是`request>uri`。 ```caddy-d query { delete replace hash } ``` 可用的操作有: - **delete** 从查询中删除给定的键。 - **replace** 用 **replacement** 替换给定查询键的值。用于插入密文占位符;您将看到查询键位于 URL 中,但值是隐藏的。 - **hash** 将给定查询键的值替换为该值的 SHA-256 哈希值的前 4 个字节(小写十六进制)。如果值敏感,则有助于模糊该值,同时能够注意到每个请求是否具有不同的值。 ##### 曲奇饼 将字段标记为执行一个或多个操作,以操作`Cookie`HTTP 标头的值。最常见的是,要过滤的字段是`request>headers>Cookie`。 ```caddy-d cookie { delete replace hash } ``` 可用的操作有: - **delete** 从标头中按名称删除给定的 cookie。 - **replace** 用 **replacement** 替换给定 cookie 的值。用于插入密文占位符;您会看到 cookie 位于标头中,但值是隐藏的。 - **hash** 将给定 cookie 的值替换为该值的 SHA-256 哈希值的前 4 个字节(小写十六进制)。如果值敏感,则有助于模糊该值,同时能够注意到每个请求是否具有不同的值。 如果为同一个 cookie 名称定义了多个操作,则仅应用第一个操作。 ##### 正则表达式 将字段标记为在编码时应用正则表达式替换。如果该字段是字符串数组(例如 HTTP 标头),则数组中的每个值都会应用替换。 ```caddy-d regexp ``` 使用的正则表达式语言是 RE2,包含在 Go 中。请参阅[RE2 语法参考](https://github.com/google/re2/wiki/Syntax)和[Go regexp 语法概述](https://pkg.go.dev/regexp/syntax)。 在替换字符串中,可以使用`${group}`引用捕获组,其中`group`是表达式中捕获组的名称或编号。捕获组`0`是完整的正则表达式匹配,`1`是第一个捕获组,`2`是第二个捕获组,依此类推。 ##### 散列 标记要替换为编码时值的 SHA-256 哈希值的前 4 个字节(8 个十六进制字符)的字段。如果字段是字符串数组(例如 HTTP 标头),则数组中的每个值都会进行哈希处理。 如果值敏感,则有助于模糊该值,同时能够注意到每个请求是否具有不同的值。 ```caddy-d hash ``` #### 附加 将字段附加到所有日志条目。 ```caddy-d format append { fields { } wrap ... } ``` 它对于添加有关生成日志条目的 Caddy 实例的信息最有用,可能是通过环境变量。字段值可以是全局占位符(例如`{env.*}`),但不是每个请求占位符,因为日志是在 HTTP 请求上下文之外写入的。 指定`wrap`是可选的;如果省略,则根据当前输出模块是[`stderr`](#stderr)还是[`stdout`](#stdout)来选择默认值,并且是交互式终端,在这种情况下选择[`console`](#console),否则选择[`json`](#json)。 可以省略`fields`块,并且可以直接在`append`块内指定字段。 ## 示例 启用对默认记录器的访问日志记录。 换句话说,默认情况下记录到`stderr`,但是可以通过使用[`log` 全局选项](/docs/caddyfile/options#log)重新配置`default`记录器来更改: ```caddy example.com { log } ``` 将日志写入文件(使用日志滚动,默认启用): ```caddy example.com { log { output file /var/log/access.log } } ``` 自定义日志滚动,每天午夜或日志文件达到 1 GB 时滚动(以先到者为准),并保留 5 个滚动文件或 30 天的日志: ```caddy example.com { log { output file /var/log/access.log { roll_at 00:00 roll_size 1gb roll_keep 5 roll_keep_for 720h } } } ``` 从日志中删除`User-Agent`请求标头: ```caddy example.com { log { format filter { request>headers>User-Agent delete } } } ``` 编辑多个敏感 cookie。 (请注意,默认情况下,某些敏感标头会使用空值进行记录;请参阅[`log_credentials` 全局选项](/docs/caddyfile/options#log-credentials)以启用记录`Cookie`标头值): ```caddy example.com { log { format filter { request>headers>Cookie cookie { replace session REDACTED delete secret } } } } ``` 从请求中屏蔽远程地址,保留 IPv4 地址的前 16 位(即 255.255.0.0),以及 IPv6 地址的前 32 位。 请注意,从 Caddy v2.7 开始,`remote_ip`和`client_ip`都会被记录,其中`client_ip`是配置[`trusted_proxies`](/docs/caddyfile/options#trusted-proxies)时的“真实 IP”: ```caddy example.com { log { format filter { request>remote_ip ip_mask 16 32 request>client_ip ip_mask 16 32 } } } ``` 要将环境变量中的服务器 ID 附加到所有日志条目,并将其与`filter`链接以删除标头: ```caddy example.com { log { format append { server_id {env.SERVER_ID} wrap filter { request>headers>Cookie delete } } } } ``` 通过为每个记录器覆盖`hostnames`为[wildcard site block](/docs/caddyfile/patterns#wildcard-certificates)中的每个子域写入单独的日志文件。这里使用[snippet](/docs/caddyfile/concepts#snippets)来避免重复: ```caddy (subdomain-log) { log { hostnames {args[0]} output file /var/log/{args[0]}.log } } *.example.com { import subdomain-log foo.example.com @foo host foo.example.com handle @foo { respond "foo" } import subdomain-log bar.example.com @bar host bar.example.com handle @bar { respond "bar" } } ``` 将特定子域的访问日志写入两个不同的文件,具有不同的格式(一个为[`transform-encoder` 插件 ](https://github.com/caddyserver/transform-encoder),另一个为[`json`](#json))。 这是通过在站点块中将记录器名称覆盖为`foo`来实现的,然后使用`include http.log.access.foo`将该记录器生成的访问日志包含在全局选项中的两个记录器中: ```caddy { log access-formatted { include http.log.access.foo output file /var/log/access-foo.log format transform "{common_log}" } log access-json { include http.log.access.foo output file /var/log/access-foo.json format json } } foo.example.com { log foo } ``` 通过采样减少日志量,例如保留每秒前 5 个请求,然后每 10 个请求保留 1 个: ```caddy example.com { log { sampling { interval 1s first 5 thereafter 10 } } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/log_append.md ================================================ --- title: log_append (Caddyfile指令) --- # log_append 为当前请求的访问日志追加一个字段。 此指令应与 [`log` 指令](log)一起使用,因为首先需要 `log` 启用访问日志。 值可以是静态字符串,也可以是一个[占位符](/docs/caddyfile/concepts#placeholders),该占位符会在请求时被替换为对应值。 ## 语法 ```caddy-d log_append [] [<] ``` 默认情况下,日志字段会在中间件链返回时添加(即“late”模式),也就是在后续所有处理器完成之后添加(例如在 [`reverse_proxy`](reverse_proxy)、[`respond`](respond) 或 [`file_server`](file_server) 等会写出响应的处理器之后),因此它会捕获请求和响应的最终状态。 如果使用 `<` 作为键名前缀,则该字段会被标记为“early”模式,意味着日志字段会在调用链中的下一个处理器之前添加到日志中,因此可以在请求被后续处理器修改之前读取它。 仅用于调试目的(不要在生产环境中使用):当值为以下占位符之一时,此处理器有特殊处理:`{http.request.body}`、`{http.request.body_base64}`、`{http.response.body}` 或 `{http.response.body_base64}`。如果使用请求体占位符,则会隐式启用“early”模式,并缓冲请求体。如果使用响应体占位符,则会启用响应缓冲以捕获响应体,并在写出响应时以“late”模式将该字段添加到日志中。 ## 示例 在日志中显示请求所服务的站点区域,是 `static` 还是 `dynamic`: ```caddy example.com { log handle /static* { log_append area "static" respond "Static response!" } handle { log_append area "dynamic" reverse_proxy localhost:9000 } } ``` 在日志中显示实际使用的反向代理上游(`node1`、`node2` 或 `node3`),以及代理到上游所花费的毫秒数和上游写出响应头所需时间: ```caddy example.com { log handle { reverse_proxy node1:80 node2:80 node3:80 { lb_policy random_choose 2 } log_append upstream_host {rp.upstream.host} log_append upstream_duration_ms {rp.upstream.duration_ms} log_append upstream_latency_ms {rp.upstream.latency_ms} } } ``` 可以通过给键名加上 `<` 前缀,让字段以“early”模式添加到日志中。这允许你在请求被后续处理器修改之前捕获请求状态。例如,记录重写之前的原始请求路径(虽然这是一个刻意构造的例子,因为原始请求路径本来就会被记录,但它有助于说明这一点): ```caddy example.com { log log_append ] ``` ## 示例 你可能希望将请求记录到不同文件中,例如把健康检查日志与主要访问日志分开。 在 `log` 中使用 `no_hostname` 可以防止日志器关联到站点块的任何主机名(此处为 `localhost`),因此只有设置了对应 `log_name` 的请求才会写入该日志器。 ```caddy localhost { log { output file ./caddy.access.log } log health_check_log { output file ./caddy.access.health.log no_hostname } handle /healthz* { log_name health_check_log respond "Healthy" } handle { respond "Hello World" } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/log_skip.md ================================================ --- title: log_skip (Caddyfile指令) --- # log_skip 对匹配的请求跳过访问日志记录。 此指令应与 [`log` 指令](log)一起使用,用于跳过那些与你需求无关的请求日志。 在 v2.8.0 之前,此指令名为 `skip_log`;后来为与其他指令保持一致而重命名为 `log_skip`。 ## 语法 ```caddy-d log_skip [] ``` ## 示例 对存储在子路径中的静态文件跳过访问日志记录: ```caddy example.com { root /srv log log_skip /static* file_server } ``` 对匹配某个模式的请求跳过访问日志;在此例中,是具有特定扩展名的文件: ```caddy-d @skip path_regexp \.(js|css|png|jpe?g|gif|ico|woff|otf|ttf|eot|svg|txt|pdf|docx?|xlsx?)$ log_skip @skip ``` 如果它位于一个已经处于匹配器中的路由内,则不需要再提供匹配器。例如,为特定子路径提供文件服务的 handle: ```caddy-d handle_path /static* { root /srv/static log_skip file_server } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/map.md ================================================ --- title: map (Caddyfile指令) --- # map 设置根据输入值进行切换的自定义占位符的值。 它将源值与映射的输入端进行比较,如果匹配,则将输出值应用到每个目标。目标则替换成对应的占位符。也可以为每个目标指定默认的输出值。 映射的占位符在使用前不会被评估,所以即使是非常大的映射,这个指令也是相当有效的。 ## Syntax ```caddy-d map [] { [~] default } ``` - **<source>** 是要切换的输入值。通常是一个占位符。 - **<destinations...>** 是要创建的容纳输出值的占位符。 - **<input>** 是要匹配的输入值。如果前缀带了`~`,它讲被作为正则表达式处理。 - **<outputs...>** 是一个或多个要存储在相关占位符中的输出值。 第一个输出写到第一个目标,第二个输出写到第二个目标,以此类推。 作为一种特殊情况,Caddyfile分析器将字面连字符(`-`)的输出视为null/nil值。如果你想在给定输入的情况下,对该特定输出使用默认值,但又想对其他输出使用非默认值,这很有用。 如果可能的话,输出将被转换类型;`true`和`false`将被转换为布尔类型,数字值将被相应地转换为整数或浮点数。为了避免这种转换,你可以用[引号](/docs/caddyfile/concepts#tokens-and-quotes)来包裹输出,它们将保持为字符串。 每个映射的输出数量不得超过目标的数量;但是,为了方便起见,输出的数量可以少于目标的数量,任何缺失的输出将被隐含地填入。 如果使用正则表达式作为输入,那么捕获组可以用`${group}`来引用,其中`group`是表达式中捕获组的名称或编号。捕获组`0`是完整的重构表达式匹配,`1`是第一个捕获组,`2`是第二个捕获组,以此类推。 - **<default>** 指定了在没有匹配输入的情况下要存储的输出值。 ## 示例 下面的例子演示了这个指令的大部分内容。 ```caddy-d map {host} {my_placeholder} {magic_number} { example.com "some value" 3 foo.example.com "another value" (.*)\.example.com "${1} subdomain" 5 ~.*\.net$ - 7 ~.*\.xyz$ - 15 default "unknown domain" 42 } ``` 这条指令切换到`{host}`的值,也就是请求的域名。 - 如果请求的是`example.com`,则将`{my_placeholder}`设`some value`,将`{magic_number}`设为`3`。 - 否则,如果请求的是`foo.example.com`,将`{my_placeholder}`设置为`another value`,并让`{magic_number}`默认为`42`。 - 否则,如果请求是针对`example.com`的任何一个子域,则将`{my_placeholder}`设置为包含正则表达式捕获的第一个组的字符串,即整个子域,并将`{magic_number}`设置为`5`。 - 否则,如果请求是针对任何以`.net`或`.xyz`结尾的主机,只需将`{magic_number}`分别设置为`7`或`15`。不设置`{my_placeholder}`。 - 否则(对于所有其他主机),将适用默认值。`{my_placeholder}`将被设置为`unknown domain`,`{magic_number}`将被设置为`42`。 ================================================ FILE: src/docs/markdown/caddyfile/directives/method.md ================================================ --- title: method (Caddyfile指令) --- # method 改变请求中的HTTP方法。 ## 语法 ```caddy-d method [] . ``` - **<method>** 是要改变请求的HTTP方法。 ## 示例 将`/api`下的所有请求的方法改为`POST`。 ```caddy-d method /api* POST ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/metrics.md ================================================ --- title: metrics (Caddyfile指令) --- # metrics 配置一个Prometheus度量标准展示端点,这样采集的指标可以被暴露出来以供抓取。 注意,[admin API](/docs/api)上也有一个`/metrics`端点。 但它不能进行配置,而且当管理API被禁用时也不能使用。 这个端点将以[Prometheus数据传输格式](https://prometheus.io/docs/instrumenting/exposition_formats/#text-based-format)返回指标。如果经过协商,也可以使用[OpenMetrics数据传输格式](https://pkg.go.dev/github.com/prometheus/client_golang@v1.9.0/prometheus/promhttp#HandlerOpts) (`application/openmetrics-text`)。 另见[用Prometheus度量标准监控Caddy](/docs/metrics)。 ## 语法 ```caddy-d metrics [] { disable_openmetrics } ``` - **disable_openmetrics** 禁用OpenMetrics格式。这个指令通常没有必要,除非需要解决解析错误。 ## 示例 在默认的`/metrics`路径下显示指标。 ```caddy-d metrics /metrics ``` 在另一个路径上显示指标。 ```caddy-d metrics /foo/bar/baz ``` 在一个单独的子域中提供指标。 ```caddy metrics.example.com { metrics } ``` 停用OpenMetrics格式。 ```caddy-d metrics /metrics { disable_openmetrics } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/php_fastcgi.md ================================================ --- title: php_fastcgi (Caddyfile directive) --- # php_fastcgi 一个固执己见的指令,将请求代理到 PHP FastCGI 服务器,例如 php-fpm。 - [语法](#syntax) - [展开形式](#expanded-form) - [解释](#explanation) - [示例](#examples) Caddy 的[`reverse_proxy`](reverse_proxy)能够为任何 FastCGI 应用程序提供服务,但该指令是专门为 PHP 应用程序量身定制的。该指令是一个方便的快捷方式,取代了[更长的配置](#expanded-form)。 它期望站点根目录中的任何`index.php`都充当路由器。如果不希望这样,可以重新配置[`try_files` 子指令](#try_files)来修改默认的重写行为,或者以[展开形式](#expanded-form)为基础并根据您的需要进行自定义。 除了下面列出的子指令之外,该指令还支持[`reverse_proxy`](reverse_proxy#syntax)的所有子指令。例如,您可以启用负载均衡和运行状况检查。 **Most modern PHP apps work fine without extra subdirectives or customization.** 子指令通常仅在某些边缘情况或旧版 PHP 应用程序中使用。 ## 语法 ```caddy-d php_fastcgi [] { root split index |off try_files env [ ] resolve_root_symlink capture_stderr dial_timeout read_timeout write_timeout } ``` - **** 是 FastCGI 服务器的[addresses](/docs/conventions#network-addresses)。通常是 TCP 套接字或 unix 套接字文件。 - **root**将根文件夹设置为站点。建议始终将[`root` 指令](root)与`php_fastcgi`结合使用,但是当您的 PHP-FPM 上游使用与 Caddy 不同的根目录时,覆盖此设置可能会很有用(请参阅[示例](#docker))。如果使用,则默认为[`root` 指令](root)的值,否则默认为 Caddy 的当前工作目录。 - **split**设置将 URI 分成两部分的子字符串。第一个匹配的子字符串将用于从路径中分割“路径信息”。第一部分以匹配的子字符串为后缀,并将被假定为实际资源(CGI 脚本)名称。第二部分将设置为 PATH_INFO 供 CGI 脚本使用。默认:`.php` - **index**指定视为目录索引文件的文件名。这会影响[展开形式](#expanded-form)中的文件匹配器。默认:`index.php`。可以设置为`off`,以在找不到匹配文件时禁用重写回退到`index.php`。 - **try_files**指定默认尝试文件重写的覆盖。详情请见[`try_files` 指令](try_files)。默认:`{path} {path}/index.php index.php`。 - **env**将额外的环境变量设置为给定值。可以为多个环境变量指定多次。默认情况下,所有相关的 FastCGI 环境变量都已设置(包括 HTTP 标头),但您可以根据需要添加或覆盖变量。 - **resolve_root_symlink**当[`root`](#root)目录是符号链接(symlink)时,这可以将其解析为其实际值。有时,通过简单地交换符号链接以指向另一个目录中的新版本,这可以用作部署策略。默认情况下禁用以避免重复的系统调用。 - **capture_stderr**可以捕获并记录上游 fastcgi 服务器在`stderr`上发送的任何消息。默认情况下,日志记录在`WARN`级别完成。如果响应具有`4xx`或`5xx`状态,则将使用`ERROR`级别。默认情况下,`stderr`被忽略。 - **dial_timeout**是[持续时间值](/docs/conventions#durations),设置连接到上游套接字时等待多长时间。默认:`3s`。 - **read_timeout**是[持续时间值](/docs/conventions#durations),设置从 FastCGI 上游读取时等待的时间。默认:无超时。 - **write_timeout**是[持续时间值](/docs/conventions#durations),设置发送到 FastCGI 上游时等待多长时间。默认:无超时。 由于该指令是反向代理上的固执己见的包装器,因此您可以使用[`reverse_proxy`](reverse_proxy#syntax)的任何子指令来自定义它。 ## 展开形式 `php_fastcgi`指令(无子指令)与以下配置相同。大多数现代 PHP 应用程序都可以很好地使用此预设。如果您没有,请随意借鉴此内容并根据需要进行自定义,而不是使用`php_fastcgi`快捷方式。 ```caddy-d route { # Add trailing slash for directory requests # This redirection is automatically disabled if "{http.request.uri.path}/index.php" # doesn't appear in the try_files list @canonicalPath { file {path}/index.php not path */ } redir @canonicalPath {http.request.orig_uri.path}/ 308 # If the requested file does not exist, try index files and assume index.php always exists @indexFiles file { try_files {path} {path}/index.php index.php try_policy first_exist_fallback split_path .php } rewrite @indexFiles {file_match.relative} # Proxy PHP files to the FastCGI responder @phpFiles path *.php reverse_proxy @phpFiles { transport fastcgi { split .php } } } ``` ### 解释 - 第一部分涉及规范化请求路径。目标是确保针对磁盘上目录的请求实际上将尾部斜杠`/`添加到请求路径中,以便只有单个 URL 对于对该目录的请求有效。 仅当`try_files`子指令包含`{path}/index.php`(默认值)时,才会发生此规范化。 这是通过使用请求匹配器来执行的,该请求匹配器仅匹配不以斜杠结尾的请求,并且映射到磁盘上包含`index.php`文件的目录,如果匹配,则执行附加尾部斜杠的 HTTP 308 重定向。例如,如果磁盘上存在`/foo/index.php`,它会将路径`/foo`的请求重定向到`/foo/`(附加`/`,以规范化目录路径)。 - 下一节将讨论根据磁盘上是否存在匹配文件来执行路径重写。这还有一个副作用,就是记住`.php`之后的路径部分(如果请求路径中有`.php`)。这对于 Caddy 正确设置 FastCGI 环境变量非常重要。 - 首先,它检查`{path}`是否是磁盘上存在的文件。如果是这样,它将重写到该路径。这本质上使其余部分短路,并确保对磁盘上_确实存在_的文件的请求不会被重写(请参阅下面的后续步骤)。因此,如果您的磁盘上有一个`/js/app.js`文件,那么对该路径的请求将保持不变。 - 其次,它检查`{path}/index.php`是否是磁盘上存在的文件。如果是这样,它将重写到该路径。对于像`/foo/`这样的目录的请求,它会查找`/foo//index.php`(它被规范化为`/foo/index.php`),并将请求重写到该路径(如果存在)。如果您在 Webroot 的子目录中运行另一个 PHP 应用程序,此行为有时会很有用。 - 最后,它总是会重写为`index.php`(它几乎总是存在于现代 PHP 应用程序中)。这允许您的 PHP 应用程序通过使用`index.php`脚本作为其入口点来处理对_不_映射到磁盘上的文件的路径的任何请求。 - 最后,最后一部分是实际代理对 PHP FastCGI(或 PHP-FPM)服务的请求以实际运行 PHP 代码。请求匹配器只会匹配以`.php`结尾的请求,因此,任何不是 PHP 脚本且存在于磁盘上的文件都不会被该指令处理,并且会失败。 `php_fastcgi`指令本身通常是不够的。它几乎应该总是与[`root` 指令](root)配对来设置文件在磁盘上的位置(对于现代 PHP 应用程序,这可能是`/var/www/html/public`,其中`public`目录包含您的`index.php`),并与[`file_server` 指令](file_server)一起提供您的静态文件(您的 JS、CSS、图像等),这些文件不会由该指令处理并失败。 ## 示例 将所有 PHP 请求代理到在`127.0.0.1:9000`监听的 FastCGI 响应程序: ```caddy-d php_fastcgi 127.0.0.1:9000 ``` 相同,但仅适用于`/blog/`下的请求: ```caddy-d php_fastcgi /blog/* localhost:9000 ``` 当使用 PHP-FPM 通过 unix 套接字监听时: ```caddy-d php_fastcgi unix//run/php/php8.2-fpm.sock ``` [`root` 指令](root)几乎总是用于指定包含 PHP 脚本的目录,而[`file_server` 指令](file_server)则用于提供静态文件: ```caddy example.com { root /var/www/html/public php_fastcgi 127.0.0.1:9000 file_server } ``` 当使用 Caddy 提供多个 PHP 应用程序时,每个应用程序的 Webroot 必须不同,以便 Caddy 可以单独读取和提供静态文件并检测 PHP 文件是否存在。 如果您使用 Docker,通常您的 PHP-FPM 容器会将文件安装在同一根目录下。在这种情况下,解决方案是将文件挂载到 Caddy 容器的不同目录中,然后使用[`root` subdirective](#root)设置每个容器的根目录: ```caddy app1.example.com { root /srv/app1/public php_fastcgi app1:9000 { root /var/www/html/public } file_server } app2.example.com { root /srv/app2/public php_fastcgi app2:9000 { root /var/www/html/public } file_server } ``` 对于不使用`index.php`作为入口点的 PHP 站点,您可以回退到发出`404`错误。可以使用[`handle_errors` 指令](handle_errors)捕获并处理该错误: ```caddy example.com { php_fastcgi localhost:9000 { try_files {path} {path}/index.php =404 } handle_errors { respond "{err.status_code} {err.status_text}" } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/push.md ================================================ --- title: push (Caddyfile指令) --- # push 配置服务器使用HTTP/2服务器预先向客户端推送资源。 通过指定响应的Link头,可以为服务器推送资源提供链接。这条指令将自动推送由上游Link头描述的资源,格式如下。 - `; as=script` - `; as=script,; as=style` - `; nopush` - `;;...` 其中``以正斜线`/`开头(也就是说,是一个具有相同主机的URI路径)。只有同主机的资源菜可以被推送。如果有属于外部资源的路径,或者标识了`nopush`的属性,它将不会被推送。 默认情况下,推送请求将包括一些被认为可以从原始请求中安全复制的头信息。 - Accept-Encoding - Accept-Language - Accept - Cache-Control - User-Agent 如果没有这些头信息,许多请求都会失败;这些header头是不需要手动配置的。 推送请求在内部被虚拟化,所以它们是非常轻量的。 ## 语法 ```caddy-d push [] [] { [GET|HEAD] headers { [+] [ []] - } } ``` - **<resource>** 是要推送的目标URI路径。如果在区块内使用,可以选择在前面加上方法(GET或POST;默认是GET)。 - **<headers>** 使用与[`header`指令](/docs/caddyfile/directives/header)相同的语法来操作推送请求的头信息。有些头信息是默认带入的,不需要明确配置(见上文)。 ## 示例 在响应中推送任何由`Link`头信息描述的资源。 ```caddy-d push ``` 和上面一样,但也向所有请求推送`/resources/style.css`。 ```caddy-d push * /resources/style.css ``` 只有在客户端请求`/foo.html`时才推送`/foo.jpg`。 ```caddy-d push /foo.html /foo.jpg ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/redir.md ================================================ --- title: redir (Caddyfile指令) --- # redir 向客户发出一个HTTP重定向。 这条指令意味着一个匹配的请求将被拒绝。它在处理程序链中被安排在很早的位置(在[`rewrite`](/docs/caddyfile/directives/rewrite)之前)。 ## 语法 ```caddy-d redir [] [] ``` - **<to>** 是目标位置。成为响应的Location的header头。 - **<code>** 是重定向要使用的HTTP状态码。可以是。 - 3xx范围内的一个正整数,或401 - `temporary` 用于临时重定向(默认为302) - `permanent` 用于永久重定向(301) - `html` 使用一个HTML文档来执行重定向(对重定向浏览器很有用,但对重定向API客户端没有用) - 一个带有状态代码值的占位符 ## 示例 将所有请求重定向到`https://example.com`。 ```caddy-d redir https://example.com ``` 和上面一样,但保留URI不变: ```caddy-d redir https://example.com{uri} ``` 相同,但是是永久重定向: ```caddy-d redir https://example.com{uri} permanent ``` 将旧的`/about-us`页面重定向到新的`/about`页面。 ```caddy-d redir /about-us /about ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/request_body.md ================================================ --- title: request_body (Caddyfile指令) --- # request_body 操作或设置对传入请求正文的限制。 ## 语法 ```caddy-d request_body [] { max_size set } ``` - **max_size** 是允许的请求体最大字节数。它接受[go-humanize](https://pkg.go.dev/github.com/dustin/go-humanize#pkg-constants)支持的所有大小值。读取超过限定的字节数将返回HTTP状态`413`的错误。 ⚠️ 实验性 | v2.10.0+ - **set** 允许将请求体设置为特定内容。内容可以包含占位符,以便动态插入数据。 ## 示例 将请求体大小限制为10兆字节: ```caddy example.com { request_body { max_size 10MB } reverse_proxy localhost:8080 } ``` 使用包含SQL查询的JSON结构设置请求体: ```caddy example.com { handle /jazz { request_body { set `\{"statementText":"SELECT name, genre, debut_year FROM artists WHERE genre = 'Jazz'"}` } reverse_proxy localhost:8080 { header_up Content-Type application/json method POST rewrite /execute-sql } } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/request_header.md ================================================ --- title: request_header (Caddyfile指令) --- # request_header 处理请求中的HTTP标头字段。它可以设置、添加和删除标头值,或使用正则表达式执行替换。 ## Syntax ```caddy-d request_header [] [[+|-] [|] []] ``` - **<field>** 是标头字段的名称。默认情况下,将覆盖任何现有的同名字段。 - 带前缀`+`的字段将会被添加而不是被替换; - 带前缀`-`的字段则会被删除。 - **<value>** 是标头字段值,被添加或设置。 - **<find>** 是要搜索的子字符串或正则表达式。 - **<replace>** 是替换值;如果执行搜索和替换,则需要。 ## 示例 从请求中删除Referer标头: ```caddy-d request_header -Referer ``` 删除请求中所有包含下划线的header头: ```caddy-d request_header -*_* ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/respond.md ================================================ --- title: respond (Caddyfile指令) --- # respond 写一个硬编码/静态响应给客户端。 如果响应体非空,此指令会在尚未设置`Content-Type`头时设置它。默认值是`text/plain; utf-8`;如果响应体是有效的JSON对象或数组,则设置为`application/json`。对于所有其他内容类型,请使用[`header`指令](/docs/caddyfile/directives/header)显式设置合适的Content-Type。 ## 语法 ```caddy-d respond [] | [] { body close } ``` - **<status>** 是要写入的HTTP状态码。 如果是`103`(Early Hints),响应会在没有响应体的情况下写出,并且处理器链会继续。(HTTP `1xx`响应是信息性响应,不是最终响应。) 默认:`200` - **<body>** 是要写入的响应体。 - **body** 是提供响应体的另一种方式;如果是多行内容会很方便。 - **close** 会在写完响应后关闭客户端与服务器的连接。 澄清一下,第一个非匹配器参数可以是3位状态码,也可以是响应体字符串。如果它是响应体,下一个参数可以是状态码。 ## 示例 对所有健康检查写入空响应体的200状态,并对所有其他请求写入简单响应体: ```caddy example.com { respond /health-check 200 respond "Hello, world!" } ``` 写入错误响应并关闭连接: ```caddy example.com { respond /secret/* "Access denied" 403 { close } } ``` 使用[heredoc语法](/docs/caddyfile/concepts#heredocs)控制空白并写入HTML响应,同时设置`Content-Type`头以匹配响应体: ```caddy example.com { header Content-Type text/html respond < Foo Foo HTML 200 } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/reverse_proxy.md ================================================ --- title: reverse_proxy (Caddyfile directive) --- # reverse_proxy 通过可配置的传输、负载均衡、运行状况检查、请求操作和缓冲选项将请求代理到一个或多个后端。 - [语法](#syntax) - [上游](#upstreams) - [上游地址](#upstream-addresses) - [动态上游](#dynamic-upstreams) - [SRV](#srv) - [A/AAAA](#aaaaa) - [Multi](#multi) - [负载均衡](#load-balancing) - [主动健康检查](#active-health-checks) - [被动健康检查](#passive-health-checks) - [事件](#events) - [流式传输](#streaming) - [标头](#headers) - [重写](#rewrites) - [传输](#transports) - [`http` 传输](#the-http-transport) - [`fastcgi` 传输](#the-fastcgi-transport) - [拦截响应](#intercepting-responses) - [示例](#examples) ## 语法 ```caddy-d reverse_proxy [] [] { # backends to dynamic ... # load balancing lb_policy [] lb_retries lb_try_duration lb_try_interval lb_retry_match # active health checking health_uri health_upstream health_port health_interval health_passes health_fails health_timeout health_method health_status health_request_body health_body health_follow_redirects health_headers { [] } # passive health checking fail_duration max_fails unhealthy_status unhealthy_latency unhealthy_request_count # streaming flush_interval request_buffers response_buffers stream_timeout stream_close_delay # request/header manipulation trusted_proxies [private_ranges] header_up [+|-] [ []] header_down [+|-] [ []] method rewrite # round trip transport { ... } # optionally intercept responses from upstream @name { status header [] } replace_status [] handle_response [] { # special directives only available in handle_response copy_response [] [] { status } copy_response_headers [] { include exclude } } } ``` ## 上游 - **<upstreams...>** 是要代理的上游(后端)列表。 - **to**是指定上游列表的另一种方法,每行一个(或多个)。 - **dynamic**配置_动态上游_ 模块。这允许为每个请求动态获取上游列表。有关标准动态上游模块的说明,请参阅下面的[动态上游](#dynamic-upstreams)。动态上游在每次代理循环迭代时都会被检索(即,如果启用了负载均衡重试,每个请求可能会多次检索),并且会优先于静态上游。如果发生错误,代理将回退到使用任何静态配置的上游。 ### 上游地址 静态上游地址可以采用仅包含方案和主机/端口的 URL 形式,或传统的[Caddy network address](/docs/conventions#network-addresses)。有效示例: - `localhost:4000` - `127.0.0.1:4000` - `[::1]:4000` - `http://localhost:4000` - `https://example.com` - `h2c://127.0.0.1` - `example.com` - `unix//var/php.sock` - `unix+h2c//var/grpc.sock` - `localhost:8001-8006` - `[fe80::ea9f:80ff:fe46:cbfd%eth0]:443` 默认情况下,通过纯文本 HTTP 与上游建立连接。使用 URL 形式时,可以使用方案来设置一些[`transport`](#transports)默认值作为简写。 - 使用`https://`作为方案将使用[`http` 传输](#the-http-transport)并启用[`tls`](#tls)。 此外,您可能需要覆盖`Host`标头,使其与 TLS SNI 值匹配,服务器使用该值进行路由和证书选择。请参阅下面的[HTTPS](#https)部分了解更多详细信息。 - 使用`h2c://`作为方案将使用[`http` 传输](#the-http-transport),并将[HTTP 版本](#versions)设置为允许明文 HTTP/2 连接。 - 使用`http://`作为方案与省略该方案相同,因为 HTTP 已经是默认值。包含此语法是为了与其他方案快捷方式对称。 方案不能混合,因为它们修改公共传输​​配置(启用 TLS 的传输不能同时承载 HTTPS 和纯文本 HTTP)。任何显式传输配置都不会被覆盖,并且省略方案或使用其他端口将不会假定特定的传输。 当将 IPv6 与区域(例如,具有特定网络接口的链接本地地址)一起使用时,方案 **cannot** 用作快捷方式,因为`%`将导致 URL 解析错误;相反,显式配置传输。 当使用[network address](/docs/conventions#network-addresses)形式时,网络类型被指定为上游地址的前缀。这不能与 URL 方案结合使用。作为特殊情况,支持`unix+h2c/`作为`unix/`网络的快捷方式,并具有与`h2c://`方案相同的效果。支持端口范围作为快捷方式,可扩展到具有同一主机的多个上游。 上游地址**cannot**包含路径或查询字符串,因为这意味着在代理时同时重写请求,而这种行为未定义或支持。如果需要,您可以使用[`rewrite`](/docs/caddyfile/directives/rewrite)指令。 如果地址不是 URL(即没有方案),则可以使用[placeholders](/docs/caddyfile/concepts#placeholders),但这会使上游“动态静态”,这意味着在健康检查和负载均衡方面,可能有许多不同的后端充当单个静态上游。如果可能的话,我们建议使用[动态上游](#dynamic-upstreams)模块。使用占位符时,必须包含端口(通过占位符替换或作为地址的静态后缀)。 ### 动态上游 Caddy 的反向代理标配了一些动态上游模块。请注意,使用动态上游会对负载均衡和运行状况检查产生影响,具体取决于特定的策略配置:动态上游不会运行主动运行状况检查;如果上游列表相对稳定且一致(尤其是循环),则最好提供负载均衡和被动健康检查。理想情况下,动态上游模块仅返回健康、可用的后端。 #### SRV 从 SRV DNS 记录检索上游。 ```caddy-d dynamic srv [] { service proto name refresh resolvers dial_timeout dial_fallback_delay } ``` - **<full_name>** 是要查找的记录的完整域名(即`_service._proto.name`)。 - **service**是全称的服务组件。 - **proto** 是全名的协议组件。`tcp`或`udp`。 - **name** 是名称组成部分。或者,如果`service`和`proto`为空,则查询完整域名。 - **refresh** 是刷新缓存结果的频率。默认:`1m` - **resolvers** 是覆盖系统解析器的 DNS 解析器列表。 - **dial_timeout** 是拨打查询的超时时间。 - **dial_fallback_delay** 是生成 RFC 6555 快速回退连接之前等待的时间。默认:`300ms` #### A/AAAA 从 A/AAAA DNS 记录检索上游。 ```caddy-d dynamic a [ ] { name port refresh resolvers dial_timeout dial_fallback_delay versions ipv4|ipv6 } ``` - **name** 是要查询的域名。 - **port** 是用于后端的端口。 - **refresh** 是刷新缓存结果的频率。默认:`1m` - **resolvers** 是覆盖系统解析器的 DNS 解析器列表。 - **dial_timeout** 是拨打查询的超时时间。 - **dial_fallback_delay** 是生成 RFC 6555 快速回退连接之前等待的时间。默认:`300ms` - **versions** 是要解析的 IP 版本列表。默认:`ipv4 ipv6`,分别对应A记录和AAAA记录。 #### 多 附加多个动态上游模块的结果。如果您需要上游的冗余源,例如:由辅助 SRV 集群备份的主 SRV 集群,则非常有用。 ```caddy-d dynamic multi { [...] } ``` - **<source>** 是动态上游模块的名称,后面是其配置。可以指定多个。 ## 负载均衡 负载均衡通常用于在多个上游之间分配流量。通过启用重试,它还可以与一个或多个上游一起使用,以保留请求,直到可以选择健康的上游(例如,在重新启动或重新部署上游时等待并减少错误)。 默认情况下,使用`random`策略启用此功能。默认情况下禁用重试。 - **lb_policy**是负载均衡策略的名称以及任何选项。默认:`random`。 对于涉及哈希的策略,[highest-random-weight (HRW)](https://en.wikipedia.org/wiki/Rendezvous_hashing)算法用于确保具有相同哈希键的客户端或请求映射到相同的上游,即使上游列表发生变化。 某些策略支持回退作为选项(如果注明),在这种情况下,它们采用[block](/docs/caddyfile/concepts#blocks)和`fallback `,后者采用另一个负载均衡策略。对于这些策略,默认后备是`random`。配置回退允许在主策略未选择策略时使用辅助策略,从而实现强大的组合。如果需要,后备可以嵌套多次。 例如,`header`可以用作主连接,以允许开发人员选择特定的上游,并为所有其他连接提供`first`的回退,以实现主/辅助故障转移。 ```caddy-d lb_policy header X-Upstream { fallback first } ``` -`random`随机选择上游 -`random_choose `随机选择两个或多个上游,然后选择负载最小的一个(`n`通常为 2) -`first`按照配置中定义的顺序选择第一个可用的上游,允许主/辅助故障转移;请记住同时启用健康检查,否则不会发生故障转移 -`round_robin`依次迭代每个上游 -`weighted_round_robin `依次迭代每个上游,尊重提供的权重。权重参数的数量应与配置的上游数量相匹配。权重应该是非负整数。例如,有两个上游且权重为`5 1`,第一个上游将连续被选择 5 次,然后第二个上游被选择一次,然后重复循环。如果使用零作为权重,这将禁止为新请求选择上游。 -`least_conn`选择当前请求数最少的上游;如果超过一台主机的请求数最少,则随机选择其中一台主机 -`ip_hash`将远程 IP(直接对等点)映射到粘性上游 -`client_ip_hash`将客户端 IP 映射到粘性上游;最好与[`servers > trusted_proxies` 全局选项](/docs/caddyfile/options#trusted-proxies)搭配使用,[`servers > trusted_proxies` 全局选项](/docs/caddyfile/options#trusted-proxies)可以实现真实客户端 IP 解析,否则其行为与`ip_hash`相同 -`uri_hash`将请求 URI(路径和查询)映射到粘性上游 -`query [key]`通过对查询值进行哈希处理,将请求查询映射到粘性上游;如果指定的键不存在,将使用回退策略选择上游(默认为`random`) -`header [field]`通过哈希标头值将请求标头映射到粘性上游;如果指定的头字段不存在,则将使用回退策略选择上游(默认为`random`) - 来自客户端的第一个请求的`cookie [ []]`(当没有 cookie 时),将使用后备策略选择上游(默认为`random`),并将`Set-Cookie`标头添加到响应中(如果未指定,默认 cookie 名称为`lb`)。 cookie 值是所选上游的上游拨号地址,使用 HMAC-SHA256 进行哈希处理(使用``作为共享密钥,如果未指定则为空字符串)。 在存在 cookie 的后续请求中,cookie 值将映射到相同的上游(如果可用);如果不可用或未找到,则使用回退策略选择新的上游,并将 cookie 添加到响应中。 如果您希望使用特定上游进行调试,您可以使用密钥对上游地址进行散列,并在 HTTP 客户端(浏览器或其他)中设置 cookie。例如,使用 PHP,您可以运行以下命令来计算 cookie 值,其中`10.1.0.10:8080`是您的上游之一的地址,`secret`是您配置的密钥。 ```php echo hash_hmac('sha256', '10.1.0.10:8080', 'secret'); // cdd96966817dd14a99f47ee17451464f29998da170814a16b483e4c1ff4c48cf ``` 您可以通过 Javascript 控制台在浏览器中设置 cookie,例如设置名为`lb`的 cookie: ```js document.cookie = "lb=cdd96966817dd14a99f47ee17451464f29998da170814a16b483e4c1ff4c48cf"; ``` - **lb_retries**是在下一个可用主机关闭时为每个请求重试选择可用后端的次数。默认情况下,重试被禁用(零)。 如果还配置了[`lb_try_duration`](#lb_try_duration),则在达到持续时间后重试可能会提前停止。换句话说,重试持续时间优先于重试计数。 - **lb_try_duration**是一个[持续时间值](/docs/conventions#durations),它定义了在下一个可用主机关闭时为每个请求尝试选择可用后端的时间。默认情况下,重试被禁用(零持续时间)。 当负载均衡器尝试查找可用的上游主机时,客户端将等待这么长时间。合理的起点可能是`5s`,因为 HTTP 传输的默认拨号超时是`3s`,因此如果无法到达第一个选定的上游,则应允许至少重试一次;但请随意尝试,为您的用例找到合适的平衡点。 - **lb_try_interval**是[持续时间值](/docs/conventions#durations),定义从池中选择下一个主机之间等待的时间。默认是`250ms`。仅当对上游主机的请求失败时才相关。请注意,如果所有后端都关闭并且延迟非常低,则将其设置为`0`并使用非零`lb_try_duration`可能会导致 CPU 旋转。 - **lb_retry_match**限制允许重试的请求。请求必须符合此条件,以便在与上游的连接成功但后续往返失败时重试。如果与上游的连接失败,则始终允许重试。默认情况下,只重试`GET`请求。 此选项的语法与[命名请求匹配器](/docs/caddyfile/matchers#named-matchers)相同,但没有`@name`。如果您只需要一个匹配器,您可以将其配置在同一行上。对于多个匹配器,需要一个块。 ### 主动健康检查 主动运行状况检查在后台通过计时器执行运行状况检查。要启用此功能,需要`health_uri`或`health_port`。 - **health_uri**是主动健康检查的 URI 路径(和可选查询)。 - **health_upstream**是用于主动健康检查的 ip:port(如果与上游不同)。这应该与`health_header`和`{http.reverse_proxy.active.target_upstream}`一起使用。 - **health_port**是用于主动运行状况检查的端口(如果与上游端口不同)。如果使用`health_upstream`则忽略。 - **health_interval**是[持续时间值](/docs/conventions#durations),定义执行主动健康检查的频率。默认:`30s`。 - **health_passes**是在将后端再次标记为健康之前所需的连续健康检查次数。默认:`1`。 - **health_fails**是将后端标记为不健康之前所需的连续健康检查次数。默认:`1`。 - **health_timeout**是一个[持续时间值](/docs/conventions#durations),定义在将后端标记为关闭之前等待回复的时间。默认:`5s`。 - **health_method**是用于主动健康检查的 HTTP 方法。默认:`GET`。 - **health_status**是健康后端期望的 HTTP 状态代码。可以是 3 位状态代码,或以`xx`结尾的状态代码类。例如:`200`(默认)或`2xx`。 - **health_request_body**是一个字符串,表示与主动健康检查一起发送的请求正文。 - **health_body**是匹配主动健康检查的响应正文的子字符串或正则表达式。如果后端没有返回匹配的body,则会被标记为down。 - **health_follow_redirects**将导致健康检查遵循上游提供的重定向。默认情况下,重定向响应将导致运行状况检查失败。 - **health_headers**允许指定要在活动健康检查请求上设置的标头。如果您需要更改`Host`标头,或者需要向后端提供一些身份验证作为健康检查的一部分,这非常有用。 ### 被动健康检查 被动健康检查与实际代理请求一致发生。要启用此功能,需要`fail_duration`。 - **fail_duration**是一个[持续时间值](/docs/conventions#durations),定义了记住失败请求的时间。持续时间 >`0`启用被动健康检查;默认为`0`(关闭)。一个合理的起点可能是`30s`,以便在将不健康的上游恢复在线时平衡错误率和响应能力;但请随意尝试,为您的用例找到合适的平衡点。 - **max_fails**是在考虑后端关闭之前`fail_duration`内所需的最大失败请求数;必须 >=`1`;默认是`1`。 - **unhealthy_status** 如果响应返回时带有这些状态代码之一,则将请求视为失败。可以是 3 位状态代码或以`xx`结尾的状态代码类,例如:`404`或`5xx`。 - **unhealthy_latency**是一个[持续时间值](/docs/conventions#durations),如果需要这么长时间才能获得响应,则将请求视为失败。 - **unhealthy_request_count**是在将后端标记为关闭之前允许的并发请求数。换句话说,如果某个特定后端当前正在处理这么多请求,则它被视为“过载”,并且将优先选择其他后端。 这应该是一个相当大的数字;配置此意味着代理将有`unhealthy_request_count × upstreams_count`并发请求总数的限制,并且该点之后的任何请求都将由于没有可用的上游而导致错误。 ## 活动 当上游从健康状态转变为不健康状态(反之亦然)时,会发出[an event](/docs/caddyfile/options#event-options)。这些事件可用于触发其他操作,例如发送通知或记录消息。活动详情如下: - 当上游之前不健康但被标记为健康时,会发出`healthy` - 当上游之前健康但被标记为不健康时,会发出`unhealthy` 在这两种情况下,`host`作为元数据包含在事件中,以标识更改状态的上游。例如,它可以用作`{event.data.host}`和`exec`事件处理程序的占位符。 ## 流媒体 默认情况下,代理会部分缓冲响应以提高线路效率。 该代理还支持 WebSocket 连接,执行 HTTP 升级请求,然后将连接转换为双向隧道。 - **flush_interval**是一个[持续时间值](/docs/conventions#durations),用于调整 Caddy 刷新客户端响应缓冲区的频率。默认情况下,不进行定期刷新。负值(通常为 -1)表示“低延迟模式”,该模式完全禁用响应缓冲并在每次写入客户端后立即刷新,并且即使客户端提前断开连接也不会取消对后端的请求。如果响应满足以下条件之一,则忽略此选项,并且响应会立即刷新到客户端: - `Content-Type: text/event-stream` -`Content-Length`未知 - 代理双方HTTP/2,`Content-Length`未知,`Accept-Encoding`要么未设置,要么是“身份” - **request_buffers**将导致代理在向上游发送请求正文之前将最多``数量的字节读取到缓冲区中。这是非常低效的,只有在上游需要立即读取请求主体时才应该这样做(这是上游应用程序应该修复的问题)。这接受[go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go)支持的所有大小格式。 - **response_buffers**将导致代理从响应正文中读取最多``数量的字节,然后将其读入缓冲区,然后再返回给客户端。出于性能原因,应尽可能避免这种情况,但如果后端具有更严格的内存限制,则这可能很有用。这接受[go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go)支持的所有大小格式。 - **stream_timeout**是[持续时间值](/docs/conventions#durations),之后 WebSocket 等流式请求将在超时结束时被强制关闭。如果连接保持打开时间过长,这实际上会取消连接。一个合理的起点可能是`24h`来剔除超过一天的连接。默认:无超时。 - **stream_close_delay**是一个[持续时间值](/docs/conventions#durations),它会延迟配置卸载时强制关闭 WebSocket 等流式请求;相反,流将保持打开状态,直到延迟完成。换句话说,启用此功能可以防止流在重新加载 Caddy 的配置时立即关闭。启用此功能可能是一个好主意,可以避免大量重新连接因之前的配置关闭而关闭连接的客户端。一个合理的起点可能是像`5m`这样的东西,允许用户在配置重新加载后有 5 分钟的时间自然离开页面。默认:无延迟。 ## 标头 代理可以**manipulate headers**: - **header_up**在上游到后端的请求标头中设置、添加(使用`+`前缀)、删除(使用`-`前缀)或执行替换(通过使用两个参数,搜索和替换)。 - **header_down**在来自后端下游的响应标头中设置、添加(使用`+`前缀)、删除(使用`-`前缀)或执行替换(通过使用两个参数,搜索和替换)。 例如,要设置请求标头,覆盖任何现有值: ```caddy-d header_up Some-Header "the value" ``` 添加响应头;请注意,标头字段可以有多个值: ```caddy-d header_down +Some-Header "first value" header_down +Some-Header "second value" ``` 要删除请求标头,防止其到达后端: ```caddy-d header_up -Some-Header ``` 要删除所有匹配的请求标头,请使用后缀匹配: ```caddy-d header_up -Some-* ``` 要删除_all_请求标头,以便能够单独添加您想要的标头(不推荐): ```caddy-d header_up -* ``` 要对请求标头执行正则表达式替换: ```caddy-d header_up Some-Header "^prefix-([A-Za-z0-9]*)$" "replaced-$1-suffix" ``` 使用的正则表达式语言是 RE2,包含在 Go 中。请参阅[RE2 语法参考](https://github.com/google/re2/wiki/Syntax)和[Go regexp 语法概述](https://pkg.go.dev/regexp/syntax)。替换字符串是[展开](https://pkg.go.dev/regexp#Regexp.Expand),允许使用捕获的值,例如`$1`是第一个捕获组。 ### 默认值 默认情况下,Caddy 不加修改地将传入标头(包括`Host`)传递到后端,但有以下三个例外: - 它设置或扩充[`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)标头字段。 - 它设置[`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto)标头字段。 - 它设置[`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host)标头字段。 对于这些`X-Forwarded-*`标头,默认情况下,代理将忽略传入请求中的值,以防止欺骗。 如果 Caddy 不是您的客户端连接到的第一个服务器(例如,当 CDN 位于 Caddy 前面时),您可以使用 IP 范围 (CIDR) 列表配置`trusted_proxies`,相信传入请求已为这些标头发送了正确的值。 强烈建议您通过[`servers > trusted_proxies` 全局选项](/docs/caddyfile/options#trusted-proxies)而不是在代理中进行配置,以便这适用于服务器中的所有代理处理程序,并且这样做的好处是启用客户端 IP 解析。 此外,当使用[`http` 传输](#the-http-transport)时,如果客户端请求中缺少`Accept-Encoding: gzip`标头,则会设置该标头。这允许上游在可能的情况下提供压缩内容。可以使用传输上的[`compression off`](#compression)禁用此行为。 ### HTTPS 由于(大多数)标头在被代理时保留其原始值,因此在代理到 HTTPS 时,通常需要使用配置的上游地址覆盖`Host`标头,以便`Host`标头与 TLS ServerName 值匹配: ```caddy-d reverse_proxy https://example.com { header_up Host {upstream_hostport} } ``` 从 Caddy v2.11.0 开始,这是自动完成的,因此在代理到 HTTPS 时不再需要显式覆盖`Host`标头。如果您希望退出此行为,您可以将`Host`标头设置为其原始值(但这很少有意义): ```caddy-d reverse_proxy https://example.com { header_up Host {hostport} } ``` `X-Forwarded-Host`标头仍然传递[默认情况下](#defaults),因此如果上游需要知道原始`Host`标头值,则仍可以使用该标头。 这同样适用于在 caddy 中终止 TLS 并通过 HTTP 进行代理(无论是端口还是 unix 套接字)。事实上,当 caddy 是`reverse_proxy`的目标时,它本身必须接收正确的 Host。在 unix 套接字情况下,`upstream_hostport`将是套接字路径,并且必须显式设置主机。 ## 重写 默认情况下,Caddy 使用与传入请求相同的 HTTP 方法和 URI 执行上游请求,除非在到达`reverse_proxy`之前在中间件链中执行了重写。 在代理之前,请求被克隆;这确保了处理程序期间对请求所做的任何修改都不会泄漏到其他处理程序。这在需要在代理之后继续处理的情况下非常有用。 除了[标头操作](#headers)之外,请求的方法和 URI 在发送到上游之前还可以更改: - **method**更改克隆请求的 HTTP 方法。如果该方法更改为`GET`或`HEAD`,则传入请求的正文将不会由此处理程序发送到上游。如果您希望允许不同的处理程序使用请求正文,这非常有用。 - **rewrite**更改克隆请求的 URI(路径和查询)。这与[`rewrite` 指令](/docs/caddyfile/directives/rewrite)类似,只是它不会将重写保留到此处理程序的范围之外。 这些重写通常对于“预检查请求”之类的模式很有用,其中请求被发送到另一台服务器以帮助决定如何继续处理当前请求。 例如,请求可以发送到身份验证网关,以确定该请求是否来自经过身份验证的用户(例如,该请求具有会话 cookie)并应该继续,或者应该重定向到登录页面。对于这种模式,Caddy 提供了一个快捷指令[`forward_auth`](/docs/caddyfile/directives/forward_auth)来跳过大部分配置样板。 ## 交通 Caddy 的代理 **transport** 是可插拔的: - **transport**定义了如何与后端通信。默认为`http`。 ### `http`运输 ```caddy-d transport http { read_buffer write_buffer max_response_header proxy_protocol v1|v2 dial_timeout dial_fallback_delay response_header_timeout expect_continue_timeout resolvers tls tls_client_auth | tls_insecure_skip_verify tls_curves tls_timeout tls_trust_pool tls_server_name tls_renegotiation tls_except_ports keepalive [off|] keepalive_interval keepalive_idle_conns keepalive_idle_conns_per_host versions compression off max_conns_per_host network_proxy } ``` - **read_buffer**是读取缓冲区的大小(以字节为单位)。它接受[go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go)支持的所有格式。默认:`4KiB`。 - **write_buffer**是写入缓冲区的大小(以字节为单位)。它接受[go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go)支持的所有格式。默认:`4KiB`。 - **max_response_header**是从响应标头读取的最大字节数。它接受[go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go)支持的所有格式。默认:`10MiB`。 - **proxy_protocol**在与上游的连接上启用[PROXY 协议](https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt)(由 HAProxy 普及),并在前面添加真实的客户端 IP 数据。如果 Caddy 位于另一个代理后面,则最好与[`servers > trusted_proxies` 全局选项](/docs/caddyfile/options#trusted-proxies)配对。支持`v1`和`v2`版本。仅当您知道上游服务器能够解析 PROXY 协议时才应使用此选项。默认情况下,此功能处于禁用状态。 - **dial_timeout**是连接到上游套接字时等待的最大[持续时间](/docs/conventions#durations)。默认:`3s`。 - **dial_fallback_delay**是在生成 RFC 6555 快速回退连接之前等待的最大[持续时间](/docs/conventions#durations)。负值会禁用此功能。默认:`300ms`。 - **response_header_timeout**是等待从上游读取响应标头的最大[持续时间](/docs/conventions#durations)。默认:无超时。 - **expect_continue_timeout**是如果请求具有`Expect: 100-continue`标头,则在完全写入请求标头后等待上游第一个响应标头的最大[持续时间](/docs/conventions#durations)。默认:无超时。 - **read_timeout**是等待后端下次读取的最大[持续时间](/docs/conventions#durations)。默认:无超时。 - **write_timeout**是等待下一次写入后端的最大[持续时间](/docs/conventions#durations)。默认:无超时。 - **resolvers**是一个 DNS 解析器列表,用于覆盖系统解析器。 - **tls**在后端使用 HTTPS。如果您使用`https://`方案指定后端,或者配置了以下任何`tls_*`选项,则会自动启用此功能。 - **tls_client_auth**通过以下两种方式之一启用 TLS 客户端身份验证:(1) 通过指定 Caddy 应获取证书并保持更新的域名,或 (2) 通过指定要向后端提供 TLS 客户端身份验证的证书和密钥文件。 - **tls_insecure_skip_verify**关闭 TLS 握手验证,使连接不安全并且容易受到中间人攻击。 _请勿在生产中使用。_ - **tls_curves**是支持上游连接的椭圆曲线列表。 Caddy 的默认设置既现代又安全,因此您只需在有特定要求时才需要配置此设置。 - **tls_timeout**是等待 TLS 握手完成的最大[持续时间](/docs/conventions#durations)。默认:无超时。 - **tls_trust_pool**配置受信任的证书颁发机构的来源,类似于`tls`指令文档中描述的[`trust_pool` 子指令](/docs/caddyfile/directives/tls#trust_pool)。标准 Caddy 安装中可用的信任池源列表可在[此处](/docs/caddyfile/directives/tls#trust-pool-providers)中找到。 - **tls_server_name**设置验证 TLS 握手中收到的证书时使用的服务器名称。默认情况下,这将使用上游地址的主机部分。 仅当您的上游地址与上游可能使用的证书不匹配时,您才需要覆盖此设置。例如,如果上游地址是 IP 地址,那么您需要将其配置为上游服务器提供服务的主机名。 可以使用请求占位符,在这种情况下,每个请求都会使用 HTTP 传输配置的克隆,这可能会导致性能损失。 - **tls_renegotiation**设置 TLS 重新协商级别。 TLS 重新协商是在第一次握手之后执行后续握手的行为。该级别可能是以下之一: -`never`(默认)禁用重新协商。 -`once`允许远程服务器每次连接请求重新协商一次。 -`freely`允许远程服务器重复请求重新协商。 - **tls_except_ports**当启用 TLS 时,如果上游目标使用给定端口之一,则将为这些连接禁用 TLS。这在配置动态上游时可能很有用,其中一些上游期望 HTTP,而另一些则期望 HTTPS 请求。 - **keepalive**是`off`或[持续时间值](/docs/conventions#durations),指定保持连接打开的时间(超时)。默认:`2m`。 ⚠️ 如果 keepalive 持续时间超过上游服务器的 keepalive 超时,则对 HTTP/1.1 上游的请求可能会因“对等方重置连接”错误而失败。幂等请求将由 Go 的 HTTP 传输重试,但在其他情况下 Caddy 将以状态代码 502 进行响应。 - **keepalive_interval**是活跃探针之间的[持续时间](/docs/conventions#durations)。默认:`30s`。 - **keepalive_idle_conns**定义保持活动的最大连接数。默认:无限制。 - **keepalive_idle_conns_per_host**如果非零,则控制保持每个主机的最大空闲(保持活动)连接。默认:`32`。 - **versions**允许自定义支持哪些版本的 HTTP。 有效选项有:`1.1`、`2`、`h2c`、`3`。 默认:`1.1 2`,或者如果[上游的 scheme](#upstream-addresses)是`h2c://`,则默认为`h2c 2`。 `h2c`支持与上游的明文 HTTP/2 连接。这是一个非标准功能,不使用 Go 的默认 HTTP 传输,因此它排除了其他功能。 `3`启用与上游的 HTTP/3 连接。 ⚠️ 这是一项实验性功能,可能会发生变化。 - **compression**可用于通过将其设置为`off`来禁用对后端的压缩。 - **max_conns_per_host**可选择限制每个主机的连接总数,包括处于拨号、活动和空闲状态的连接。默认:无限制。 - **network_proxy**指定用于向上游服务器发出请求的网络代理模块的名称。如果未明确配置,Caddy 会按照[Go 标准库](https://pkg.go.dev/golang.org/x/net/http/httpproxy#FromEnvironment)尊重通过环境变量配置的代理,即`HTTP_PROXY`、`HTTPS_PROXY`和`NO_PROXY`。当为此参数提供值时,请求将按以下顺序流经反向代理:客户端(用户)→`reverse_proxy`→`network_proxy`→ 上游。内置模块有: -`none`,用于忽略`HTTP_PROXY`、`HTTPS_PROXY`、`NO_PROXY`的环境设置。 -`url `,用于指定覆盖环境配置的单个 URL。 ### `fastcgi`运输 ```caddy-d transport fastcgi { root split env resolve_root_symlink dial_timeout read_timeout write_timeout capture_stderr } ``` - **root**是网站的根目录。默认:`{http.vars.root}`或当前工作目录。 - **split**是分割路径以获取 URI 末尾的 PATH_INFO 的位置​​。 - **env**将额外的环境变量设置为给定值。可以为多个环境变量指定多次。 - **resolve_root_symlink**通过评估符号链接(如果存在)来将`root`目录解析为其实际值。 - **dial_timeout**是连接到上游套接字时等待的时间。接受[持续时间值](/docs/conventions#durations)。默认:`3s`。 - **read_timeout**是从 FastCGI 服务器读取时等待的时间。接受[持续时间值](/docs/conventions#durations)。默认:无超时。 - **write_timeout**是发送到FastCGI 服务器时等待的时间。接受[持续时间值](/docs/conventions#durations)。默认:无超时。 - **capture_stderr**可以捕获并记录上游 fastcgi 服务器在`stderr`上发送的任何消息。默认情况下,日志记录在`WARN`级别完成。如果响应具有`4xx`或`5xx`状态,则将使用`ERROR`级别。默认情况下,`stderr`被忽略。 ## 拦截响应 反向代理可以配置为拦截来自后端的响应。为了实现这一点,可以定义[响应匹配器](/docs/caddyfile/response-matchers)(类似于请求匹配器的语法),并且将调用第一个匹配的`handle_response`路由。 当调用响应处理程序时,来自后端的响应不会写入客户端,而是会执行配置的`handle_response`路由,并由该路由来写入响应。如果路由确实_不_写入响应,则请求处理将继续使用[排序在其后](/docs/caddyfile/directives#directive-order)此`reverse_proxy`的任何处理程序。 - **@name** 是[响应匹配器](/docs/caddyfile/response-matchers)的名称。只要每个响应匹配器都有唯一的名称,就可以定义多个匹配器。响应可以根据状态代码和响应标头的存在或值进行匹配。 - **replace_status**在与给定匹配器匹配时仅更改响应的状态代码。 - **handle_response**定义当与给定匹配器匹配时执行的路由(或者,如果省略匹配器,则所有响应)。将应用第一个匹配块。在`handle_response`块内,可以使用任何其他[directives](/docs/caddyfile/directives)。 此外,在`handle_response`内部,可以使用两个特殊的处理程序指令: - **copy_response**将从后端收到的响应正文复制回客户端。执行此操作时,可以选择允许更改响应的状态代码。该指令是[排序在 `respond` 之前](/docs/caddyfile/directives#directive-order)。 - **copy_response_headers**将响应标头从后端复制到客户端,可选地包含 _或_ 排除标头字段列表(不能同时指定`include`和`exclude`)。该指令是[排序在 `header` 之后](/docs/caddyfile/directives#directive-order)。 `handle_response`路由中将提供三个占位符: -`{rp.status_code}`后端响应的状态码。 -`{rp.status_text}`后端响应的状态文本。 -`{rp.header.*}`后端响应的标头。 虽然反向代理响应处理程序可以将从代理接收到的新响应复制回客户端,但它无法将该新响应传递给后续反向代理。每次使用`reverse_proxy`都会收到原始请求(或使用不同模块修改的)的正文。 ## 示例 将所有请求反向代理到本地后端: ```caddy example.com { reverse_proxy localhost:9005 } ``` [Load-balance](#load-balancing)所有请求[between 3 backends](#upstreams): ```caddy example.com { reverse_proxy node1:80 node2:80 node3:80 } ``` 相同,但仅限`/api`内的请求,并使用[`cookie` policy](#lb_policy)进行粘性: ```caddy example.com { reverse_proxy /api/* node1:80 node2:80 node3:80 { lb_policy cookie api_sticky } } ``` 使用[active health checks](#active-health-checks)来确定哪些后端是健康的,并在连接失败时启用[retries](#lb_try_duration),保留请求直到找到健康的后端: ```caddy example.com { reverse_proxy node1:80 node2:80 node3:80 { health_uri /healthz lb_try_duration 5s } } ``` 配置一些[传输选项](#transports): ```caddy example.com { reverse_proxy localhost:8080 { transport http { dial_timeout 2s response_header_timeout 30s } } } ``` 反向代理[HTTPS upstream](#https)(从 v2.11.0 开始,Caddy 会自动设置`Host`标头以匹配上游主机,因此不再需要手动执行此操作): ```caddy example.com { reverse_proxy https://example.com } ``` 反向代理到 HTTPS 上游,但[⚠️ disable TLS verification](#tls_insecure_skip_verify)。不建议这样做,因为它会禁用 HTTPS 提供的所有安全检查;如果可能的话,首选在专用网络中通过 HTTP 进行代理,因为它避免了错误的安全感: ```caddy example.com { reverse_proxy 10.0.0.1:443 { transport http { tls_insecure_skip_verify } } } ``` 相反,您可以通过显式[trusting the upstream's certificate](#tls_trust_pool)与上游建立信任,并(可选)设置 TLS-SNI 以匹配上游证书中的主机名: ```caddy example.com { reverse_proxy 10.0.0.1:443 { transport http { tls_trust_pool file /path/to/cert.pem tls_server_name app.example.com } } } ``` 代理前的[去除路径前缀](handle_path);但要注意[子文件夹问题 ](https://caddy.community/t/the-subfolder-problem-or-why-cant-i-reverse-proxy-my-app-into-a-subfolder/8575): ```caddy example.com { handle_path /prefix/* { reverse_proxy localhost:9000 } } ``` 在代理之前使用[`rewrite`](/docs/caddyfile/directives/rewrite)替换路径前缀: ```caddy example.com { handle_path /old-prefix/* { rewrite /new-prefix{path} reverse_proxy localhost:9000 } } ``` `X-Accel-Redirect`支持,即按请求提供静态文件,通过[intercepting the response](#intercepting-responses): ```caddy example.com { reverse_proxy localhost:8080 { @accel header X-Accel-Redirect * handle_response @accel { root /path/to/private/files rewrite {rp.header.X-Accel-Redirect} method GET file_server } } } ``` 来自上游的错误的自定义错误页面,由[intercepting error responses](#intercepting-responses)通过状态代码: ```caddy example.com { reverse_proxy localhost:8080 { @error status 500 503 handle_response @error { root /path/to/error/pages rewrite /{rp.status_code}.html file_server } } } ``` 从[`A`/`AAAA` record](#aaaaa)DNS 查询中获取后端[dynamically](#dynamic-upstreams): ```caddy example.com { reverse_proxy { dynamic a example.com 9000 } } ``` 从[`SRV` record](#srv)DNS 查询中获取后端[dynamically](#dynamic-upstreams): ```caddy example.com { reverse_proxy { dynamic srv _api._tcp.example.com } } ``` 在创建中间服务以进行更彻底的健康检查时,使用[active health checks](#active-health-checks)和`health_upstream`会很有帮助。 然后,`{http.reverse_proxy.active.target_upstream}`可以用作标头,向健康检查服务提供原始上游。 ```caddy example.com { reverse_proxy node1:80 node2:80 node3:80 { health_uri /health health_upstream 127.0.0.1:53336 health_headers { Full-Upstream {http.reverse_proxy.active.target_upstream} } } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/rewrite.md ================================================ --- title: rewrite (Caddyfile指令) --- # rewrite 对请求进行内部重写。重写会改变请求URI的部分或全部内容。请注意,URI不包括方案或授权(主机和端口),而且客户通常不发送片段。因此,这个指令主要用于路径和查询字符串的处理。 重写会改变请求URI的部分或全部内容。请注意,URI不包含scheme或authority(主机和端口),而且客户端通常不会发送fragment。因此,此指令主要用于**路径**和**查询**字符串操作。 `rewrite`指令表示接受该请求,但要进行修改。 它与同一块中的其他`rewrite`指令相互排斥,因此可以安全地定义原本会互相级联的重写,因为只会执行第一个匹配的重写。 在`rewrite`之前匹配请求的[请求匹配器](/docs/caddyfile/matchers),在`rewrite`之后可能不再匹配同一个请求。如果想让你的`rewrite`与其他处理器共享一条路由,请使用[`route`](route)或[`handle`](handle)指令。 ## 语法 ```caddy-d rewrite [] ``` - **<to>** 是要将请求重写到的URI。只有重写中指定的URI组成部分(路径或查询字符串)会被操作。URI路径是`?`之前的任意子串。如果省略`?`,则整个标记都被视为路径。 在v2.8.0之前,如果``参数以`/`开头,解析器可能会把它误认为[匹配器标记](/docs/caddyfile/matchers#syntax),因此必须指定通配符匹配器标记(`*`)。 ## 类似指令 还有一些指令也会执行重写,但表达不同的意图,或在不完全替换URI的情况下进行重写: - [`uri`](uri)操作URI(剥离前缀、后缀或替换子串)。 - [`try_files`](try_files)根据文件是否存在来重写请求。 ## 示例 将所有请求重写到`index.html`,保留任何查询字符串不变: ```caddy example.com { rewrite /index.html } ``` 为所有请求加上`/api`前缀,保留URI的其余部分,然后反向代理到应用: ```caddy api.example.com { rewrite /api{uri} reverse_proxy localhost:8080 } ``` 将API请求的查询字符串替换为`a=b`,路径保持不变: ```caddy example.com { rewrite ?a=b } ``` 仅对`/api/`的请求保留现有查询字符串,并添加一个键值对: ```caddy example.com { rewrite /api/* ?{query}&a=b } ``` 同时改变路径和查询字符串,保留原始查询字符串,并将原始路径作为`p`参数添加: ```caddy example.com { rewrite /index.php?{query}&p={path} } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/root.md ================================================ --- title: root (Caddyfile指令) --- # root 设置网站的根路径,由各种匹配器和访问文件系统的指令使用。如果不设置,默认的网站根目录是当前工作目录。 具体来说,这个指令设置了`{http.vars.root}`占位符。它与同一区块中的其他`root'指令是相互排斥的,所以用相交的匹配器定义多个根是安全的:它们不会级联和相互覆盖。 该指令不会自动启用静态文件的服务,所以它通常与[`file_server`指令](/docs/caddyfile/directives/file_server)或[`php_fastcgi`指令](/docs/caddyfile/directives/php_fastcgi)一起使用。 ## 语法 ```caddy-d root [] ``` - **<path>** 是用于网站根目录的路径。 注意``参数如果以`/`开头,可能会被解析器混淆为[匹配器标记](/docs/caddyfile/matchers#syntax)。为了消除混淆,可以指定一个通配符匹配器标记(`*`)。见下面的例子。 ## 示例 为所有请求设置网站根目录为`/home/user/public_html`。 (注意,这里需要一个[通配符匹配器](/docs/caddyfile/matchers#wildcard-matchers),因为第一个参数与[路径匹配器](/docs/caddyfile/matchers#path-matchers)不明确。) ```caddy-d root * /home/user/public_html ``` 为所有请求设置网站根目录为`public_html`(相对于当前工作目录)。 (这里不需要匹配器标记,因为我们的网站根目录是一个相对路径,所以它不是以正斜杠开始的,因此不会产生歧义。) ```caddy-d root public_html ``` 只为`/foo/*`中的请求改变网站根。 ```caddy-d root /foo/* /home/user/public_html/foo ``` root "指令通常与[`file_server`](/docs/caddyfile/directives/file_server)配对,为静态文件提供服务,或者与[`php_fastcgi`](/docs/caddyfile/directives/php_fastcgi)配对,为PHP网站提供服务。 ```caddy-d root * /home/user/public_html file_server ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/route.md ================================================ --- title: route (Caddyfile指令) --- # route 将一组指令按字面意思作为一个单元进行评估。 路由块中包含的指令不会在内部被重新排序。只有HTTP处理指令(将处理程序或中间件添加到链中的指令)可以在路由块中使用。 这个指令是一个特例,它的子指令也是常规指令。 ## 语法 ```caddy-d route [] { } ``` - **** 是一个指令或指令块的列表,每行一个,就像在路由块外面一样;只是这些指令不会被重新排序。只有HTTP处理指令可以被使用。 ## 实用性 `路由`指令在某些高级用例或边缘用例中很有帮助,可以对HTTP处理程序链的部分进行绝对控制。 因为HTTP中间件的评估顺序很重要,Caddyfile通常会在解析后重新排列指令,以使Caddyfile更容易使用;你不必担心你输入东西的顺序。 虽然内置的顺序与大多数网站兼容,但有时你需要对顺序进行手动控制,可以是整个网站,也可以只是其中的一部分。这就是 "路由 "指令的用处。 为了说明这一点,考虑两个终止处理程序的情况。`redir`和`file_server`。这两个处理程序都向客户端写入响应,并且不调用链中的下一个处理程序,所以对于某个请求,只有其中一个会被执行。哪个先执行?通常情况下,`redir`在`file_server`之前执行,因为通常你只想在特定情况下发出重定向,在一般情况下提供文件。 然而,在有些情况下,第二个指令(`redir`)比第二个指令(`file_server`)有更具体的匹配器。换句话说,你想在一般情况下重定向,而只服务于一个特定的文件。 所以你可以尝试这样的Caddyfile(但这不会像预期的那样工作!)。 ```caddy example.com file_server /specific.html redir https://anothersite.com{uri} ``` 问题是,在内部,`redir`排在`file_server`之前,但在这种情况下,`redir`的匹配器是`file_server`的匹配器的超集(`*`是`/specific.html`的超集)。 幸运的是,解决方案很简单:只要把这两个指令包在一个`路由`块中。 ```caddy example.com route { file_server /specific.html redir https://anothersite.com{uri} } ``` 而现在`file_server`将在`redir`之前被链入,因为这个顺序是按字面意思来的。 ## 类似的指令 还有其他一些指令可以包装HTTP处理程序指令,但每个指令都有其用途,取决于你想表达的行为。 - [`handle`](handle)像`route`那样包装其他指令,但有两个区别。 - 1)handle块是相互排斥的 - 2)通常handle中的指令是[重新排序的](/docs/caddyfile/directives#directive-order)。 - [`handle_path`](handle_path)的作用与`handle`相同,但它在运行其处理程序之前从请求中剥离了一个前缀。 - [`handle_errors`](handle_errors)和`handle`一样,但只有当Caddy在处理请求时遇到错误才会调用。 ## 示例 在代理所有API请求到后端之前,从请求路径中去除`/api`前缀。 ```caddy-d route /api/* { uri strip_prefix /api reverse_proxy localhost:9000 } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/templates.md ================================================ --- title: templates (Caddyfile指令) --- # templates 将响应体作为[template](/docs/modules/http.handlers.templates)文件执行。模板提供了制作简单动态页面的功能基元。功能包括HTTP子请求、HTML文件包含、Markdown渲染、JSON解析、基本数据结构、随机性、时间等。 ## 语法 ```caddy-d templates [] { mime between root extensions { { ... } } } ``` - **mime** 是模板中间件会处理的MIME类型;任何不具备合格`Content-Type`的响应都不会被作为模板求值。 默认:`text/html text/plain`。 - **between** 是模板动作的开始和结束定界符。如果它们与文档其他部分冲突,你可以更改它们。 默认:`{{printf "{{ }}"}}`。 - **root** 是使用访问文件系统的函数时的站点根目录。 默认为[`root`](root)指令设置的站点根目录;如果未设置,则为当前工作目录。 - **extensions** 允许你注册由`http.handlers.templates.functions.*`命名空间中的模块提供的自定义模板函数。 块内的每个子指令都对应一个模块名称。这些模块可以向模板函数映射添加自定义函数,通常用于实现可复用组件。此功能主要面向插件。 内置模板函数的文档可在[templates模块](/docs/modules/http.handlers.templates#docs)中找到。 ## 示例 关于使用模板提供markdown服务的完整站点示例,请查看[这个网站](https://github.com/caddyserver/website)的源代码!具体来说,请查看[`Caddyfile`](https://github.com/caddyserver/website/blob/master/Caddyfile)和[`src/docs/index.html`](https://github.com/caddyserver/website/blob/master/src/docs/index.html)。 为静态站点启用模板: ```caddy example.com { root /srv templates file_server } ``` 要使用模板提供简单的静态响应,请确保设置`Content-Type`: ```caddy example.com { header Content-Type text/plain templates respond `Current year is: {{printf "{{"}}now | date "2006"{{printf "}}"}}` } ``` 使用模板扩展(插件): ```caddy example.com { root /srv templates { extensions { # 需要 caddy-hitcounter 插件: # https://github.com/mholt/caddy-hitcounter hitCounter { style bright_green pad_digits 6 } } } file_server } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/tls.md ================================================ --- title: tls (Caddyfile指令) --- # tls 为网站配置TLS。 **Caddy的默认TLS设置是安全的。只有在你有充分的理由并了解其影响的情况下才能改变这些设置。**这个指令最常见的用途是指定一个ACME账户的电子邮件地址、改变ACME CA端点,或者提供你自己的证书。 兼容性说明:由于其作为安全协议的敏感性质,在新的次要版本或补丁版本中可能会对TLS默认值进行有意的调整。旧的或坏的TLS版本、密码、功能等可能在任何时候被删除。如果你的部署对变化非常敏感,你应该明确指定那些必须保持不变的值,并对升级保持警惕。在几乎所有情况下,我们建议使用默认设置。 ## 语法 ```caddy-d tls [internal|force_automate|] | [ ] { protocols [] ciphers curves alpn load ca ca_root key_type ed25519|p256|p384|rsa2048|rsa4096 dns [] propagation_timeout propagation_delay dns_ttl dns_challenge_override_domain resolvers eab on_demand reuse_private_keys client_auth { mode [request|require|verify_if_given|require_and_verify] trust_pool verifier } issuer [] get_certificate [] insecure_secrets_log renewal_window_ratio force_automate } ``` - **internal**意味着使用Caddy内部的、本地信任的CA来为这个网站制作证书。要进一步配置[`internal`](#internal)发行者,请使用[`issuer`](#issuer)子指令。 - **force_automate**强制Caddy为站点自动管理证书,即使已经有其他托管证书适用。 - **<email>**是用于管理网站证书的ACME账户电子邮件地址。你也可以用[`email`全局选项](/docs/caddyfile/options#email)一次性为所有站点配置。 - **<cert_file>**和**<key_file>**是证书和私钥PEM文件的路径。只指定一个是无效的。 - **protocols** 指定最小和最大协议版本。除非你知道自己在做什么,否则不要修改。通常不需要配置它,因为Caddy会始终使用现代默认值。 默认最小值:`tls1.2`,默认最大值:`tls1.3`。 - **ciphers** 指定按偏好降序排列的密码套件名称列表。除非你知道自己在做什么,否则不要修改。请注意,TLS 1.3的密码套件不可自定义;并且并非所有TLS 1.2密码都默认启用。支持的名称如下(按Go标准库偏好顺序): - `TLS_AES_128_GCM_SHA256` - `TLS_CHACHA20_POLY1305_SHA256` - `TLS_AES_256_GCM_SHA384` - `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` - `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` - `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` - `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` - `TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256` - `TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256` - `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA` - `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA` - `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA` - `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA` - `TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA` - **curves** 指定要支持的EC组列表。建议不要修改默认值。支持的值是: - `x25519mlkem768`(PQC) - `x25519` - `secp256r1` - `secp384r1` - `secp521r1` - **alpn** 是在TLS握手的[ALPN扩展](https://developer.mozilla.org/en-US/docs/Glossary/ALPN)中公布的值列表。 - **load** 指定一个文件夹列表,从该文件夹中加载证书+密钥捆绑的PEM文件。 - **ca** 改变ACME CA端点。这最常用于测试时设置[Let's Encrypt暂存端点](https://letsencrypt.org/docs/staging-environment/),或内部ACME服务器。(要为整个Caddyfile改变这个值,请使用`acme_ca`[全局选项](/docs/caddyfile/options)代替。) - **ca_root** 指定一个PEM文件,其中包含ACME CA端点的可信根证书,如果不在系统信任存储中。 - **key_type** 是生成CSR时要使用的密钥类型。只有在你有特定要求时才设置这个。 - **dns** 使用指定的提供者插件启用[DNS挑战](/docs/automatic-https#dns-challenge),该插件必须来自[`caddy-dns` ](https://github.com/caddy-dns)仓库之一。每个提供者插件可能在名称后有自己的语法,详情请参考各自文档。维护每个DNS提供商的支持是一项社区工作。[了解如何在我们的维基上为你的提供商启用DNS挑战。](https://caddy.community/t/how-to-use-dns-provider-modules-in-caddy-2/8148) - **propagation_timeout** 是一个[持续时间值](/docs/conventions#durations),设置使用DNS挑战时等待DNS TXT记录出现的最长时间。设置为`-1`可禁用传播检查。默认2分钟。 - **propagation_delay** 是一个[持续时间值](/docs/conventions#durations),设置使用DNS挑战时,在开始DNS TXT记录传播检查前等待多长时间。默认`0`(不等待)。 - **dns_ttl** 是一个[持续时间值](/docs/conventions#durations),设置DNS挑战使用的`TXT`记录TTL。很少需要设置。 - **dns_challenge_override_domain** 覆盖用于DNS挑战的域名。这用于将挑战委托给另一个域名。 如果你的主域名DNS提供商没有可用的[DNS插件](https://github.com/caddy-dns),你可能会用到它。你可以在主域名添加`_acme-challenge`子域的`CNAME`记录,指向一个你 _确实_ 有插件的辅助域名。此选项 _不_ 要求插件提供特殊支持。 当ACME签发者尝试为主域名完成DNS挑战时,会跟随`CNAME`到辅助域名查找`TXT`记录。 **注意:**这里的值应使用CNAME记录中的完整规范名称;不会自动添加`_acme-challenge`子域。 - **resolvers** 自定义执行DNS挑战时使用的DNS解析器;这些解析器优先于系统解析器或任何默认解析器。如果在这里设置,解析器将传播到所有配置的证书签发者。 这通常是一个IP地址列表。例如,使用[Google Public DNS](https://developers.google.com/speed/public-dns): ```caddy-d resolvers 8.8.8.8 8.8.4.4 ``` - **eab** 为这个站点配置ACME外部账户绑定(EAB),使用你的CA提供的密钥ID和MAC密钥。 - **on_demand** 为网站块地址中给出的主机名启用[按需TLS](/docs/automatic-https#on-demand-tls)。**安全警告:**在生产中这样做是不安全的,除非你也配置了[`on_demand_tls`全局选项](/docs/caddyfile/options#on-demand-tls)以减少滥用。 - **reuse_private_keys** 启用证书续期时复用私钥。默认情况下,每张新证书都会创建新密钥,以缓解固定密钥并降低密钥泄露影响范围。密钥固定违背行业最佳实践。除非你有明确理由,否则不建议使用此选项;它将来可能被移除。 - **client_auth** 启用并配置TLS客户端认证: - **mode** 是验证客户端的模式。允许的值是: | 模式 | 说明 | |--------------------|------------------------------------------------------------------------------------------| | request | 要求客户提供证书,但即使没有证书也允许;不对其进行验证。| | require | 要求客户出示证书,但不进行验证。| | verify_if_given | 要求客户提供证书,即使没有也允许,但如果有则验证。| | require_and_verify | 要求客户出示经过验证的有效证书。| 默认值:如果提供`trust_pool`模块则为`require_and_verify`;否则为`require`。 - **trust_pool** 配置证书颁发机构(CA)的来源,用于提供验证客户端证书的证书池。 提供受信证书池的证书颁发机构及其配置取决于所配置的信任池模块。Caddy中可用的标准模块[列在下方](#trust-pool-providers)。完整模块列表(包括第三方模块)见[`trust_pool`JSON文档](/docs/json/apps/http/servers/tls_connection_policies/client_authentication/#trust_pool)。 - **verifier** 启用自定义客户端证书验证器模块。这些模块可以执行自定义客户端认证检查,例如确保证书未被吊销。 - **issuer** 配置一个自定义的证书颁发者,或一个获得证书的来源。使用哪一个签发者以及这一段后面的选项取决于可用的签发者模块(标准签发者见下文;插件可以添加其他的)。其他一些子指令,如`ca`和`dns`实际上是配置`acme`签发者的快捷方式(这个子指令是后来添加的),所以指定这个指令和其他一些指令是混乱的,因此禁止使用。这个子指令可以被多次指定,以配置多个冗余的签发者;如果一个签发失败,将尝试下一个签发者。 - **get_certificate** 可以在握手时从一个[管理模块](#certificate-managers)获取证书。 - **insecure_secrets_log** 启用将TLS密钥记录到文件。这也称为`SSLKEYLOGFILE`,使用NSS密钥日志格式,可由Wireshark或其他工具解析。⚠️**安全警告:**这是不安全的,因为它允许其他程序或工具解密TLS连接,从而完全破坏安全性。不过,此能力可用于调试和排查问题。 - **renewal_window_ratio** 是0到1之间的比率,用于决定证书剩余多少生命周期时Caddy开始尝试续期。例如,如果证书生命周期为90天,而此比率为`0.3333`(默认值),则Caddy会在证书剩余30天或更少时持续尝试续期。也可以通过[`renewal_window_ratio`全局选项](/docs/caddyfile/options#renewal_window_ratio)设置。 你通常很少需要修改它,但如果CA签发时间很长,稍晚续期可能有用。 请记住,这只是一个建议,因为ACME签发者可能实现[ARI扩展](https://datatracker.ietf.org/doc/rfc9773/)。ARI会指定ACME客户端(这里是Caddy)应尝试续期的窗口,而该窗口可能与此比率不一致。 - **force_automate**与在行内指定相同(见上文)。 ### 信任池提供者 以下是可以在`trust_pool`子指令中使用的标准信任池提供者: #### inline `inline`模块会直接解析Caddyfile中列出的base64 DER编码受信根证书。`trust_der`指令可以重复多次。 ```caddy-d trust_pool inline { trust_der } ``` - **trust_der** 是用于验证客户端证书的base64 DER编码CA证书。 #### file `file`模块从磁盘上的PEM文件读取受信根证书。`pem_file`指令可以在同一行接受多个文件路径,也可以重复多次。 ```caddy-d ... file [...] { pem_file ... } ``` - **pem_file** 是用于验证客户端证书的PEM CA证书文件路径。 #### pki_root `pki_root`模块从[PKI应用](/docs/caddyfile/options#pki-options)中定义的证书颁发机构获取并信任 _根_ 证书。`authority`指令可以同时接受多个机构,也可以重复多次。 ```caddy-d ... pki_root [...] { authority ... } ``` - **authority** 是PKI应用中配置的证书颁发机构名称。 #### pki_intermediate `pki_intermediate`模块从[PKI应用](/docs/caddyfile/options#pki-options)中定义的证书颁发机构获取并信任 _中间_ 证书。`authority`指令可以同时接受多个机构,也可以重复多次。 ```caddy-d ... pki_intermediate [...] { authority ... } ``` - **authority** 是PKI应用中配置的证书颁发机构名称。 #### storage `storage`模块从Caddy[存储](/docs/caddyfile/options#storage)中提取受信证书根。`keys`指令可以同时接受多个存储键,也可以重复多次。 ```caddy-d ... storage [...] { storage keys ... } ``` - **storage** 是要使用的可选存储模块。如果未指定,将使用默认存储模块。如果指定,只能指定一次。 - **keys** 是存放证书PEM文件的存储键列表。该指令可以在同一行接受多个值,也可以重复多次。 #### http `http`模块从HTTP端点获取受信证书。`endpoints`指令可以同时接受多个端点,也可以重复多次。 ```caddy-d ... http [] { endpoints tls } ``` - **endpoints** 是获取证书的HTTP端点列表。该指令可以在同一行接受多个值,也可以重复多次。 - **tls** 是连接HTTP端点时要使用的可选TLS配置。片段解析方式见[下一节](#tls-1)。 ##### TLS ```caddy-d ... { ca insecure_skip_verify handshake_timeout server_name renegotiation } ``` - **ca** 是用于定义信任池提供者的可选指令。配置行为与[`trust_pool`](#trust_pool)相同。如果指定,只能指定一次。 - **insecure_skip_verify** 关闭TLS握手验证,使连接不安全并容易受到中间人攻击。_不要在生产环境中使用。_验证会针对系统信任的证书颁发机构,或由[`ca`](#ca)指令决定的机构执行。 - **handshake_timeout** 是等待TLS握手完成的最大[持续时间](/docs/conventions#durations)。默认:无超时。 - **server_name** 设置验证TLS握手中收到的证书时使用的服务器名称。默认使用上游地址的主机部分。 - **renegotiation** 设置TLS重新协商级别。TLS重新协商是指在第一次握手之后执行后续握手。级别可以是: - `never`(默认)禁用重新协商。 - `once`允许远程服务器每个连接请求一次重新协商。 - `freely`允许远程服务器反复请求重新协商。 ### 验证器 如果配置了`trust_pool`,客户端证书验证器模块会在验证证书由受信证书颁发机构签发之后执行。标准Caddy当前提供的验证器是`leaf`。 #### Leaf `leaf`验证器检查客户端证书是否属于一组定义好的允许证书。证书集合通过[加载器](https://caddyserver.com/docs/modules/tls.client_auth.verifier.leaf#leaf_certs_loaders)模块加载。 ##### 加载器 标准Caddy发行版捆绑4个加载器,其中3个可在Caddyfile中使用。 ###### File `file`加载器从指定PEM文件中加载证书集合。 ```caddy-d ... file ``` ###### Folder `folder`加载器会递归遍历指定目录,查找要作为已接受客户端证书加载的PEM文件。 ```caddy-d ... folder ``` ###### PEM `pem`加载器接受以内联方式写在Caddyfile中的PEM格式证书。 ```caddy-d ... pem ``` ### 发行人 以下签发者随`tls`指令标准提供: #### acme 使用ACME协议获取证书。请注意,`acme`是默认签发者(使用Let's Encrypt),所以通常不需要显式配置。 ```caddy-d ... acme [] { dir test_dir email timeout disable_http_challenge disable_tlsalpn_challenge alt_http_port alt_tlsalpn_port eab trusted_roots dns [ []] propagation_timeout propagation_delay dns_ttl dns_challenge_override_domain resolvers preferred_chains [smallest] { root_common_name any_common_name } profile } ``` - **dir** 是ACME CA目录的URL。 默认值:`https://acme-v02.api.letsencrypt.org/directory` - **test_dir** 是一个可选的后备目录,在重试挑战时使用;如果所有挑战失败,在重试时将使用该端点;如果CA有暂存端点且你想避免其生产端点的速率限制,则非常有用。 默认值:`https://acme-staging-v02.api.letsencrypt.org/directory` - **email** 是ACME帐户的联系电子邮件地址。 - **timeout** 是一个[持续时间值](/docs/conventions#durations),设置ACME操作超时前要等待多长时间。 - **disable_http_challenge** 将禁用HTTP挑战。 - **disable_tlsalpn_challenge** 将禁用TLS-ALPN挑战。 - **alt_http_port** 是提供HTTP挑战的备用端口;它必须发生在80端口,所以你必须将数据包转发到这个备用端口。 - **alt_tlsalpn_port** 是一个备用端口,用于提供TLS-ALPN挑战;它必须发生在443端口,所以你必须将数据包转发到这个备用端口。 - **eab** 指定外部账户绑定,某些ACME CA可能需要它。 - **trusted_roots** 是一个或多个根证书(作为PEM文件名),当连接到ACME CA服务器时要信任。 - **dns** 配置DNS挑战。除非[`dns`全局选项](/docs/caddyfile/options#dns)指定了全局适用的DNS提供者模块,否则必须在这里配置提供者。 - **propagation_timeout** 是一个[持续时间值](/docs/conventions#durations),设置使用DNS挑战时等待DNS TXT记录出现的最长时间。设置为`-1`可禁用传播检查。默认2分钟。 - **propagation_delay** 是一个[持续时间值](/docs/conventions#durations),设置使用DNS挑战时,在开始DNS TXT记录传播检查前等待多长时间。默认0(不等待)。 - **dns_ttl** 是一个[持续时间值](/docs/conventions#durations),设置DNS挑战使用的`TXT`记录TTL。很少需要设置。 - **dns_challenge_override_domain** 覆盖用于DNS挑战的域名。这用于将挑战委托给另一个域名。 如果你的主域名DNS提供商没有可用的[DNS插件](https://github.com/caddy-dns),你可能会用到它。你可以在主域名添加`_acme-challenge`子域的`CNAME`记录,指向一个你 _确实_ 有插件的辅助域名。此选项 _不_ 要求插件提供特殊支持。 当ACME签发者尝试为主域名完成DNS挑战时,会跟随`CNAME`到辅助域名查找`TXT`记录。 **注意:**这里的值应使用CNAME记录中的完整规范名称;不会自动添加`_acme-challenge`子域。 - **resolvers** 自定义执行DNS挑战时使用的DNS解析器;这些解析器优先于系统解析器或任何默认解析器。如果在这里设置,解析器将传播到所有配置的证书签发者。 这通常是一个IP地址列表。例如,使用[Google Public DNS](https://developers.google.com/speed/public-dns): ```caddy-d resolvers 8.8.8.8 8.8.4.4 ``` - **preferred_chains** 指定Caddy应该优先使用哪些证书链;如果你的CA提供多个证书链,这会很有用。使用以下选项之一: - **smallest** 将告诉Caddy倾向于使用字节数最少的链。 - **root_common_name** 是一个或多个通用名称的列表;Caddy将选择第一个根部与指定通用名称中至少一个相匹配的链。 - **any_common_name** 是一个或多个通用名称的列表;Caddy将选择第一个具有与指定通用名称中至少一个相匹配的发行者的链。 - **profile**是订购证书时要应用的[ACME配置文件](https://datatracker.ietf.org/doc/draft-aaron-acme-profiles/)名称。如果指定了它,所有配置的(无论隐式还是显式)CA都必须支持该配置文件。可用配置文件请参考你的CA文档;某些CA可能不支持配置文件。实验性:ACME配置文件规范仍处于草案状态,因此此功能可能发生变化或被移除。 #### zerossl 使用[ZeroSSL专有证书签发API](https://zerossl.com/documentation/api/)获取证书。需要API密钥,并且根据你的套餐可能需要付费。请注意,这与[ZeroSSL的ACME端点](https://zerossl.com/documentation/acme/)不同。若要使用ZeroSSL的ACME端点,请使用上面描述的`acme`签发者,并配置ZeroSSL的ACME目录端点。 ```caddy-d ... zerossl { validity_days alt_http_port dns ... propagation_delay propagation_timeout resolvers dns_ttl } ``` - **validity_days** 定义证书生命周期。只接受某些值;详情见[ZeroSSL文档](https://zerossl.com/documentation/api/create-certificate/)。 - **alt_http_port** 是完成ZeroSSL HTTP验证时要使用的端口,如果不是80端口。 - **dns** 使用命名DNS提供者及给定配置启用CNAME验证方法,以便自动创建记录。DNS提供者插件必须从[`caddy-dns` ](https://github.com/caddy-dns)仓库安装。每个提供者插件可能在名称后有自己的语法,详情请参考各自文档。维护每个DNS提供商的支持是一项社区工作。 - **propagation_delay** 是在检查CNAME记录传播前等待的时间。 - **propagation_timeout** 是放弃前等待CNAME记录传播的时间。 - **resolvers** 定义检查CNAME记录传播时使用的自定义DNS解析器。 - **dns_ttl** 配置作为验证过程一部分创建的CNAME记录TTL。 #### internal 从一个内部证书颁发机构获取证书。 ```caddy-d ... internal { ca lifetime sign_with_root } ``` - **ca** 是要使用的内部CA名称。默认值:`local`。参见[PKI应用全局选项](/docs/caddyfile/options#pki-options)来配置`local`CA,或创建其他CA。 默认情况下,根CA证书生命周期为`3600d`(10年),中间证书生命周期为`7d`(7天)。 Caddy会尝试将根CA证书安装到系统信任存储,但当Caddy以非特权用户运行或在Docker容器中运行时可能失败。在这种情况下,需要手动安装根CA证书,可以使用[`caddy trust`](/docs/command-line#caddy-trust)命令,或[从容器中复制出来](/docs/running#usage)。 - **lifetime** 是一个[持续时间值](/docs/conventions#durations),设置内部签发的叶子证书有效期。默认值:`12h`。除非绝对必要,否则不建议修改。它必须短于中间证书生命周期。 - **sign_with_root** 强制由根证书而不是中间证书签发。不建议这样做,只应在设备/客户端不能正确验证证书链时使用(非常罕见)。 ### 证书管理器 证书管理器模块与签发者模块不同:使用管理器模块意味着外部工具或服务负责保持证书续期,而签发者模块意味着Caddy自身管理证书。(签发者模块以证书签名请求(CSR)作为输入,而证书管理器模块以TLS ClientHello作为输入。) 以下管理器模块随`tls`指令标准提供: #### tailscale 从本地运行的[Tailscale](https://tailscale.com)实例获取证书。[你的Tailscale账户必须启用HTTPS](https://tailscale.com/kb/1153/enabling-https/)(或你的开源[Headscale服务器](https://github.com/juanfont/headscale));并且Caddy进程必须以root身份运行,或者你必须配置`tailscaled`授予Caddy用户[获取证书的权限](https://github.com/caddyserver/caddy/pull/4541#issuecomment-1021568348)。 _**注意:这通常是不必要的!** Caddy会自动对所有`*.ts.net`域名使用Tailscale,不需要任何额外配置。_ ```caddy-d get_certificate tailscale # often unnecessary! ``` #### http 通过发出HTTP(S)请求来获取证书。响应必须有`200`状态码,正文必须包含PEM链,包括完整证书(含中间证书)以及私钥。 ```caddy-d get_certificate http ``` - **url** 是要请求的完整URL。出于性能原因,强烈建议它是本地端点。该URL会附加以下查询字符串参数: - `server_name`:SNI值 - `signature_schemes`:签名算法十六进制ID的逗号分隔列表 - `cipher_suites`:密码套件十六进制ID的逗号分隔列表 - `local_ip`:客户端发起请求时连接到的IP地址 ## 示例 使用自定义证书和密钥。证书应具有与站点地址匹配的[SAN](https://en.wikipedia.org/wiki/Subject_Alternative_Name): ```caddy example.com { tls cert.pem key.pem } ``` 为当前网站块上的所有主机使用本地信任的证书,而不是通过ACME / Let's Encrypt的公共证书(在开发环境中很有用): ```caddy example.com { tls internal } ``` 使用本地信任的证书,但使用[按需](/docs/automatic-https#on-demand-tls)管理而不是后台管理。这允许你将任意域名指向Caddy实例,并自动为其配置证书。如果你的Caddy实例可公开访问,**不应**使用它,因为攻击者可能利用它耗尽服务器资源: ```caddy https:// { tls internal { on_demand } } ``` 对内部CA使用自定义选项(不能使用`tls internal`的快捷方式): ```caddy example.com { tls { issuer internal { ca foo } } } ``` 为你的ACME账户指定一个电子邮件地址(但如果所有网站只使用一个电子邮件,我们建议用`email`[全局选项](/docs/caddyfile/options)代替): ```caddy example.com { tls your@email.com } ``` 为Cloudflare上管理的域名启用DNS挑战,在环境变量中使用账户凭证。这会解锁通配符证书支持,而通配符证书需要DNS验证: ```caddy *.example.com { tls { dns cloudflare {env.CLOUDFLARE_API_TOKEN} } } ``` 通过HTTP获取证书链,而不是让Caddy管理它。请注意,[`get_certificate`](#certificate-managers)意味着启用[`on_demand`](#on_demand),即使用模块获取证书而不是触发ACME签发: ```caddy https:// { tls { get_certificate http http://localhost:9007/certs } } ``` 启用TLS客户端认证,并要求客户端提供有效证书,通过[`trust_pool`](#trust_pool)的`file`提供者对所有提供的CA进行验证: ```caddy example.com { tls { client_auth { trust_pool file ../caddy.ca.cer ../root.ca.cer } } } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/tracing.md ================================================ --- title: tracing (Caddyfile指令) --- # tracing 它提供了与OpenTelemetry追踪设施的整合。 当启用时,它将传播一个现有的跟踪上下文或初始化一个新的。 它基于[github.com/open-telemetry/opentelemetry-go](https://github.com/open-telemetry/opentelemetry-go)。 它使用[gRPC](https://github.com/grpc/)作为输出协议,使用W3C[tracecontext](https://www.w3.org/TR/trace-context/)和[baggage](https://www.w3.org/TR/baggage/)作为传播器。 ## 语法 ```caddy-d tracing { [span ] } ``` - **<span_name>** - 是一个span的名称。请参阅 span 命名[指南](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/trace/api.md)。 ## 配置 ### 环境变量 可以使用[OpenTelemetry]定义的环境变量对其进行配置。 OpenTelemetry环境变量规范](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/sdk-environment-variables.md)。 关于导出器的配置细节,请 见[spec](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.7.0/specification/protocol/exporter.md)。 比如说: ```bash export OTEL_EXPORTER_OTLP_HEADERS="myAuthHeader=myToken,anotherHeader=value" export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://my-otlp-endpoint:55680 ``` ## 示例 下面是一个**Caddyfile**的例子: ``` handle /myHandler { tracing { span my-span } reverse_proxy 127.0.0.1:8081 } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/try_files.md ================================================ --- title: try_files (Caddyfile指令) --- # try_files 将请求URI路径重写为站点根目录中存在的第一个列出的文件。如果没有文件匹配,则不执行重写。 ## 语法 ```caddy-d try_files { policy first_exist|first_exist_fallback|smallest_size|largest_size|most_recently_modified } ``` - **** 是要尝试的文件列表。URI路径会被重写为第一个存在的文件。 要匹配目录,请在路径后追加正斜杠`/`。所有文件路径都相对于站点[root](root),并且会展开[glob模式](https://pkg.go.dev/path/filepath#Match)。 每个参数也可以包含查询字符串;如果匹配到该特定文件,查询字符串也会被更改。 如果`try_policy`是`first_exist`(默认值),则列表中的最后一项可以是以`=`为前缀的数字(例如`=404`),作为后备,它会发出带有该代码的错误;该错误可以用[`handle_errors`](handle_errors)捕获和处理。 - **policy** 是从文件列表中选择文件的策略。 默认:`first_exist` ## 扩展形式 `try_files`指令基本上是下面配置的快捷方式: ```caddy-d @try_files file rewrite @try_files {file_match.relative} ``` 请注意,此指令不接受匹配器标记。如果需要更复杂的匹配逻辑,请以上面的扩展形式为基础。 更多细节请参见[`file`匹配器](/docs/caddyfile/matchers#file)。 ## 示例 如果请求没有匹配任何静态文件,则重写到你的PHP index/router入口: ```caddy-d try_files {path} /index.php ``` 同样如此,但会把原始路径加入查询字符串(某些旧版PHP应用需要): ```caddy-d try_files {path} /index.php?{query}&p={path} ``` 同样如此,但也匹配目录: ```caddy-d try_files {path} {path}/ /index.php?{query}&p={path} ``` 如果文件或目录存在,则尝试重写到它;否则发出404错误(可用[`handle_errors`](handle_errors)捕获和处理): ```caddy-d try_files {path} {path}/ =404 ``` 选择最近部署的静态文件版本(例如请求`index.html`时提供`index.be331df.html`): ```caddy-d try_files {file.base}.*.{file.ext} { policy most_recently_modified } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/uri.md ================================================ --- title: uri (Caddyfile指令) --- # uri 操作请求的URI。它可以剥离路径前缀/后缀,或替换整个URI中的子串。 此指令不同于[`rewrite`](rewrite):`uri`是对URI做差异化修改,而不是像`rewrite`那样将其重置为完全不同的内容。虽然`rewrite`会作为内部重定向被特殊处理,但`uri`只是另一个中间件。 ## 语法 支持多种不同的操作: ```caddy-d uri [] strip_prefix uri [] strip_suffix uri [] replace [] uri [] path_regexp uri [] query [-|+] [] uri [] query { [] [] ... } ``` 第一个(非匹配器)参数指定操作: - **strip_prefix** 从路径中剥离前缀。 - **strip_suffix** 从路径中剥离后缀。 - **replace** 在整个URI上执行子串替换。 - **<target>** 是前缀、后缀或搜索字符串/正则表达式。如果是前缀,可以省略前导正斜杠,因为路径总是以正斜杠开头。 - **<replacement>** 是替换字符串。支持使用`$name`或`${name}`语法的捕获组,或使用数字索引,例如`$1`。详见[Go文档](https://golang.org/pkg/regexp/#Regexp.Expand)。如果替换值是`""`,则从值中删除匹配文本。 - **<limit>** 是最大替换次数的可选限制。 - **path_regexp** 在URI的路径部分执行正则表达式替换。 - **<target>** 是前缀、后缀或搜索字符串/正则表达式。如果是前缀,可以省略前导正斜杠,因为路径总是以正斜杠开头。 - **<replacement>** 是替换字符串。支持使用`$name`或`${name}`语法的捕获组,或使用数字索引,例如`$1`。详见[Go文档](https://golang.org/pkg/regexp/#Regexp.Expand)。如果替换值是`""`,则从值中删除匹配文本。 - **query** 对URI查询执行操作,其模式取决于参数名前缀或参数数量。可以使用块一次指定多个操作,这些操作会分组并按此顺序执行:重命名 🡒 设置 🡒 追加 🡒 替换 🡒 删除。 - 没有前缀时,会在查询中用给定值设置该参数。 例如,`uri query foo bar`会将`foo`参数的值设置为`bar`。 - 使用`-`前缀会从查询中移除该参数。 例如,`uri query -foo`会删除`foo`参数。 - 使用`+`前缀会向查询追加一个带有给定值的参数。这_不会_覆盖同名已有参数(省略`+`则会覆盖)。 例如,`uri query +foo bar`会向查询追加`foo=bar`。 - 参数中以`>`作为中缀时,会把该参数重命名为`>`后的值。 例如,`uri query foo>bar`会将`foo`参数重命名为`bar`。 - 使用三个参数时,会执行查询值正则表达式替换,其中第一个参数是查询参数名,第二个是搜索值,第三个是替换值。第一个参数(参数名)可以是`*`,表示对所有查询参数执行替换。 支持使用`$name`或`${name}`语法的捕获组,或使用数字索引,例如`$1`。详见[Go文档](https://golang.org/pkg/regexp/#Regexp.Expand)。如果替换值是`""`,则从值中删除匹配文本。 例如,`uri query foo ^(ba)r $1z`会替换`foo`参数的值;当该值以`bar`开头时,结果会变为`baz`。 URI变更发生在URI的规范化或未转义形式上。不过,转义序列可以用于前缀或后缀模式,以便只匹配请求路径中这些位置上的字面转义。例如,`uri strip_prefix /a/b`会把`/a/b/c`和`/a%2Fb/c`都重写为`/c`;而`uri strip_prefix /a%2Fb`会把`/a%2Fb/c`重写为`/c`,但不会匹配`/a/b/c`。 URI路径会在修改前清理目录遍历点。此外,多个斜杠(例如`//`)会被合并,除非``也包含多个斜杠。 ## 类似指令 其他一些指令也可以操作请求URI。 - [`rewrite`](rewrite)将整个路径和查询改为新值,而不是部分改变该值。 - [`handle_path`](handle_path)与[`handle`](handle)相同,但会在运行其处理器之前从请求中剥离一个前缀。在许多情况下,可以用它替代`uri strip_prefix`,以减少一行配置。 ## 示例 从所有请求路径开头剥离`/api`: ```caddy-d uri strip_prefix /api ``` 从所有请求路径末尾剥离`.php`: ```caddy-d uri strip_suffix .php ``` 在任何请求URI中将 "/docs/" 替换为 "/v1/docs/": ```caddy-d uri replace /docs/ /v1/docs/ ``` 将请求路径中所有重复斜杠(但不包括请求查询)折叠为单个斜杠: ```caddy-d uri path_regexp /{2,} / ``` 将`foo`查询参数的值设置为`bar`: ```caddy-d uri query foo bar ``` 从查询中移除`foo`参数: ```caddy-d uri query -foo ``` 将`foo`查询参数重命名为`bar`: ```caddy-d uri query foo>bar ``` 向查询追加`bar`参数: ```caddy-d uri query +foo bar ``` 将`foo`查询参数中以`bar`开头的值替换为`baz`: ```caddy-d uri query foo ^(ba)r $1z ``` 一次执行多个查询操作: ```caddy-d uri query { +foo bar -baz qux test renamethis>renamed } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives/vars.md ================================================ --- title: vars (Caddyfile指令) --- # vars 将一个或多个变量设置为一个特定的值,以便在以后的请求处理链中使用。 访问变量的主要方式是使用占位符,其形式为`{vars.variable_name}`,或者使用[`vars`](/docs/caddyfile/matchers#vars)和[`vars_regexp`](/docs/caddyfile/matchers#vars_regexp) 请求匹配器。 ## 语法 ```caddy-d vars [] [ ] { ... } ``` - **<name>**是要设置的变量名称。 - **<value>**是该变量的值。 如果可能的话,该值将进行类型转换;`true`和`false`将被转换为布尔类型,数字值将被相应地转换为整数或浮点数。为了避免这种转换,你可以用[引号](/docs/caddyfile/concepts#tokens-and-quotes)来包裹输出,它们将保持为字符串。 ## 示例 设置一个单一的变量,该值是基于请求路径的条件,然后用该值进行响应: ```caddy-d vars /foo* isFoo "yep" vars isFoo "nope" respond {vars.isFoo} ``` 要设置多个变量,每个变量都转换为适当的标量类型: ```caddy-d vars { # boolean abc true # integer def 1 # float ghi 2.3 # string jkl "example" } ``` ================================================ FILE: src/docs/markdown/caddyfile/directives.md ================================================ --- title: Caddyfile指令 --- # Caddyfile指令 指令是出现在站点[块](/docs/caddyfile/concepts#blocks)中的功能关键字。有时,它们会打开自己的块,其中可以包含 _子指令_;但除非另有说明,指令**不能**在其他指令中使用。例如,不能在`file_server`块中使用`basic_auth`,因为`file_server`不知道如何进行身份验证。不过,你 _可以_ 在`handle`和`route`这样的特殊指令块中使用一些指令,因为它们专门用于组合HTTP处理器指令。 - [语法](#语法) - [指令顺序](#指令顺序) - [排序算法](#排序算法) 以下指令是Caddy的标准配置,可在HTTP Caddyfile中使用:
指令 | 说明 ----------|------------ **[abort](/docs/caddyfile/directives/abort)** | 中止HTTP请求 **[acme_server](/docs/caddyfile/directives/acme_server)** | 嵌入式ACME服务器 **[basic_auth](/docs/caddyfile/directives/basic_auth)** | 强制执行HTTP基本身份验证 **[bind](/docs/caddyfile/directives/bind)** | 自定义服务器的套接字地址 **[encode](/docs/caddyfile/directives/encode)** | 编码(通常是压缩)响应 **[error](/docs/caddyfile/directives/error)** | 触发错误 **[file_server](/docs/caddyfile/directives/file_server)** | 从磁盘提供文件 **[forward_auth](/docs/caddyfile/directives/forward_auth)** | 将身份验证委托给外部服务 **[fs](/docs/caddyfile/directives/fs)** | 设置文件I/O使用的文件系统 **[handle](/docs/caddyfile/directives/handle)** | 一组互斥的指令 **[handle_errors](/docs/caddyfile/directives/handle_errors)** | 定义路由的错误处理器 **[handle_path](/docs/caddyfile/directives/handle_path)** | 像处理器,但去掉路径前缀 **[header](/docs/caddyfile/directives/header)** | 设置或删除响应标头 **[import](/docs/caddyfile/directives/import)** | 包括片段或文件 **[intercept](/docs/caddyfile/directives/intercept)** | 拦截其他处理器写出的响应 **[invoke](/docs/caddyfile/directives/invoke)** | 调用命名路由 **[log](/docs/caddyfile/directives/log)** | 启用访问/请求日志记录 **[log_append](/docs/caddyfile/directives/log_append)** | 向访问日志追加字段 **[log_skip](/docs/caddyfile/directives/log_skip)** | 对匹配的请求跳过访问日志 **[log_name](/docs/caddyfile/directives/log_name)** | 覆盖要写入的日志器名称 **[map](/docs/caddyfile/directives/map)** | 将输入值映射到一个或多个输出 **[method](/docs/caddyfile/directives/method)** | 在内部更改HTTP方法 **[metrics](/docs/caddyfile/directives/metrics)** | 配置Prometheus指标展示端点 **[php_fastcgi](/docs/caddyfile/directives/php_fastcgi)** | 通过FastCGI服务PHP站点 **[push](/docs/caddyfile/directives/push)** | 使用HTTP/2服务器推送将内容推送到客户端 **[redir](/docs/caddyfile/directives/redir)** | 向客户端发出HTTP重定向 **[request_body](/docs/caddyfile/directives/request_body)** | 操作请求包 **[request_header](/docs/caddyfile/directives/request_header)** | 操作请求头 **[respond](/docs/caddyfile/directives/respond)** | 向客户端写入硬编码响应 **[reverse_proxy](/docs/caddyfile/directives/reverse_proxy)** | 强大且可扩展的反向代理 **[rewrite](/docs/caddyfile/directives/rewrite)** | 在内部重写请求 **[root](/docs/caddyfile/directives/root)** | 设置站点根目录的路径 **[route](/docs/caddyfile/directives/route)** | 将一组指令从字面上视为单个单元 **[templates](/docs/caddyfile/directives/templates)** | 对响应执行模板 **[tls](/docs/caddyfile/directives/tls)** | 自定义TLS设置 **[tracing](/docs/caddyfile/directives/tracing)** | 集成OpenTelemetry的tracing **[try_files](/docs/caddyfile/directives/try_files)** | 取决于文件的存在的重写 **[uri](/docs/caddyfile/directives/uri)** | 操作URL **[vars](/docs/caddyfile/directives/vars)** | 设置任意变量
## 语法 每个指令的语法如下所示: ```caddy-d directive [] { subdirective [] } ``` `<>`表示要由实际值替换的标记。 `[]`表示可选参数。 `...`表示延续,即一个或多个参数,或者多行。 除非另有说明,否则子指令始终是可选的,即使它们没有出现在`[]`. ### 匹配器 大多数——但不是全部——指令接受[匹配器标记](/docs/caddyfile/matchers#syntax),它可以让你过滤请求。匹配器标记通常是可选的。如果你在指令的语法中看到这一点: ```caddy-d [] ``` 然后该指令接受一个匹配器令牌,让你过滤该指令适用于哪些请求。 由于匹配器标记的工作方式相同,因此不会在每一页上都描述匹配器令牌的各种可能性,以减少重复。如果想了解详情,请统一参考[匹配器文档](/docs/caddyfile/matchers)。 ## 指令顺序 许多指令操纵HTTP处理程序链。这些指令的默认顺序已经被硬编码到Caddy中,评估其顺序是很重要的事情: ```caddy-d tracing map vars fs root log_append log_skip log_name header copy_response_headers # 仅在 reverse_proxy 的 handle_response 块中可用 request_body redir # 传入请求操作 method rewrite uri try_files # 中间件处理器;其中一些会包装响应 basic_auth forward_auth request_header encode push intercept templates # 特殊路由和分派指令 invoke handle handle_path route # 通常会响应请求的处理器 abort error copy_response # 仅在 reverse_proxy 的 handle_response 块中可用 respond metrics reverse_proxy php_fastcgi file_server acme_server ``` 你可以使用[`order`全局选项](/docs/caddyfile/options)或[`route`指令](/docs/caddyfile/directives/route)覆盖/自定义该排序。 ## 排序算法 为了便于使用,Caddyfile适配器会按照以下规则对指令排序: - 不同名称的指令会根据它们在[默认顺序](#指令顺序)中的位置排序。默认顺序可以通过[`order`全局选项](/docs/caddyfile/options)覆盖。插件提供的指令 _没有_ 顺序,因此应使用[`order`](/docs/caddyfile/options)全局选项或[`route`](/docs/caddyfile/directives/route)指令来设置顺序。 - 同名指令会根据它们的[匹配器](/docs/caddyfile/matchers#syntax)排序。 - 最高优先级是只带有单个[路径匹配器](/docs/caddyfile/matchers#path-matchers)的指令。 路径匹配器会按具体程度排序,从最具体到最不具体。 一般来说,这是按路径匹配器长度排序。有一个例外:如果路径以`*`结尾,且两个匹配器的路径除此之外相同,则没有`*`的匹配器会被认为更具体并排在前面。 例如: - `/foobar`比`/foo`更具体 - `/foo`比`/foo*`更具体 - `/foo/*`比`/foo*`更具体 - 带有任何其他匹配器的指令排在后面,按它们在Caddyfile中出现的顺序排序。 这包括带有多个值的路径匹配器,以及[命名匹配器](/docs/caddyfile/matchers#named-matchers)。 - 没有匹配器的指令(即匹配所有请求)排在最后。 - [`vars`](/docs/caddyfile/directives/vars)指令按匹配器排序的顺序相反,因为它会设置可能相互覆盖的值,所以最具体的匹配器应最后评估。 - [`route`](/docs/caddyfile/directives/route)指令的内容会忽略上述所有规则,并保留指令在其中出现的顺序。 ================================================ FILE: src/docs/markdown/caddyfile/matchers.md ================================================ --- title: 请求匹配器 --- # 请求匹配器 **请求匹配器** 可用于按特定标准过滤(或分类)请求。 ### 菜单 - [语法](#syntax) - [例子](#examples) - [通配符匹配器](#wildcard-matchers) - [路径匹配器](#path-matchers) - [命名匹配器](#named-matchers) - [标准匹配器](#standard-matchers) - [expression](#expression) - [file](#file) - [header](#header) - [header_regexp](#header-regexp) - [host](#host) - [method](#method) - [not](#not) - [path](#path) - [path_regexp](#path-regexp) - [protocol](#protocol) - [query](#query) - [remote_ip](#remote-ip)

语法

在Caddyfile中,紧跟在指令后面的**匹配器标记**可以限制该指令的范围。匹配器标记可以是以下形式之一: 1. **`*`** 匹配所有请求(通配符;默认)。 2. **`/path`** 以正斜杠开头以匹配请求路径。 3. **`@name`** 指定一个命名匹配器。 匹配器标记[通常是可选](/docs/caddyfile/directives#matchers)的。如果省略匹配器标记,则它与通配符匹配器(`*`)相同。

例子

该指令适用于[所有](#wildcard-matchers)HTTP 请求: ```caddy-d reverse_proxy localhost:9000 ``` 这是一样的: ```caddy-d reverse_proxy * localhost:9000 ``` 但此指令仅适用于以`/api/`开头的[路径](#path-matchers): ```caddy-d reverse_proxy /api/* localhost:9000 ``` 要匹配路径以外的任何内容,请定义一个[命名匹配器](#named-matchers)并使用`@name`引用它: ```caddy-d @postfoo { method POST path /foo/* } reverse_proxy @postfoo localhost:9000 ```

通配符匹配器

通配符(或“catch-all”)匹配器`*`匹配所有请求,并且仅在需要匹配器标记时才需要。例如,如果你要给出指令的第一个参数也恰好是路径,那么它看起来就像一个路径匹配器!因此,你可以使用通配符匹配器来消除歧义,例如: ```caddy-d root * /home/www/mysite ``` 否则,这个匹配器不经常使用。尽可能省略它很方便;只是一个偏好问题。

路径匹配器

因为按路径匹配非常普遍,所以可以内联单个路径匹配器,如下所示: ```caddy-d redir /old.html /new.html ``` 路径匹配器标记必须以正斜杠`/`开头。 **[路径匹配](/docs/caddyfile/matchers#path) 默认为精确匹配;**你必须附加`*`以进行快速前缀匹配。请注意,`/foo*`将匹配`/foo`、`/foo/`和`/foobar`;你可能实际是想要`/foo/*`。

命名匹配器

所有不是路径或通配符匹配器的匹配器都必须命名为匹配器。这是一个在任何特定指令之外定义的匹配器,并且可以重用。 定义具有唯一名称的匹配器为你提供了更大的灵活性,允许你将[任何可用的匹配器](#standard-matchers)组合成一个集合: ```caddy-d @name { ... } ``` 或者,如果集合中只有一个匹配器: ```caddy-d @name ... ``` 然后你可以像这样使用匹配器:`@name` 例如: ```caddy-d @websockets { header Connection *Upgrade* header Upgrade websocket } reverse_proxy @websockets localhost:6001 ``` 这仅代理具有名为“Connection”的标头字段(包含“Upgrade”)和另一个名为“Upgrade”且值为“websocket”的字段的请求。 如果匹配器集仅包含一个匹配器,则单行语法也适用: ```caddy-d @post method POST reverse_proxy @post localhost:6001 ``` 与指令一样,命名匹配器定义必须放在使用它们的站点块内。 一个命名的匹配器定义构成一个_匹配器集_。集合中的匹配器是“与”的关系,也就是说,必须所有的都被匹配。例如,如果集合中有`aheader`和`path`匹配器,则两者都必须匹配。 相同类型的国歌匹配器可以被(AND/OR)组合起来(例如,同一个集合中的多个`path`匹配器),如下面的相应部分所述。

标准匹配器

完整的匹配器文档可以[在每个匹配器模块的文档中](/docs/json/apps/http/servers/routes/match/)找到。 ### expression ⚠️ _此模块仍处于试验阶段,因此可能会发生重大变化。_ ```caddy-d expression ``` 通过任何[CEL(通用表达式语言)](https://github.com/google/cel-spec) 表达式返回`true`或者`false`。 作为一种特殊情况,可以在这些CEL表达式中使用Caddy[占位符](/docs/conventions#placeholders) (或[Caddyfile缩写](/docs/caddyfile/concepts#placeholders)),因为它们在被CEL环境解释之前经过预处理并转换为常规CEL函数调用。 #### 示例: 匹配以`P`开头的请求方法,例如`PUT`或`POST`。 ```caddy-d expression {method}.startsWith("P") ``` 处理返回`404`错误状态代码的请求,且与[`handle_errors`指令](/docs/caddyfile/directives/handle_errors)结合起来处理。 ```caddy-d expression {http.error.status_code} == 404 ``` --- ### 文件 ```caddy-d file { root try_files try_policy first_exist|smallest_size|largest_size|most_recent_modified split_path } ``` 通过文件进行匹配。 - `root`定义在其中查找文件的目录。默认是当前工作目录,或者`root`[变量](/docs/modules/http.handlers.vars) (`{http.vars.root}`)对应的位置 (可以通过[`root`指令](/docs/caddyfile/directives/root)设置)。 - `try_files`检查其列表中与重试策略(try_policy)匹配的文件。如果`try_policy`是`first_exist`,那么列表中的最后一项可能是一个以`=`(比如`=404`)开头的数字,作为后备,将触发以这个数字作为错误码的回调; 该错误也可以使用[`handle_errors`](/docs/caddyfile/directives/handle_errors)捕获和处理错误。 - `try_policy`指定如何选择文件。默认为`first_exist`. - `first_exist`检查文件是否存在。选择存在的第一个文件。 - `smallest_size`选择大小最小的文件。 - `largest_size`选择最大的文件。 - `most_recent_modified`选择最近修改的文件。 - `split_path`将导致路径在每个要尝试的文件路径中找到的列表中的第一个分隔符处拆分。对于每个拆分值,拆分的左侧(包括分隔符本身)将是尝试的文件路径。例如,`/remote.php/dav/`使用`.php`作为分隔符,将尝试文件`/remote.php`。每个分隔符必须出现在 URI 路径组件的末尾,才能用作拆分分隔符。这是一个小众设置,主要用于为 PHP 站点提供服务。 因为`try_files`策略`first_exist`如此普遍,所以有一条捷径: ```caddy-d file ``` 一个空`file` 匹配器(后面没有列出任何文件),将通过URI从相对于[站点根目录](/docs/caddyfile/directives/root)的位置逐字比对查找文件是否存在。 由于基于磁盘上文件的存在进行重写非常普遍,因此还有一个[`try_files`指令](/docs/caddyfile/directives/try_files),它是`file`匹配器和[`rewrite`处理器](/docs/caddyfile/directives/rewrite)的快捷方式。 匹配后,将可以使用两个新的占位符: - `{http.matchers.file.relative}`文件的根相对路径。这在重写请求时通常很有用。 - `{http.matchers.file.absolute}`匹配文件的绝对路径。 #### 示例: 匹配路径是存在文件的请求。 ```caddy-d file ``` 匹配请求,其中后跟的路径`.html`是存在的文件,或者如果不存在,则路径是存在的文件。 ```caddy-d file { try_files {path}.html {path} } ``` 与上面相同,除了使用单行快捷方式,如果找不到文件,则回退到发出404错误。 ```caddy-d file {path}.html {path} =404 ``` --- ### header ```caddy-d header [] ``` 通过请求头字段进行匹配。 - ``是要检查的 HTTP 标头字段的名称。 - 如果以`!`为前缀,则该字段必须不存在才能匹配 (省略`value`参数). - ``是字段必须匹配的值。 - 如果前缀是`*`,则执行快速后缀匹配。 - 如果后缀为`*`,则执行快速前缀匹配。 - 如果用`*`括起来,它将执行快速子字符串匹配。 - 否则,它是快速精确匹配。 统一集合的不同header字段是“和”的关系。每个字段的多个值之间是“或”的关系。 #### 示例: 匹配请求`Connection`标头字段包含`Upgrade`的请求: ```caddy-d header Connection *Upgrade* ``` 匹配`Foo`标头字段包含`bar`或者`baz`的请求: ```caddy-d @foo { header Foo bar header Foo baz } ``` 匹配根本没有`Foo`标头字段的请求: ```caddy-d @not_foo { header !Foo } ``` --- ### header_regexp ```caddy-d header_regexp [] ``` 和`header`类似,但是支持正则表达式。 捕获组可以通过[占位符](/docs/caddyfile/concepts#placeholders)访问,如`{re.name.capture_group}`,其中`name`是正则表达式的名称(可选,单推荐),且`capture_group`是表达式中捕获组的名称或编号。捕获组`0`是完整的正则表达式匹配,`1`是第一个捕获组,`2`是第二个捕获组,依此类推。 使用的正则表达式语言是GO语言中内置的`RE2`。具体请查阅[RE2语法参考](https://github.com/google/re2/wiki/Syntax)和[Go正则语法概述](https://pkg.go.dev/regexp/syntax)。 每个标头字段仅支持一个正则表达式。多个不同的字段是“与”的关系。 #### 示例: 将 Cookie 标头包含`login_`后跟十六进制字符串的请求,包含了一个可以通过`{re.login.1}`访问的捕获组。 ```caddy-d header_regexp login Cookie login_([a-f0-9]+) ``` --- ### host ```caddy-d host ``` 通过请求的`Host`标头字段匹配请求。在 Caddyfile 中使用它并不常见,因为大多数站点块已经在站点地址中明确主机。此匹配器主要用于未定义特定主机名的站点块。 多个`host`匹配器之间是“或”的关系。 #### 示例: ```caddy-d host sub.example.com ``` --- ### method ```caddy-d method ``` 通过HTTP请求的方法(动词)匹配请求。动词应该是大写的,比如`POST`。可以匹配一种或多种方法。 多个`method`匹配之间是“或”的关系。 #### 示例: 匹配请求方法为`GET`的请求。 ```caddy-d method GET ``` 匹配请求方法为`PUT`或者`DELETE`的请求。 ```caddy-d method PUT DELETE ``` --- ### not ```caddy-d not ``` 或者,要同时否定多个匹配器,请打开一个块: ```caddy-d not { } ``` 包含起来的匹配器的结果将被否定。 #### 示例: 匹配路径不以`/css/`或`/js/`开头的请求。 ```caddy-d not path /css/* /js/* ``` 匹配两者关系为`NEIGHER`的请求: - 路径的前缀是`/api/`的,或非(NOR) - 请求方法为`POST` 也就是说,必须__没有任何符合这些条件__(none of these)的请求才能被匹配: ```caddy-d not path /api/* not method POST ``` 匹配两者关系为`WITHOUT BOTH`的请求: - 路径的前缀是`/api/`,和(AND) - 请求方法为`POST` 也就是说,必须__都不或者任何一个不__(neither or either)才能匹配: ```caddy-d not { path /api/* method POST } ``` --- ### path ```caddy-d path ``` 通过请求路径进行匹配,表示请求URI的路径部分。路径匹配是精确的,但也可以使用通配符`*`: - 放在最后,进行前缀匹配 (`/prefix/*`) - 放在开始,进行后缀匹配 (`*.suffix`) - 在两边,进行子字符串匹配 (`*/contains/*`) - 在中间,进行球状匹配 (`/accounts/*/info`) 请求路径在匹配前经过URL解码、小写(不区分大小写)和清理(折叠双斜杠和目录遍历点)。例如`/foo*`也会匹配`/FOO`、`//foo`和`/%2F/foo`。 多个`path`匹配之间是“或”的关系。 --- ### path_regexp ```caddy-d path_regexp [] ``` 和`path`类似,但是支持正则表达式。捕获组可以通过[占位符](/docs/caddyfile/concepts#placeholders)访问,如`{re.name.capture_group}`,其中`name`是正则表达式的名称(可选,单推荐),且`capture_group`是表达式中捕获组的名称或编号。捕获组`0`是完整的正则表达式匹配,`1`是第一个捕获组,`2`是第二个捕获组,依此类推。 请求路径在匹配前经过URL解码、小写(不区分大小写)和清理(折叠双斜杠和目录遍历点)。例如`/foo*`也会匹配`/FOO`、`//foo`和`/%2F/foo`。 使用的正则表达式语言是GO语言中内置的`RE2`。具体请查阅[RE2语法参考](https://github.com/google/re2/wiki/Syntax)和[Go正则语法概述](https://pkg.go.dev/regexp/syntax)。 每个命名匹配器只能有一个`path_regexp`匹配器。 #### 示例: 匹配路径以6个字符的十六进制字符串结尾的请求,后跟`.css`或`.js`作为文件扩展名,捕获组可以分别用`{re.static.1}`和`{re.static.2}`访问包含在`( )`中间的每个部分。 ```caddy-d path_regexp static \.([a-f0-9]{6})\.(css|js)$ ``` --- ### protocol ```caddy-d protocol http|https|grpc ``` 通过请求协议进行匹配。 每个命名匹配器只能有一个`protocol`。 --- ### query ```caddy-d query =... ``` 通过查询字符串参数匹配请求。应该是`key=value`的键值对。键完全匹配,区分大小写。值可以包含占位符。值完全匹配,但也支持`*`匹配任何值。 每个命名匹配器可以有多个`query`匹配器,具有相同键的对之间是“或”的关系。 #### 示例: 匹配带有`sort`查询参数且值为`asc`的请求。 ```caddy-d query sort=asc ``` --- ### remote_ip ```caddy-d remote_ip [forwarded] ``` 通过远程(客户端)IP地址。接受确切的`IP`或`CIDR` 范围。如果第一个参数是`forwarded`,则`X-Forwarded-For`请求标头中的第一个IP(如果存在)将被首选作为参考IP,而不是默认的直接对等点(immediate peer)的IP。 多个`remote_ip`匹配器是“或”的关系。 #### 示例: 匹配来自私有 IPv4 地址的请求。 ```caddy-d remote_ip 192.168.0.0/16 172.16.0.0/12 10.0.0.0/8 ``` ================================================ FILE: src/docs/markdown/caddyfile/options.md ================================================ --- title: 全局选项 --- # 全局选项 Caddyfile可以让你指定全局应用的选项。一些选项充当默认值,而其他选项自定义Caddyfile[适配器](/docs/config-adapters)的行为。 Caddyfile的最顶部可以是**全局选项块**。这是一个没有键的块: ```caddy { ... } ``` 最多只能有一个,而且必须是Caddyfile的第一个块。 可能的选项是: ```caddy { # General Options debug http_port https_port order first|last|[before|after ] storage { } storage_clean_interval admin off| { origins enforce_origin } log [name] { output ... format ... level include exclude } grace_period # TLS Options auto_https off|disable_redirects|ignore_loaded_certs email default_sni local_certs skip_install_trust acme_ca acme_ca_root acme_eab acme_dns ... on_demand_tls { ask interval burst } key_type ed25519|p256|p384|rsa2048|rsa4096 cert_issuer ... ocsp_stapling off preferred_chains [smallest] { root_common_name any_common_name } # Server Options servers [] { listener_wrappers { } timeouts { read_body read_header write idle } max_header_size protocol { allow_h2c experimental_http3 strict_sni_host } } } ``` ## 常规选项 ##### `debug` 启用调试模式,将默认日至器的日志级别设置为`DEBUG`。这将展示在排除故障时展示更多有用的细节(且在生产模式下将非常详细)。请你在[社区](https://caddy.community)寻求帮助之前先启用此功能。 ##### `http_port` 服务器用于HTTP的端口。仅限内部使用; 不会更改客户端的HTTP端口。默认:`80` ##### `https_port` 服务器用于HTTPS的端口。仅限内部使用; 不会更改客户端的HTTPS端口。默认:`443` ##### `order` 对HTTP处理指令进行排序。由于HTTP处理器按照顺序链执行,因此处理程序必须以正确的顺序执行。标准指令有[预定义顺序](/docs/caddyfile/directives#directive-order),但如果使用第三方 HTTP 处理程序模块,则需要通过使用此选项或将指令放在 例如,要使用[`replace-response`插件](https://github.com/caddyserver/replace-response),而且你希望它在`encode`之后才被执行,以便它可以在响应编码之前进行。(因为响应流向上处理程序链,而不是向下): ```caddy-d order replace after encode ``` ##### `storage` 配置Caddy的存储机制。默认值为 [`file_system`](/docs/json/storage/file_system/)。还有许多其他可用的存储模块作为插件提供。 例如,要更改文件系统的存储位置: ```caddy-d storage file_system /path/to/custom/location ``` 在跨多个Caddy实例同步Caddy的存储时,通常需要自定义存储模块,以确保它们都使用相同的证书和密钥。有关更多详细信息,请参阅[有关存储的自动HTTPS]部分(/docs/automatic-https#storage)。 ##### `storage_clean_interval` 多久扫描一次存储单元以查找旧资源或过期资源并将其移除。这些扫描会在存储模块上进行大量读取(和列表操作),因此对于大型部署需要设置成更长的时间间隔。该值是一个持续时间值。默认值:24小时。 该过程首次启动时,总是会清理存储。然后,如果上次清理在该间隔的一半时间内完成,则在上次清理开始后的这段时间内将开始新的清洁(否则将跳过下次启动)。 ##### `admin` 自定义[管理API端点](/docs/api)。如果为`off`,则管理端点将被禁用。如果禁用,则在不停止和启动服务器的情况下将无法更改配置。 - **origins** 配置允许连接到端点的远程/源列表。 - **enforce_origin** 启用Origin标头的强制执行。(这与通常强制执行起源不同,后者总是执行。) ##### `log` 自定义命名日志器。可以传递名称以指示要为其自定义行为的特定日志器。如果未指定名称,则修改默认日志器的行为。可以多次指定此选项以配置不同的日志器。你可以在[日志记录文档](/docs/logging)中阅读有关默认日志器和其他日志记录行为的更多信息。 - **output** 配置写入日志的位置。有关更多信息,请参阅[log指令](/docs/caddyfile/directives/log#output-modules)文档,该文档具有相同的结构。 - **format** 描述如何编码或格式化日志。有关更多信息,请参阅[log指令](/docs/caddyfile/directives/log#format-modules)文档,该文档具有相同的结构。 - **level** 是要记录的最低入口级别。默认:`INFO` - **include** 标识此日志配置中包含的记录器。有关更多信息,请参阅[JSON文档](/docs/json/logging/logs/include/)。 - **exclude** 标识从该日志配置中排除的记录器。有关更多信息,请参阅[JSON文档](/docs/json/logging/logs/exclude/)。 ##### `grace_period` 定义在配置重新加载期间关闭HTTP服务器的宽限期。如果客户端没有在宽限期内完成他们的请求,服务器将被强制终止以允许重新加载完成并释放资源。默认情况下,没有设置宽限期。 ## TLS选项 ##### `auto_https` 配置自动HTTPS。它可以完全禁用(`off`),仅禁用HTTP到HTTPS的重定向(`disable_redirects`),或者配置为自动生成证书,即使是出现在手动加载的证书上的名称(`ignore_loaded_certs`)。有关更多详细信息,请参阅[自动HTTPS](/docs/automatic-https) 页面。 ##### `email` 你的电子邮件地址。主要在使用 CA 创建 ACME 帐户时使用,强烈建议在证书出现问题时使用。 ##### `default_sni` 当客户端在其`ClientHello`中不使用SNI时,设置默认TLS服务器名称(TLS ServerName)。 ##### `local_certs` 导致所有证书默认在内部颁发,而不是通过(公共)ACME CA,例如Let's Encrypt。这在开发环境中很有用。 ##### `skip_install_trust` 跳过将本地CA的根安装到系统信任库以及Java和Mozilla Firefox信任库的尝试。 ##### `acme_ca` 指定ACME CA目录的URL。强烈建议将此设置为Let's Encrypt的[暂存端点](https://letsencrypt.org/docs/staging-environment/)以进行测试或开发。默认值:ZeroSSL和Let's Encrypt 的生产端点。 ##### `acme_ca_root` 指定一个PEM文件,其中包含ACME CA端点的受信任根证书(如果不在系统信任库中)。 ##### `acme_eab` 指定用于所有 ACME 交易的外部帐户绑定(External Account Binding)。 ##### `acme_dns` 配置用于所有ACME事务的ACME DNS质询提供者。在该标识后设置的提供者名字指定了提供者,就像在[`tls`指令的`acme`问题](/docs/caddyfile/directives/tls#acme)中指定的一样。 ##### `on_demand_tls` 在启用的地方配置[按需TLS](/docs/automatic-https#on-demand-tls),但不启用它(要启用它,请使用[按需`tls`子指令](/docs/caddyfile/directives/tls#syntax))。强烈建议只在生产环境中使用,以防止滥用。 - **ask** 将导致Caddy使用包含域名值的查询字符串`?domain=`向给定URL发出HTTP请求。如果端点返回 200 OK,Caddy 将被授权获取该名称的证书。 - **interval**和**burst** 允许在 ``间隔进行``次证书操作。 ##### `key_type` 指定为 TLS 证书生成的密钥类型;仅当你有特定需要对其进行自定义时才更改此设置。可能的值为:`ed25519`、`p256`、`p384`、`rsa2048`、`rsa4096`。 ##### `cert_issuer` 定义TLS证书的颁发者(或来源)。发行者名称后面的标记设置发行者,就像在[tls指令](/docs/caddyfile/directives/tls#issuer)中指定的一样。如果你希望配置多个发行者来尝试,可以重复。它们将按照定义的顺序进行尝试。 ##### `ocsp_stapling` 可以设置`off`为禁用OCSP装订。在由于防火墙而无法访问响应者的环境中很有用。 ##### `preferred_chains` 如果你的CA提供多个证书链,你可以使用此选项来指定Caddy应该首选哪个链。设置以下选项之一: - **smallest** 将告诉Caddy首选字节数最少的链。 - **root_common_name** 是一个或多个常用名称的列表;Caddy将选择第一个具有与至少一个指定的通用名称匹配的根的链。 - **any_common_name** 是一个或多个常用名称的列表;Caddy将选择第一个具有与至少一个指定的通用名称匹配的发行者的链。 请注意,如果没有任何[覆盖发行人级别的配置](/docs/caddyfile/directives/tls#acme),`preferred_chains`将被作为全局选项影响所有发行人。 ## 服务器选项 使用可能跨越多个站点的设置自定义[HTTP服务器](/docs/json/apps/http/servers/),因此无法在站点块中正确配置。这些选项会影响侦听器/套接字或 HTTP 层下的其他行为。 可以多次指定,使用不同的`listener_address`值,为每个服务器配置不同的选项。例如,`servers :443`将仅适用于绑定到侦听器地址的服务器`:443`。省略侦听器地址会将选项应用于任何剩余的服务器。 例如,要为port`:80`和`:443`指定不同的服务器配置,你可以指定两个`servers`块: ```caddy { servers :443 { protocol { experimental_http3 } } servers :80 { protocol { allow_h2c } } } ``` ##### `listener_wrappers` 允许配置[监听包装器](/docs/json/apps/http/servers/listener_wrappers/),它可以修改基本侦听器的行为。它们按给定的顺序应用。 有一个特殊的无操作[`tls`](/docs/json/apps/http/servers/listener_wrappers/tls/)侦听器包装器作为标准模块提供,它标记应在侦听器包装器链中处理TLS的位置。仅当必须在TLS握手之前放置另一个侦听器包装器时才应使用它。 例如,假设你安装了[`proxy_protocol`](/docs/json/apps/http/servers/listener_wrappers/proxy_protocol/)插件: ```caddy-d listener_wrappers { proxy_protocol { timeout 2s allow 192.168.86.1/24 192.168.86.1/24 } tls } ``` ##### `timeouts` - **read_body** 是一个[持续时间值](/docs/conventions#durations),它设置允许从客户端上传读取多长时间。将此设置为一个较短的非零值可以减轻慢速攻击,但也可能影响合法慢速客户端。默认为无超时。 - **read_header** 是一个[持续时间值](/docs/conventions#durations),它设置允许从客户端的请求标头读取多长时间。默认为无超时。 - **write** 是一个[持续时间值](/docs/conventions#durations),用于设置允许写入客户端的时间长度。请注意,在提供大文件时将其设置为较小的值可能会对合法缓慢的客户端产生负面影响。默认为无超时。 - - **idle** 是一个[持续时间值](/docs/conventions#durations),用于设置启用 keep-alives 时等待下一个请求的最长时间。默认为 5 分钟,以帮助避免资源耗尽。 ##### `max_header_size` 从客户端的 HTTP 请求标头中解析的最大大小。它接受[go-humanize](https://github.com/dustin/go-humanize/blob/master/bytes.go)支持的所有格式。 ##### `protocol`([DEPRECATED since 2022-08](https://github.com/caddyserver/caddy/blob/6d9a83376b5e19b3c0368541ee46044ab284038b/caddyconfig/httpcaddyfile/serveroptions.go#L241)) - **allow_h2c** 启用 H2C(“明文 HTTP/2”或“H2 over TCP”)支持,如果客户端支持,它将通过明文 TCP 连接提供 HTTP/2。由于 Go 标准库没有实现这一点,因此使用 H2C 与该服务器的大多数其他选项不兼容。不要仅仅为了实现最大的客户端兼容性而启用它。在实践中,很少有客户端实现 H2C,甚至更少需要它。此设置仅适用于未加密的 HTTP 侦听器。⚠️实验功能;可能会更改或删除。 - **experimental_http3** 启用实验性草案 HTTP/3 支持。请注意,HTTP/3 不是一个完整的规范,客户端支持非常有限。此选项将在未来消失。此选项不受兼容性承诺的约束。 - **strict_sni_host** 要求请求的`Host`标头与客户端的TLS ClientHello发送的ServerName的值匹配;使用TLS客户端身份验证时,通常是必要的保护措施。 ================================================ FILE: src/docs/markdown/caddyfile/patterns.md ================================================ --- title: 常见Caddyfile模式 --- # 常见Caddyfile模式 此页面演示了一些用于常见用例的完整和最小的Caddyfile配置。这些可能是你自己的Caddyfile文档的有用起点。 这些不是即插即用的解决方案;你将不得不自定义你的域名、端口/套接字、目录路径等。它们旨在说明一些最常见的配置模式。 #### Menu - [静态文件服务器](#静态文件服务器) - [反向代理](#反向代理) - [PHP](#PHP) - [重定向到`www.`子域名](#重定向到`www.`子域名) - [尾随斜杠](#尾随斜杠) - [通配符](#通配符) - [单页面应用(SPAs)](#单页面应用(SPAs)) ## 静态文件服务器 ```caddy example.com root * /var/www file_server ``` 像往常一样,第一行是站点地址。该[`root`](/docs/caddyfile/directives/root)指令指定站点根目录的路径(`*`匹配所有请求的方法,以便与[路径匹配器](/docs/caddyfile/matchers#path-matchers)消除歧义);如果站点不是当前工作目录,则更改站点的路径。最后,我们启用静态文件服务器。 ## 反向代理 代理所有的请求: ```caddy example.com reverse_proxy localhost:5000 ``` 只代理以`/api/`开头的请求,并为其他所有内容提供静态文件: ```caddy example.com root * /var/www reverse_proxy /api/* localhost:5000 file_server ``` ## PHP ### PHP-FPM 在运行PHP FastCGI服务时,类似下面的配置适用于大多数现代PHP应用: ```caddy example.com { root /srv/public encode php_fastcgi localhost:9000 file_server } ``` 请按实际情况调整站点根目录;此示例假设应用的Web根目录位于`public`目录中。磁盘上存在的文件将由[`file_server`](/docs/caddyfile/directives/file_server)直接返回,其他请求会路由到`index.php`由PHP应用处理。 有时你也可以用unix socket连接PHP-FPM: ```caddy-d php_fastcgi unix//run/php/php8.2-fpm.sock ``` [`php_fastcgi`指令](/docs/caddyfile/directives/php_fastcgi)本质上是[多段配置](/docs/caddyfile/directives/php_fastcgi#expanded-form)的快捷写法。 ### FrankenPHP 你也可以使用[FrankenPHP](https://frankenphp.dev/),它是一个通过CGO直接调用PHP的Caddy发行版。相比PHP-FPM,性能可高出数倍,启用worker模式时提升通常更明显。 ```caddy { frankenphp order php_server before file_server } example.com { root /srv/public encode zstd br gzip php_server } ``` 在运行PHP FastCGI服务的情况下,类似这样的内容适用于大多数现代PHP应用程序: ```caddy example.com root * /var/www php_fastcgi /blog/* localhost:9000 file_server ``` 请对应地调整站点根目录和路径匹配器;此示例假定PHP仅位于`/blog/`子目录中——所有其他请求将作为静态文件提供。 该[`php_fastcgi`指令](/docs/caddyfile/directives/php_fastcgi)实际上只是[几个配置](/docs/caddyfile/directives/php_fastcgi#expanded-form)的快捷方式。 ## 重定向到`www.`子域名 T使用HTTP重定向,给域名**添加**`www.`子域。 ```caddy example.com { redir https://www.example.com{uri} } www.example.com { } ``` 要**删除**它: ```caddy www.example.com { redir https://example.com{uri} } example.com { } ``` ## 尾随斜杠 你通常不需要自己进行配置;该[`file_server`指令](/docs/caddyfile/directives/file_server)将通过 HTTP 重定向自动添加或删除请求中的尾部斜杠,具体取决于请求的资源是目录还是文件。 但是,如果需要,你仍然可以在配置中强制使用斜杠。有两种方法可以做到:内部或外部。 ### 内部执法 这使用[`rewrite`](/docs/caddyfile/directives/rewrite)指令。Caddy将在内部重写URI以添加或删除尾部斜杠: ```caddy example.com rewrite /add /add/ rewrite /remove/ /remove ``` 使用重写,带有和不带有斜杠的请求将是相同的。 ### 外部执行 这使用[`redir`](/docs/caddyfile/directives/redir)指令。Caddy 将要求浏览器更改 URI 以添加或删除尾部斜杠: ```caddy example.com redir /add /add/ redir /remove/ /remove ``` 使用重定向,客户端将不得不重新发出请求,为资源强制执行一个可接受的URI。 ## 通配符证书 如果你需要使用相同的通配符证书为多个子域提供服务,处理它们的最佳方法是使用如下所示的Caddyfile,利用[`handle`](/docs/caddyfile/directives/handle)指令和[`host`][`host`](/docs/caddyfile/matchers#host)匹配器: ```caddy *.example.com { tls { dns [] } @foo host foo.example.com handle @foo { respond "Foo!" } @bar host bar.example.com handle @bar { respond "Bar!" } # Fallback for otherwise unhandled domains handle { abort } } ``` 请注意,你必须启用[ACME DNS 质询](/docs/automatic-https#dns-challenge)才能让 Caddy 自动管理通配符证书。 ## 单页面应用(SPAs) 当一个网页进行自己的路由时,服务器可能会收到大量的请求,这些请求并不存在于服务器端,但只要提供单一的索引文件,这些请求就可以在客户端呈现。这样架构的Web应用程序被称为SPA,或单页应用程序。 其主要思想是让服务器“尝试文件”来查看请求的文件在服务器端是否存在,如果不存在,则返回到一个索引文件,客户端在其中进行路由(通常使用客户端JavaScript):`try_files {path} /index.html` 最基本的SPA配置通常是这样的: ```caddy example.com root * /path/to/site try_files {path} /index.html file_server ``` 如果你的SPA与API或其他仅在服务器端使用的端点相结合,你会想要使用`handle`块来专门处理它们: ```caddy example.com handle /api/* { reverse_proxy backend:8000 } handle { root * /path/to/site try_files {path} /index.html file_server } ``` ## Caddy代理到另一个Caddy 如果你有一个公网可访问的Caddy实例(称为“front”),以及一个位于私网、承载真实应用的Caddy实例(称为“back”),可以用[`reverse_proxy`指令](/docs/caddyfile/directives/reverse_proxy)进行转发。 前置实例: ```caddy foo.example.com, bar.example.com { reverse_proxy 10.0.0.1:80 } ``` 后置实例: ```caddy { servers { trusted_proxies static private_ranges } } http://foo.example.com { reverse_proxy foo-app:8080 } http://bar.example.com { reverse_proxy bar-app:9000 } ``` ================================================ FILE: src/docs/markdown/caddyfile/response-matchers.md ================================================ --- title: 响应匹配器(Caddyfile) --- # 响应匹配器 **响应匹配器**可用于按特定条件过滤(或分类)响应。 它通常只会作为某些指令内部的配置出现,用来在向客户端写出响应时进行判断。 - [语法](#syntax) - [匹配器](#matchers) - [status](#status) - [header](#header) ## 语法 如果某个指令支持响应匹配器,语法文档通常写作`[]`或`[]`。 - ****可以是已声明的命名响应匹配器名称。例如:`@name`。 - ****可以直接写响应条件本身,无需提前声明。例如:`status 200`。 ### 命名形式 ```caddy-d @name { status header [] } ``` 如果指令只关心响应的一个维度,也可以把名称和条件写在同一行: ```caddy-d @name status ``` ### 内联形式 ```caddy-d ... { status header [] } ``` ```caddy-d ... status ``` ```caddy-d ... header [] ``` ## 匹配器 ### status ```caddy-d status ``` 按HTTP状态码匹配。 - **<code...>**是HTTP状态码列表。特殊写法如`2xx`和`3xx`分别匹配`200`-`299`与`300`-`399`范围内全部状态码。 #### 示例: ```caddy-d @success status 2xx ``` ### header ```caddy-d header [] ``` 按响应头字段匹配。 - ``是要检查的HTTP头字段名。 - 若以`!`开头,表示该字段必须不存在才能匹配(此时省略value参数)。 - ``是字段必须匹配的值。 - 若以`*`开头,表示快速后缀匹配(出现在末尾)。 - 若以`*`结尾,表示快速前缀匹配(出现在开头)。 - 若前后都包裹`*`,表示快速子串匹配(出现在任意位置)。 - 否则为快速精确匹配。 同一个集合中,不同字段之间是AND关系;同一字段的多个值是OR关系。 注意:同一个响应头字段可能重复出现且值不同。后端应用必须把响应头字段值视为数组而非单值;遇到这种情况时,Caddy不会解释其语义。 #### 示例: 匹配响应头`Foo`中包含`bar`的响应: ```caddy-d @upgrade header Foo *bar* ``` 匹配响应头`Foo`值为`bar`或`baz`的响应: ```caddy-d @foo { header Foo bar header Foo baz } ``` 匹配完全不包含`Foo`响应头字段的响应: ```caddy-d @not_foo header !Foo ``` ================================================ FILE: src/docs/markdown/caddyfile/spec.md ================================================ --- title: Caddyfile Spec --- TODO: this page is unfinished # Caddyfile Specification This page describes the syntax of the Caddyfile. If it is your first time writing a Caddyfile, try the Caddyfile primer tutorial instead. This page is not beginner-friendly; it is technical and kind of boring. Although this article is verbose, the Caddyfile is designed to be easily readable and writable by humans. You will find that it is easy to remember, not cumbersome, and flows off the fingers. The term "Caddyfile" often refers to a file, but more generally means a blob of Caddy configuration text. A Caddyfile can be used to configure any Caddy server type: HTTP, DNS, etc. The basic structure and syntax of the Caddyfile is the same for all server types, but semantics change. Because of this variability, this document treats the Caddyfile only as the generic configuration syntax as it applies to all server types. Caddyfile documentation for specific types may be found within their respective docs. For instance, the HTTP server documents the semantics of its Caddyfile. #### Topics 1. [File format & encoding](#) 2. [Lexical syntax](#) 3. [Structure](#) 4. [Labels](#) 5. [Directives](#) 6. [Environment variables](#) 7. [Import](#) 8. [Reusable snippets](#) 9. [Examples](#) ## File Format & Encoding The Caddyfile is plain Unicode text encoded with UTF-8. Each code point is distinct; specifically, lowercase and uppercase characters are different. A leading byte order mark (0xFEFF), if present, will be ignored. ## Lexical Syntax A token is a sequence of whitespace-delimited characters in the Caddyfile. A token that starts with quotes " is read literally (including whitespace) until the next instance of quotes " that is not escaped. Quote literals may be escaped with a backslash like so: \". Only quotes are escapable. “Smart quotes” are not valid as quotes. Lines are delimited with the \n (newline) character only. Carriage return \r is discarded unless quoted. Blank, unquoted lines are allowed and ignored. Comments are discarded by the lexer. Comments begin with an unquoted hash # and continue to the end of the line. Comments may start a line or appear in the middle of a line as part of an unquoted token. For the purposes of this document, commented and blank lines are no longer considered. Tokens are then evaluated by the parser for structure. ## Structure A Caddyfile has no global scope or inheritence between separate blocks. The most global unit of the Caddyfile is an entry. An entry consists of a list of labels and a definition associated with those labels. A label is a string identifier, and a definition is a body (one or more lines) of tokens grouped together in a block: list of labels definition (block) A Caddyfile with only one entry may consist simply of the label line(s) followed by the definition on the next line(s), as shown above. However, a Caddyfile with more than one entry must enclose each definition in curly braces { }. The opening curly brace { must be at the end of the label line, and the closing curly brace } must be the only token on its line: list of labels { definition (block) } list of labels { definition (block) }

Consistent tab indentation is encouraged within blocks enclosed by curly braces.

The first line of a Caddyfile is always a label line. Comment lines, empty lines, and import lines are the exceptions.

Labels

Labels are the only tokens that appear outside of blocks (with one exception being the import directive). A label line may have just one label:

label

or several labels, separated by spaces:

label1 label2 ...

If many labels are to head a block, the labels may be suffixed with a comma. A comma-suffixed label may be followed by a newline, in which case the next line will be considered part of the same line:

label1, label2

Mixing of these patterns is valid (but discouraged), as long as the last label of the line has a comma if the next line is to continue the list of labels:

label1 label2, label3, label4, label5

A definition with multiple labels is replicated across each label as if they had been defined separately but with the same definition.

Directives

The body of the definition follows label lines. The first token of each line in a definition body is a directive. Every token after the directive on the same line is an argument. Arguments are optional:

directive1 directive2 arg1 arg2 directive3 arg3

Commas are not acceptable delimiters for arguments; they will be treated as part of the argument value. Arguments are delimited solely by same-line whitespace.

Directives may span multiple lines by opening a block. Blocks are enclosed by curly braces { }. The opening curly brace { must be at the end of the directive's first line, and the closing curly brace } must be the only token on its line:

directive { ... }

Within a directive block, the first token of each line may be considered a subdirective or property, depending on how it is used (other terms may be applied). And as before, they can have arguments:

directive arg1 { subdir arg2 arg3 ... }

Subdirectives cannot open new blocks. In other words, nested directive blocks are not supported. If a directive block is empty, the curly braces should be omitted entirely.

Environment Variables

Any token (label, directive, argument, etc.) may contain or consist solely of an environment variable, which takes the Unix form or Windows form, enclosed in curly braces { } without extra whitespace:

label_{$ENV_VAR_1} directive {%ENV_VAR_2%}

Either form works on any OS. A single environment variable does not expand out into multiple tokens, arguments, or values.

Import

The import directive is a special case, because it can appear outside a definition block. The consequence of this is that no label can take on the value of "import".

Where an import line is, that line will be replaced with the contents of the imported file, unmodified. See the import docs for more information.

Reusable Snippets

You can define snippets to be reused later in your Caddyfile by defining a block with a single-token label surrounded by parentheses:

(mysnippet) { ... }

Then you can invoke the snippet with the import directive:

import mysnippet

Examples

A very simple Caddyfile with only one entry: label1 directive1 argument1 directive2

Appending the prior example with another entry introduces the need for curly braces: label1 { directive1 arg1 directive2 } label2, label3 { directive3 arg2 directive4 arg3 arg4 }

Some people prefer to always use braces even if there's just one entry; this is fine, but unnecessary: label1 { directive1 arg1 directive2 }

Example in which a directive opens a block: label1 directive arg1 { subdir arg2 arg3 } directive arg4

Similarly, but in an indented definition body, and with a comment: label1 { directive1 arg1 directive2 arg2 { subdir1 arg3 arg4 subdir2 # nested blocks not supported } directive3 }

================================================ FILE: src/docs/markdown/caddyfile-tutorial.md ================================================ --- title: Caddyfile教程 --- # Caddyfile教程 本教程将教你[HTTP Caddyfile](/docs/caddyfile)的基础知识,以便你可以快速轻松地生成美观、功能强大的站点配置。 **目标:** - 🔲 第一个站点 - 🔲 静态文件服务器 - 🔲 模板 - 🔲 压缩 - 🔲 多个站点 - 🔲 匹配器 - 🔲 环境变量 - 🔲 注释 **先决条件:** - 基本的终端/命令行技能 - 基本的文本编辑器技能 - PATH变量包含`caddy` --- 新建一个名为`Caddyfile`(无扩展名)的文本文件。 首先应该输入的是你的网站[地址](/docs/caddyfile/concepts#addresses)。 ```caddy localhost ``` 然后按回车键并输入你想要它执行的操作。对于本教程,使你的Caddyfile如下所示: ```caddy localhost respond "Hello, world!" ``` 保存并运行Caddy(因为这是一个培训教程,我们将使用该`--watch`标志,以便自动应用对Caddyfile的更改):
caddy run --watch
第一次,系统会要求你输入密码。这样Caddy就可以通过HTTPS为你的网站提供服务。 在你的浏览器中使用HTTPS浏览[https://localhost](https://localhost),检查你的网站服务器是否正常运行。 这并不是特别令人兴奋,所以让我们将静态响应更改为启用目录列表的[文件服务器](/docs/caddyfile/directives/file_server) : ```caddy localhost file_server browse ``` 保存你的 Caddyfile,然后刷新你的浏览器页面。如果当前目录中有索引文件,你应该会看到文件列表或HTML页面。 ## 添加功能 利用文件服务器还可以做一些更有意思事情:基于模板页面展示。创建一个新文件并粘贴如下内容: ```html Caddy tutorial Page loaded at: {{`{{`}}now | date "Mon Jan 2 15:04:05 MST 2006"{{`}}`}} ``` 将其在当前目录保存为`caddy.html`,然后在浏览器中访问:[https://localhost/caddy.html](https://localhost/caddy.html) 输出内容如下: ``` Page loaded at: {{`{{`}}now | date "Mon Jan 2 15:04:05 MST 2006"{{`}}`}} ``` 等一下,我们不是应该能看到今天的日期吗?为什么它不起作用呢?这是因为:服务器尚未配置模板!小事一桩,只需在Caddyfile中添加一行即可: ```caddy localhost templates file_server browse ``` 保存它,然后刷新浏览器页面,你将会看到: ``` Page loaded at: {{now | date "Mon Jan 2 15:04:05 MST 2006"}} ``` 使用Caddy的[模板模块](/docs/modules/http.handlers.templates),你可以对静态文件做很多有用的事情,例如包含其他HTML文件、制作子请求、设置响应头、处理数据结构等等! 使用快速且现代的压缩算法压缩响应是一种很好的做法。使用 [`encode`](/docs/caddyfile/directives/encode)可以启用Gzip和Zstandard支持: ```caddy localhost encode zstd gzip templates file_server browse ``` 这是启动和运行半高级、可应用于生产的站点的基本过程! 当你准备好开启[自动HTTPS](/docs/automatic-https)时,只需将你的网站地址(`localhost`在我们的教程中)替换为你的域名即可。有关更多信息,请参阅我们的[HTTPS快速入门指南](/docs/quick-starts/https)。 ## 多个站点 使用我们当前的Caddyfile,我们只能有一个站点定义!只有第一行可以是站点的地址,然后文件的所有其余部分都必须是该站点的指令。 但是制作起来很容易,所以我们可以添加更多网站! 到目前为止,我们的Caddyfile内容如下: ```caddy localhost encode zstd gzip templates file_server browse ``` 相当于这个: ```caddy localhost { encode zstd gzip templates file_server browse } ``` 这样就能添加两个甚至更多的站点了。 通过将我们的站点块包裹在花括号`{ }`中,我们可以在同一个Caddyfile中定义多个不同的站点。 例如: ```caddy :8080 { respond "I am 8080" } :8081 { respond "I am 8081" } ``` 当用花括号包裹站点块时,只有[地址](/docs/caddyfile/concepts#addresses)出现在花括号外,[指令](/docs/caddyfile/directives)都出现在花括号内。 对于共享相同配置的多个站点,你可以添加更多地址,例如: ```caddy :8080, :8081 { ... } ``` 然后,你可以根据需要定义任意数量的不同站点,只要每个地址都是唯一的。 ## 匹配器 我们可能只想将某些指令应用于某些请求。例如,假设我们想要同时拥有一个文件服务器和一个反向代理,但我们显然不能在每个请求上都这样做!文件服务器将写入静态文件,或者反向代理将请求代理到后端。 这个配置不会像我们想要的那样工作: ```caddy localhost file_server reverse_proxy 127.0.0.1:9005 ``` 在实践中,我们可能只想对 API 请求使用反向代理,即基本路径为`/api/`。通过添加[匹配器标记](/docs/caddyfile/matchers#syntax)很容易做到这一点: ```caddy localhost file_server reverse_proxy /api/* 127.0.0.1:9005 ``` 这里,现在反向代理只会处理所有以`/api/`开始的请求。 我们刚刚添加的`/api/*`标记就被称为**匹配器标记**,你可以说它是一个匹配器标记,因为它以正斜杠开头,并且出现在指令之后(但你始终可以在[指令文档](/docs/caddyfile/directives)中查找它以确定)。 匹配器真的很强大。你可以命名匹配器并使用它们`@name`来匹配不仅仅是请求路径!在继续之前花点时间了解更多关于[匹配器](/docs/caddyfile/matchers)的信息! ## 环境变量 Caddyfile适配器允许在解析Caddyfile之前替换[环境变量](/docs/caddyfile/concepts#environment-variables)。 首先,设置一个环境变量(在运行Caddy的同一shell中):
export SITE_ADDRESS=localhost:9055
然后你可以在Caddyfile中这样使用它: ```caddy {$SITE_ADDRESS} file_server ``` 在解析Caddyfile之前,它将被扩展为: ```caddy localhost:9055 file_server ``` 你可以在Caddyfile中的任何位置使用环境变量,使用数量也没有限制。 ## 注释 最后一件你会发现最有帮助的事情:如果你想在你的Caddyfile中添加注释或注释任何东西,你可以将`#`放在行首: ```caddy # this starts a comment ``` ## 进一步阅读 - [常见模式](/docs/caddyfile/patterns) - [Caddyfile概念](/docs/caddyfile/concepts) - [指令](/docs/caddyfile/directives) ================================================ FILE: src/docs/markdown/caddyfile.md ================================================ --- title: Caddyfile --- # Caddyfile **Caddyfile**是一种方便用户使用的Caddy配置格式。这是大多数人最喜欢使用Caddy的方式,因为它易于编写、易于理解,且能满足绝大部分的使用场景。 它看起来像这样 ```caddy example.com root * /var/www/wordpress php_fastcgi unix//run/php/php-version-fpm.sock file_server ``` (这是一个真正的、生产就绪的Caddyfile,它通过完全托管的HTTPS为WordPress提供服务。) 基本思路是,先填写网站的地址,然后填写网站需要具备的特性或功能。查看更多[常见模式](/docs/caddyfile/patterns)。 ## 菜单 - #### [快速入门指南](/docs/quick-starts/caddyfile) - #### [完整的Caddyfile教程](/docs/caddyfile-tutorial) - #### [Caddyfile概念](/docs/caddyfile/concepts) - #### [指令](/docs/caddyfile/directives) - #### [请求匹配器](/docs/caddyfile/matchers) - #### [全局选项](/docs/caddyfile/options) - #### [常见模式](/docs/caddyfile/patterns) ## 备注 Caddyfile只是Caddy的[配置适配器](/docs/config-adapters)。在手工制作配置时通常首选它,但它不如Caddy的[原生JSON结构](/docs/json/)那样富有表现力、灵活或可编程。如果你正在尝试将你的的Caddy配置/部署实现自动化,你可能希望将JSON结合Caddy的[API](/docs/api)一起使用。(实际上,也可以将Caddyfile与API一起使用,只是在有限的范围内。) ================================================ FILE: src/docs/markdown/command-line.md ================================================ # 命令行 Caddy有一个标准的类unix命令行接口,基本用法如下: ```bash caddy [] ``` - `<>`代表要被你输入替换参数。 - `[]`代表可选的参数。 - `...`表示延续,即一个或多个参数。 __快速开始:`caddy help`__ - [caddy adapt](#caddy-adapt) 将配置文档适配为原生JSON - [caddy build-info](#caddy-build-info) 打印构建信息 - [caddy environ](#caddy-environ) 打印环境 - [caddy file-server](#caddy-file-server) 一个简单但可用于生产的文件服务器 - [caddy fmt](#caddy-fmt) 格式化一个 Caddyfile - [caddy hash-password](#caddy-hash-password) 散列密码并输出 base64 - [caddy help](#caddy-help) 查看 caddy 命令的帮助 - [caddy list-modules](#caddy-list-modules) 列出已安装的 Caddy 模块 - [caddy reload](#caddy-reload) 更改正在运行的 Caddy 进程的配置 - [caddy reverse-proxy](#caddy-reverse-proxy) 一个简单但可用于生产的 HTTP(S) 反向代理 - [caddy run](#caddy-run) 在前台启动 Caddy 进程 - [caddy start](#caddy-start) 在后台启动 Caddy 进程 - [caddy stop](#caddy-stop) 停止正在运行的 Caddy 进程 - [caddy trust](#caddy-trust) 将证书安装到本地信任存储中 - [caddy untrust](#caddy-untrust) 不信任来自本地信任存储的证书 - [caddy upgrade](#caddy-upgrade) 将 Caddy 升级到最新版本 - [caddy add-package](#caddy-add-package) 将 Caddy 升级到最新版本,添加了额外的插件 - [caddy remove-package](#caddy-remove-package) 将 Caddy 升级到最新版本,删除了一些插件 - [caddy validate](#caddy-validate) 测试配置文件是否有效 - [caddy version](#caddy-version) 打印版本 ## 子命令 ### caddy adapt ```bash caddy adapt [--config ] [--adapter ] [--pretty] [--validate] ``` 将配置适配成Caddy的原生JSON配置结构,并通过stdout输出,如果有任何stderr的警告,则直接退出。 `--config`是配置文件的路径。如果省略,则假定当前目录存在`Caddyfile`文件;否则,必须指定该选项。 `--adapter`指定要使用的配置适配器;默认为`caddyfile`。 `--pretty`将使用缩进格式化输出以提高可读性。 `--validate`将加载并提供适配了的配置以检查有效性(但它实际上不会开始运行配置)。 请注意,成功适配了的配置仍可能无法通过验证。例如,使用这个Caddyfile: ```caddy localhost tls cert_notexist.pem key_notexist.pem ``` 尝试适配它: ```bash caddy adapt --config Caddyfile ``` 它成功了且没有错误,然后运行下面的命令: ```bash caddy adapt --config Caddyfile --validate adapt: validation: loading app modules: module name 'tls': provision tls: loading certificates: open cert_notexist.pem: no such file or directory ``` 即使Caddyfile可以毫无错误地适配JSON,但实际的证书和/或密钥文件不存在,因此验证失败,因为该错误出现在配置阶段。因此,验证(`--validate`)是比适配更强的错误检查。 #### 例子 要使Caddyfile适配JSON,可以轻松地手动读取和调整: ```bash caddy adapt--config /path/to/Caddyfile --pretty ``` ### caddy build-info ```bash caddy build-info ``` 打印`Go`提供的关于构建的信息(主模块路径、包版本、模块替换)。 ### caddy environ ```bash caddy environ ``` 打印 caddy 看到的环境,然后退出。在调试 init 系统或进程管理器单元(如 systemd)时很有用。 ### caddy file-server ```bash caddy file-server [--root ] [--listen ] [--domain ] [--browse] [--templates] [--access-log] ``` 启动一个简单但可用于生产的静态文件服务器。 `--root`指定根文件路径。默认为当前工作目录。 `--listen`接受一个监听地址。默认为:80,除非--domain使用,否则:443将是默认值。 `--domain`将仅通过该主机名提供文件,并且 Caddy 将尝试通过 HTTPS 提供文件,因此如果它是公共域名,请确保首先正确配置任何公共 DNS。默认端口将更改为 443。 `--browse`如果请求没有索引文件的目录,将启用目录列表。 `--templates`将启用模板渲染。 `--access`-log启用请求/访问日志。 此命令禁用管理 API,从而更容易在本地开发机器上运行多个实例。 ### caddy fmt ```bash caddy fmt [--overwrite] [] ``` 格式化或美化 Caddyfile,然后退出。除非使用,否则结果将打印到标准输出--overwrite。 指定 Caddyfile 的路径。如果-,则从标准输入读取输入。如果省略,则假定为当前目录中名为 Caddyfile 的文件。 `--overwrite`导致结果写入输入文件而不是打印到终端。如果输入不是常规文件,则此标志无效。 ### caddy hash-password ```bash caddy hash-password [--plaintext ] [--algorithm ] [--salt ] ``` 散列密码并以 base64 编码将输出写入标准输出,然后退出。 `--plaintext`是密码的明文形式。如果省略,将采用交互模式,并提示用户手动输入密码。 `--algorithm`可能是 bcrypt 或 scrypt。默认为 bcrypt。 `--salt`仅在算法需要外部盐(如 scrypt)时使用。 ### caddy help ```bash caddy help[] ``` 打印 CLI 帮助文本,可选择用于特定子命令,然后退出。 ### caddy list-modules ```bash caddy list-modules [--packages] [--versions] [--skip-standard] ``` 打印已安装的 Caddy 模块,可选择包含来自其关联 Go 模块的包和/或版本信息,然后退出。 在某些脚本化的情况下,打印所有标准模块可能是多余的,因此你可以使用--skip-standard从输出中省略那些。 注意:由于Go 中的一个错误,版本信息仅在 Caddy 构建为依赖项而不是主模块时可用。使用xcaddy使这更容易。 ### caddy reload ```bash caddy reload [--config ] [--adapter ] [--address ] [--force] ``` 为正在运行的 Caddy 实例提供新配置。这与将文档发布到/load 端点具有相同的效果,但是此命令对于围绕配置文件的简单工作流很方便。与stop、start和run命令相比,这个单一命令是更改/重新加载运行配置的正确语义方式。 由于此命令使用 API,因此不得禁用管理端点。 `--config`是要应用的配置文件。如果-,则从标准输入读取配置。如果未指定,它将尝试Caddyfile在当前工作目录中调用的文件,如果存在,它将使用caddyfile配置适配器对其进行调整;否则,如果没有要加载的配置文件,则会出错。 `--adapter`指定要使用的配置适配器(如果有)。 `--address`如果管理端点没有监听默认地址并且它与提供的配置文件中的地址不同,则需要使用。请注意,此时仅支持 TCP 地址。 `--force`即使指定的配置与 Caddy 已经在运行的配置相同,也会导致重新加载。强制 Caddy 重新配置其模块可能很有用,这可能会产生副作用,例如:重新加载手动加载的 TLS 证书。 ### caddy reverse-proxy ```bash caddy reverse-proxy [--from ] `--to` [--change-host-header] ``` 启动一个简单但可用于生产的 HTTP(S) 反向代理。 `--from`是代理的地址。 `--to`是要代理的地址。 `--change`-host-header将导致 Caddy 将 Host 标头从传入值更改为上游的地址。 `--from`和参数都--to可以是 URL,因为方案和域名将从提供的 URL 中推断出来(路径和查询字符串被忽略)。或者它们可以是简单的网络地址而不是完整的 URL。 此命令禁用管理 API,因此更容易在本地开发机器上运行多个实例。 ### caddy run ```bash caddy run [--config ] [--adapter ] [--pidfile ] [--environ] [--envfile ] [--resume] [--watch] ``` 使用“守护进程”模式无限期地运行Caddy。 `--config`指定要立即加载和使用的初始配置文件。如果指定为`-`,则从标准输入读取配置。如果未指定配置,Caddy将以空白配置运行,并使用管理API端点的默认设置,可用于为其提供新配置。作为一种特殊情况,如果当前工作目录有一个名为“Caddyfile”的文件并且配置了`caddyfile`适配器(默认),那么即使没有任何命令行标志,该文件也将被加载并用于配置Caddy。 `--adapter`是加载初始配置时使用的配置适配器的名称(如果有)。如果`--config`指定的文件名以“Caddyfile”开头,则已经假定使用`caddyfile`作为适配器,则不需要此标志。否则,如果提供的配置文件不是Caddy的原生JSON格式,则需要此标志。任何警告都将打印到日志中,但请注意,任何没有错误的适配都会立即被使用,即使有警告也是如此。如果要先查看适配结果,请使用[`caddy adapt](#caddy-adapt)子命令。 `--pidfile`将PID写入指定文件。 `--environ`在开始之前打印出环境。这与[`caddy environ`](#caddy-environ)命令相同,但打印后不退出。 `--envfile`从指定文件加载环境变量。 `--resume`使用自动保存的最后加载的配置,覆盖`--config`标志(如果存在)。使用此标志可通过机器重新启动或进程重新启动来保证配置的持久性。它在以[API](api)为中心的部署中最有用。 `--watch`将监视配置文件并在更改后自动重新加载它。 ⚠️此功能仅供本地开发环境使用! > 在生产中运行时不要停止服务器来更改配置!这将导致停机。(这应该很明显,但你会惊讶于我们收到了多少关于它的投诉。)请改用[`caddy reload`](#caddy-reload)命令。 ### caddy start ```bash caddy start [--config ] [--adapter ] [--envfile ] [--pidfile ] [--watch] ``` 与`caddy run`相同,但该命令在后台运行。此命令仅在后台进程运行成功(或运行失败)之前阻塞,然后返回。 注意:该标志`--config`不支持通过`-`选项从标准输入读取配置。 不鼓励在系统服务或Windows上使用此命令。在Windows上,子进程将保持连接到终端,因此关闭窗口将强制停止Caddy,这并不明显。考虑改为将Caddy[作为服务](/docs/running)运行。 启动后,你可以使用[`caddy stop`](#caddy-stop)或者[`/ stop`](api#post-stop)API端点退出后台进程。 ### caddy stop ```bash caddy stop[--address ] ``` > 停止(和重新启动)服务器与配置更改正交。__不要使用stop命令更改生产中的配置,除非你想要停机__。请改用[caddy reload](#caddy-reload)命令。 优雅地停止正在运行的Caddy进程(而不是直接停止进程)并使其退出。它使用管理API的[`POST /stop`](api#post-stop)端点来执行平滑关闭。 `--address` 如果正在运行的实例的管理API不在默认端口上,则可以使用;也可以在此处指定备用地址。 如果要停止当前配置但不想退出进程,请使用`caddy reload`空白配置或[`DELETE /config/`](api#delete-configpath)端点。 ### caddy trust ```bash caddy trust ``` 将Caddy的默认内部CA(名为“local”)的根证书安装到本地信任库中;仅用于开发环境。如果没有足够的权限,可能会提示输入密码。 这个命令通常是不必要的。因为Caddy将在第一次需要时自动将其根证书安装到本地信任存储中,所以此命令仅在你需要在具有提升的权限时预安装证书时有用,例如在自动化环境中的系统配置期间。 ### caddy untrust ```bash caddy untrust [--ca ] [--cert ] ``` 不信任来自本地信任存储的根证书。仅用于开发环境。可以分别指定`--ca`或`--cert`标志,但不能同时指定两者。如果两者均未指定,则为Caddy的默认CA(`local`)。 `--ca`指定不信任的Caddy CA的ID。默认的CA的ID是`local`。 `--cert`指定要卸载的PEM编码证书文件的路径。 ### caddy upgrade ```bash caddy upgrade [--keep-backup] ``` 将当前的Caddy二进制文件替换为[我们下载页面](https://caddyserver.com/download)中安装了相同模块的最新版本,包括在Caddy网站上注册的所有第三方插件。 升级不会中断正在运行的服务器;目前,该命令仅替换磁盘上的二进制文件。如果我们能找到更好的方法,这种升级模式可能会被改变。 这种升级过程是容错的;当前二进制文件首先会被备份(在当前二进制文件复制出来一份到同目录)并在出现任何问题时自动恢复。如果你希望在升级过程完成后保留备份,你可以使用`--keep-backup`选项。 该命令执行时如果你的用户无权写入可执行文件,则此需要提升权限。 ### caddy add-package ```bash caddy add-package [--keep-backup] ``` 与`caddy upgrade`类似,将当前Caddy二进制文件替换为安装了相同模块的最新版本,另外会安装通过参数指定的包。从我们的[下载页面](https://caddyserver.com/download)找到你可以安装的软件包列表。每个参数都应该是完整的包名。 例如: ```bash caddy add-package github.com/caddy-dns/cloudflare ``` ### caddy remove-package ```bash caddy remove-package [--keep-backup] ``` 与`caddy upgrade`命令类似,将当前Caddy二进制文件替换为安装了相同模块的最新版本,且会将通过参数列出的包删除掉。运行`caddy list-modules --packages`可以查看当前二进制文件中包含的非标准模块的包名列表。 ### caddy validate ```bash caddy validate [--config ] [--adapter ] ``` 验证配置文件,然后退出。此命令将反序列化配置,然后加载和配置其所有模块,就好像启动配置一样(但实际上并未启动配置)。这会把加载或配置阶段出现的配置错误暴露出来,是比仅将配置序列化为JSON更强大的错误检查方式。 `--config`是要验证的配置文件。如果指定该选项为`-`,则从标准输入stdin读取配置。默认使用当前目录下的`Caddyfile`,前提是这个文件存在。 如果配置文件不是Caddy的原生JSON格式,`--adapter`是要使用的配置适配器的名称。如果配置文件以`Caddyfile`开头,则默认使用`caddyfile`这个适配器。 ### caddy version ```bash caddy version ``` 打印版本并退出。 ================================================ FILE: src/docs/markdown/config-adapters.md ================================================ --- title: 配置适配器 --- # 配置适配器 Caddy 的原生配置语言是[JSON](https://www.json.org/json-en.html),但手动编写 JSON 可能很乏味且容易出错。这就是Caddy支持通过**配置适配器**配置其他语言的原因。这些适配器是可以将你喜欢的格式输出成[Caddy JSON](/docs/json/)格式的Caddy插件。 例如,配置适配器可以[将NGINX配置转化成Caddy JSON](https://github.com/caddyserver/nginx-adapter)。 ## 已知的配置适配器 以下配置适配器当前可用(一些是第三方项目): - [**caddyfile**](/docs/caddyfile) (标准) - [**nginx**](https://github.com/caddyserver/nginx-adapter) - [**jsonc**](https://github.com/caddyserver/jsonc-adapter) - [**json5**](https://github.com/caddyserver/json5-adapter) - [**yaml**](https://github.com/abiosoft/caddy-yaml) - [**cue**](https://github.com/caddyserver/cue-adapter) - [**toml**](https://github.com/awoodbeck/caddy-toml-adapter) - [**hcl**](https://github.com/francislavoie/caddy-hcl) (此列表是已知适配器的临时位置,直到我们的新网站完成。) ## 使用配置适配器 你可以通过在命令行上使用大多数接受配置的子命令上的`--adapter` 标志来指定它来使用配置适配器:
caddy run --config caddy.yaml --adapter yaml
或者通过[`/load`端点](/docs/api#post-load)的APi:
curl localhost:2019/load \
	-X POST \
	-H "Content-Type: application/yaml" \
	--data-binary @caddy.yaml
如果你只想获取输出JSON而不运行它,可以使用以下[`caddy adapt`](/docs/command-line#caddy-adapt)命令:
caddy adapt --config caddy.yaml --adapter yaml
## 注意事项 并非所有配置语言都与 Caddy 100% 兼容;某些功能或行为根本无法很好地转换或尚未编程到适配器或 Caddy 本身。 一些适配器会进行1-1转换,例如YAML->JSON或TOML->JSON。其他是专门为Caddy设计的,例如Caddyfile。通常,这些适配器将始终有效。 然而,并不是所有的适配器都能一直工作。配置适配器尽最大努力将你的输入转换为具有最高保真度和正确性的Caddy JSON。因为不能保证这个转换过程始终是完整和正确的,所以我们不称他们为“转换器”或“翻译者”。它们是“适配器”,因为它们至少会给你一个很好的起点来完成你的最终JSON配置。 配置适配器可以输出生成的JSON、警告和错误。如果没有发生错误,则结果为JSON。当输入有问题(例如,语法错误)时会发生错误。当适应出现问题但不一定是致命的(例如,不支持的功能)时,会发出警告。如果使用带有警告的配置,建议小心。 ================================================ FILE: src/docs/markdown/conventions.md ================================================ --- title: 约定 --- # 约定 Caddy生态系统遵循一些约定,以使整个平台的事情保持一致和直观。 ## 网络地址 指定要拨号或绑定的网络地址时,Caddy接受以下格式的字符串: ``` network/address ``` 网络部分是可选的,是[Go的`net`包](https://golang.org/pkg/net/)可以识别的任何内容。默认网络是`tcp`。如果指定了网络,则必须用单个正斜杠`/`分隔网络和地址部分。 地址部分可以是以下任何一种形式: - `host` - `host:port` - `:port` - `/path/to/unix/socket` 主机可以是任何主机名、可解析的域名或IP地址。 端口可以是单个值 ( `:8080`)或包含范围(`:8080-8085`))。端口范围将乘以单个地址。并非所有配置字段都接受端口范围。特殊端口`:0`是指任何可用的端口。 仅当使用 unix* 网络类型时,unix 套接字路径才可接受。分隔网络和地址的正斜杠不被视为路径的一部分。 有效示例: ``` :8080 127.0.0.1:8080 localhost:8080 localhost:8080-8085 tcp/localhost:8080 tcp/localhost:8080-8085 udp/localhost:9005 unix//path/to/socket ``` ## 占位符 Caddy 的配置支持使用 _占位符_ (变量)。使用占位符是一种将动态值注入静态配置的简单方法。 占位符的两边都用花括号括起来`{ }`,里面包含变量名,例如:`{foo.bar}`。占位符大括号可以转义,如`\{like so\}`。变量名通常用点命名,以避免模块之间的冲突。 哪些占位符可用取决于上下文。并非所有占位符在配置的所有部分都可用。例如,[HTTP应用程序设置的占位符](/docs/json/apps/http/)仅在与处理 HTTP 请求相关的配置区域中可用。 以下占位符始终可用: 占位符 | 描述 ------------|------------- `{env.*}` | 环境变量(例如`{env.HOME}`) `{system.hostname}` | 系统的本地主机名 `{system.slash}` | 系统的文件路径分隔符 `{system.os}` | 系统的操作系统 `{system.arch}` | 系统架构 `{time.now}` | Go时间结构的当前时间 `{time.now.unix}` | 当前时间,以秒为单位的unix时间戳 `{time.now.unix_ms}` | 当前时间,以毫秒为单位的unix时间戳 `{time.now.common_log}` | 通用日志格式的当前时间 `{time.now.year}` | YYYY格式的当前年份 并非所有配置字段都支持占位符,但大多数都支持你期望的位置。 ## 文件位置 本节包含有关在何处查找各种文件的信息。此处描述的文件和目录路径充其量是默认值;有些可以被覆盖。 ### 你的配置文件 没有一个单一的、传统的地方可以放置你的配置文件。将它们放在对你最有意义的地方。 带有默认配置文件的发行版应该记录这个配置文件的位置,即使它对包/发行版维护者来说是显而易见的。 ### 数据目录 Caddy 将 TLS 证书和其他重要资产存储在数据目录中,该目录由[配置的存储模块](/docs/json/storage/)支持(默认:本地文件系统)。 如果`XDG_DATA_HOME`设置了环境变量,则为`$XDG_DATA_HOME/caddy`。 否则,它的路径因平台而异,遵守操作系统约定: 操作系统 | 数据目录路径 ---|--------------------- **Linux, BSD** | `$HOME/.local/share/caddy` **Windows** | `%AppData%\Caddy` **macOS** | `$HOME/Library/Application Support/Caddy` **Plan 9** | `$HOME/lib/caddy` **Android** | `$HOME/caddy`(或`/sdcard/caddy`) 所有其他操作系统都使用 Linux/BSD 目录路径。 **数据目录不能被视为缓存。** 它的内容**不是**短暂的,也不是仅仅为了表演。Caddy 将 TLS 证书、私钥、OCSP 订书钉和其他必要信息存储到数据目录中。在不了解其含义的情况下,不应将其清除。 至关重要的是,这个目录是持久的并且可由Caddy写入。 ### 配置目录 这是 Caddy 可以将某些配置存储到磁盘的地方。最值得注意的是,它将最后一个活动配置(默认情况下)保存到此文件夹,以便以后使用[`caddy run --resume`](/docs/command-line#caddy-run)。 如果`XDG_CONFIG_HOME`设置了环境变量,则为`$XDG_CONFIG_HOME/caddy`。 否则,它的路径因平台而异,遵守操作系统约定: 操作系统 | 配置目录路径 ---|--------------------- **Linux, BSD** | `$HOME/.config/caddy` **Windows** | `%AppData%\Caddy` **macOS** | `$HOME/Library/Application Support/Caddy` **Plan 9** | `$HOME/lib/caddy` 所有其他操作系统都使用 Linux/BSD 目录路径。 至关重要的是,这个目录是持久的并且可由Caddy写入。 ## 持续时间 持续时间字符串通常在Caddy的配置中使用。它们采用与[Go的`time.ParseDuration`语法](https://golang.org/pkg/time/#ParseDuration),除此之外,你还能`d`表示一天(为简单起见,我们假定1天=24小时)。有效单位是: - `ns` (纳秒) - `us`/`µs` (微秒) - `ms` (毫秒) - `s` (秒) - `m` (分) - `h` (小时) - `d` (天) 例子: - `250ms` - `5s` - `1.5h` - `2h45m` - `90d` 在[JSON配置](/docs/json/)中,持续时间值也可以是表示纳秒的整数。 ================================================ FILE: src/docs/markdown/examples.md ================================================ 示例 ======== 这个页面后续可能会建设成一个由社区共同维护的示例集合。当前请先参考我们社区论坛Wiki中的示例: - [论坛Wiki示例](https://caddy.community/c/wiki/13) - [按关键字搜索Wiki分类](https://caddy.community/search?q=%23wiki%20) ================================================ FILE: src/docs/markdown/extending-caddy/caddyfile.md ================================================ --- title: Caddyfile支持 --- # Caddyfile支持 Caddy模块在[注册](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#RegisterModule)时,凭借其命名空间自动添加到[本地JSON配置](/docs/json/)中,使其既可使用又有记录。这使得对Caddyfile的支持纯粹是可选的,但它经常被那些喜欢Caddyfile的用户要求。 ## Unmarshaler 要为你的模块添加Caddyfile支持,只需实现[`caddyfile.Unmarshaler`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/caddyfile?tab=doc#Unmarshaler)接口。你可以通过解析标记的方式来选择你的模块的Caddyfile语法。 unmarshaler的工作是简单地设置你的模块类型,例如,通过填充它的字段,使用传递给它的[`caddyfile.Dispenser`](https://pkg.go.dev/github.com/caddyserver/caddy/v2/caddyconfig/caddyfile?tab=doc#Dispenser)。例如,一个名为`Gizmo`的模块类型可能有这样的方法。 ```go // UnmarshalCaddyfile实现了caddyfile.Unmarshaler。语法: // // gizmo [