Full Code of phpple/caddy2-cn-doc for AI

master 554fac221e84 cached
116 files
608.3 KB
223.9k tokens
18 symbols
1 requests
Download .txt
Showing preview only (827K chars total). Download the full file or copy to clipboard to get everything.
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}}
<!DOCTYPE html>
<html>
<head>
    <title>{{$title}} &mdash; Caddy v2中文文档</title>
    {{include "/includes/docs/head.html"}}
    <meta property="og:title" content="{{$title}} - Caddy v2中文文档">
    <meta name="twitter:title" value="{{$title}} - Caddy v2中文文档">
</head>
<body>
{{include "/includes/docs/header.html"}}
<main>
    {{include "/includes/docs/nav.html"}}
    <div class="article-container">
        <div class="paper" id="paper1"></div>
        <div class="paper" id="paper2"></div>
        <div class="paper paper3">
            <article>{{markdown $markdownFile.Body}}</article>

            {{include "/includes/donate.html"}}
        </div>
    </div>
    <div class="sidebar"></div>
</main>
{{include "/includes/footer.html"}}

</body>
</html>

================================================
FILE: src/docs/json/index.html
================================================
<!DOCTYPE html>
<html>
	<head>
		<title>JSON配置结构 - Caddy V2中文文档</title>
		{{include "/includes/docs/head.html"}}
		<link rel="stylesheet" href="/resources/css/docs-json.css">
		<script src="/resources/js/marked-0.8.0.min.js"></script>
		<script src="/resources/js/docs-api.js"></script>
		<script src="/resources/js/json-docs.js"></script>
	</head>
	<body>
		{{include "/includes/docs/header.html"}}
		<main>
			{{include "/includes/docs/nav.html"}}
			<div class="article-container">
				<div class="paper" id="paper1"></div>
				<div class="paper" id="paper2"></div>
				<div class="paper paper3">
					<article id="json-docs-container">
						<div class="breadcrumbs">
							<!--Populated by JS-->
						</div>
						{{include "/includes/docs/renderbox.html"}}
						{{include "/includes/docs/details.html"}}
					</article>
				</div>
			</div>
			<div class="sidebar"></div>
		</main>

		{{include "/includes/docs/hovercard.html"}}

		{{include "/includes/footer.html"}}
	</body>
</html>

================================================
FILE: src/docs/markdown/api-tutorial.md
================================================
---
title: "API教程"
---

# API教程

本教程将向你展示如何使用Caddy的[管理API](/docs/api),这使得以可编程方式实现自动化成为可能。

**目标:**
- 🔲 运行守护程序
- 🔲 给 Caddy 一个配置
- 🔲 测试配置
- 🔲 替换活动配置
- 🔲 遍历配置
- 🔲 使用`@id`标签

**必备:**
- 基本的终端/命令行技能
- 基本的JSON经验
- PATH支持`caddy`和`curl`

---

要启动 Caddy 守护程序,请使用`run`子命令:

<pre><code class="cmd bash">caddy run</code></pre>

<aside class="complete">运行守护程序</aside>

这永远阻塞,但它在做什么?此刻……什么都没有。默认情况下,Caddy的配置(“config”)为空白。我们可以使用另一个终端中的[管理API](/docs/api)来验证这一点:

<pre><code class="cmd bash">curl localhost:2019/config/</code></pre>

