# Copyright (c) 2017-2022 Cloudflare, Inc. # Licensed under the Apache 2.0 license found in the LICENSE file or at: # https://opensource.org/licenses/Apache-2.0 @0xe6afd26682091c01; # This file defines the schema for configuring the workerd runtime. # # A config file can be written as a `.capnp` file that imports this file and then defines a # constant of type `Config`. Alternatively, various higher-level tooling (e.g. wrangler) may # generate configs for you, outputting a binary Cap'n Proto file. # # To start a server with a config, do: # # workerd serve my-config.capnp constantName # # You can also build a new self-contained binary which combines the `workerd` binary with your # configuration and all your source code: # # workerd compile my-config.capnp constantName -o my-server-bin # # This binary can then be run stand-alone. # # A common theme in this configuration is capability-based design. We generally like to avoid # giving a Worker the ability to access external resources by name, since this makes it hard # to see and restrict what each Worker can access. Instead, the default is that a Worker has # access to no privileged resources at all, and you must explicitly declare "bindings" to give # it access to specific resources. A binding gives the Worker a JavaScript API object that points # to a specific resource. This means that by changing config alone, you can fully control which # resources an Worker connects to. (You can even disallow access to the public internet, although # public internet access is granted by default.) # # This config format is fairly powerful, allowing you to do things like define a TLS-terminating # reverse proxy server without using any actual JavaScript code. However, you should not be # afraid to fall back to code for anything the config cannot express, as Workers are very fast # to execute! # Any capnp files imported here must be: # 1. embedded into workerd-meta.capnp # 2. added to `tryImportBulitin` in workerd.c++ (grep for '"/workerd/workerd.capnp"'). using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("workerd::server::config"); $Cxx.allowCancellation; struct Config { # Top-level configuration for a workerd instance. services @0 :List(Service); # List of named services defined by this server. These names are private; they are only used # to refer to the services from elsewhere in this config file, as well as for logging and the # like. Services are not reachable until you configure some way to make them reachable, such # as via a Socket. # # If you do not define any service called "internet", one is defined implicitly, representing # the ability to access public internet servers. An explicit definition would look like: # # ( name = "internet", # network = ( # allow = ["public"], # Allows connections to publicly-routable addresses only. # tlsOptions = (trustBrowserCas = true) # ) # ) # # The "internet" service backs the global `fetch()` function in a Worker, unless that Worker's # configuration specifies some other service using the `globalOutbound` setting. sockets @1 :List(Socket); # List of sockets on which this server will listen, and the services that will be exposed # through them. v8Flags @2 :List(Text); # List of "command-line" flags to pass to V8, like "--expose-gc". We put these in the config # rather than on the actual command line because for most use cases, managing these via the # config file is probably cleaner and easier than passing on the actual CLI. # # WARNING: Use at your own risk. V8 flags can have all sorts of wild effects including completely # breaking everything. V8 flags also generally do not come with any guarantee of stability # between V8 versions. Most users should not set any V8 flags. extensions @3 :List(Extension); # Extensions provide capabilities to all workers. Extensions are usually prepared separately # and are late-linked with the app using this config field. autogates @4 :List(Text); # A list of gates which are enabled. # These are used to gate features/changes in workerd and in our internal repo. See the equivalent # config definition in our internal repo for more details. } # ======================================================================================== # Sockets struct Socket { name @0 :Text; # Each socket has a unique name which can be used on the command line to override the socket's # address with `--socket-addr <name>=<addr>` or `--socket-fd <name>=<fd>`. address @1 :Text; # Address/port on which this socket will listen. Optional; if not specified, then you will be # required to specify the socket on the command line with with `--socket-addr <name>=<addr>` or # `--socket-fd <name>=<fd>`. # # Examples: # - "*:80": Listen on port 80 on all local IPv4 and IPv6 interfaces. # - "1.2.3.4": Listen on the specific IPv4 address on the default port for the protocol. # - "1.2.3.4:80": Listen on the specific IPv4 address and port. # - "1234:5678::abcd": Listen on the specific IPv6 address on the default port for the protocol. # - "[1234:5678::abcd]:80": Listen on the specific IPv6 address and port. # - "unix:/path/to/socket": Listen on a Unix socket. # - "unix-abstract:name": On Linux, listen on the given "abstract" Unix socket name. # - "example.com:80": Perform a DNS lookup to determine the address, and then listen on it. If # this resolves to multiple addresses, listen on all of them. # # (These are the formats supported by KJ's parseAddress().) union { http @2 :HttpOptions; https :group { options @3 :HttpOptions; tlsOptions @4 :TlsOptions; } # TODO(someday): TCP, TCP proxy, SMTP, Cap'n Proto, ... } service @5 :ServiceDesignator; # Service name which should handle requests on this socket. # TODO(someday): Support mapping different hostnames to different services? Or should that be # done strictly via JavaScript? } # ======================================================================================== # Services struct Service { # Defines a named service. Each server has a list of named services. The names are private, # used to refer to the services within this same config file. name @0 :Text; # Name of the service. Used only to refer to the service from elsewhere in the config file. # Services are not accessible unless you explicitly configure them to be, such as through a # `Socket` or through a binding from another Worker. union { unspecified @1 :Void; # (This catches when someone forgets to specify one of the union members. Do not set this.) worker @2 :Worker; # A Worker! network @3 :Network; # A service that implements access to a network. fetch() requests are routed according to # the URL hostname. external @4 :ExternalServer; # A service that forwards all requests to a specific remote server. Typically used to # connect to a back-end server on your internal network. disk @5 :DiskDirectory; # An HTTP service backed by a directory on disk, supporting a basic HTTP GET/PUT. Generally # not intended to be exposed directly to the internet; typically you want to bind this into # a Worker that adds logic for setting Content-Type and the like. } # TODO(someday): Allow defining a list of middlewares to stack on top of the service. This would # be a list of Worker names, where each Worker must have a binding called `next`. This # implicitly creates an inherited worker that wraps this service, with the `next` binding # pointing to the service itself (or to the next middleware in the stack). } struct ServiceDesignator { # A reference to a service from elsewhere in the config file, e.g. from a service binding in a # Worker. # # In the case that only `name` needs to be specified, then you can provide a raw string wherever # `ServiceDesignator` is needed. Cap'n proto automatically assumes the string is intended to be # the value for `name`, since that is the first field. In other words, if you would otherwise # write something like: # # bindings = [(service = (name = "foo"))] # # You can write this instead, which is equivalent: # # bindings = [(service = "foo")] name @0 :Text; # Name of the service in the Config.services list. entrypoint @1 :Text; # A modules-syntax Worker can export multiple named entrypoints. `export default {` specifies # the default entrypoint, whereas `export let foo = {` defines an entrypoint named `foo`. If # `entrypoint` is specified here, it names an alternate entrypoint to use on the target worker, # otherwise the default is used. # TODO(someday): Options to specify which event types are allowed. # TODO(someday): Allow adding an outgoing middleware stack here (see TODO in Service, above). } struct Worker { union { modules @0 :List(Module); # The Worker is composed of ES modules that may import each other. The first module in the list # is the main module, which exports event handlers. serviceWorkerScript @1 :Text; # The Worker is composed of one big script that uses global `addEventListener()` to register # event handlers. # # The value of this field is the raw source code. When using Cap'n Proto text format, use the # `embed` directive to read the code from an external file: # # serviceWorkerScript = embed "worker.js" inherit @2 :Text; # Inherit the configuration of some other Worker by its service name. This Worker is a clone # of the other worker, but various settings can be modified: # * `bindings`, if specified, overrides specific named bindings. (Each binding listed in the # derived worker must match the name and type of some binding in the inherited worker.) # * `globalOutbound`, if non-null, overrides the one specified in the inherited worker. # * `compatibilityDate` and `compatibilityFlags` CANNOT be modified; they must be null. # * If the inherited worker defines durable object namespaces, then the derived worker must # specify `durableObjectStorage` to specify where its instances should be stored. Each # devived worker receives its own namespace of objects. `durableObjectUniqueKeyModifier` # must also be specified by derived workers. # # This can be useful when you want to run the same Worker in multiple configurations or hooked # up to different back-ends. Note that all derived workers run in the same isolate as the # base worker; they differ in the content of the `env` object passed to them, which contains # the bindings. (When using service workers syntax, the global scope contains the bindings; # in this case each derived worker runs in its own global scope, though still in the same # isolate.) } struct Module { name @0 :Text; # Name (or path) used to import the module. union { esModule @1 :Text; # An ES module file with imports and exports. # # As with `serviceWorkerScript`, above, the value is the raw source code. commonJsModule @2 :Text; # A common JS module, using require(). text @3 :Text; # A raw text blob. Importing this will produce a string with the value. data @4 :Data; # A raw data blob. Importing this will produce an ArrayBuffer with the value. wasm @5 :Data; # A Wasm module. The value is a compiled binary Wasm module file. Importing this will produce # a `WebAssembly.Module` object, which you can then instantiate. json @6 :Text; # Importing this will produce the result of parsing the given text as JSON. nodeJsCompatModule @7 :Text; # A Node.js module is a specialization of a commonJsModule that: # (a) allows for importing Node.js-compat built-ins without the node: specifier-prefix # (b) exposes the subset of common Node.js globals such as process, Buffer, etc that # we implement in the workerd runtime. pythonModule @8 :Text; # A Python module. All bundles containing this value type are converted into a JS/WASM Worker # Bundle prior to execution. pythonRequirement @9 :Text; # A Python package that is required by this bundle. The package must be supported by # Pyodide (https://pyodide.org/en/stable/usage/packages-in-pyodide.html). All packages listed # will be installed prior to the execution of the worker. } namedExports @10 :List(Text); # For commonJsModule and nodeJsCompatModule, this is a list of named exports that the # module expects to be exported once the evaluation is complete. } compatibilityDate @3 :Text; compatibilityFlags @4 :List(Text); # See: https://developers.cloudflare.com/workers/platform/compatibility-dates/ # # `compatibilityDate` must be specified, unless the Worker inhits from another worker, in which # case it must not be specified. `compatibilityFlags` can optionally be specified when # `compatibilityDate` is specified. bindings @5 :List(Binding); # List of bindings, which give the Worker access to external resources and configuration # settings. # # For Workers using ES modules syntax, the bindings are delivered via the `env` object. For # service workers syntax, each binding shows up as a global variable. struct Binding { name @0 :Text; union { unspecified @1 :Void; # (This catches when someone forgets to specify one of the union members. Do not set this.) parameter :group { # Indicates that the Worker requires a binding of the given type, but it won't be specified # here. Another Worker can inherit this Worker and fill in this binding. type @2 :Type; # Expected type of this parameter. optional @3 :Bool; # If true, this binding is optional. Derived workers need not specify it, in which case # the binding won't be present in the environment object passed to the worker. # # When a Worker has any non-optional parameters that haven't been filled in, then it can # only be used for inheritance; it cannot be invoked directly. } text @4 :Text; # A string. data @5 :Data; # An ArrayBuffer. json @6 :Text; # A value parsed from JSON. wasmModule @7 :Data; # A WebAssembly module. The binding will be an instance of `WebAssembly.Module`. Only # supported when using Service Workers syntax. # # DEPRECATED: Please switch to ES modules syntax instead, and embed Wasm modules as modules. cryptoKey @8 :CryptoKey; # A CryptoKey instance, for use with the WebCrypto API. # # Note that by setting `extractable = false`, you can prevent the Worker code from accessing # or leaking the raw key material; it will only be able to use the key to perform WebCrypto # operations. service @9 :ServiceDesignator; # Binding to a named service (possibly, a worker). durableObjectNamespace @10 :DurableObjectNamespaceDesignator; # Binding to the durable object namespace implemented by the given class. # # In the common case that this refers to a class in the same Worker, you can specify just # a string, like: # # durableObjectNamespace = "MyClass" kvNamespace @11 :ServiceDesignator; # A KV namespace, implemented by the named service. The Worker sees a KvNamespace-typed # binding. Requests to the namespace will be converted into HTTP requests targeting the # given service name. r2Bucket @12 :ServiceDesignator; r2Admin @13 :ServiceDesignator; # R2 bucket and admin API bindings. Similar to KV namespaces, these turn operations into # HTTP requests aimed at the named service. wrapped @14 :WrappedBinding; # Wraps a collection of inner bindings in a common api functionality. queue @15 :ServiceDesignator; # A Queue binding, implemented by the named service. Requests to the # namespace will be converted into HTTP requests targeting the given # service name. fromEnvironment @16 :Text; # Takes the value of an environment variable from the system. The value specified here is # the name of a system environment variable. The value of the binding is obtained by invoking # `getenv()` with that name. If the environment variable isn't set, the binding value is # `null`. analyticsEngine @17 :ServiceDesignator; # A binding for Analytics Engine. Allows workers to store information through Analytics Engine Events. # workerd will forward AnalyticsEngineEvents to designated service in the body of HTTP requests # This binding is subject to change and requires the `--experimental` flag hyperdrive :group { designator @18 :ServiceDesignator; database @19 :Text; user @20 :Text; password @21 :Text; scheme @22 :Text; } # A binding for Hyperdrive. Allows workers to use Hyperdrive caching & pooling for Postgres # databases. unsafeEval @23 :Void; # A simple binding that enables access to the UnsafeEval API. memoryCache :group { # A binding representing access to an in-memory cache. id @24 :Text; # The identifier associated with this cache. Any number of isolates # can access the same in-memory cache (within the same process), and # each worker may use any number of in-memory caches. limits @25 :MemoryCacheLimits; } # TODO(someday): dispatch, other new features } struct Type { # Specifies the type of a parameter binding. union { unspecified @0 :Void; # (This catches when someone forgets to specify one of the union members. Do not set this.) text @1 :Void; data @2 :Void; json @3 :Void; wasm @4 :Void; cryptoKey @5 :List(CryptoKey.Usage); service @6 :Void; durableObjectNamespace @7 :Void; kvNamespace @8 :Void; r2Bucket @9 :Void; r2Admin @10 :Void; queue @11 :Void; analyticsEngine @12 : Void; hyperdrive @13: Void; } } struct DurableObjectNamespaceDesignator { # The type of a Durable Object namespace binding. className @0 :Text; # Exported class name that implements the Durable Object. serviceName @1 :Text; # The service name of the worker that defines this class. If omitted, the current worker # is assumed. # # Use of this field is discouraged. Instead, when accessing a different Worker's Durable # Objects, specify a `service` binding to that worker, and have the worker implement an # appropriate API. # # (This is intentionally not a ServiceDesignator because you cannot choose an alternate # entrypoint here; the class name IS the entrypoint.) } struct CryptoKey { # Parameters to crypto.subtle.importKey(). union { raw @0 :Data; hex @1 :Text; base64 @2 :Text; # Raw key material, possibly hex or base64-encoded. Use this for symmetric keys. # # Hint: `raw` would typically be used with Cap'n Proto's `embed` syntax to embed an # external binary key file. `hex` or `base64` could do that too but can also be specified # inline. pkcs8 @3 :Text; # Private key in PEM-encoded PKCS#8 format. spki @4 :Text; # Public key in PEM-encoded SPKI format. jwk @5 :Text; # Key in JSON format. } algorithm :union { # Value for the `algorithm` parameter. name @6 :Text; # Just a name, like `AES-GCM`. json @7 :Text; # An object, encoded here as JSON. } extractable @8 :Bool = false; # Is the Worker allowed to export this key to obtain the underlying key material? Setting # this false ensures that the key cannot be leaked by errant JavaScript code; the key can # only be used in WebCrypto operations. usages @9 :List(Usage); # What operations is this key permitted to be used for? enum Usage { encrypt @0; decrypt @1; sign @2; verify @3; deriveKey @4; deriveBits @5; wrapKey @6; unwrapKey @7; } } struct MemoryCacheLimits { maxKeys @0 :UInt32; maxValueSize @1 :UInt32; maxTotalValueSize @2 :UInt64; } struct WrappedBinding { # A binding that wraps a group of (lower-level) bindings in a common API. moduleName @0 :Text; # Wrapper module name. # The module must be an internal one (provided by extension or registered in the c++ code). # Module will be instantitated during binding initialization phase. entrypoint @1 :Text = "default"; # Module needs to export a function with a given name (default export gets "default" name). # The function needs to accept a single `env` argument - a dictionary with inner bindings. # Function will be invoked during initialization phase and its return value will be used as # resulting binding value. innerBindings @2 :List(Binding); # Inner bindings that will be created and passed in the env dictionary. # These bindings shall be used to implement end-user api, and are not available to the # binding consumers unless "re-exported" in wrapBindings function. } } globalOutbound @6 :ServiceDesignator = "internet"; # Where should the global "fetch" go to? The default is the service called "internet", which # should usually be configured to talk to the public internet. cacheApiOutbound @11 :ServiceDesignator; # Where should cache API (i.e. caches.default and caches.open(...)) requests go? durableObjectNamespaces @7 :List(DurableObjectNamespace); # List of durable object namespaces in this Worker. struct DurableObjectNamespace { className @0 :Text; # Exported class name that implements the Durable Object. # # Changing the class name will not break compatibility with existing storage, so long as # `uniqueKey` stays the same. union { uniqueKey @1 :Text; # A unique, stable ID associated with this namespace. This could be a GUID, or any other # string which does not appear anywhere else in the world. # # This string is used to ensure that objects of this class have unique identifiers distinct # from objects of any other class. Object IDs are cryptographically derived from `uniqueKey` # and validated against it. It is impossible to guess or forge a valid object ID without # knowing the `uniqueKey`. Hence, if you keep the key secret, you can prevent anyone from # forging IDs. However, if you don't care if users can forge valid IDs, then it's not a big # deal if the key leaks. # # DO NOT LOSE this key, otherwise it may be difficult or impossible to recover stored data. ephemeralLocal @2 :Void; # Instances of this class are ephemeral -- they have no durable storage at all. The # `state.storage` API will not be present. Additionally, this namespace will allow arbitrary # strings as IDs. There are no `idFromName()` nor `newUniqueId()` methods; `get()` takes any # string as a parameter. # # Ephemeral objects are NOT globally unique, only "locally" unique, for some definition of # "local". For example, on Cloudflare's network, these objects are unique per-colo. # # WARNING: Cloudflare Workers currently limits this feature to Cloudflare-internal users # only, because using them correctly requires deep understanding of Cloudflare network # topology. We're working on something better for public consuption. Until then for # "ephemeral" use cases we recommend using regular durable objects and just not storing # anything. An object that hasn't stored anything will not consume any storage space on # disk. } preventEviction @3 :Bool; # By default, Durable Objects are evicted after 10 seconds of inactivity, and expire 70 seconds # after all clients have disconnected. Some applications may want to keep their Durable Objects # pinned to memory forever, so we provide this flag to change the default behavior. # # Note that this is only supported in Workerd; production Durable Objects cannot toggle eviction. } durableObjectUniqueKeyModifier @8 :Text; # Additional text which is hashed together with `DurableObjectNamespace.uniqueKey`. When using # worker inheritance, each derived worker must specify a unique modifier to ensure that its # Durable Object instances have unique IDs from all other workers inheriting the same parent. # # DO NOT LOSE this value, otherwise it may be difficult or impossible to recover stored data. durableObjectStorage :union { # Specifies where this worker's Durable Objects are stored. none @9 :Void; # Default. The worker has no Durable Objects. `durableObjectNamespaces` must be empty, or # define all namespaces as `ephemeralLocal`, or this must be an abstract worker (meant to be # inherited by other workers, who will specify `durableObjectStorage`). inMemory @10 :Void; # The `state.storage` API stores in-memory only. All stored data will persist for the # lifetime of the process, but will be lost upon process exit. # # Individual objects will still shut down when idle as normal -- only data stored with the # `state.storage` interface is persistent for the lifetime of the process. # # This mode is intended for local testing purposes. localDisk @12 :Text; # ** EXPERIMENTAL; SUBJECT TO BACKWARDS-INCOMPATIBLE CHANGE ** # # Durable Object data will be stored in a directory on local disk. This field is the name of # a service, which must be a DiskDirectory service. For each Durable Object class, a # subdirectory will be created using `uniqueKey` as the name. Within the directory, one or # more files are created for each object, with names `<id>.<ext>`, where `.<ext>` may be any of # a number of different extensions depending on the storage mode. (Currently, the main storage # is a file with the extension `.sqlite`, and in certain situations extra files with the # extensions `.sqlite-wal`, and `.sqlite-shm` may also be present.) } # TODO(someday): Support distributing objects across a cluster. At present, objects are always # local to one instance of the runtime. moduleFallback @13 :Text; } struct ExternalServer { # Describes the ability to talk to a specific server, typically a back-end server available # on the internal network. # # When a Worker contains a service binding that points to an ExternalServer, *all* fetch() # calls on that binding will be delivered to that server, regardless of whether the hostname # or protocol specified in the URL actually match the hostname or protocol used by the actual # server. Typically, a Worker implementing a reverse proxy would use this to forward a request # to a back-end application server. Such a back-end typically does not have a real public # hostname, since it is only reachable through the proxy, but the requests forwarded to it will # keep the hostname that was on the original request. # # Note that this also implies that regardless of whether the original URL was http: or https:, # the request will be delivered to the target server using the protocol specified below. A # header like `X-Forwarded-Proto` can be used to pass along the original protocol; see # `HttpOptions`. address @0 :Text; # Address/port of the server. Optional; if not specified, then you will be required to specify # the address on the command line with with `--external-addr <name>=<addr>`. # # Examples: # - "1.2.3.4": Connect to the given IPv4 address on the protocol's default port. # - "1.2.3.4:80": Connect to the given IPv4 address and port. # - "1234:5678::abcd": Connect to the given IPv6 address on the protocol's default port. # - "[1234:5678::abcd]:80": Connect to the given IPv6 address and port. # - "unix:/path/to/socket": Connect to the given Unix Domain socket by path. # - "unix-abstract:name": On Linux, connect to the given "abstract" Unix socket name. # - "example.com:80": Perform a DNS lookup to determine the address, and then connect to it. # # (These are the formats supported by KJ's parseAddress().) union { http @1 :HttpOptions; # Talk to the server over unencrypted HTTP. https :group { # Talk to the server over encrypted HTTPS. options @2 :HttpOptions; tlsOptions @3 :TlsOptions; certificateHost @4 :Text; # If present, expect the host to present a certificate authenticating it as this hostname. # If `certificateHost` is not provided, then the certificate is checked against `address`. } tcp :group { # Connect to the server over raw TCP. Bindings to this service will only support the # `connect()` method; `fetch()` will throw an exception. tlsOptions @5 :TlsOptions; certificateHost @6 :Text; } # TODO(someday): Cap'n Proto RPC } } struct Network { # Describes the ability to talk to a network. # # This is commonly used to define the "internet" service which is the default `globalOutbound` # for all Workers. To prevent SSRF, by default Workers will not be permitted to reach internal # network addresses using global fetch(). It's recommended that you create ExternalServer # bindings instead to grant access to specific servers. However, if you really want to, you # can configure a service that grants arbitrary internal network access, like: # # ( name = "internalNetwork", # network = ( # allow = ["public", "private"], # ) # ) allow @0 :List(Text) = ["public"]; deny @1 :List(Text); # Specifies which network addresses the Worker will be allowed to connect to, e.g. using fetch(). # The default allows publicly-routable IP addresses only, in order to prevent SSRF attacks. # # The allow and deny lists specify network blocks in CIDR notation (IPv4 and IPv6), such as # "192.0.2.0/24" or "2001:db8::/32". Traffic will be permitted as long as the address # matches at least one entry in the allow list and none in the deny list. # # In addition to IPv4 and IPv6 CIDR notation, several special strings may be specified: # - "private": Matches network addresses that are reserved by standards for private networks, # such as "10.0.0.0/8" or "192.168.0.0/16". This is a superset of "local". # - "public": Opposite of "private". # - "local": Matches network addresses that are defined by standards to only be accessible from # the local machine, such as "127.0.0.0/8" or Unix domain addresses. # - "network": Opposite of "local". # - "unix": Matches all Unix domain socket addresses. (In the future, we may support specifying a # glob to narrow this to specific paths.) # - "unix-abstract": Matches Linux's "abstract unix domain" addresses. (In the future, we may # support specifying a glob.) # # In the case that the Worker specifies a DNS hostname rather than a raw address, these rules are # used to filter the addresses returned by the lookup. If none of the returned addresses turn # out to be permitted, then the system will behave as if the DNS entry did not exist. # # (The above is exactly the format supported by kj::Network::restrictPeers().) tlsOptions @2 :TlsOptions; } struct DiskDirectory { # Configures access to a directory on disk. This is a type of service which will expose an HTTP # interface to the directory content. # # This is very bare-bones, generally not suitable for serving a web site on its own. In # particular, no attempt is made to guess the `Content-Type` header. You normally would wrap # this in a Worker that fills in the metadata in the way you want. # # A GET request targeting a directory (rather than a file) will return a basic JSAN directory # listing like: # # [{"name":"foo","type":"file"},{"name":"bar","type":"directory"}] # # Possible "type" values are "file", "directory", "symlink", "blockDevice", "characterDevice", # "namedPipe", "socket", "other". # # `Content-Type` will be `application/octet-stream` for files or `application/json` for a # directory listing. Files will have a `Content-Length` header, directories will not. Symlinks # will be followed (but there is intentionally no way to create one, even if `writable` is # `true`), and treated according to the type of file they point to. The other inode types cannot # be opened; trying to do so will produce a "406 Not Acceptable" error (on the theory that there # is no acceptable format for these, regardless of what the client says it accepts). # # `HEAD` requests are properly optimized to perform a stat() without actually opening the file. path @0 :Text; # The filesystem path of the directory. If not specified, then it must be specified on the # command line with `--directory-path <service-name>=<path>`. # # Relative paths are interpreted relative to the current directory where the server is executed, # NOT relative to the config file. So, you should usually use absolute paths in the config file. writable @1 :Bool = false; # Whether to support PUT requests for writing. A PUT will write to a temporary file which # is atomically moved into place upon successful completion of the upload. Parent directories are # created as needed. allowDotfiles @2 :Bool = false; # Whether to allow access to files and directories whose name starts with '.'. These are made # inaccessible by default since they very often store metadata that is not meant to be served, # e.g. a git repository or an `.htaccess` file. # # Note that the special links "." and ".." will never be accessible regardless of this setting. } # ======================================================================================== # Protocol options struct HttpOptions { # Options for using HTTP (as a client or server). In particular, this specifies behavior that is # important in the presence of proxy servers, whether forward or reverse. style @0 :Style = host; enum Style { host @0; # Normal HTTP. The request line contains only the path, and the separate `Host` header # specifies the hostname. proxy @1; # HTTP proxy protocol. The request line contains a full URL instead of a path. No `Host` # header is required. This is the protocol used by HTTP forward proxies. This allows you to # implement such a proxy as a Worker. } forwardedProtoHeader @1 :Text; # If specified, then when the given header is present on a request, it specifies the protocol # ("http" or "https") that was used by the original client. The request URL reported to the # Worker will reflect this protocol. Otherwise, the URL will reflect the actual physical protocol # used by the server in receiving the request. # # This option is useful when this server sits behind a reverse proxy that performs TLS # termination. Typically such proxies forward the original protocol in a header named something # like "X-Forwarded-Proto". # # This setting is ignored when `style` is `proxy`. cfBlobHeader @2 :Text; # If set, then the `request.cf` object will be encoded (as JSON) into / parsed from the header # with this name. Otherwise, it will be discarded on send / `undefined` on receipt. injectRequestHeaders @3 :List(Header); # List of headers which will be automatically injected into all requests. This can be used # e.g. to add an authorization token to all requests when using `ExternalServer`. It can also # apply to incoming requests received on a `Socket` to modify the headers that will be delivered # to the app. Any existing header with the same name is removed. injectResponseHeaders @4 :List(Header); # Same as `injectRequestHeaders` but for responses. struct Header { name @0 :Text; # Case-insensitive. value @1 :Text; # If null, the header will be removed. } capnpConnectHost @5 :Text; # A CONNECT request for this host+port will be treated as a request to form a Cap'n Proto RPC # connection. The server will expose a WorkerdBootstrap as the bootstrap interface, allowing # events to be delivered to the target worker via capnp. Clients will use capnp for non-HTTP # event types (especially JSRPC). # TODO(someday): When we support TCP, include an option to deliver CONNECT requests to the # TCP handler. } struct TlsOptions { # Options that apply when using TLS. Can apply on either the client or the server side, depending # on the context. # # This is based on KJ's TlsContext::Options. keypair @0 :Keypair; # The default private key and certificate to use. Optional when acting as a client. struct Keypair { privateKey @0 :Text; # Private key in PEM format. Supports PKCS8 keys as well as "traditional format" RSA and DSA # keys. # # Remember that you can use Cap'n Proto's `embed` syntax to reference an external file. certificateChain @1 :Text; # Certificate chain in PEM format. A chain can be constructed by concatenating multiple # PEM-encoded certificates, starting with the leaf certificate. } # TODO(someday): Support SNI-based keypair selection? Is a hostname -> keypair map good enough? # Does it need to support wildcards? Maybe we should just let you provide a pile of certs and # we can figure out which hosts each one matches? requireClientCerts @1 :Bool = false; # If true, then when acting as a server, incoming connections will be rejected unless they bear # a certificate signed by one of the trusted CAs. # # Typically, when using this, you'd set `trustBrowserCas = false` and list a specific private CA # in `trustedCertificates`. trustBrowserCas @2 :Bool = false; # If true, trust certificates which are signed by one of the CAs that browsers normally trust. # You should typically set this true when talking to the public internet, but you may want to # set it false when talking to servers on your internal network. trustedCertificates @3 :List(Text); # Additional CA certificates to trust, in PEM format. Remember that you can use Cap'n Proto's # `embed` syntax to read the certificates from other files. minVersion @4 :Version = goodDefault; # Minimum TLS version that will be allowed. Generally you should not override this unless you # have unusual backwards-compatibility needs. enum Version { goodDefault @0; # A good default chosen by the code maintainers. May change over time. ssl3 @1; tls1Dot0 @2; tls1Dot1 @3; tls1Dot2 @4; tls1Dot3 @5; } cipherList @5 :Text; # OpenSSL cipher list string. The default is a curated list designed to be compatible with # almost all software in current use (specifically, based on Mozilla's "intermediate" # recommendations). The defaults will change in future versions of this software to account # for the latest cryptanalysis. # # Generally you should only specify your own `cipherList` if: # - You have extreme backwards-compatibility needs and wish to enable obsolete and/or broken # algorithms. # - You need quickly to disable an algorithm recently discovered to be broken. } # ======================================================================================== # Extensions struct Extension { # Additional capabilities for workers. modules @0 :List(Module); # List of javascript modules provided by the extension. # These modules can either be imported directly as user-level api (if not marked internal) # or used to define more complicated workerd constructs such as wrapped bindings and events. struct Module { # A module extending workerd functionality. name @0 :Text; # Full js module name. internal @1 :Bool = false; # Internal modules can be imported by other extension modules only and not the user code. esModule @2 :Text; # Raw source code of ES module. } }