syntax = "proto3"; package config.format; // the root config // // each of these fields will show up at the root of your config file // // at the minimum, you'll need at least 1 `domains` entry to define your // sites, and one `bind_to_tcp` entry to define how the proxy itself // serves content. message Config { // the domains to serve map domains = 1; // bind to tcp ports, with optional tls repeated TCPBinding bind_to_tcp = 2; // lower-level pingora config // // (you probably don't need to touch this) Pingora pingora = 3; } // a single, served domain // // you'll want at least 1 backend (`https`, `http`, or `uds`), // but you can repeat each one to define multiple backends // and load-balance between them, and you can (if you really need // to) mix and match types. // // you may also want an (optional) `oidc_auth` configuration to turn on // authentication-termination // // you can also use `manage_headers` to inject things like `X-Forwarded-For`, // or clear headers that you don't want going to your backend. message Domain { // require oidc auth if this is set optional OIDC oidc_auth = 1; // https backends repeated HTTPSBackend https = 3; // http backends repeated HTTPSBackend http = 7; // unix domain socket backends repeated UDSBackend uds = 4; enum TLSMode { // don't support redirects, they can be _very_ unsafe. just use hsts // only allow https, no redirect TLS_MODE_ONLY = 0; // allow http, for testing purposes TLS_MODE_UNSAFE_ALLOW_HTTP = 1; } // allow disabling TLS termination, for testing TLSMode tls_mode = 5; // set or clear headers on the backend request ManageHeaders manage_headers = 6; // configure tls settings message TLS { // path to the (public) tls certificate, with all intermediate certificates (fullchain.pem for most acme clients) string cert_path = 1; // path to the (privat) tls key string key_path = 2; // override the default (using the domain name) for SNI purposes // useful if the domain contains a port optional string sni = 3; } // configure tls // // you should _always_ have this TLS tls = 8; } // configure oidc/oauth v2.1 termination message OIDC { // the base oidc discovery url, without the `.well-known/openid-configuration` part // // per [OIDC Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html) // and [RFC 8414](https://datatracker.ietf.org/doc/html/rfc8414). string discovery_url_base = 1; // your oauth client id, from your oauth provider string client_id = 2; // your oauth client secret, from your oauth provider string client_secret_path = 3; // a set of scopes you wish to ask the sever for // // (`openid` will always be automatically included) Scopes scopes = 4; // map returned "claims" (pieces of user information) // to header in the backend request. // // for example, you can use this to tell backend services the name of the // authenticated user. Claims claims = 5; // per oidc core v1-with-errata-2ยง3.1.3.7 point 6, we _may_ skip validation // of the id token if it was received over tls. which it will be, in our // case. some folks may want to be extra paranoid, but generally you either // trust tls, or you can't trust discovery, and thus can't trust the jwks info, // so default this to false. // // generally, you can leave this off. bool validate_with_jwk = 6; // where to redirect to on logout string logout_url = 7; } // scopes to ask the server for message Scopes { // the scopes you need from the server for your claims map to work, or that // you want to request to ensure that the user is authorized to continue to // your site. repeated string required = 2; // optional scopes, not requested from the server // // not currently used repeated string optional = 1; } // information on how to process returned claims message Claims { // maps a claim to a header name & value message ClaimToHeader { // the name of the claim string claim = 1; // the name to the header string header = 2; // how to serialize compound (object, array) typed-claims optional Serialization serialize_as = 3; } // map the given claims to a header in the backend request // // headers specified here with no corresponding claim value will be wiped repeated ClaimToHeader claim_to_header = 1; // how to serialize compound (object, array) typed-claims // // this doesn't cover _deeply_ nested identical objects (e.g. // arrays-of-arrays), or selecting/projecting, but covers most usecases. in // theory i could implement, say, jq or something but that feels like // overkill. // // values that are `null` will always be skipped, and map entries with a null // value with also be skipped. message Serialization { // how to join keys to values (e.g. `=` means `key=value`) optional string join_keys_and_values_with = 1; // how to join key-value pairs to each other (e.g. `; ` means `key=value; key=value`) optional string join_key_value_pairs_with = 2; // how to join array items to each other (e.g. `, ` means `item, item, item`) optional string join_array_items_with = 3; } } // a standard https backend message HTTPSBackend { // full ipv4 or v6 address, including port string addr = 1; // weight of this backend, if load-balancing optional uint64 weight = 2; // skip verifying certificates on tls backends // // useful if your backend certs are self-signed, // or for some reason not valid for the backend itself. // // generally prefer to use `ca_path` instead. bool skip_verifying_certs = 3; // path to the CA file used to verify the backend's certs, on tls backends // // useful if the backend is using self-signed certs optional string ca_path = 4; } // a unix domain socket backend message UDSBackend { // path to the uds socket string path = 1; // weight of this backend, if load-balancing optional uint64 weight = 2; } // these headers will be set if they are set to something // // either way, they will be wiped if the client tries to send them message ManageHeaders { // set the given header to be the request host optional string host = 1; // set an `X-Forwarded-For`-style header, appending `,` to any existing value optional string x_forwarded_for = 2; // set an `X-Forwarded-Proto`-style header to the original scheme of the request optional string x_forwarded_proto = 3; // set an `X-Real-IP`-style header (i.e. _just_ the remote address) optional string remote_addr = 4; // always clear these headers repeated string always_clear = 5; } // equivalent to [`pingora::server::configuration::Config`] // // See [pingora](https://docs.rs/pingora/latest/pingora/server/configuration/struct.ServerConf.html) // for details on what these do message Pingora { optional uint64 version = 1; optional bool daemon = 2; optional string error_log = 3; optional string pid_file = 4; optional string upgrade_sock = 5; optional string user = 6; optional string group = 7; optional uint64 threads = 8; optional uint64 listener_tasks_per_fd = 9; optional bool work_stealing = 10; optional string ca_file = 11; optional uint64 grace_period_seconds = 12; optional uint64 graceful_shutdown_timeout_seconds = 13; repeated string client_bind_to_ipv4 = 14; repeated string client_bind_to_ipv6 = 15; optional uint64 upstream_keepalive_pool_size = 16; optional uint64 upstream_connect_offload_threadpools = 17; optional uint64 upstream_connect_offload_thread_per_pool = 18; optional bool upstream_debug_ssl_keylog = 19; optional uint64 max_retries = 20; optional uint64 upgrade_sock_connect_accept_max_retries = 21; } // bind to a tcp port // // this configures which ports you'll serve https & grpc traffic on. // // you'll want to chose an address. // // tls is configured per-domain in the domain settings. message TCPBinding { // TODO(feature): default tls settings // host an port to bind to string addr = 1; // TODO(feature): surface tcp options from pingora }