我们可以通过给它一个配置来使Caddy变得有用。一种方法是向 [/load](/docs/api#post-load)端点发出 POST 请求。就像任何 HTTP 请求一样,有很多方法可以做到这一点,但在本教程中,我们将使用`curl`。

## 你的第一个配置

为了能发起请求,我们需要进行配置。Caddy的配置只是一个[JSON文档](/docs/json/) (或[任何能转换为JSON](/docs/config-adapters)的文件)。

<aside class="tip">
    不需要配置文件。配置API始终可以在没有文件的情况下使用,这非常利于实现自动化。本教程则使用文件,因为它更方便手动编辑。	
</aside>

将下面的内容保存到JSON文件:

```json
{
	"apps": {
		"http": {
			"servers": {
				"example": {
					"listen": [":2015"],
					"routes": [
						{
							"handle": [{
								"handler": "static_response",
								"body": "Hello, world!"
							}]
						}
					]
				}
			}
		}
	}
}
```

然后上传:

<pre><code class="cmd bash">curl localhost:2019/load \
	-H "Content-Type: application/json" \
	-d @caddy.json
</code></pre>

<aside class="tip">
    确保不要忘记文件名前面的`@`;这告诉`curl`你正在发送一个文件。
</aside>

<aside class="complete">给Caddy一个配置</aside>

我们可以验证 Caddy 是否通过另一个 GET 请求应用了我们的新配置:

<pre><code class="cmd bash">curl localhost:2019/config/</code></pre>

通过在浏览器中访问[localhost:2015](http://localhost:2015)或使用`curl`命令来测试它是否有效:

<pre><code class="cmd"><span class="bash">curl localhost:2015</span>
Hello, world!</code></pre>

<aside class="complete">测试配置</aside>

如果你看到_Hello, world!_,就恭喜啦——它已经工作了!确保你的配置按预期工作始终是一个好主意,尤其是在部署到生产环境之前。

```json
{
	"handler": "static_response",
	"body": "I can do hard things."
}
```

保存配置文件,然后通过再次运行相同的POST请求来更新Caddy的活动配置:

<pre><code class="cmd bash">curl localhost:2019/load \
	-H "Content-Type: application/json" \
	-d @caddy.json
</code></pre>

<aside class="complete">替换活动配置</aside>

为了更好地衡量,请验证配置是否已更新:

<pre><code class="cmd bash">curl localhost:2019/config/</code></pre>

通过在浏览器中刷新页面(或再次运行`curl`)来测试它,你将看到一条鼓舞人心的消息!

## 遍历配置

让我们使用 Caddy API 的强大功能来进行更改,而不需要修改我们的配置文件,而不是上传整个配置文件。

通过像我们上面所做的那样替换整个配置来对生产服务器进行少量更改可能是危险的;这就像拥有对文件系统的root访问权限。Caddy的API允许你限制更改的范围,以确保配置的其他部分不会被意外更改。
使用请求URI的路径,我们可以遍历配置结构并仅更新消息字符串(如果被遮挡,请确保向右滚动):

<aside class="tip">
通过像我们上面所做的那样替换整个配置来对生产服务器进行少量更改可能是危险的;这就像拥有对文件系统的root访问权限。Caddy的API允许你限制更改的范围,以确保配置的其他部分不会被意外更改。
</aside>

使用请求 URI 的路径,我们可以遍历配置结构并仅更新消息字符串(如果被遮挡,请确保向右滚动):

<pre><code class="cmd bash">curl \
	localhost:2019/config/apps/http/servers/example/routes/0/handle/0/body \
	-H "Content-Type: application/json" \
	-d '"Work smarter, not harder."'
</code></pre>

<aside class="tip">
	每次你使用 API 更改配置时,Caddy 都会保留一份新配置的副本,便于你可以通过<a href="/docs/command-line#caddy-run"><b>--resume</b>恢复</a>!
</aside>

你可以验证它是否适用于类似的GET请求,例如:

<pre><code class="cmd bash">curl localhost:2019/config/apps/http/servers/example/routes</code></pre>

你应该看到:

```json
[{"handle":[{"body":"Work smarter, not harder.","handler":"static_response"}]}]
```

<aside class="tip">
    你可以使用<a href="https://stedolan.github.io/jq/">jq command</a>命令来美化 JSON 输出:<code>curl ... | jq</code>
</aside>

<aside class="complete">遍历配置</aside>

**重要提示:**
显而易见,一旦你使用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),使它更容易访问:

<pre><code class="cmd bash">curl \
	localhost:2019/config/apps/http/servers/example/routes/0/handle/0/@id \
	-H "Content-Type: application/json" \
	-d '"msg"'
</code></pre>

这给我们的处理对象添加了一个属性:"@id": "msg",所以它现在看起来像这样:

```json
{
	"@id": "msg",
	"body": "Work smarter, not harder.",
	"handler": "static_response"
}
```

<aside class="tip">
    <b>@id</b>标签可以放在任何对象中,并且可以有任何原始值(通常是字符串)。<a href="/docs/api#using-id-in-json">了解更多</a>
</aside>

然后我们可以直接访问它:

<pre><code class="cmd bash">curl localhost:2019/id/msg</code></pre>

现在我们也通过更短的路径更改消息:

<pre><code class="cmd bash">curl \
	localhost:2019/id/msg/body \
	-H "Content-Type: application/json" \
	-d '"Some shortcuts are good."'
</code></pre>

并再次检查:

<pre><code class="cmd bash">curl localhost:2019/id/msg/body</code></pre>

<aside class="complete">使用<code>@id</code>标签</aside>


================================================
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配置中的地址始终优先于默认设置。

<aside class="tip">
	如果你在服务器上运行不受信任的代码(哎呀😬),请确保通过隔离进程、修补易受攻击的程序以及将端点配置为绑定到许可的unix套接字来保护你管理的端点。
</aside>

最新的配置将在任何更改后保存到磁盘(除非[禁用](/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/&lt;id&gt;](#get-pkicaltidgt)**
  返回有关特定[PKI应用](/docs/json/apps/pki/)的CA的信息

- **[GET /pki/ca/&lt;id&gt;/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`。

### 示例

设置新的活动配置:

<pre><code class="cmd bash">curl "http://localhost:2019/load" \
	-H "Content-Type: application/json" \
	-d @caddy.json</code></pre>

注意:`curl`的`-d`标志会删除换行符,因此如果你的配置格式对换行符敏感(例如 Caddyfile),请改用`--data-binary`:

<pre><code class="cmd bash">curl "http://localhost:2019/load" \
	-H "Content-Type: text/caddyfile" \
	--data-binary @Caddyfile</code></pre>


## POST /stop

优雅地关闭服务器并退出进程。要仅停止正在运行的配置而不退出进程,请使用[DELETE /config/](#delete-configpath)。

### 示例

停止进程:

<pre><code class="cmd bash">curl -X POST "http://localhost:2019/stop"</code></pre>


## GET /config/[path]

在命名路径中导出 Caddy 的当前配置。返回 JSON 正文。

### 示例

导出整个配置并漂亮地打印它:

<pre><code class="cmd"><span class="bash">curl "http://localhost:2019/config/" | jq</span>
{
	"apps": {
		"http": {
			"servers": {
				"myserver": {
					"listen": [
						":443"
					],
					"routes": [
						{
							"match": [
								{
									"host": [
										"example.com"
									]
								}
							],
							"handle": [
								{
									"handler": "file_server"
								}
							]
						}
					]
				}
			}
		}
	}
}</code></pre>

仅导出侦听器地址:

<pre><code class="cmd"><span class="bash">curl "http://localhost:2019/config/apps/http/servers/myserver/listen"</span>
[":443"]</code></pre>



## POST /config/[path]

将 Caddy 的配置更改为请求的 JSON 正文的命名路径。如果目标值是一个数组,则追加 POST;如果是一个对象,则会进行创建或替换。

作为一种特殊情况,如果满足以下条件,可以将许多项目添加到数组中:

1. 路径结束于`/...`
2. `/...`之前的路径元素指的是一个数组
3. 有效载荷是一个数组

在这种情况下,有效载荷数组中的元素将被扩展,并且每个元素都将附加到目标数组中。在 Go 术语中,这将具有与以下相同的效果:

```go
baseSlice = append(baseSlice, newElems...)
```

### 示例

添加监听地址:

<pre><code class="cmd bash">curl \
	-H "Content-Type: application/json" \
	-d '":8080"' \
	"http://localhost:2019/config/apps/http/servers/myserver/listen"</code></pre>

添加多个监听地址:

<pre><code class="cmd bash">curl \
	-H "Content-Type: application/json" \
	-d '[":8080", ":5133"]' \
	"http://localhost:2019/config/apps/http/servers/myserver/listen/..."</code></pre>

## PUT /config/[path]

将 Caddy 的配置更改为请求的 JSON 正文的命名路径。如果目标值是数组中的位置(索引),则 PUT 插入;如果是一个对象,它会严格创建一个新值。

### 示例

在第一个槽中添加监听地址:

<pre><code class="cmd bash">curl -X PUT \
	-H "Content-Type: application/json" \
	-d '":8080"' \
	"http://localhost:2019/config/apps/http/servers/myserver/listen/0"</code></pre>


## PATCH /config/[path]

将 Caddy 的配置更改为请求的 JSON 正文的命名路径。PATCH 严格替换现有值或数组元素。

### 示例

替换监听地址:

<pre><code class="cmd bash">curl -X PATCH \
	-H "Content-Type: application/json" \
	-d '[":8081", ":8082"]' \
	"http://localhost:2019/config/apps/http/servers/myserver/listen"</code></pre>



## DELETE /config/[path]

在命名路径中删除 Caddy 的配置。DELETE 删除目标值。

### 示例

要卸载整个当前配置但保持进程运行:

<pre><code class="cmd bash">curl -X DELETE "http://localhost:2019/config/"</code></pre>

只停止一个 HTTP 服务器:

<pre><code class="cmd bash">curl -X DELETE "http://localhost:2019/config/apps/http/servers/myserver"</code></pre>


<h2 id="using-id-in-json">在JSON中使用`@id`</h2>

你可以在 JSON 文档中嵌入 ID,以便更轻松地直接访问 JSON 的这些部分。

只需添加一个称为`"@id"`对象的字段并为其指定一个唯一名称。例如,如果你有一个想要经常访问的反向代理处理程序:

<pre><code class="cmd json">{
	"@id": "my_proxy",
	"handler": "reverse_proxy"
}</code></pre>

要使用它,只需以与`/config/`相应端点相同的方式向`/id/`API端点发出请求,但无需完整路径。ID 将请求直接带入你的配置范围。

例如,要在没有 ID 的情况下访问反向代理的上游,路径将类似于:

<pre><code class="cmd">/config/apps/http/servers/myserver/routes/1/handle/0/upstreams</code></pre>

但是有了ID,路径就变成了:

<pre><code class="cmd">/id/my_proxy/upstreams</code></pre>

这更容易记忆和手写。

<h2 id="concurrent-config-changes">并发配置更改</h2>

<aside class="tip">
本节适用于所有`/config/`端点。它是实验性的,可能会发生变化。
</aside>

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/&lt;id&gt;
<a name="get-pkicaltidgt"></a>

通过其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/&lt;id&gt;/certificates
<a name="get-pkicaltidgtcertificates"></a>

通过其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
<a name="get-reverse-proxyupstreams"></a>

将配置的反向代理上游(后端)的当前状态作为 JSON 文档返回。

<pre><code class="cmd"><span class="bash">curl "http://localhost:2019/reverse_proxy/upstreams" | jq</span>
[
	{"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}
]</code></pre>

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)。这是你从操作系统启动进程的方式。这里的代码和逻辑数量相当少,并且仅具有以用户所需方式引导核心所需的内容。我们有意避免使用标记和环境变量进行配置,除非它们与引导配置有关。


<aside class="tip">
	模块可以向命令行界面添加子命令。例如,<a href="/docs/command-line#caddy-file-server"><code>caddy file-server</code></a>命令就是从这里来的。这些添加的命令可以使用任何标志或环境变量,尽管核心Caddy命令会尽量减少它们的使用。
</aside>

**[核心库](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 中,称为 _标准模块_。这是是对大多数用户而言最有用的。

<aside class="tip">
	有时术语“模块”、“插件”和“扩展”可以互换使用,通常这是可以的。从技术上讲,所有模块都是插件,但并非所有插件都是模块。模块是一种特定类型的插件,可以扩展Caddy的<a href="/docs/json/">配置结构</a>。
</aside>




## 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()`。


启动应用的模块时,它会初始化应用模块的生命周期。


<aside class="tip">
	如果你是构建 Caddy 模块的程序员,你可以在我们的<a href="/docs/extending-caddy">扩展指南</a>找到类似的信息,但更关注代码。
</aside>


## 模块生命周期

有两种模块:_主机模块_ 和 _访客模块_。


**主机模块**(或“父”模块)是加载其他模块的模块。

**访客模块**(或“子”模块)是那些被加载的模块。所有模块都是访客模块——甚至是应用程序模块。

模块被加载,被配置和验证,被使用,然后被清理,按以下顺序:

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 进程启动时,它通过名称知道每个模块。它甚至可以在模块值和名称之间关联,反之亦然。

<aside class="tip">
	无需修改 Caddy 代码库即可添加插件。<a href="https://github.com/caddyserver/caddy/#with-version-information-andor-plugins">自述</a>文件中有执行此 操作的说明!
</aside>


## 管理配置

由于服务器需要的高并发性和数千个参数,更改正在运行的服务器的活动配置(通常称为“重新加载”)可能会很棘手。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)类似于语言运行时的垃圾收集器的工具来保持全局状态的整洁。

一种明显的在线配置更新方法是同步对每个配置参数的访问,即使在热路径中也是如此。这在性能和复杂性方面非常糟糕——&mdash;尤其&mdash;是在规模上——因此 Caddy 不使用这种方法。

相反,配置被视为不可变的原子单元:要么整个东西被替换,要么什么都没有改变。[管理API端点](/docs/api)&mdash;&mdash;允许通过遍历结构进行精细更改——仅改变配置的内存表示,从中生成并加载一个全新的配置文档。这种方法在简单性、性能和一致性方面具有巨大的优势。由于只有一把锁,Caddy 很容易处理快速重新加载。



================================================
FILE: src/docs/markdown/automatic-https.md
================================================
---
title: "自动HTTPS"
---

# 自动HTTPS

**Caddy是第一个也是唯一一个_默认_自动使用HTTPS的Web服务器。**

自动HTTPS为你的所有站点提供TLS证书并保持更新。它还为你将HTTP重定向到HTTPS!Caddy使用安全且现代的默认设置——无需停机、额外配置或单独的工具。

<aside class="tip">Caddy创新自动HTTPS技术;我们从2015年第一天就开始这样做了。Caddy的HTTPS自动化逻辑是世界上最成熟和最强大的。</aside>

这是一个28秒的视频,展示了它的工作原理:

<iframe width="100%" height="480" src="https://www.youtube-nocookie.com/embed/nk4EWHvvZtI?rel=0" frameborder="0" allowfullscreen=""></iframe>


**菜单:**

- [概览(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根目录的情况下访问该站点的客户端都会显示安全错误。

**对于公共域名:**

<aside class="tip">
    这些是任何基本生产网站的常见要求,而不仅仅是Caddy。主要区别是在运行 Caddy<b>之前</b>正确设置 DNS 记录,以便它可以提供证书。
</aside>

- 如果你的域的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将尝试将其安装到系统的本地信任库中。如果它没有权限这样做,它会提示输入密码。如果不需要,可以在配置中禁用此行为。

<aside class="tip">
只要你的计算机没有受到威胁并且你的唯一根密钥没有泄露,那么在你自己的计算机上信任 Caddy 的根证书是安全的。
</aside>

安装 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 <provider config...>
	ech example.com
}
```

若使用JSON,可在`tls`应用中配置:

```json
"encrypted_client_hello": {
	"configs": [
		{
			"public_name": "example.com"
		}
	]
},
"dns": {
	"name": "<provider 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(见上文)

克隆仓库:

<pre><code class="cmd bash">git clone "https://github.com/caddyserver/caddy.git"</code></pre>

如果你没有git,也可以[从GitHub](https://github.com/caddyserver/caddy)下载源码压缩包。每个[发布版本](https://github.com/caddyserver/caddy/releases)也提供源码快照。

构建:

<pre><code class="cmd"><span class="bash">cd caddy/cmd/caddy/</span>
<span class="bash">go build</span></code></pre>


<aside class="tip">

由于[Go中的一个bug](https://github.com/golang/go/issues/29228),以上基础步骤不会嵌入版本信息。若你需要版本号(`caddy version`),应将Caddy作为依赖而非主模块来编译。具体说明在Caddy的[main.go](https://github.com/caddyserver/caddy/blob/master/cmd/caddy/main.go)文件中。或者可使用[`xcaddy`](#xcaddy)自动处理。

</aside>

Go程序很容易交叉编译到其他平台。只需设置不同的`GOOS`、`GOARCH`和/或`GOARM`环境变量。(详见[go文档](https://golang.org/doc/install/source#environment))

例如,当你当前不在Windows上时,编译Windows版Caddy:

<pre><code class="cmd bash">GOOS=windows go build</code></pre>

类似地,当你当前不在Linux或ARMv6上时,编译Linux ARMv6版:

<pre><code class="cmd bash">GOOS=linux GOARCH=arm GOARM=6 go build</code></pre>



## xcaddy

[`xcaddy`命令](https://github.com/caddyserver/xcaddy)是构建带版本信息和/或插件Caddy的最简单方式。

要求:

- 已安装Go(见上文)
- 确保[`xcaddy`](https://github.com/caddyserver/xcaddy/releases)在你的`PATH`中

你**不需要**下载Caddy源码(它会自动完成)。

然后,构建Caddy(包含版本信息)只需:

<pre><code class="cmd bash">xcaddy build</code></pre>

若要携带插件构建,使用`--with`:

<pre><code class="cmd bash">xcaddy build \
    --with github.com/caddyserver/nginx-adapter
	--with github.com/caddyserver/ntlm-transport@v0.1.1</code></pre>

如你所见,可以通过`@`语法指定插件版本。版本可以是tag名、commit SHA或分支。

使用`xcaddy`的跨平台编译方式与`go`命令一致。例如,为macOS交叉编译:

<pre><code class="cmd bash">GOOS=darwin xcaddy build</code></pre>



## Docker

你可以使用`:builder`镜像,快速构建带自定义模块的新Caddy二进制:

```Dockerfile
FROM caddy:<version>-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:<version>

COPY --from=builder /usr/bin/caddy /usr/bin/caddy
```

请将`<version>`替换为当前最新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`二进制应位于当前目录

流程:
<pre><code class="cmd"><span class="bash">sudo dpkg-divert --divert /usr/bin/caddy.default --rename /usr/bin/caddy</span>
<span class="bash">sudo mv ./caddy /usr/bin/caddy.custom</span>
<span class="bash">sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.default 10</span>
<span class="bash">sudo update-alternatives --install /usr/bin/caddy caddy /usr/bin/caddy.custom 50</span>
<span class="bash">sudo systemctl restart caddy</span>
</code></pre>

说明:

- `dpkg-divert`会把`/usr/bin/caddy`二进制移动到`/usr/bin/caddy.default`,并设置diversion,以防后续软件包再向该路径安装文件。

- `update-alternatives`会创建到`/usr/bin/caddy`的符号链接,指向你期望的caddy二进制。

- `systemctl restart caddy`会停止默认版本Caddy服务并启动自定义版本。

你可以执行下面命令并按屏幕提示,在默认/自定义`caddy`二进制之间切换;完成后重启Caddy服务。

<pre><code class="cmd bash">update-alternatives --config caddy</code></pre>

完成上述配置后,你可运行[`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)


<h2 id="structure">结构</h2>

下面的图片可以直观地描述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文本。


<h2 id="addresses">地址</h2>

地址总是出现在站点块的顶部,并且通常出现在Caddyfile中的第一行。

这些是有效地址的示例:

- `localhost`
- `example.com`
- `:443`
- `http://example.com`
- `localhost:8080`
- `127.0.0.1`
- `[::1]:2015`
- `example.com/foo/*`
- `*.example.com`
- `http://`

<aside class="tip">
    如果你的站点地址包含主机名或 IP 地址,则会启用<a href="/docs/automatic-https">自动HTTPS</a>。然而,这种行为纯粹是隐含的,因此它永远不会覆盖任何显式配置。例如,如果站点的地址是<code>http://example.com</code>,则不会激活自动HTTPS,因为该方案是明确的<code>http://</code>。	
</aside>

从地址中,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
```

请注意逗号如何表示地址的延续。

地址必须是唯一的;你不能多次指定同一个地址。



<h2 id="matchers">匹配器</h2>

默认情况下,注入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
```

完全省略匹配器标记,则可以匹配所有的
Download .txt
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
Download .txt
SYMBOL INDEX (18 symbols across 4 files)

FILE: src/resources/js/common.js
  function isStandard (line 3) | function isStandard(packagePath) {
  function truncate (line 7) | function truncate(str, maxLen) {
  function moduleDocsPreview (line 19) | function moduleDocsPreview(mod, maxLen) {

FILE: src/resources/js/docs-api.js
  function beginRenderingInto (line 160) | function beginRenderingInto($tpl, moduleID, module) {
  function renderData (line 202) | function renderData($tpl, module, data, nesting, path, $group) {
  function renderModuleInlineKey (line 307) | function renderModuleInlineKey($tpl, module, data, nesting, $group) {
  function appendToFieldDocs (line 322) | function appendToFieldDocs($tpl, module, cleanFieldPath, fieldDoc) {
  function indent (line 330) | function indent(nesting, $group) {
  function makeSubmoduleList (line 336) | function makeSubmoduleList(module, path, value) {
  function canTraverse (line 363) | function canTraverse(data) {
  function newGroup (line 367) | function newGroup() {
  function replaceGoTypeNameWithCaddyModuleName (line 371) | function replaceGoTypeNameWithCaddyModuleName(docs, module, moduleID) {
  function markdown (line 388) | function markdown(input) {

FILE: src/resources/js/docs.js
  function hasPrefix (line 2) | function hasPrefix(str, prefix) {
  function addLinksToSubdirectives (line 64) | function addLinksToSubdirectives() {
  function stripScheme (line 75) | function stripScheme(url) {
  function splitTypeName (line 82) | function splitTypeName(fqtn) {

FILE: src/resources/js/json-docs.js
  function setPageTitle (line 28) | function setPageTitle() {
Condensed preview — 116 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (853K chars).
[
  {
    "path": ".gitignore",
    "chars": 40,
    "preview": "_book/\n.*\n!.gitignore\nreferences\nagent/\n"
  },
  {
    "path": "Caddyfile",
    "chars": 498,
    "preview": "http://127.0.0.1:22020\n\nroot * src\n\nfile_server\ntemplates\nencode gzip\n\ntry_files {path}.html {path}\n\nredir   /docs/json "
  },
  {
    "path": "readme.md",
    "chars": 458,
    "preview": "Caddy v2 中文文档\n=================\n\n这是Caddy v2中文文档的网站, [https://caddy2.dengxiaolong.com/](https://caddy2.dengxiaolong.com/d"
  },
  {
    "path": "src/api/docs/config.json",
    "chars": 74743,
    "preview": "{\n  \"status_code\": 200,\n  \"result\": {\n    \"structure\": {\n      \"type\": \"struct\",\n      \"type_name\": \"github.com/caddyser"
  },
  {
    "path": "src/api/modules/index.json",
    "chars": 84280,
    "preview": "{\n  \"status_code\": 200,\n  \"result\": {\n    \"admin.api.load\": [\n      {\n        \"name\": \"admin.api.load\",\n        \"docs\": "
  },
  {
    "path": "src/docs/index.html",
    "chars": 1154,
    "preview": "{{$pathParts := splitList \"/\" .OriginalReq.URL.Path}}\n{{$markdownFilename := default \"index\" (slice $pathParts 2 | join "
  },
  {
    "path": "src/docs/json/index.html",
    "chars": 993,
    "preview": "<!DOCTYPE html>\n<html>\n\t<head>\n\t\t<title>JSON配置结构 - Caddy V2中文文档</title>\n\t\t{{include \"/includes/docs/head.html\"}}\n\t\t<link"
  },
  {
    "path": "src/docs/markdown/api-tutorial.md",
    "chars": 4457,
    "preview": "---\ntitle: \"API教程\"\n---\n\n# API教程\n\n本教程将向你展示如何使用Caddy的[管理API](/docs/api),这使得以可编程方式实现自动化成为可能。\n\n**目标:**\n- 🔲 运行守护程序\n- 🔲 给 Cadd"
  },
  {
    "path": "src/docs/markdown/api.md",
    "chars": 9315,
    "preview": "---\ntitle: \"API\"\n---\n\n# API\n\nCaddy是通过管理端点进行配置的,该端点可以使用[REST](https://en.wikipedia.org/wiki/Representational_state_transf"
  },
  {
    "path": "src/docs/markdown/architecture.md",
    "chars": 4225,
    "preview": "---\ntitle: 架构\n---\n\n架构\n============\n\nCaddy 是一个单一的、自包含的、静态的二进制文件,外部依赖项为零,因为它是用 Go 编写的。这些价值观构成了项目愿景的重要组成部分,因为它们简化了部署并减少了生产环"
  },
  {
    "path": "src/docs/markdown/automatic-https.md",
    "chars": 10499,
    "preview": "---\ntitle: \"自动HTTPS\"\n---\n\n# 自动HTTPS\n\n**Caddy是第一个也是唯一一个_默认_自动使用HTTPS的Web服务器。**\n\n自动HTTPS为你的所有站点提供TLS证书并保持更新。它还为你将HTTP重定向到H"
  },
  {
    "path": "src/docs/markdown/build.md",
    "chars": 4074,
    "preview": "---\ntitle: 从源码构建\n---\n\n# 从源码构建\n\n如果你需要自定义构建(例如带插件),构建Caddy有多种方式:\n- [Git](#git):从Git仓库构建\n- [`xcaddy`](#xcaddy):使用`xcaddy`构建"
  },
  {
    "path": "src/docs/markdown/caddyfile/concepts.md",
    "chars": 7754,
    "preview": "---\ntitle: Caddyfile概念\n---\n\n# Caddyfile概念\n\n本文档将帮助你详细了解HTTP Caddyfile。\n\n1. [结构](#structure)\n2. [地址](#addresses)\n3. [匹配器]("
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/abort.md",
    "chars": 362,
    "preview": "---\ntitle: abort (Caddyfile指令)\n---\n\n# abort\n\n通过立即中止HTTP处理链和关闭连接,阻止对客户端的任何响应。同一连接上的任何并发的、活动的HTTP流都会被中断。\n\n\n## 语法\n\n```caddy"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/acme_server.md",
    "chars": 2051,
    "preview": "---\ntitle: acme_server (Caddyfile指令)\n---\n\n# acme_server\n\n一个嵌入式[ACME协议](https://tools.ietf.org/html/rfc8555)服务器处理程序。这允许一个"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/basic_auth.md",
    "chars": 1505,
    "preview": "---\ntitle: basic_auth (Caddyfile指令)\n---\n\n# basic_auth\n\n启用 HTTP 基本身份验证,可用于使用用户名和散列密码保护目录和文件。\n\n**请注意,基本身份验证在普通 HTTP 上并不安全。"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/bind.md",
    "chars": 1120,
    "preview": "---\ntitle: bind (Caddyfile指令)\n---\n\n# bind\n\n指定服务器的套接字绑定的接口。通常情况下,监听器会绑定到空(通配符)接口。然而,你可以强制监听器绑定到另一个主机名或IP。(这个指令只接受一个主机,而不能"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/encode.md",
    "chars": 3109,
    "preview": "---\ntitle: encode (Caddyfile指令)\n---\n\n<script>\nready(function() {\n// We'll add links to all the subdirectives if a matchi"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/error.md",
    "chars": 759,
    "preview": "---\ntitle: error (Caddyfile 指令)\n---\n\n# error\n\n触发HTTP处理链中的一个错误,有一个可选的消息和推荐的HTTP状态码。\n\n这个处理程序并不会输出响应。相反,它应该与[`handle_errors"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/file_server.md",
    "chars": 4792,
    "preview": "---\ntitle: file_server(Caddyfile指令)\n---\n\n<script>\nready(function() {\n\t// 修正行内browse参数的高亮,并链接到browse小节。\n\tfor (let item of"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/forward_auth.md",
    "chars": 3482,
    "preview": "---\ntitle: forward_auth (Caddyfile指令)\n---\n\n<script>\nready(function() {\n// Fix > in code blocks\n$$_('pre.chroma .k').forE"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/fs.md",
    "chars": 683,
    "preview": "---\ntitle: fs (Caddyfile指令)\n---\n\n# fs\n\n设置执行文件 I/O 时应使用哪个文件系统。\n\n这可以让你连接到云端运行的远程文件系统、具有类文件接口的数据库,甚至读取嵌入到 Caddy 二进制文件中的文件。\n"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/handle.md",
    "chars": 1352,
    "preview": "---\ntitle: handle (Caddyfile指令)\n---\n\n# handle\n\n评估一组指令,这些指令与同级嵌套的其他`handle`块相互排斥。\n\n换句话说,当多个`handle`指令连续出现时,只会评估第一个_匹配_的`h"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/handle_errors.md",
    "chars": 2732,
    "preview": "---\ntitle: handle_errors (Caddyfile指令)\n---\n\n# handle_errors\n\n设置错误处理程序。\n\n当正常的HTTP请求处理程序返回错误时,正常处理会停止,错误处理程序会被调用。错误处理程序形成一"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/handle_path.md",
    "chars": 1560,
    "preview": "---\ntitle: handle_path (Caddyfile指令)\n---\n\n<script>\nready(function() {\n// Add a link to [<path_matcher>] as a special cas"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/header.md",
    "chars": 3724,
    "preview": "---\ntitle: header (Caddyfile directive)\n---\n\n# header\n\n操作 HTTP 响应标头字段。它可以设置、添加和删除标头值,或使用正则表达式执行替换。\n\n默认情况下,除非删除任何标头(`-`前缀"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/import.md",
    "chars": 2831,
    "preview": "---\ntitle: import (Caddyfile directive)\n---\n\n# import\n\n包含[snippet](/docs/caddyfile/concepts#snippets)或文件,将此指令替换为代码片段或文件的"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/intercept.md",
    "chars": 3017,
    "preview": "---\ntitle: intercept (Caddyfile指令)\n---\n\n<script>\nready(function() {\n\t// Fix response matchers to render with the right c"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/invoke.md",
    "chars": 978,
    "preview": "---\ntitle: invoke (Caddyfile指令)\n---\n\n# invoke\n\n<i>⚠️ 实验性</i>\n\n调用一个[命名路由](/docs/caddyfile/concepts#named-routes)。\n\n当与拥有自身"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/log.md",
    "chars": 14594,
    "preview": "---\ntitle: log (Caddyfile directive)\n---\n\n<script>\nready(function() {\n\t// Fix > in code blocks\n\t$$_('pre.chroma .k').for"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/log_append.md",
    "chars": 1953,
    "preview": "---\ntitle: log_append (Caddyfile指令)\n---\n\n# log_append\n\n为当前请求的访问日志追加一个字段。\n\n此指令应与 [`log` 指令](log)一起使用,因为首先需要 `log` 启用访问日志。"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/log_name.md",
    "chars": 743,
    "preview": "---\ntitle: log_name (Caddyfile指令)\n---\n\n# log_name\n\n在使用 [`log` 指令](log)写入访问日志时,覆盖当前请求要使用的日志器名称。\n\n当你想根据请求路径或方法等条件,将请求记录到不同"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/log_skip.md",
    "chars": 627,
    "preview": "---\ntitle: log_skip (Caddyfile指令)\n---\n\n# log_skip\n\n对匹配的请求跳过访问日志记录。\n\n此指令应与 [`log` 指令](log)一起使用,用于跳过那些与你需求无关的请求日志。\n\n在 v2.8"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/map.md",
    "chars": 1810,
    "preview": "---\ntitle: map (Caddyfile指令)\n---\n\n# map\n\n设置根据输入值进行切换的自定义占位符的值。\n\n它将源值与映射的输入端进行比较,如果匹配,则将输出值应用到每个目标。目标则替换成对应的占位符。也可以为每个目标指"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/method.md",
    "chars": 220,
    "preview": "---\ntitle: method (Caddyfile指令)\n---\n\n# method\n\n改变请求中的HTTP方法。\n\n\n## 语法\n\n```caddy-d\nmethod [<matcher>] <method>.\n```\n\n- **&"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/metrics.md",
    "chars": 870,
    "preview": "---\ntitle: metrics (Caddyfile指令)\n---\n\n# metrics\n\n配置一个Prometheus度量标准展示端点,这样采集的指标可以被暴露出来以供抓取。\n\n注意,[admin API](/docs/api)上也"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/php_fastcgi.md",
    "chars": 5917,
    "preview": "---\ntitle: php_fastcgi (Caddyfile directive)\n---\n\n<script>\nready(function() {\n\t// We'll add links to all the subdirectiv"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/push.md",
    "chars": 1093,
    "preview": "---\ntitle: push (Caddyfile指令)\n---\n\n# push\n\n配置服务器使用HTTP/2服务器预先向客户端推送资源。\n\n通过指定响应的Link头,可以为服务器推送资源提供链接。这条指令将自动推送由上游Link头描述的"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/redir.md",
    "chars": 738,
    "preview": "---\ntitle: redir (Caddyfile指令)\n---\n\n# redir\n\n向客户发出一个HTTP重定向。\n\n这条指令意味着一个匹配的请求将被拒绝。它在处理程序链中被安排在很早的位置(在[`rewrite`](/docs/ca"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/request_body.md",
    "chars": 865,
    "preview": "---\ntitle: request_body (Caddyfile指令)\n---\n\n# request_body\n\n操作或设置对传入请求正文的限制。\n\n## 语法\n\n```caddy-d\nrequest_body [<matcher>] "
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/request_header.md",
    "chars": 538,
    "preview": "---\ntitle: request_header (Caddyfile指令)\n---\n\n# request_header\n\n处理请求中的HTTP标头字段。它可以设置、添加和删除标头值,或使用正则表达式执行替换。\n\n## Syntax\n\n`"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/respond.md",
    "chars": 1286,
    "preview": "---\ntitle: respond (Caddyfile指令)\n---\n\n# respond\n\n写一个硬编码/静态响应给客户端。\n\n如果响应体非空,此指令会在尚未设置`Content-Type`头时设置它。默认值是`text/plain;"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/reverse_proxy.md",
    "chars": 28885,
    "preview": "---\ntitle: reverse_proxy (Caddyfile directive)\n---\n\n<script>\nready(function() {\n\t// Fix response matchers to render with"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/rewrite.md",
    "chars": 1555,
    "preview": "---\ntitle: rewrite (Caddyfile指令)\n---\n\n# rewrite\n\n对请求进行内部重写。重写会改变请求URI的部分或全部内容。请注意,URI不包括方案或授权(主机和端口),而且客户通常不发送片段。因此,这个指令"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/root.md",
    "chars": 1154,
    "preview": "---\ntitle: root (Caddyfile指令)\n---\n\n# root\n\n设置网站的根路径,由各种匹配器和访问文件系统的指令使用。如果不设置,默认的网站根目录是当前工作目录。\n\n具体来说,这个指令设置了`{http.vars.r"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/route.md",
    "chars": 1738,
    "preview": "---\ntitle: route (Caddyfile指令)\n---\n\n# route\n\n将一组指令按字面意思作为一个单元进行评估。\n\n路由块中包含的指令不会在内部被重新排序。只有HTTP处理指令(将处理程序或中间件添加到链中的指令)可以在"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/templates.md",
    "chars": 1597,
    "preview": "---\ntitle: templates (Caddyfile指令)\n---\n\n# templates\n\n将响应体作为[template](/docs/modules/http.handlers.templates)文件执行。模板提供了制作"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/tls.md",
    "chars": 18138,
    "preview": "---\ntitle: tls (Caddyfile指令)\n---\n\n<script>\nready(function() {\n\t// We'll add links to all the subdirectives if a matching"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/tracing.md",
    "chars": 1182,
    "preview": "---\ntitle: tracing (Caddyfile指令)\n---\n\n# tracing\n\n它提供了与OpenTelemetry追踪设施的整合。\n\n当启用时,它将传播一个现有的跟踪上下文或初始化一个新的。\n\n它基于[github.co"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/try_files.md",
    "chars": 1368,
    "preview": "---\ntitle: try_files (Caddyfile指令)\n---\n\n# try_files\n\n将请求URI路径重写为站点根目录中存在的第一个列出的文件。如果没有文件匹配,则不执行重写。\n\n\n## 语法\n\n```caddy-d\nt"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/uri.md",
    "chars": 2929,
    "preview": "---\ntitle: uri (Caddyfile指令)\n---\n\n# uri\n\n操作请求的URI。它可以剥离路径前缀/后缀,或替换整个URI中的子串。\n\n此指令不同于[`rewrite`](rewrite):`uri`是对URI做差异化修"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives/vars.md",
    "chars": 768,
    "preview": "---\ntitle: vars (Caddyfile指令)\n---\n\n# vars\n\n将一个或多个变量设置为一个特定的值,以便在以后的请求处理链中使用。\n\n访问变量的主要方式是使用占位符,其形式为`{vars.variable_name}`"
  },
  {
    "path": "src/docs/markdown/caddyfile/directives.md",
    "chars": 5239,
    "preview": "---\ntitle: Caddyfile指令\n---\n\n<style>\n#directive-table table {\n\tmargin: 0 auto;\n\toverflow: hidden;\n}\n\n#directive-table tr:"
  },
  {
    "path": "src/docs/markdown/caddyfile/matchers.md",
    "chars": 8510,
    "preview": "---\ntitle: 请求匹配器\n---\n\n# 请求匹配器\n\n**请求匹配器** 可用于按特定标准过滤(或分类)请求。\n\n### 菜单\n\n- [语法](#syntax)\n    - [例子](#examples)\n    - [通配符匹配器"
  },
  {
    "path": "src/docs/markdown/caddyfile/options.md",
    "chars": 8341,
    "preview": "---\ntitle: 全局选项\n---\n\n<script>\n$(function() {\n\t// We'll add links on the options in the code block at the top\n\t// to thei"
  },
  {
    "path": "src/docs/markdown/caddyfile/patterns.md",
    "chars": 4171,
    "preview": "---\ntitle: 常见Caddyfile模式\n---\n\n# 常见Caddyfile模式\n\n此页面演示了一些用于常见用例的完整和最小的Caddyfile配置。这些可能是你自己的Caddyfile文档的有用起点。\n\n这些不是即插即用的解决方"
  },
  {
    "path": "src/docs/markdown/caddyfile/response-matchers.md",
    "chars": 2357,
    "preview": "---\ntitle: 响应匹配器(Caddyfile)\n---\n\n<script>\nready(function() {\n\t// Response matchers\n\t$$_('pre.chroma .nd').forEach(item ="
  },
  {
    "path": "src/docs/markdown/caddyfile/spec.md",
    "chars": 10234,
    "preview": "---\ntitle: Caddyfile Spec\n---\n\nTODO: this page is unfinished\n\n<style>\n\t\n</style>\n\n# Caddyfile Specification\n\nThis page d"
  },
  {
    "path": "src/docs/markdown/caddyfile-tutorial.md",
    "chars": 4745,
    "preview": "---\ntitle: Caddyfile教程\n---\n\n# Caddyfile教程\n\n本教程将教你[HTTP Caddyfile](/docs/caddyfile)的基础知识,以便你可以快速轻松地生成美观、功能强大的站点配置。\n\n**目标:"
  },
  {
    "path": "src/docs/markdown/caddyfile.md",
    "chars": 972,
    "preview": "---\ntitle: Caddyfile\n---\n\n# Caddyfile\n\n**Caddyfile**是一种方便用户使用的Caddy配置格式。这是大多数人最喜欢使用Caddy的方式,因为它易于编写、易于理解,且能满足绝大部分的使用场景。\n"
  },
  {
    "path": "src/docs/markdown/command-line.md",
    "chars": 8073,
    "preview": "# 命令行\n\nCaddy有一个标准的类unix命令行接口,基本用法如下:\n\n```bash\ncaddy <command> [<args...>]\n```\n\n- `<>`代表要被你输入替换参数。\n- `[]`代表可选的参数。\n- `...`"
  },
  {
    "path": "src/docs/markdown/config-adapters.md",
    "chars": 1712,
    "preview": "---\ntitle: 配置适配器\n---\n\n# 配置适配器\n\nCaddy 的原生配置语言是[JSON](https://www.json.org/json-en.html),但手动编写 JSON 可能很乏味且容易出错。这就是Caddy支持通"
  },
  {
    "path": "src/docs/markdown/conventions.md",
    "chars": 3425,
    "preview": "---\ntitle: 约定\n---\n\n# 约定\n\nCaddy生态系统遵循一些约定,以使整个平台的事情保持一致和直观。\n\n\n## 网络地址\n\n指定要拨号或绑定的网络地址时,Caddy接受以下格式的字符串:\n\n```\nnetwork/addre"
  },
  {
    "path": "src/docs/markdown/examples.md",
    "chars": 174,
    "preview": "示例\n========\n\n这个页面后续可能会建设成一个由社区共同维护的示例集合。当前请先参考我们社区论坛Wiki中的示例:\n\n- [论坛Wiki示例](https://caddy.community/c/wiki/13)\n- [按关键字搜索"
  },
  {
    "path": "src/docs/markdown/extending-caddy/caddyfile.md",
    "chars": 4574,
    "preview": "---\ntitle: Caddyfile支持\n---\n\n# Caddyfile支持\n\nCaddy模块在[注册](https://pkg.go.dev/github.com/caddyserver/caddy/v2?tab=doc#Regis"
  },
  {
    "path": "src/docs/markdown/extending-caddy/config-adapters.md",
    "chars": 1883,
    "preview": "---\ntitle: 编写配置适配器\n---\n\n# 编写配置适配器\n\n由于各种原因,你可能希望使用一种不是[JSON](/docs/json/)的格式来配置Caddy。Caddy通过[配置适配器](/docs/config-adapters"
  },
  {
    "path": "src/docs/markdown/extending-caddy/namespaces.md",
    "chars": 5325,
    "preview": "---\ntitle: \"模块命名空间\"\n---\n\n# 模块命名空间\n\nCaddy的客户端模块以`interface{}`或`any`类型进行通用加载。为了使主机模块能够使用它们,加载的客户端模块通常首先进行已知类型的类型断言。本页面描述了所"
  },
  {
    "path": "src/docs/markdown/extending-caddy/placeholders.md",
    "chars": 2517,
    "preview": "---\ntitle: \"占位符支持\"\n---\n\n# 占位符\n\n在Caddy中,占位符由各个插件按需处理;它们不会在所有地方自动生效。\n\n这意味着如果你希望自己的插件支持占位符,就必须显式实现这项支持。\n\n如果你还不熟悉占位符,请先阅读[这里"
  },
  {
    "path": "src/docs/markdown/extending-caddy.md",
    "chars": 10080,
    "preview": "---\ntitle: 扩展Caddy\n---\n\n# 扩展Caddy\n\nCaddy很容易扩展,因为它是模块化结构。大多数类型的Caddy扩展(或插件)被称为_modules_,如果它们扩展或插入Caddy的配置结构。为了清楚起见,Caddy的"
  },
  {
    "path": "src/docs/markdown/faq.md",
    "chars": 67,
    "preview": "常见问题\n===\n\n这个页面目前仍在建设中(就像90年代网站常见的“under construction”页面)。请稍后再来查看!\n\n"
  },
  {
    "path": "src/docs/markdown/getting-started.md",
    "chars": 5364,
    "preview": "---\ntitle: 入门指南\n---\n\n# 入门指南\n\n欢迎使用Caddy!本教程会带你了解使用Caddy的基础,并在较高层次上建立整体认知。\n\n**目标:**\n- 🔲 运行守护进程\n- 🔲 体验API\n- 🔲 给Caddy加载配置\n- "
  },
  {
    "path": "src/docs/markdown/index.md",
    "chars": 1187,
    "preview": "---\ntitle: 欢迎\n---\n\n# 欢迎使用Caddy\n\nCaddy是一款基于Go语言编写的强大且可扩展的平台,可以给你的站点、服务和应用程序提供服务。如果你是Caddy的新手,那么你提供Web服务的方式即将改变。\n\n## 介绍\n大多"
  },
  {
    "path": "src/docs/markdown/install.md",
    "chars": 7699,
    "preview": "---\ntitle: 安装\n---\n\n# 安装\n\n本页介绍了在你的系统上安装Caddy的多种方式。\n\n**官方维护:**\n\n- [静态二进制文件](#static-binaries)\n- [Debian、Ubuntu、Raspbian软件包"
  },
  {
    "path": "src/docs/markdown/json.md",
    "chars": 561,
    "preview": "<div id=\"json-docs-container\" class=\"fullspan\">\n\t<div class=\"breadcrumbs\">\n\t\t<!--由JS填充-->\n\t</div>\n\t{{include \"/includes/"
  },
  {
    "path": "src/docs/markdown/logging.md",
    "chars": 4153,
    "preview": "---\ntitle: 日志如何工作\n---\n\n日志如何工作\n=================\n\nCaddy 具有强大而灵活的日志记录工具,但它们可能与你习惯的不同,特别是如果你来自更古老的共享主机或其他旧式 Web 服务器。\n\n## 概述"
  },
  {
    "path": "src/docs/markdown/metrics.md",
    "chars": 6265,
    "preview": "---\ntitle: 使用Prometheus监控Caddy\n---\n\n# 使用Prometheus监控Caddy\n\n无论你是在云中运行数千个Caddy实例,还是在嵌入式设备上运行单个Caddy服务器,在某些时候你可能希望对Caddy正在做"
  },
  {
    "path": "src/docs/markdown/modules.md",
    "chars": 766,
    "preview": "<div id=\"module-list-container\">\n\t<h1>全部模块</h1>\n\t<p>\n\t\t本页列出所有已注册的Caddy模块。模块是用于扩展Caddy<a href=\"/docs/json\">JSON配置结构</a>的插"
  },
  {
    "path": "src/docs/markdown/profiling.md",
    "chars": 4467,
    "preview": "---\ntitle: Caddy性能剖析\n---\n\nCaddy性能剖析\n================\n\n**程序剖析(profile)**是程序运行时资源使用情况的快照。它对定位问题区域、排查bug/崩溃、优化代码非常有帮助。\n\nCad"
  },
  {
    "path": "src/docs/markdown/quick-starts/api.md",
    "chars": 2167,
    "preview": "---\ntitle: API快速入门\n---\n\n# API快速入门\n\n**前提条件:**\n- 基本的终端/命令行技能\n- `caddy`和`curl`已在你的PATH中\n\n---\n\n先启动Caddy:\n\n<pre><code class=\""
  },
  {
    "path": "src/docs/markdown/quick-starts/caddyfile.md",
    "chars": 1776,
    "preview": "---\ntitle: Caddyfile 快速入门\n---\n\n# Caddyfile 快速入门\n\n创建一个名为Caddyfile(无扩展名)的新文本文件。\n\n最先在Caddyfile输入的内容是你的站点访问地址:\n\n```caddy\nloc"
  },
  {
    "path": "src/docs/markdown/quick-starts/https.md",
    "chars": 1901,
    "preview": "---\ntitle: HTTPS快速入门\n---\n\n# HTTPS快速入门\n\n本指南将向你展示如何立即启动并运行[完全托管的HTTPS](/docs/automatic-https)。\n\n<aside class=\"tip\">\n    Ca"
  },
  {
    "path": "src/docs/markdown/quick-starts/railway.md",
    "chars": 1688,
    "preview": "---\ntitle: Railway快速入门\n---\n\n# Railway快速入门\n\n在Railway上部署Caddy是一种简单、无负担的方式,可部署带插件的自定义Caddy构建。\n\n**前置条件:**\n- 一个免费的[Railway](h"
  },
  {
    "path": "src/docs/markdown/quick-starts/reverse-proxy.md",
    "chars": 2511,
    "preview": "---\ntitle: 反向代理快速入门\n---\n\n# 反向代理快速入门\n\n本指南将向你展示如何快速启动并运行可用于生产的反向代理。\n\n**先决条件:**\n- 基本的终端/命令行技能\n- PATH变量支持`caddy`\n- 要代理到的正在运行"
  },
  {
    "path": "src/docs/markdown/quick-starts/static-files.md",
    "chars": 1260,
    "preview": "---\ntitle: 静态文件快速入门\n---\n\n# 静态文件快速入门\n\n本指南将向你展示如何快速启动并运行可用于生产的静态文件服务器。\n\n**先决条件:**\n- 基本的终端/命令行技能\n- PATH变量包含`caddy`\n- 包含你的网站"
  },
  {
    "path": "src/docs/markdown/quick-starts.md",
    "chars": 351,
    "preview": "---\ntitle: 快速入门\n---\n\n# 快速入门\n\n这些教程的目的是让你能快速上手并运行,而不需要做太多的解释。\n\n强烈建议你继续阅读其他教程和参考文档,以完全理解web服务器的工作方式。\n\n## 菜单\n\n* [使用API](/doc"
  },
  {
    "path": "src/docs/markdown/running.md",
    "chars": 5755,
    "preview": "---\ntitle: 保持Caddy运行\n---\n\n# 保持Caddy运行\n\n虽然Caddy可以通过直接使用它的[命令行界面](/docs/command-line)成功运行,但使用服务管理器来保持它的运行有很多好处,例如确保它在系统启动时"
  },
  {
    "path": "src/docs/markdown/signature-verification.md",
    "chars": 3012,
    "preview": "---\ntitle: 验证构件签名\n---\n\n# 签名验证\n\n构件签名可用于验证你拿到的构件是否与项目工作流生成的一致,以及是否被未授权方篡改(例如中间人攻击)。这能让所有参与方确认自己讨论的是同一个字节集合(可执行文件、SBOM、文本文件"
  },
  {
    "path": "src/docs/markdown/troubleshooting.md",
    "chars": 1776,
    "preview": "故障排查策略\n=====================\n\n本页给出一套通用、系统化的方法,帮助你在使用Caddy时自行解决大多数问题(不依赖AI)。当你在论坛求助时,我们也建议采用类似步骤。很多情况下,通过严谨思考,你可以自己回答问题或修"
  },
  {
    "path": "src/docs/markdown/v2-upgrade.md",
    "chars": 9310,
    "preview": "---\ntitle: 升级到Caddy 2\n---\n\n升级指南\n=============\n\n为了改进Caddy 1,Caddy 2从头开始编码,是一个全新的代码库。Caddy 2不向后兼容Caddy 1。但也不用太担心,大多数基本设置其实"
  },
  {
    "path": "src/docs/modules/index.html",
    "chars": 2085,
    "preview": "<!DOCTYPE html>\n<html>\n<head>\n    <title>模块 - Caddy V2中文文档</title>\n    {{include \"/includes/docs/head.html\"}}\n    <link "
  },
  {
    "path": "src/includes/docs/details.html",
    "chars": 862,
    "preview": "<div>\n    <div class=\"nonstandard-notice\">\n        <b>This module does not come with Caddy.</b> It can be added by using"
  },
  {
    "path": "src/includes/docs/head.html",
    "chars": 514,
    "preview": "{{include \"/includes/head.html\"}}\n<link rel=\"stylesheet\" href=\"/resources/css/docs.css\">\n<link rel=\"stylesheet\" href=\"/r"
  },
  {
    "path": "src/includes/docs/header.html",
    "chars": 712,
    "preview": "<header>\n\n    <div>\n        <div id=\"logo-container\">\n            <a href=\"/\"><img src=\"/resources/images/caddy-wordmark"
  },
  {
    "path": "src/includes/docs/hovercard.html",
    "chars": 779,
    "preview": "<div id=\"hovercard\" class=\"arrow-box\">\n    <div id=\"hovercard-docs\" class=\"hovercard-elem\"><!--Populated by JS--></div>\n"
  },
  {
    "path": "src/includes/docs/nav.html",
    "chars": 3386,
    "preview": "<nav class=\"sidebar\">\n    <ul>\n        <li><a href=\"/docs/\">欢迎</a></li>\n        <li><a href=\"https://caddy.community/c/w"
  },
  {
    "path": "src/includes/docs/renderbox.html",
    "chars": 69,
    "preview": "<pre><code class=\"json renderbox\"><!--Populated by JS--></code></pre>"
  },
  {
    "path": "src/includes/donate.html",
    "chars": 4602,
    "preview": "<style>\n    #donate-modal-container{position:fixed;height:100%;width:100%;top:0;left:0;z-index:999;transform:scale(0)}#d"
  },
  {
    "path": "src/includes/footer.html",
    "chars": 603,
    "preview": "<div class=\"wrapper\">\n    <footer>\n        <div>\n            <img src=\"/resources/images/caddy-logo.svg\" alt=\"Caddy\" id="
  },
  {
    "path": "src/includes/head.html",
    "chars": 738,
    "preview": "<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<link rel=\"icon\" href=\"/re"
  },
  {
    "path": "src/index.html",
    "chars": 25,
    "preview": "<a href=\"/docs/\">docs</a>"
  },
  {
    "path": "src/resources/321140.cast",
    "chars": 13256,
    "preview": "{\"version\": 2, \"width\": 79, \"height\": 20, \"timestamp\": 1587149050, \"env\": {\"SHELL\": \"/bin/zsh\", \"TERM\": \"xterm-256color\""
  },
  {
    "path": "src/resources/css/account/common.css",
    "chars": 3638,
    "preview": "* {\n\tmargin: 0;\n\tpadding: 0;\n\tbox-sizing: border-box;\n}\n\nhtml, body {\n\tmin-height: 100%;\n}\n\nhtml {\n\t/* by setting the mi"
  },
  {
    "path": "src/resources/css/account/dashboard.css",
    "chars": 183,
    "preview": "input[name=path] {\n\tfont-size: 14px;\n\tpadding: 4px;\n\tborder-radius: 4px;\n\twidth: auto;\n\t/* max-width: 450px; */\n\tmax-wid"
  },
  {
    "path": "src/resources/css/asciinema-player-2.6.1.css",
    "chars": 50722,
    "preview": ".asciinema-player-wrapper {\n  position: relative;\n  text-align: center;\n  outline: none;\n}\n.asciinema-player-wrapper .ti"
  },
  {
    "path": "src/resources/css/chroma.css",
    "chars": 7911,
    "preview": "/*\n\tDerived from https://gist.github.com/nicolashery/5765395\n\tAdjusted to be high-contrast\n*/\n\n\n/*\n\tSolarized Light (Hig"
  },
  {
    "path": "src/resources/css/common.css",
    "chars": 3667,
    "preview": "* {\n\tmargin: 0;\n\tpadding: 0;\n\tbox-sizing: border-box;\n}\n\nbody {\n\tfont-family: Inter, sans-serif;\n\t-webkit-font-smoothing"
  },
  {
    "path": "src/resources/css/docs-json.css",
    "chars": 381,
    "preview": "article {\n\tpadding-top: 0 !important;\n}\n\narticle h1 {\n\tpadding-top: 8%;\n}\n\n.renderbox {\n\tborder-radius: 0;\n\tfont-size: 2"
  },
  {
    "path": "src/resources/css/docs.css",
    "chars": 20914,
    "preview": "body {\n\tfont-family: Maven Pro, sans-serif;\n\tbackground: #f1f4f5;\n}\n\nheader {\n\tpadding: 20px 40px;\n}\n\n#logo-container {\n"
  },
  {
    "path": "src/resources/css/download.css",
    "chars": 4023,
    "preview": "body {\n\tbackground-color: #f0f6f9;\n}\n\n.download-bar {\n\tdisplay: flex;\n\tjustify-content: space-between;\n\tbackground: whit"
  },
  {
    "path": "src/resources/css/home.css",
    "chars": 4176,
    "preview": "body {\n\tfont-family: 'Inter', sans-serif;\n}\n\n.hero {\n\tbackground-repeat: no-repeat;\n\tbackground-size: cover;\n\tpadding-bo"
  },
  {
    "path": "src/resources/css/v2-landing.css",
    "chars": 5725,
    "preview": "body {\n\tbackground: #fcfcfc;\n}\n\n#v2logo {\n\twidth: 100%;\n\tmax-width: 600px;\n\tmargin: 100px auto 0;\n\tdisplay: block;\n}\n\nse"
  },
  {
    "path": "src/resources/js/common.js",
    "chars": 717,
    "preview": "const caddyImportPath = 'github.com/caddyserver/caddy/v2';\n\nfunction isStandard(packagePath) {\n\treturn packagePath.start"
  },
  {
    "path": "src/resources/js/docs-api.js",
    "chars": 13406,
    "preview": "// TODO: sanitize all HTML renderings, especially markdown: https://github.com/cure53/DOMPurify\n\nvar pageDocs = {};\nvar "
  },
  {
    "path": "src/resources/js/docs.js",
    "chars": 3676,
    "preview": "$(function() {\n\tfunction hasPrefix(str, prefix) {\n\t\tif (!prefix) return true;\n\t\tif (!str)    return false;\n\t\treturn str."
  },
  {
    "path": "src/resources/js/json-docs.js",
    "chars": 1520,
    "preview": "const jsonDocsPathPrefix = \"/docs/json/\";\n\nvar configPath = window.location.pathname.substr(jsonDocsPathPrefix.length-1)"
  },
  {
    "path": "src/resources/js/module-docs.js",
    "chars": 3100,
    "preview": "const moduleDocsPathPrefix = \"/docs/modules/\";\n\nvar moduleID = window.location.pathname.substr(moduleDocsPathPrefix.leng"
  }
]

About this extraction

This page contains the full source code of the phpple/caddy2-cn-doc GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 116 files (608.3 KB), approximately 223.9k tokens, and a symbol index with 18 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!