diff --git a/README.md b/README.md index bb41d4dc1d..323ae900c6 100644 --- a/README.md +++ b/README.md @@ -84,3 +84,18 @@ pnpm run build For bug reports, feature request, questions and community support please ooen an issue or discussion in our [ngrok Community](https://github.com/ngrok/ngrok). To report a problem with our documentation, please open a new [Github issue](https://github.com/ngrok/ngrok-docs/issues). + +## Troubleshooting + +### EMFILE: too many open files error + +Sometimes when you run `pnpm run dev`, docusaurus fails to build the site with the following error: + +```bash +Error: Docusaurus could not load module at path "C:/.../ngrok-docs/sidebars.js" +Cause: EMFILE: too many open files, open 'C:/.../ngrok-docs/sidebars.js' +``` + +You can fix this by running `pnpm run clean-dev`. + +The issue appears to be related to the npm cache being too large. `pnpm run clean-dev` clears and verifies the cache before running `pnpm run dev` for you. diff --git a/docs/agent/agent-tls-termination.mdx b/docs/agent/agent-tls-termination.mdx index ba209af108..e851237670 100644 --- a/docs/agent/agent-tls-termination.mdx +++ b/docs/agent/agent-tls-termination.mdx @@ -7,7 +7,7 @@ title: Agent TLS Termination Agent TLS termination enables you to secure your traffic with end-to-end encryption without needing to reconfigure your server. :::tip -If your service doesn't support TLS termination, you can still use Agent TLS termination with [Zero-Knowledge TLS](/universal-gateway/tls-termination/#end-to-end-encryption). +If your service doesn't support TLS termination, you can still use Agent TLS termination with [Zero-Knowledge TLS](/universal-gateway/tls/tls-termination/#end-to-end-encryption). ::: ## Quickstart diff --git a/docs/agent/cli.mdx b/docs/agent/cli.mdx index 0bf15b5ccd..9b02a7c9e3 100644 --- a/docs/agent/cli.mdx +++ b/docs/agent/cli.mdx @@ -610,7 +610,7 @@ of a tunnel-group backend. Endpoint configurations containing a tunnel-group backend will cause traffic to their associated reserved domain or address to be forwarded to the tunnel-group. -See the [Tunnel Group backends](/network-edge/edges/#tunnel-group) and [Edges](/network-edge/edges/) pages for more information. +See the [Tunnel Group backends](/universal-gateway/edges/#tunnel-group) and [Edges](/universal-gateway/edges/) pages for more information. ### Usage diff --git a/docs/agent/ssh-reverse-tunnel-agent.mdx b/docs/agent/ssh-reverse-tunnel-agent.mdx index a016e343ee..c73af39627 100644 --- a/docs/agent/ssh-reverse-tunnel-agent.mdx +++ b/docs/agent/ssh-reverse-tunnel-agent.mdx @@ -183,7 +183,7 @@ differences from the ngrok agent includes: - You can't [forward to upstream https services](/universal-gateway/http/#https-forwarding) - You can't create multiple endpoints over the same connection - You can't [serve file system directories](/universal-gateway/http/#serving-file-directories) with the `file://` protocol -- You can't terminate TLS at the agent when using [end-to-end encryption](/universal-gateway/tls-termination/#end-to-end-encryption) +- You can't terminate TLS at the agent when using [end-to-end encryption](/universal-gateway/tls/tls-termination/#end-to-end-encryption) - You can't run labeled tunnels for use with [Edges](/universal-gateway/edges). ## Pricing diff --git a/docs/errors/index.md b/docs/errors/index.md index 6c8d6eacea..addc5b5c8c 100644 --- a/docs/errors/index.md +++ b/docs/errors/index.md @@ -60,3 +60,42 @@ complete list of all of ngrok's error codes. ## Customize Error Pages for your Traffic To access and provide feedback on a development preview of custom error pages [Fill out the form](https://ngrok.com/new-features/custom-error-pages?ref=errordoc). + +## HTTP Errors + +If ngrok fails to handle an HTTP request it will set the `ngrok-error-code` header in the HTTP response with a [unique ngrok Error Code](/errors/) describing the failure. + +ngrok guarantees that the upstream service may never set the `ngrok-error-code` HTTP response header so you know reliably that it was set by ngrok. + +ngrok may return an error under the following conditions: + +- Your upstream service timed out or rejected the connection +- Your upstream service returned a response that was not valid HTTP +- A [Traffic Policy](/traffic-policy) action rejected the request. +- [Traffic Policy](/traffic-policy) execution encountered a runtime error. +- ngrok encountered an internal error + +## TLS Errors + +If a TLS handshake fails, an appropriate TLS abort code will be sent to the +client. + +In all other cases, if an error is encountered while handling TLS connections +to your endpoints (e.g. no available backends or internal server error), the +connection will be closed. The TLS protocol and its implementations are not +sufficiently flexible enough to deliver additional rich error information when +failures are encountered. + +Use the [observability](#observability) features to understand connection +handling errors. + +## TCP Errors + +If an error is encountered while handling connections to a TCP endpoint for any +reason (e.g. traffic policy action error, internal server error), the +connection will be closed. Because of the low-level nature of the TCP protocol, +there is no mechanism used to transmit information about what error code was +encountered. + +Use the [observability](/obs/events/reference/#tcp-connection-closed) features to understand connection +handling errors. diff --git a/docs/faq/faq.mdx b/docs/faq/faq.mdx index 2a93a37f2f..24da8e9de6 100644 --- a/docs/faq/faq.mdx +++ b/docs/faq/faq.mdx @@ -66,7 +66,7 @@ and port 443 as well for TLS endpoints. This behavior is not configurable. TCP endpoints use the port of the TCP address that was assigned when you acquires the TCP address. [This port is assigned and not -configurable](/universal-gateway/tcp-addresses/#address-assignment). +configurable](/universal-gateway/tcp-addresses/how-are-tcp-addresses-assigned/). ## Will the ngrok agent work if my network changes? {#network-changes} diff --git a/docs/getting-started/go.mdx b/docs/getting-started/go.mdx index fb18544462..7b2dd9968d 100644 --- a/docs/getting-started/go.mdx +++ b/docs/getting-started/go.mdx @@ -1,6 +1,6 @@ --- title: Go -pagination_next: universal-gateway/http +pagination_next: universal-gateway/http-s/index --- # Quickstart: ngrok-go diff --git a/docs/getting-started/index.mdx b/docs/getting-started/index.mdx index 3ad6d5313b..1959df4d10 100644 --- a/docs/getting-started/index.mdx +++ b/docs/getting-started/index.mdx @@ -1,6 +1,6 @@ --- title: Quickstart -pagination_next: universal-gateway/http +pagination_next: universal-gateway/http-s/index --- import TabItem from "@theme/TabItem"; diff --git a/docs/getting-started/rust.mdx b/docs/getting-started/rust.mdx index 1c8195f514..8ebfd32396 100644 --- a/docs/getting-started/rust.mdx +++ b/docs/getting-started/rust.mdx @@ -1,6 +1,6 @@ --- title: Rust -pagination_next: universal-gateway/http +pagination_next: universal-gateway/http-s/index --- # Quickstart: ngrok-rust diff --git a/docs/guides/api-gateway/get-started.mdx b/docs/guides/api-gateway/get-started.mdx index a2e61b6a87..1e6c92f11d 100644 --- a/docs/guides/api-gateway/get-started.mdx +++ b/docs/guides/api-gateway/get-started.mdx @@ -78,8 +78,8 @@ ngrok api reserved-domains create --domain {YOUR_NGROK_DOMAIN} ``` This example uses an -[ngrok-managed domain](/universal-gateway/domains/#ngrok-managed-domains), but you can use -your own [branded domain](/universal-gateway/domains/#branded-domains) when you're ready for production. +[ngrok-managed domain](/universal-gateway/domains/what-are-managed-domains), but you can use +your own [branded domain](/universal-gateway/bring-your-own-domain) when you're ready for production. In that case, substitute your branded domain for `{YOUR_NGROK_DOMAIN}` in the command above, and [follow the steps](/guides/other-guides/how-to-set-up-a-custom-domain/#create-cname-record-in-domain-dns) to configure DNS. @@ -540,7 +540,7 @@ out our [integrations guides](/integrations/) for specific examples. 1. Leave the default values for **JSON Web Token (JWT) Profile \*** and **JSON Web Token Signing Algorithm \***. 1. Click **Create**. -Auth0 Create API +Auth0 Create API #### Access your JWT diff --git a/docs/guides/device-gateway/agent.md b/docs/guides/device-gateway/agent.md index 27340a4100..1ddb14a013 100644 --- a/docs/guides/device-gateway/agent.md +++ b/docs/guides/device-gateway/agent.md @@ -123,7 +123,7 @@ https://api.ngrok.com/agent_ingresses ## Create a custom wildcard domain -Next, create a custom [wildcard domain](/universal-gateway/domains/#wildcard-domains), which will allow you to +Next, create a custom [wildcard domain](/universal-gateway/domains/what-are-domains/#wildcard-domains), which will allow you to create endpoints and receive traffic on any subdomain of your domain. For example, you might create `*.customer1.{YOUR_DOMAIN}`. You would then be able to create endpoints diff --git a/docs/guides/device-gateway/arm64.md b/docs/guides/device-gateway/arm64.md index f9ce8bc75d..19fdc3b87d 100644 --- a/docs/guides/device-gateway/arm64.md +++ b/docs/guides/device-gateway/arm64.md @@ -102,7 +102,7 @@ If you already established a TCP tunnel for SSH access, you'll either need to cr Forwarding https://12345.ngrok.app -> http://localhost:8080 ``` -1. Optionally, you can reserve a [static subdomain](/universal-gateway/domains/) like so: +1. Optionally, you can reserve a [static subdomain](/universal-gateway/domains/what-are-domains/) like so: ``` ngrok http 8080 --url https://example.ngrok.app diff --git a/docs/guides/other-guides/how-to-set-up-a-custom-domain.mdx b/docs/guides/other-guides/how-to-set-up-a-custom-domain.mdx deleted file mode 100644 index 0a632fa17a..0000000000 --- a/docs/guides/other-guides/how-to-set-up-a-custom-domain.mdx +++ /dev/null @@ -1,65 +0,0 @@ ---- -title: Custom Domains ---- - -ngrok allows for using hostnames from a custom domain that you own to be used with your tunnel endpoints or [Edges](/universal-gateway/edges/). Utilizing CNAMEs, ngrok will host an endpoint using your custom domain while also providing the ability to manage the complete TLS certficate lifecycyle for you. - -ngrok is not a domain registrar and will not provide or manage custom domains. As a prerequisite it is required that you have already reserved your custom domain from any available domain registrar. For demo purposes in this guide, we've registered the domain name `example.com` with a domain name registrar and will be using it with ngrok. - -To get the hostname `foo.example.com` working with an ngrok tunnel we'll need to perform one step within the ngrok account dashboard and one step with the DNS host for your domain. In many cases your DNS records are hosted by your domain name registrar, but not always. The process can be summed up in 3 steps. - -- Create hostname within ngrok dashboard -- Create CNAME record in domain DNS -- Start ngrok tunnel using hostname - -## **Create Hostname Within ngrok Dashboard** - -Adding your custom domain hostname will be done from within your ngrok account, this "reservation" process is performed from the domains page of [your ngrok dashboard](https://dashboard.ngrok.com/domains). - -Select "New Domain" and then put `foo.example.com` into the form that appears to add that domain hostname to your account. ngrok will validate that the custom name isn't currently reserved. Select the available name from the list provided and then you'll be able to add a Description, attach an Edge if desired and select your TLS Certificate configuration (we recommend our automated TLS certificates). - -After adding your domain you should see instructions along with the CNAME value to be used when creating the CNAME record. Copy the `value` of your newly-added domain's CNAME target hostname, which will be something like `..ngrok-cname.com.` - -## **Create CNAME Record in Domain DNS** - -Head over to your DNS provider and create a new record on the `example.com` domain. Every DNS provider has a distinct user interface but just by way of example here's what this interface looks like when setting up a DNS CNAME record within Squarespace: - -![](/img/docs/customdomain-img1.png) - -Create a record of type CNAME where the host name is `foo` and the data value is your ngrok CNAME target,`..ngrok-cname.com`. This will ensure that any DNS queries for `foo.example.com` are resolved with an IP from our service edge. - -#### Testing the CNAME - -Once created it might take a few minutes before the new record is reflected in the DNS, but you can confirm that your record is created using a command line tool like `dig` or `nslookup`. If the ngrok dashboard is still displayed with your CNAME target hostname from Step 1, the "Check Status" button at the bottom right of the page can also be used to confirm that your CNAME record is resolving correctly. - -```bash -nslookup foo.example.com - -Server: 127.0.0.1 -Address: 127.0.0.1#53 - -Non-authoritative answer: -foo.example.com canonical name = 4bvatzaa19xbdzvcv.2hgtjydm4lbzrtfge.ngrok-cname.com. -Name: 4bvatzaa19xbdzvcv.2hgtjydm4lbzrtfge.ngrok-cname.com -Address: 192.0.2.39 -Name: 4bvatzaa19xbdzvcv.2hgtjydm4lbzrtfge.ngrok-cname.com -Address: 192.0.2.75 -Name: 4bvatzaa19xbdzvcv.2hgtjydm4lbzrtfge.ngrok-cname.com -Address: 198.51.100.134 -Name: 4bvatzaa19xbdzvcv.2hgtjydm4lbzrtfge.ngrok-cname.com -Address: 198.51.100.205 -Name: 4bvatzaa19xbdzvcv.2hgtjydm4lbzrtfge.ngrok-cname.com -Address: 203.0.113.165 -Name: 4bvatzaa19xbdzvcv.2hgtjydm4lbzrtfge.ngrok-cname.com -Address: 203.0.113.94 -``` - -## **Start ngrok Tunnel using Hostname** - -Once your DNS record is in place you can create a tunnel using your new domain. Try running: - -```bash -ngrok http --url foo.example.com 8080 -``` - -and presuming you're actually running an application on port 8080 then making an HTTP request to `https://foo.example.com` should return a response from your app. diff --git a/docs/guides/other-guides/how-to-terminate-traffic-with-ngrok-configs.mdx b/docs/guides/other-guides/how-to-terminate-traffic-with-ngrok-configs.mdx index 86680c3393..c7483f72f7 100644 --- a/docs/guides/other-guides/how-to-terminate-traffic-with-ngrok-configs.mdx +++ b/docs/guides/other-guides/how-to-terminate-traffic-with-ngrok-configs.mdx @@ -3,7 +3,7 @@ Agent TLS termination enables you to secure your traffic with end-to-end encryption without needing to reconfigure your server. :::tip -If your service doesn't support TLS termination, you can still use Agent TLS termination with [Zero-Knowledge TLS](/universal-gateway/tls-termination/#end-to-end-encryption). +If your service doesn't support TLS termination, you can still use Agent TLS termination with [Zero-Knowledge TLS](/universal-gateway/tls/tls-termination/#end-to-end-encryption). ::: ## Quickstart diff --git a/docs/guides/other-guides/securing-your-tunnels.mdx b/docs/guides/other-guides/securing-your-tunnels.mdx index a8829c491a..4e971520a3 100644 --- a/docs/guides/other-guides/securing-your-tunnels.mdx +++ b/docs/guides/other-guides/securing-your-tunnels.mdx @@ -26,7 +26,7 @@ For our HTTP tunnel type, use `scheme https` to configure the ngrok agent to ope If your local service is not running on the same machine as the ngrok agent, we recommend that you set up TLS encryption for the ngrok agent to upstream service leg of the tunnel using our [local HTTPS feature](/universal-gateway/http/#https-forwarding). -For custom domains, use ngrok's [Automated TLS certificates](/universal-gateway/tls-certificates/#automated) to have ngrok automatically provision a TLS certificate for your endpoint from Let's Encrypt. +For custom domains, use ngrok's [Automated TLS certificates](/universal-gateway/tls-certificatesautomatic-certificate-management/) to have ngrok automatically provision a TLS certificate for your endpoint from Let's Encrypt. :::note @@ -42,7 +42,7 @@ If your organization uses a custom ingress domain, your default ngrok configurat ### TLS termination -TLS Encryption is terminated at different locations depending on the ngrok Tunnel / Edge type and configuration. See the documentation on [Terminating TLS Connections](/universal-gateway/tls-termination/) for more details. +TLS Encryption is terminated at different locations depending on the ngrok Tunnel / Edge type and configuration. See the documentation on [Terminating TLS Connections](/universal-gateway/tls/tls-termination/) for more details. ### Minimum TLS version diff --git a/docs/guides/site-to-site-connectivity/apis-mtls.mdx b/docs/guides/site-to-site-connectivity/apis-mtls.mdx index 921257ed5e..bb11110aa3 100644 --- a/docs/guides/site-to-site-connectivity/apis-mtls.mdx +++ b/docs/guides/site-to-site-connectivity/apis-mtls.mdx @@ -131,7 +131,7 @@ https://api.ngrok.com/agent_ingresses ## Create a custom wildcard domain -Next, create a custom [wildcard domain](/universal-gateway/domains/#wildcard-domains), which will allow you to +Next, create a custom [wildcard domain](/universal-gateway/domains/what-are-domains/#wildcard-domains), which will allow you to create endpoints and receive traffic on any subdomain of your domain. For example, you might create `*.customer1.{YOUR_DOMAIN}`. You would then be able to create endpoints diff --git a/docs/guides/site-to-site-connectivity/apis.mdx b/docs/guides/site-to-site-connectivity/apis.mdx index dc2c163701..bba7c17354 100644 --- a/docs/guides/site-to-site-connectivity/apis.mdx +++ b/docs/guides/site-to-site-connectivity/apis.mdx @@ -113,7 +113,7 @@ https://api.ngrok.com/agent_ingresses ## Create a custom wildcard domain -Next, create a custom [wildcard domain](/universal-gateway/domains/#wildcard-domains), which will allow you to +Next, create a custom [wildcard domain](/universal-gateway/domains/what-are-domains/#wildcard-domains), which will allow you to create endpoints and receive traffic on any subdomain of your domain. For example, you might create `*.customer1.{YOUR_DOMAIN}`. You would then be able to create endpoints diff --git a/docs/guides/site-to-site-connectivity/dbs-mtls.mdx b/docs/guides/site-to-site-connectivity/dbs-mtls.mdx index 8a30ae8078..8fdde312fa 100644 --- a/docs/guides/site-to-site-connectivity/dbs-mtls.mdx +++ b/docs/guides/site-to-site-connectivity/dbs-mtls.mdx @@ -134,7 +134,7 @@ https://api.ngrok.com/agent_ingresses ## Create a custom wildcard domain -Next, create a custom [wildcard domain](/universal-gateway/domains/#wildcard-domains), which will allow you to +Next, create a custom [wildcard domain](/universal-gateway/domains/what-are-domains/#wildcard-domains), which will allow you to create endpoints and receive traffic on any subdomain of your domain. For example, you might create `*.customer1.{YOUR_DOMAIN}`. You would then be able to create endpoints diff --git a/docs/guides/site-to-site-connectivity/end-customers.mdx b/docs/guides/site-to-site-connectivity/end-customers.mdx index 6b3752ad25..a68859e6f7 100644 --- a/docs/guides/site-to-site-connectivity/end-customers.mdx +++ b/docs/guides/site-to-site-connectivity/end-customers.mdx @@ -140,8 +140,8 @@ your vendor. The agent always connects to the ngrok network via TLS. We support three encryption models based on where TLS is _terminated_: 1. **TLS termination at the ngrok network**. This is the default behavior when using HTTPS tunnels, where ngrok manages TLS certificate generation and renewal for both you and your vendor. -2. **TLS termination at the ngrok agent**. Often referred to as [zero-knowledge TLS](/universal-gateway/tls-termination/#end-to-end-encryption), this model encrypts your TLS tunnels end-to-end, using filesystem paths to your TLS certificate and key, without requiring you to reconfigure your upstream service for TLS termination. -3. **TLS termination at your upstream service**. This model implements [end-to-end zero-knowledge encryption](/universal-gateway/tls-termination/#end-to-end-encryption), where the ngrok network forwards unterminated connections through to your upstream application. +2. **TLS termination at the ngrok agent**. Often referred to as [zero-knowledge TLS](/universal-gateway/tls/tls-termination/#end-to-end-encryption), this model encrypts your TLS tunnels end-to-end, using filesystem paths to your TLS certificate and key, without requiring you to reconfigure your upstream service for TLS termination. +3. **TLS termination at your upstream service**. This model implements [end-to-end zero-knowledge encryption](/universal-gateway/tls/tls-termination/#end-to-end-encryption), where the ngrok network forwards unterminated connections through to your upstream application. ### Is my data end-to-end encrypted? @@ -196,7 +196,7 @@ Your vendor can also work with ngrok to provision dedicated IPs for their custom At this point, you can block the default agent ingress address at `connect.ngrok-agent.com:443`, which all agents use by default to connect outbound to ngrok’s network. This address resolves to a dynamic set of IP addresses, and blocking it at your network prevents any usage outside of this site-to-site connectivity use case in partnership with your vendor, such as developers utilizing ngrok to tunnel local development environments to the public internet. -You should also block the [ngrok-managed public domains](/universal-gateway/domains/#ngrok-managed-domains), e.g. `ngrok.app`, `ngrok.io`, etc. +You should also block the [ngrok-managed public domains](/universal-gateway/domains/what-are-managed-domains), e.g. `ngrok.app`, `ngrok.io`, etc. Work with your vendor to design an architecture that [prevents unauthorized use](#how-can-i-prevent-ngrok-from-being-used-for-any-purpose-other-than-in-site-to-site-connectivity-with-my-vendor?) diff --git a/docs/integrations/digitalocean/gslb.mdx b/docs/integrations/digitalocean/gslb.mdx index fb842e6d6e..507eb9dacc 100644 --- a/docs/integrations/digitalocean/gslb.mdx +++ b/docs/integrations/digitalocean/gslb.mdx @@ -44,7 +44,7 @@ To simplify authenticating your account with the ngrok API, export the API key o export NGROK_API_KEY= ``` -Next, create a domain that is a subdomain of an [ngrok-managed domain](/universal-gateway/domains/). For an example deployment like this, `YOUR_COMPANY-digitalocean-gslb.ngrok.app` would work great. +Next, create a domain that is a subdomain of an [ngrok-managed domain](/universal-gateway/domains/what-are-domains/). For an example deployment like this, `YOUR_COMPANY-digitalocean-gslb.ngrok.app` would work great. You can reserve your domain in one of two ways: with the [ngrok API](/api/), or in the [ngrok dashboard](https://dashboard.ngrok.com/domains). diff --git a/docs/integrations/linode/gslb.mdx b/docs/integrations/linode/gslb.mdx index 0c7f3018e1..40be5a02bc 100644 --- a/docs/integrations/linode/gslb.mdx +++ b/docs/integrations/linode/gslb.mdx @@ -44,7 +44,7 @@ To simplify authenticating your account with the ngrok API, export the API key o export NGROK_API_KEY= ``` -Next, create a domain that is a subdomain of an [ngrok-managed domain](/universal-gateway/domains/). For an example deployment like this, `YOUR_COMPANY-linode-gslb.ngrok.app` would work great. +Next, create a domain that is a subdomain of an [ngrok-managed domain](/universal-gateway/domains/what-are-domains/). For an example deployment like this, `YOUR_COMPANY-linode-gslb.ngrok.app` would work great. You can reserve your domain in one of two ways: with the [ngrok API](/api/), or in the [ngrok dashboard](https://dashboard.ngrok.com/domains). diff --git a/docs/k8s/guides/bindings.mdx b/docs/k8s/guides/bindings.mdx index 9d185f62ed..9ed6ad7158 100644 --- a/docs/k8s/guides/bindings.mdx +++ b/docs/k8s/guides/bindings.mdx @@ -215,6 +215,22 @@ You can modify your operator to only process a subset of them with the `bindings It defaults to `["true"]` which causes it to process all endpoints with a Kubernetes type binding. This can be modified to anything you like to control which endpoints the operator should process. This strategy can enable you to easily only project endpoints into certain clusters running the ngrok Kubernetes operator. +### Selecting endpoints for a cluster + +If you don't want all kubernetes endpoints in your account to appear inside of +a cluster, you may specify an Endpoint Selector which filters which Kubernetes +endpoints are projected into the cluster it runs in. Endpoint Selectors are a +CEL expression which is evaluated against each Kubernetes Endpoint in your +account. The operator will only projects endpoints that the selector returns +`true` for. + +For example, to only project kubernetes endpoints in the billing namespace, you would +add the following flag when installing the Kubernetes Operator: + +```bash + --set binding.endpointSelector="ep.hostname.endsWith('.billing')" \ +``` + ## Bindings with `Ingresses` By default, creating an `Ingress` will create a `CloudEndpoint` that has a `public` binding, meaning that its URL is accessible via the public internet, and an `AgentEndpoint` with an `internal` binding, meaning that its URL is only accessible using the `forward-internal` traffic policy action. diff --git a/docs/k8s/index.mdx b/docs/k8s/index.mdx index 2705ba1194..bb3db119a1 100644 --- a/docs/k8s/index.mdx +++ b/docs/k8s/index.mdx @@ -32,6 +32,24 @@ The Operator supports its own native custom resource types, including: You can use a different configuration type for each domain. ::: + +## How do I enable or disable Kubernetes endpoints on an existing installation? + +By default, if you don't change the endpoint selector, all endpoints with a Kubernetes binding will be bound to the cluster the Operator is installed on. Changing the binding allows you to restrict which endpoints that operator will handle. + +See [the docs on enabling bindings](/docs/k8s/guides/bindings/#enable-bindings-for-the-operator) to learn more. + +## Using the API + +Kubernetes endpoints can be created programatically. Consult the documentation on [Endpoint APIs](/api/resources/endp + +## Type and Pooling + +- Kubernetes endpoints support all [Endpoint + Types](/universal-gateway/types) (`agent` and `cloud`). +- Kubernetes endpoints support [Endpoint + Pooling](/universal-gateway/endpoint-pooling). + ## Pricing The ngrok Kubernetes Operator is available to all ngrok users at no diff --git a/docs/obs/events/reference.mdx b/docs/obs/events/reference.mdx index 8aa385be95..99d0bb1031 100644 --- a/docs/obs/events/reference.mdx +++ b/docs/obs/events/reference.mdx @@ -898,88 +898,88 @@ Triggers when a TCP address is updated Triggers when a TLS certificate is created -| Field | Type | Description | -| ------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | -| `id` | string | unique identifier for this TLS certificate | -| `uri` | string | URI of the TLS certificate API resource | -| `created_at` | string | timestamp when the TLS certificate was created, RFC 3339 format | -| `description` | string | human-readable description of this TLS certificate. optional, max 255 bytes. | -| `metadata` | string | arbitrary user-defined machine-readable data of this TLS certificate. optional, max 4096 bytes. | -| `certificate_pem` | string | chain of PEM-encoded certificates, leaf first. See [Certificate Bundles](/universal-gateway/tls-certificates/#certificate-bundles). | -| `subject_common_name` | string | subject common name from the leaf of this TLS certificate | -| `subject_alternative_names.dns_names` | List<string> | set of additional domains (including wildcards) this TLS certificate is valid for | -| `subject_alternative_names.ips` | List<string> | set of IP addresses this TLS certificate is also valid for | -| `issued_at` | string | timestamp (in RFC 3339 format) when this TLS certificate was issued automatically, or null if this certificate was user-uploaded | -| `not_before` | string | timestamp when this TLS certificate becomes valid, RFC 3339 format | -| `not_after` | string | timestamp when this TLS certificate becomes invalid, RFC 3339 format | -| `key_usages` | List<string> | set of actions the private key of this TLS certificate can be used for | -| `extended_key_usages` | List<string> | extended set of actions the private key of this TLS certificate can be used for | -| `private_key_type` | string | type of the private key of this TLS certificate. One of rsa, ecdsa, or ed25519. | -| `issuer_common_name` | string | issuer common name from the leaf of this TLS certificate | -| `serial_number` | string | serial number of the leaf of this TLS certificate | -| `subject_organization` | string | subject organization from the leaf of this TLS certificate | -| `subject_organizational_unit` | string | subject organizational unit from the leaf of this TLS certificate | -| `subject_locality` | string | subject locality from the leaf of this TLS certificate | -| `subject_province` | string | subject province from the leaf of this TLS certificate | -| `subject_country` | string | subject country from the leaf of this TLS certificate | +| Field | Type | Description | +| ------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | string | unique identifier for this TLS certificate | +| `uri` | string | URI of the TLS certificate API resource | +| `created_at` | string | timestamp when the TLS certificate was created, RFC 3339 format | +| `description` | string | human-readable description of this TLS certificate. optional, max 255 bytes. | +| `metadata` | string | arbitrary user-defined machine-readable data of this TLS certificate. optional, max 4096 bytes. | +| `certificate_pem` | string | chain of PEM-encoded certificates, leaf first. See [Certificate Bundles](/universal-gateway/tls-certificates/what-is-a-certificate-bundle/). | +| `subject_common_name` | string | subject common name from the leaf of this TLS certificate | +| `subject_alternative_names.dns_names` | List<string> | set of additional domains (including wildcards) this TLS certificate is valid for | +| `subject_alternative_names.ips` | List<string> | set of IP addresses this TLS certificate is also valid for | +| `issued_at` | string | timestamp (in RFC 3339 format) when this TLS certificate was issued automatically, or null if this certificate was user-uploaded | +| `not_before` | string | timestamp when this TLS certificate becomes valid, RFC 3339 format | +| `not_after` | string | timestamp when this TLS certificate becomes invalid, RFC 3339 format | +| `key_usages` | List<string> | set of actions the private key of this TLS certificate can be used for | +| `extended_key_usages` | List<string> | extended set of actions the private key of this TLS certificate can be used for | +| `private_key_type` | string | type of the private key of this TLS certificate. One of rsa, ecdsa, or ed25519. | +| `issuer_common_name` | string | issuer common name from the leaf of this TLS certificate | +| `serial_number` | string | serial number of the leaf of this TLS certificate | +| `subject_organization` | string | subject organization from the leaf of this TLS certificate | +| `subject_organizational_unit` | string | subject organizational unit from the leaf of this TLS certificate | +| `subject_locality` | string | subject locality from the leaf of this TLS certificate | +| `subject_province` | string | subject province from the leaf of this TLS certificate | +| `subject_country` | string | subject country from the leaf of this TLS certificate | #### tls_certificate_deleted.v0 Triggers when a TLS certificate is deleted -| Field | Type | Description | -| ------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | -| `id` | string | unique identifier for this TLS certificate | -| `uri` | string | URI of the TLS certificate API resource | -| `created_at` | string | timestamp when the TLS certificate was created, RFC 3339 format | -| `description` | string | human-readable description of this TLS certificate. optional, max 255 bytes. | -| `metadata` | string | arbitrary user-defined machine-readable data of this TLS certificate. optional, max 4096 bytes. | -| `certificate_pem` | string | chain of PEM-encoded certificates, leaf first. See [Certificate Bundles](/universal-gateway/tls-certificates/#certificate-bundles). | -| `subject_common_name` | string | subject common name from the leaf of this TLS certificate | -| `subject_alternative_names.dns_names` | List<string> | set of additional domains (including wildcards) this TLS certificate is valid for | -| `subject_alternative_names.ips` | List<string> | set of IP addresses this TLS certificate is also valid for | -| `issued_at` | string | timestamp (in RFC 3339 format) when this TLS certificate was issued automatically, or null if this certificate was user-uploaded | -| `not_before` | string | timestamp when this TLS certificate becomes valid, RFC 3339 format | -| `not_after` | string | timestamp when this TLS certificate becomes invalid, RFC 3339 format | -| `key_usages` | List<string> | set of actions the private key of this TLS certificate can be used for | -| `extended_key_usages` | List<string> | extended set of actions the private key of this TLS certificate can be used for | -| `private_key_type` | string | type of the private key of this TLS certificate. One of rsa, ecdsa, or ed25519. | -| `issuer_common_name` | string | issuer common name from the leaf of this TLS certificate | -| `serial_number` | string | serial number of the leaf of this TLS certificate | -| `subject_organization` | string | subject organization from the leaf of this TLS certificate | -| `subject_organizational_unit` | string | subject organizational unit from the leaf of this TLS certificate | -| `subject_locality` | string | subject locality from the leaf of this TLS certificate | -| `subject_province` | string | subject province from the leaf of this TLS certificate | -| `subject_country` | string | subject country from the leaf of this TLS certificate | +| Field | Type | Description | +| ------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | string | unique identifier for this TLS certificate | +| `uri` | string | URI of the TLS certificate API resource | +| `created_at` | string | timestamp when the TLS certificate was created, RFC 3339 format | +| `description` | string | human-readable description of this TLS certificate. optional, max 255 bytes. | +| `metadata` | string | arbitrary user-defined machine-readable data of this TLS certificate. optional, max 4096 bytes. | +| `certificate_pem` | string | chain of PEM-encoded certificates, leaf first. See [Certificate Bundles](/universal-gateway/tls-certificates/what-is-a-certificate-bundle/). | +| `subject_common_name` | string | subject common name from the leaf of this TLS certificate | +| `subject_alternative_names.dns_names` | List<string> | set of additional domains (including wildcards) this TLS certificate is valid for | +| `subject_alternative_names.ips` | List<string> | set of IP addresses this TLS certificate is also valid for | +| `issued_at` | string | timestamp (in RFC 3339 format) when this TLS certificate was issued automatically, or null if this certificate was user-uploaded | +| `not_before` | string | timestamp when this TLS certificate becomes valid, RFC 3339 format | +| `not_after` | string | timestamp when this TLS certificate becomes invalid, RFC 3339 format | +| `key_usages` | List<string> | set of actions the private key of this TLS certificate can be used for | +| `extended_key_usages` | List<string> | extended set of actions the private key of this TLS certificate can be used for | +| `private_key_type` | string | type of the private key of this TLS certificate. One of rsa, ecdsa, or ed25519. | +| `issuer_common_name` | string | issuer common name from the leaf of this TLS certificate | +| `serial_number` | string | serial number of the leaf of this TLS certificate | +| `subject_organization` | string | subject organization from the leaf of this TLS certificate | +| `subject_organizational_unit` | string | subject organizational unit from the leaf of this TLS certificate | +| `subject_locality` | string | subject locality from the leaf of this TLS certificate | +| `subject_province` | string | subject province from the leaf of this TLS certificate | +| `subject_country` | string | subject country from the leaf of this TLS certificate | #### tls_certificate_updated.v0 Triggers when a TLS certificate is updated -| Field | Type | Description | -| ------------------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | -| `id` | string | unique identifier for this TLS certificate | -| `uri` | string | URI of the TLS certificate API resource | -| `created_at` | string | timestamp when the TLS certificate was created, RFC 3339 format | -| `description` | string | human-readable description of this TLS certificate. optional, max 255 bytes. | -| `metadata` | string | arbitrary user-defined machine-readable data of this TLS certificate. optional, max 4096 bytes. | -| `certificate_pem` | string | chain of PEM-encoded certificates, leaf first. See [Certificate Bundles](/universal-gateway/tls-certificates/#certificate-bundles). | -| `subject_common_name` | string | subject common name from the leaf of this TLS certificate | -| `subject_alternative_names.dns_names` | List<string> | set of additional domains (including wildcards) this TLS certificate is valid for | -| `subject_alternative_names.ips` | List<string> | set of IP addresses this TLS certificate is also valid for | -| `issued_at` | string | timestamp (in RFC 3339 format) when this TLS certificate was issued automatically, or null if this certificate was user-uploaded | -| `not_before` | string | timestamp when this TLS certificate becomes valid, RFC 3339 format | -| `not_after` | string | timestamp when this TLS certificate becomes invalid, RFC 3339 format | -| `key_usages` | List<string> | set of actions the private key of this TLS certificate can be used for | -| `extended_key_usages` | List<string> | extended set of actions the private key of this TLS certificate can be used for | -| `private_key_type` | string | type of the private key of this TLS certificate. One of rsa, ecdsa, or ed25519. | -| `issuer_common_name` | string | issuer common name from the leaf of this TLS certificate | -| `serial_number` | string | serial number of the leaf of this TLS certificate | -| `subject_organization` | string | subject organization from the leaf of this TLS certificate | -| `subject_organizational_unit` | string | subject organizational unit from the leaf of this TLS certificate | -| `subject_locality` | string | subject locality from the leaf of this TLS certificate | -| `subject_province` | string | subject province from the leaf of this TLS certificate | -| `subject_country` | string | subject country from the leaf of this TLS certificate | +| Field | Type | Description | +| ------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | +| `id` | string | unique identifier for this TLS certificate | +| `uri` | string | URI of the TLS certificate API resource | +| `created_at` | string | timestamp when the TLS certificate was created, RFC 3339 format | +| `description` | string | human-readable description of this TLS certificate. optional, max 255 bytes. | +| `metadata` | string | arbitrary user-defined machine-readable data of this TLS certificate. optional, max 4096 bytes. | +| `certificate_pem` | string | chain of PEM-encoded certificates, leaf first. See [Certificate Bundles](/universal-gateway/tls-certificates/what-is-a-certificate-bundle/). | +| `subject_common_name` | string | subject common name from the leaf of this TLS certificate | +| `subject_alternative_names.dns_names` | List<string> | set of additional domains (including wildcards) this TLS certificate is valid for | +| `subject_alternative_names.ips` | List<string> | set of IP addresses this TLS certificate is also valid for | +| `issued_at` | string | timestamp (in RFC 3339 format) when this TLS certificate was issued automatically, or null if this certificate was user-uploaded | +| `not_before` | string | timestamp when this TLS certificate becomes valid, RFC 3339 format | +| `not_after` | string | timestamp when this TLS certificate becomes invalid, RFC 3339 format | +| `key_usages` | List<string> | set of actions the private key of this TLS certificate can be used for | +| `extended_key_usages` | List<string> | extended set of actions the private key of this TLS certificate can be used for | +| `private_key_type` | string | type of the private key of this TLS certificate. One of rsa, ecdsa, or ed25519. | +| `issuer_common_name` | string | issuer common name from the leaf of this TLS certificate | +| `serial_number` | string | serial number of the leaf of this TLS certificate | +| `subject_organization` | string | subject organization from the leaf of this TLS certificate | +| `subject_organizational_unit` | string | subject organizational unit from the leaf of this TLS certificate | +| `subject_locality` | string | subject locality from the leaf of this TLS certificate | +| `subject_province` | string | subject province from the leaf of this TLS certificate | +| `subject_country` | string | subject country from the leaf of this TLS certificate | ### Tunnel Credential diff --git a/docs/overview/index.mdx b/docs/overview/index.mdx index 886a9f72f9..7c99a4d9d6 100644 --- a/docs/overview/index.mdx +++ b/docs/overview/index.mdx @@ -13,21 +13,21 @@ import Link from "@docusaurus/Link"; ngrok is your app's front door. ngrok is a globally distributed reverse proxy that secures, protects and accelerates your applications and network services, no matter where you run them. ngrok supports delivering HTTP, TLS or TCP-based - applications. More about how ngrok works → + applications. More about how ngrok works →

You can use ngrok in development for webhook testing or in production as an API Gateway, Kubernetes Ingress, or Identity-Aware Proxy. You can also run ngrok to easily create secure connectivity to APIs in your customers' networks or on your devices in the field.{" "} - More about what you can do with ngrok → + More about what you can do with ngrok →

## Get Started
diff --git a/docs/pricing-limits/endpoint-limits.mdx b/docs/pricing-limits/endpoint-limits.mdx new file mode 100644 index 0000000000..16bcf6e69c --- /dev/null +++ b/docs/pricing-limits/endpoint-limits.mdx @@ -0,0 +1,72 @@ +--- +title: Endpoint Limits +description: Learn about data limits and timeouts for endpoints on ngrok. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; +import TlsLimits from "../universal-gateway/_tls_limits.mdx"; + +[Contact us](mailto:support@ngrok.com) if you need to configure limits and timeouts on connections to HTTP/S, TLS, or TCP endpoints. + +## Connection limits + + + + +| Limit | Name | Notes | +| --------- | ------------------- | ------------------------------------------------------------ | +| 5 minutes | Client Idle Timeout | Time since data was last transmitted by the upstream service | +| 5 minutes | Server Idle Timeout | Time since data was last transmitted by the upstream service | +| No limit | Data transmitted | Data transmitted by the client or upstream service | + + + + +| Limit | Name | Notes | +| --------- | ------------------- | -------------------------------------------------------------- | +| 3 seconds | ClientHello Timeout | Time between connection establishment and ClientHello received | +| 5 minutes | Client Idle Timeout | Time since data was last transmitted by the upstream service | +| 5 minutes | Server Idle Timeout | Time since data was last transmitted by the upstream service | +| No limit | Data transmitted | Data transmitted by the client or upstream service | + + + + + +## TLS certificate limits + + + +## HTTP timeout limits + +| Limit | Name | Notes | +| ---------- | ------------------ | --------------------------------------------- | +| No timeout | Round Trip Timeout | Time for the entire HTTP request and response | + +## HTTP Request limits + +| Limit | Name | Notes | +| ---------- | ---------------------- | ---------------------------------------------------- | +| 1 MB | Request Header Size | Includes method, URI and headers | +| 1 MB | Request URI Length | Limited by the size of the request header | +| No timeout | Request Timeout | Time to read the entire HTTP request from the client | +| No timeout | Request Header Timeout | Time to read the HTTP request header from the client | +| No limit | Request Body Size | | + +## HTTP Response limits + +| Limit | Name | Notes | +| ---------- | ----------------------- | ----------------------------------------------------- | +| 1 MB | Response Header Size | Includes method, URI and headers | +| No timeout | Response Timeout | Time to read the entire HTTP response from the server | +| No timeout | Response Header Timeout | Time to read the HTTP response header from the server | +| No limit | Response Body Size | | + +## TCP timeout limits + +| Limit | Name | Notes | +| --------- | ------------------- | ------------------------------------------------------------ | +| 5 minutes | Client Idle Timeout | Time since data was last transmitted by the upstream service | +| 5 minutes | Server Idle Timeout | Time since data was last transmitted by the upstream service | +| No limit | Data transmitted | Data transmitted by the client or upstream service | diff --git a/docs/pricing-limits/index.mdx b/docs/pricing-limits/index.mdx index 7579f83442..92c9d670bf 100644 --- a/docs/pricing-limits/index.mdx +++ b/docs/pricing-limits/index.mdx @@ -14,7 +14,7 @@ For information on free plans, see [Free Plan Limts](/pricing-limits/free-plan-l | Feature | Free Users | Development Plans (Personal, Pro, Enterprise) | Production Pay-as-You-Go Plans | | --------------------------------------------- | ------------------- | --------------------------------------------- | ----------------------------------------------------------------- | -| **Domains** | 1 static domain | 1 per license | No limit, priced on-demand | +| **[Domains](#domain-configuration-pricing)** | 1 static domain | 1 per license | No limit, priced on-demand | | **Endpoints** | 3 | 3 per license | No limit, priced on-demand | | **Cloud Endpoints** | 3 | NA | No limit, priced on-demand | | **TCP Endpoints** | 3 per agent session | 1 per TCP address | No limit, priced on-demand | @@ -45,6 +45,16 @@ For information on free plans, see [Free Plan Limts](/pricing-limits/free-plan-l You can check your usage [in the Usage page in the dashboard](https://dashboard.ngrok.com/usage). ::: +## Domain configuration pricing + +Domains are available on all plans. Some Domain features require upgrades. See the [Pricing page](https://ngrok.com/pricing) for details. + +| Feature | Plans | +| ---------------------- | --------------------------------------------------------------------------------- | +| Domains | All plans. The Domain name is assigned on Free, you may choose it on other plans. | +| Bring-your-own domains | Personal, Pro, Enterprise, Pay-as-you-go | +| Wildcard Domains | Enterprise | + ## General limits Each license at ngrok roughly represents a developer using an ngrok agent for building an application. It includes the ability to run an ngrok agent (or use the agent SDKs or ngrok Kubernetes Operator) with a custom domain or TCP Address. @@ -63,9 +73,7 @@ This limit does not refresh at the end of each calendar month. ## Wildcard and Subdomain Usage -When reserving a wildcard domain on the paid plans, subdomains are counted towards your usage. For example, if you reserve `*.example.com`, `sub1.example.com` and `sub2.example.com` are counted as two subdomains. -You will be charged for each subdomain you use. -You may need to enable overages in order to do this on your paid plan. +Reserving subdomains of a wildcard domain within the ngrok dashboard count towards the number of reserved domains in your account. For example, if you reserve `foo.example.com` and `*.example.com`, you have reserved two domains.. You will be charged for each subdomain you use. You may need to enable overages in order to do this on your paid plan. ## Free vs paid plans diff --git a/docs/pricing-limits/pooling-limits.mdx b/docs/pricing-limits/pooling-limits.mdx new file mode 100644 index 0000000000..369d019606 --- /dev/null +++ b/docs/pricing-limits/pooling-limits.mdx @@ -0,0 +1,41 @@ +--- +title: Endpoint Pooling Limits +description: Learn about the technical limits associated with ngrok's endpoint pools. +--- + +Learn about the technical limits associated with ngrok's endpoint pools. + +## Endpoint pool lifecycle + +An Endpoint Pool is automatically created whenever you create two endpoints with: + +- The same URL +- The same binding +- Pooling enabled + +When only a single endpoint remains in a pool, the pool is deleted. + +## Max pool size + +There is no limit on the number of endpoints that may be in a pool. + +## Supported protocols, bindings, and types + +Endpoint pooling supports all: + +- Protocols +- Bindings +- Types (and you can mix types in an endpoint pool) + +## Conflicting endpoints + +Endpoint pooling happens when two or more endpoints share a URL and binding, but both **only if these endpoints have [pooling enabled](/universal-gatway/pooling/#enabling-pooling)**. If an existing endpoint does not have pooling enabled, ngrok will return a conflict error when you try to create a new endpoint with the same URL and binding. + +:::note +Conflicts can only occur during endpoint creation because both the URL and the `pooling_enabled` property may not be updated after an endpoint has been created. +::: + +### Endpoint pool protocols + +The URLs of all endpoints in a pool must share the same protocol. For example, you may not pool the endpoints `https://foo.internal:1234` and +`tcp://foo.internal:1234` together because they have a different protocol. diff --git a/docs/universal-gateway/agent-endpoints.mdx b/docs/universal-gateway/agent-endpoints.mdx index 4344f1e459..a7fa158141 100644 --- a/docs/universal-gateway/agent-endpoints.mdx +++ b/docs/universal-gateway/agent-endpoints.mdx @@ -1,6 +1,7 @@ --- -title: Agent Endpoints -description: Learn about creating endpoints managed by Secure Tunnel agents. +sidebar_label: Using Agent Endpoints +title: What are Agent Endpoints? +description: Learn about creating endpoints managed by Secure Tunnel agents run on your local machines. --- Agent Endpoints are public or internal Endpoints created by Secure Tunnel agents, which include any of the following: @@ -11,9 +12,9 @@ Agent Endpoints are public or internal Endpoints created by Secure Tunnel agents Agent Endpoints live for the lifetime of, and forward connections to, the agent process that started them. -## Get started - -To set up your first Agent endpoint, see [the Getting Started with ngrok](/getting-started/) guide. +:::tip +The counterpart to Agent Endpoints are Cloud Endpoints, which are always-on and centrally managed via the ngrok API or Dashboard. See [the Cloud Endpoints documentation](/universal-gateway/cloud-endpoints/) for more information. +::: ## Use cases @@ -26,6 +27,10 @@ Agent endpoints are a good choice when you want to: - **You can use agent endpoints to create connectivity to apps running on your localhost, an IoT device in the field, or an EC2 instance**. - Because agent endpoints are created via [Secure Tunnel agents](/agent/), they are excellent for connecting to apps running on all networks, even those behind a NAT. +## Get started + +To set up your first Agent endpoint, see [the Getting Started with ngrok](/getting-started/) guide. + ## Differences from Cloud Endpoints :::note diff --git a/docs/universal-gateway/agent-forwarding/forward-original-connection-data.mdx b/docs/universal-gateway/agent-forwarding/forward-original-connection-data.mdx new file mode 100644 index 0000000000..f09ea1819c --- /dev/null +++ b/docs/universal-gateway/agent-forwarding/forward-original-connection-data.mdx @@ -0,0 +1,193 @@ +--- +title: Forwarding Original Connection Data +description: Learn how to forward original connection data to your upstream services. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; +import { ContentSwitcher } from "@site/src/components/LangSwitcher/ContentSwitcher"; + +import ProxyProtoAgentConfigExample from "/examples/agent-config/tcp-proxyproto.mdx"; +import ProxyProtoKubernetesExample from "/examples/k8s/tcp-proxyproto.mdx"; + +When you forward traffic to an upstream TCP service, becuase traffic is coming from the ngrok agent, it won't have access to connection information like the original client IP address. You can add the [PROXY protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) header on connections to your upstream service to send original connection information to your upstream service. + +You will need to configure your upstream service to handle the PROXY protocol header. + +:::info + +PROXY protocol is not support for SSH + +::: + +## TCP proxy protocol example + + + + +```bash +ngrok tcp 22 --upstream-proxy-protocol=2 +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.TCPEndpoint( + config.WithProxyProto(2), + ), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```python +import ngrok + +listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + proto="tcp", + proxy_proto="2") + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; + +async fn listen_ngrok() -> anyhow::Result { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + + let tun = sess + .tcp_endpoint() + .proxy_proto(ProxyProto::V2) + .listen() + .await?; + + println!("Listening on URL: {:?}", tun.url()); + + Ok(tun) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + proto: "tcp", + proxy_proto: "2", + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + + + + + + + + + + + + +## TLS proxy protocol example + + + + +```bash +ngrok tls 443 --upstream-proxy-protocol=2 +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.TLSEndpoint( + config.WithProxyProto(2), + ), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + proto: "tls", + proxy_proto: "2", + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + proto="tls", + proxy_proto="2") + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; + +async fn listen_ngrok() -> anyhow::Result { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + + let tun = sess + .tls_endpoint() + .proxy_proto(ProxyProto::V2) + .listen() + .await?; + + println!("Listening on URL: {:?}", tun.url()); + + Ok(tun) +} +``` + + + + + + + + + + + diff --git a/docs/universal-gateway/agent-forwarding/index.mdx b/docs/universal-gateway/agent-forwarding/index.mdx new file mode 100644 index 0000000000..cdc243c82c --- /dev/null +++ b/docs/universal-gateway/agent-forwarding/index.mdx @@ -0,0 +1,223 @@ +--- +title: How Do I Forward Traffic To My Upstream Services? +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; +import { ContentSwitcher } from "@site/src/components/LangSwitcher/ContentSwitcher"; + +import ForwardHttpsAgentConfigExample from "/examples/agent-config/http-forward-https.mdx"; +import ForwardHttpsKubernetesExample from "/examples/k8s/http-forward-https.mdx"; + +import ReencryptUpstreamAgentConfigExample from "/examples/agent-config/tls-reencrypt-upstream.mdx"; + +The [ngrok agent](/agent/) and [Agent SDKs](/agent-sdks/) forward traffic that your endpoints receive to upstream services. You specify a URL or port number to instruct the ngrok agent where and how to forward traffic. + +:::note +This page covers forwarding traffic to upstream resources. If you specifically want to forward traffic from one endpoint to another, [use Traffic Policy](/universal-gateway/chain-endpoints). +::: + +## HTTPS forwarding + +The scheme in your upstream URL is used to determine whether to forward HTTP or HTTPS traffic to the upstream service. If you do not specify a scheme, the default `http` scheme is chosen _unless_ you forward to port `443`, in which case ngrok will use `https`. Consult the following table of examples. + +| Upstream URL | Normalized Value | +| ------------------------ | ------------------------ | +| `http://localhost:1234` | `http://localhost:1234` | +| `https://localhost:1234` | `https://localhost:1234` | +| `localhost:1234` | `http://localhost:1234` | +| `1234` | `http://localhost:1234` | +| `localhost:443` | `https://localhost:443` | +| `443` | `https://localhost:443` | + +ngrok assumes that the network you run the agent on is private and it does not verify the TLS certificate presented by the upstream service. You may change this behavior with the [flags `--upstream-tls-verify` and `upstream-tls-verify-cas`](/agent/cli/#ngrok-http). + +:::info +Forwarding to an upstream HTTPS service is not supported via SSH. +::: + + + + +```bash +ngrok http https://localhost:8443 +``` + +```go +import ( + "context" + "net/url" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" + +) + +func ngrokForwarder(ctx context.Context) (ngrok.Forwarder, error) { +backendUrl, err := url.Parse("https://localhost:8443") +if err != nil { +return nil, err +} + + return ngrok.ListenAndForward(ctx, + backendUrl, + config.HTTPEndpoint(), + ngrok.WithAuthtokenFromEnv(), + ) + +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: "https://localhost:8443", + authtoken_from_env: true, + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +listener = ngrok.forward("https://localhost:8443", authtoken_from_env=True) + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; +use ngrok::tunnel; +use ngrok::forwarder::Forwarder; +use url::Url; + +async fn forward_ngrok() -> Result, Error> { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + sess + .http_endpoint() + .listen_and_forward(Url::parse("https://localhost:8443")?) + .await + .map_err(Into::into) +} +``` + + + + + + + + + + + + + + + + +:::note +For HTTP/2 Use: `config.HTTPEndpoint(config.WithAppProtocol("http2"))` +::: + + + +### HTTP/2 forwarding + +When agents forward to upstream http/2 services, connections use HTTP/1.1 by +default. + +You can configure the agent, SDKs and Kubernetes Operator to instead use HTTP/2 +when forwarding to your upstream service. + +| Forwarder | Option | Docs | +| ------------------- | --------------------------------- | ----------------------------------------- | +| Agent | `--upstream-protocol` | [Agent CLI flags](/agent/cli/#ngrok-http) | +| Agent SDKs | language-dependent | [Agent SDKs](/agent-sdks) | +| Kubernetes Operator | `appProtocol` on the `Tunnel` CRD | [Kubernetes Operator](/k8s) | + +When http2 forwarding is enabled, all requests to your upstream service will be +transmitted over HTTP/2 Cleartext since TLS was already terminated at the ngrok +cloud service. We cannot use +[TLS-ALPN](https://httpwg.org/specs/rfc7540.html#TLS-ALPN) at this time. We +rely on [HTTP/2 with Prior +Knowledge](https://httpwg.org/specs/rfc7540.html#known-http) currently. + +### How do I encrypt traffic forwarded to upstream services? + +If you terminate TLS at the ngrok cloud service or ngrok agent, you may want to +re-encrypt the connection from the agent to your upstream service. The ngrok +agent supports this behavior by using the non-standard `tls://` scheme syntax. + + + + + +```bash +ngrok tls tls://localhost:443 --terminate-at=edge +``` + +```python +import ngrok + +listener = ngrok.forward("tls://localhost:443", authtoken_from_env=True, + proto="tls" + crt=bytearray(), + key=bytearray()) + +print(f"Ingress established at: {listener.url()}"); +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: "tls://localhost:443", + authtoken_from_env: true, + proto: "tls", + crt: "", + key: "", + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + + + + + An empty certificate and key will default to the ngrok edge's automatically + provisioned keypair. The upstream certificate of `localhost:443` will be + validated by a filepath specified in the `SSL_CERT_FILE` environment variable + (e.g. `SSL_CERT_FILE=/path/to/ca.crt`), or falling back to the host OS + installed trusted certificate authorities. + + + + + + + +TLS endpoints are not supported by the ngrok Kubernetes Operator + + + +:::info + +Re-encrypting the connection to your upstream service with TLS is not supported for: + +- SSH +- Go +- Rust + +::: diff --git a/docs/universal-gateway/agent-forwarding/non-local-forwarding.mdx b/docs/universal-gateway/agent-forwarding/non-local-forwarding.mdx new file mode 100644 index 0000000000..8e8292fdae --- /dev/null +++ b/docs/universal-gateway/agent-forwarding/non-local-forwarding.mdx @@ -0,0 +1,201 @@ +--- +title: Forwarding Traffic to External Services +description: Learn how to forward traffic to a non-local address or URL. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; +import { ContentSwitcher } from "@site/src/components/LangSwitcher/ContentSwitcher"; + +import NonLocalAgentConfigExample from "/examples/agent-config/http-nonlocal.mdx"; +import NonLocalAgentConfigExampleTCP from "/examples/agent-config/tcp-nonlocal.mdx"; +import NonLocalKubernetesExample from "/examples/k8s/http-nonlocal.mdx"; +import NonLocalKubernetesExampleTCP from "/examples/k8s/tcp-nonlocal.mdx"; + +Aside from ports on your localhost, ngrok Agents can [forward traffic](/universal-gateway/agent-forwarding/) to any address or URL reachable from the agent. + +## HTTP non-local forwarding + +The following example demonstrates how to forward traffic to an HTTP server running on your network at `192.168.1.2:80`: + + + + + ```bash + ngrok http 192.168.1.2:80 + ``` + + ```sh tabName="SSH" + ssh -R 0:192.168.1.2:80 v2@connect.ngrok-agent.com http + ``` + + ```go + import ( + "context" + "net/url" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" + ) + + func ngrokForwarder(ctx context.Context) (ngrok.Forwarder, error) { + backendUrl, err := url.Parse("http://192.168.1.2:80") + if err != nil { + return nil, err + } + + return ngrok.ListenAndForward(ctx, + backendUrl, + config.HTTPEndpoint(), + ngrok.WithAuthtokenFromEnv(), + ) + } + + ``` + + ```jsx + const ngrok = require("@ngrok/ngrok"); + + (async function () { + const listener = await ngrok.forward({ + addr: "192.168.1.2:80", + authtoken_from_env: true, + }); + + console.log(`Ingress established at: ${listener.url()}`); + })(); + ``` + + ```python + import ngrok + + listener = ngrok.forward("192.168.1.2:80", authtoken_from_env=True) + + print(f"Ingress established at: {listener.url()}"); + ``` + + ```rust + use ngrok::prelude::*; + use ngrok::tunnel; + use ngrok::forwarder::Forwarder; + use url::Url; + + async fn forward_ngrok() -> Result, Error> { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + sess + .http_endpoint() + .listen_and_forward(Url::parse("http://192.168.1.2:80")?) + .await + .map_err(Into::into) + } + ``` + + + + + + + + + + + + + +## TCP non-local forwarding + +The following example demonstrates how to forward traffic to a Postgres server running on your network at `192.168.1.2:5432`: + + + + + +```bash +ngrok tcp 192.168.1.2:5432 +``` + +```sh tabName="SSH" +ssh -R 0:192.168.1.2:5432 v2@connect.ngrok-agent.com tcp +``` + +```go +import ( + "context" + "net/url" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokForwarder(ctx context.Context) (ngrok.Forwarder, error) { + backendUrl, err := url.Parse("tcp://192.168.1.2:80") + if err != nil { + return nil, err + } + + return ngrok.ListenAndForward(ctx, + backendUrl, + config.TCPEndpoint(), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: "192.168.1.2:5432", + authtoken_from_env: true, + proto: "tcp", + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +listener = ngrok.forward("192.168.1.2:5432", authtoken_from_env=True, + proto="tcp") + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; +use ngrok::tunnel; +use ngrok::forwarder::Forwarder; +use url::Url; + +async fn forward_ngrok() -> Result, Error> { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + sess + .tcp_endpoint() + .listen_and_forward(Url::parse("tcp://127.0.0.1:8090")?) + .await + .map_err(Into::into) +} +``` + + + + + + + + + + + + diff --git a/docs/universal-gateway/agent-forwarding/serving-file-directories.mdx b/docs/universal-gateway/agent-forwarding/serving-file-directories.mdx new file mode 100644 index 0000000000..848d73d342 --- /dev/null +++ b/docs/universal-gateway/agent-forwarding/serving-file-directories.mdx @@ -0,0 +1,152 @@ +--- +title: Serving File Directories +description: Learn how to serve content from a local directory using the ngrok agent. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; + +The ngrok agent supports the `file://` scheme in [a forwarding URL](/universal-gateway/agent-forwarding/). When you use the `file://` scheme, the ngrok agent serves local file system directories by using its own built-in file server, no separate server needed. It works just like [`python3 -m http.server`](https://docs.python.org/3.4/library/http.server.html), but it is built directly into the ngrok agent. + +Paths in `file://` URLs must be specified as absolute paths. + +:::info + +Serving directory files is not supported with: + +- SSH +- JavaScript +- Python +- Rust +- Kubernetes Operator + ::: + +## Serve files in `/var/log` + + + + + ```bash + ngrok http "file:///var/log" + ``` + + ```go + import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" + ) + + func serveFiles(ctx context.Context) error { + l, _ := ngrok.Listen(ctx, + config.HTTPEndpoint(), + ngrok.WithAuthtokenFromEnv(), + ) + http.Serve(l, http.FileServer(http.Dir("/var/log"))) + } + ``` + + + + + + +```yaml +version: 3 +endpoints: + - name: example + url: "https://example.ngrok.app" + upstream: + url: "file:///var/log" +``` + + + + + +## Serve files on Windows + + + + + +```bash +ngrok http "file://C:\Users\alan\Directory Name" +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func serveFiles(ctx context.Context) error { + l, _ := ngrok.Listen(ctx, + config.HTTPEndpoint(), + ngrok.WithAuthtokenFromEnv(), + ) + http.Serve(l, http.FileServer(http.Dir("C:\Users\alan\Directory Name"))) +} +``` + + + + + + +```yaml +version: 3 +endpoints: + - name: example + url: "https://example.ngrok.app" + upstream: + url: "file://C:\Users\alan\Directory Name" +``` + + + + + +
+ +## Serve files in your current working directory + + + + +```bash +ngrok http file://`pwd` +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func serveFiles(ctx context.Context) error { + l, _ := ngrok.Listen(ctx, + config.HTTPEndpoint(), + ngrok.WithAuthtokenFromEnv(), + ) + http.Serve(l, http.FileServer(http.Dir("."))) +} +``` + + + + + Serving the current working directory is not supported via the agent configuration file. + + + diff --git a/docs/universal-gateway/bindings.mdx b/docs/universal-gateway/bindings.mdx index e9a9b21260..5340a67b62 100644 --- a/docs/universal-gateway/bindings.mdx +++ b/docs/universal-gateway/bindings.mdx @@ -1,12 +1,14 @@ --- -title: Endpoint Bindings +sidebar_label: Endpoint Bindings +title: What are Endpoint Bindings? +description: Learn about the different types of ngrok endpoint bindings and how they work. --- -[Endpoints](/universal-gateway/endpoints) have a **binding**, which dictates how traffic can access it. +Every [ngrok Endpoint](/universal-gateway/endpoints) has a **binding**, which dictates how traffic can access it. ## Public Endpoints -Endpoints with a `public` binding have a publicly addressable URL that receives traffic from the internet via the ngrok cloud service's global points of presence. e.g. These endpoints might use an ngrok subdomain or a custom domain. +Endpoints with a `public` binding have a publicly addressable [URL](/universal-gateway/what-are-endpoint-urls) that receives traffic from the internet via the ngrok cloud service's global points of presence. e.g. These endpoints might use an ngrok subdomain or a custom domain. Example URLs: @@ -37,4 +39,8 @@ Example URLs: - `http://service.namespace` - `tcp://db.controlplane:5432` +:::note +TLS endpoints don't support the `kubernetes` binding. +::: + Learn more about [Kubernetes Endpoints](/universal-gateway/kubernetes-endpoints). diff --git a/docs/universal-gateway/chain-endpoints.mdx b/docs/universal-gateway/chain-endpoints.mdx new file mode 100644 index 0000000000..05ed30c173 --- /dev/null +++ b/docs/universal-gateway/chain-endpoints.mdx @@ -0,0 +1,30 @@ +--- +sidebar_label: Chaining Endpoints Together +title: How Do I Chain Endpoints? +description: Learn how to route traffic from one endpoint to multiple other endpoints based on request attributes. +--- + +import ConfigExample from "/src/components/ConfigExample.tsx"; + +You can route traffic from one endpoint to multiple other endpoints based on request attributes such as the URL, hostname, path, cookies, or headers. + +See the [Traffic Policy Action request variables documentation](/docs/traffic-policy/variables/req/) for a full list of request attributes you can use. + +## Example + +This rule forwards requests containing a `X-Endpoint-Name: {ENDPOINT}` header to `https://{ENDPOINT}.internal`. + + diff --git a/docs/universal-gateway/cloud-endpoints/index.mdx b/docs/universal-gateway/cloud-endpoints/index.mdx index 3b9a5c464f..1abea77b55 100644 --- a/docs/universal-gateway/cloud-endpoints/index.mdx +++ b/docs/universal-gateway/cloud-endpoints/index.mdx @@ -1,12 +1,15 @@ -# Cloud Endpoints +--- +title: What are Cloud Endpoints? +description: Learn how to use ngrok's Cloud Endpoints to centrally manage traffic to your services. +--- -## Overview -Cloud Endpoints are persistent, always-on endpoints whose creation, deletion and configuration is managed centrally via the Dashboard or API. They exist pemanently until they are explicitly deleted. Cloud Endpoints do not forward their traffic to an agent by default and instead only use their attached Traffic Policy to handle connections. +Cloud Endpoints are persistent, always-on endpoints whose creation, deletion and configuration is managed centrally via the Dashboard or API. They exist permanently until they are explicitly deleted. -## Get started +:::tip +Cloud Endpoints are the counterpart to Agent Endpoints, which are created and managed by Secure Tunnel agents. See [the Agent Endpoints documentation](/universal-gateway/agent-endpoints/) for more information. +::: -You can create a Cloud Endpoint in the Dashboard or using the API. See [the Cloud Endpoints Quickstart](/universal-gateway/cloud-endpoints/quickstart) to learn more. ## Use cases @@ -27,6 +30,14 @@ action](/traffic-policy/actions/forward-internal/). The traffic policy of a Cloud Endpoint must terminate traffic via actions such as `deny`, `redirect`, `custom-response`, or `forward-internal`. +:::note +Cloud Endpoints do not forward their traffic to an agent by default. This behavior must be configured with a traffic policy. +::: + +## Get started + +You can create a Cloud Endpoint in the Dashboard or using the API. See [the Cloud Endpoints Quickstart](/universal-gateway/cloud-endpoints/quickstart) to learn more. + ## Differences from Agent Endpoints :::note diff --git a/docs/universal-gateway/cloud-endpoints/quickstart.mdx b/docs/universal-gateway/cloud-endpoints/quickstart.mdx index b9d5366e2a..04633bd3b3 100644 --- a/docs/universal-gateway/cloud-endpoints/quickstart.mdx +++ b/docs/universal-gateway/cloud-endpoints/quickstart.mdx @@ -1,6 +1,5 @@ --- -title: Cloud Endpoints Quickstart -sidebar_label: Quickstart +title: Cloud Endpoint Quickstart description: Set up your first ngrok Cloud Endpoint to start managing traffic to your services. --- diff --git a/docs/universal-gateway/ddos-protection.mdx b/docs/universal-gateway/ddos-protection.mdx index 7ca81dd83c..5ccd011717 100644 --- a/docs/universal-gateway/ddos-protection.mdx +++ b/docs/universal-gateway/ddos-protection.mdx @@ -1,11 +1,10 @@ --- -title: DDoS Protection +sidebar_label: Automatic DDoS Protection +title: How Does ngrok Handle DDoS Attacks? +description: Learn how ngrok protects your applications from DDoS attacks. --- -# DDoS Protection - -ngrok automatically protects your applications with out-of-the-box protection -from distributed denial of service (DDoS) attacks. +ngrok automatically protects your applications from distributed denial of service (DDoS) attacks. ## DDoS Firewall diff --git a/docs/universal-gateway/domains.mdx b/docs/universal-gateway/domains.mdx deleted file mode 100644 index 04769e4c50..0000000000 --- a/docs/universal-gateway/domains.mdx +++ /dev/null @@ -1,215 +0,0 @@ ---- -title: Domains ---- - -# Domains - -## Overview - -Domains enable you to create public endpoints with hostnames matching the -domain. For example, after you create the domain `your-name.ngrok.app`, you may -create the Endpoint `https://your-name.ngrok.app` - -Domain names may be a subdomain of an [ngrok-managed -domain](#ngrok-managed-domains) like `foo.ngrok.app` or you can [bring your own -domain](#branded-domains) like `example.your-domain.com` by creating a CNAME -DNS record with your domain's DNS provider. - -Domains also enable you configure other domain-level behaviors including: - -- [**Global Load Balancer configuration**](#global-load-balancer) - Choose which points of presence handle traffic to a Domain's matching endpoints. -- [**TLS Certificate management**](#tls-certificates) - Configure automatic certificate provisioning or select a certificate you uploaded yourself. -- [**Dedicated IP address configuration**](#dedicated-ips) - Attach static, dedicated IPs for a Domain's matching endpoints receive traffic on. - -You can manage Domains on your [ngrok Dashboard](https://dashboard.ngrok.com/domains) -or via the [ngrok API](#api). - -## Public endpoints - -A Domain's primary responsibility is to enable you to create [public -endpoints](/universal-gateway/public-endpoints/) with a hostname matching the -domain. These are called "matching endpoints". For example, after you create -the Domain `app.example.com`, you can create the Endpoint -`https://app.example.com`. - -When you create a Domain, you may create matching public endpoints with the -following constraints: - -| Endpoint Protocol | Allowed Endpoints | -| ----------------- | ------------------------------------------------------------------------------------------------ | -| `http` | Matching endpoints on port `80` of the Domain. | -| `https` | Matching endpoints on port `443` of the Domain. | -| `tls` | Matching endpoints on port `443` of the Domain. | -| `tcp` | Not allowed. Public TCP endpoints must match a [TCP Address](/universal-gateway/tcp-addresses/). | - -If you configure your Domain to use [dedicated IPs](#dedicated-ips), these -restrictions are removed and you may create matching endpoints on any ports. - -### Wildcard Domains - -You may create a Domain with a wildcard name, e.g. `*.example.com`. A wildcard -domain enables you to: - -- Create an endpoint which receives traffic for all of its subdomains, e.g. - `https://*.example.com`. Consult the documentation for [wildcard - endpoints](/universal-gateway/http/#wildcard-endpoints) to understand - the rules for matching and precedence. - -- Create an endpoint on any subdomain which matches the wildcard, e.g. - `https://foo.example.com` or `https://foo.bar.baz.example.com` - -The wildcard `*` character may only be used as the first part of a -domain, you may not create domains like `app.*.example.com` or -`*-app.example.com`. - -:::note -Wildcard domains are available on our Enterprise plan self service. They are also available on Pay-as-You-Go plans if you contact support@ngrok.com. For Pay-as-You-Go when you create a wildcard domain and run endpoints domain `*.foo.com`, endpoints `https://a.foo.com` and `https://b.foo.com`, we bill you for each individual endpoint, which is why we ask that you request the feature. -::: - -:::note -Reserving subdomains of a wildcard domain within the ngrok dashboard count towards the number of reserved domains in your account. For example, if you reserve `foo.example.com` and `*.example.com`, you have reserved two domains. -::: - -### Ownership - -Your account exclusively owns its Domains and all of their nested subdomains -within ngrok. That means: - -- No account may create a Domain with a name that is a subdomain of your Domains. -- No other account may create endpoints with a hostname matching your Domain or - any of its nested subdomains. - -For example, if you create a Domain with the name `foo.ngrok.app`: - -- No other account create the Domains `foo.ngrok.app` or `bar.foo.ngrok.app`. -- No other account may create the endpoints `https://foo.ngrok.app` or `https://bar.foo.ngrok.app`. - -## Bring your own domain {#branded-domains} - -You can use any domain name that you already own with ngrok, e.g. -`app.your-domain.com`. To do so, you will create a CNAME record for that domain -to point traffic from the domain to ngrok's cloud service. When you create a -Domain, you will be presented with a target value for the CNAME record you need -to create. If you [create the Domain via -API](/api/resources/reserved-domains/), this value is the `cname_target` field. - -If you bring your own [wildcard domain](#wildcard-domains), you will need to -create a second DNS CNAME record for [wildcard TLS Certificate -provisioning](/universal-gateway/tls-certificates/#wildcard-domains). - -ngrok is not a domain registrar; you must already own a domain name to use it -with ngrok. - -### Apex domains - -If you want to use an apex domain (e.g. `example.com`) with ngrok, you must use -a DNS provider that supports an ALIAS record or CNAME flattening because the -DNS RFC does not permit CNAME records for apex domains. Because of how -ALIAS/CNAME flattening is implemented, apex domains will not take advantage of -the [Global Load Balancer](#global-load-balancer). If you are trying to create -your apex domain because you need to create endpoints for multiple subdomains, -use a [wildcard domain](#wildcard-domains) instead. - -## Global Load Balancer - -The [Global Load Balancer](/universal-gateway/global-load-balancer) -uses latency-aware DNS records to direct clients to the IPs of the nearest -[points of presence](/universal-gateway/points-of-presence/). - -Domains allow you to configure which points of presence the Global Load -Balancer may resolve clients to. This allows you to select which points of -presence will receive traffic for the Domain's matching endpoints. To disable -the Global Load Balancer, you may configure a domain to only resolve a single -point of presence. - -:::info Coming Soon - -Per-region global load balancer configuration is coming soon, [request access -to the developer preview](https://dashboard.ngrok.com/developer-preview). - -::: - -## TLS Certificates - -Domains manage the [TLS Certificate](/universal-gateway/tls-certificates/) used -to terminate TLS connections to the Domain's matching endpoints. When you -create a Domain, you may choose to allow ngrok to automatically provision TLS -certificates for you or to upload your own TLS certificate. - -Consult the documentation on [TLS -Certificates](/universal-gateway/tls-certificates/) for additional details on -certificate provisioning and management. - -## Dedicated IPs - -By default, a Domain's matching Endpoints receive traffic on a set of -multi-tenant [IP addresses](/universal-gateway/ip-addresses) that are -shared among all ngrok accounts. You may instead configure a Domain's matching -endpoints to receive traffic on IP addresses that are dedicated to your -account. - -If your Domain uses dedicated IPs, you may create public endpoints on _any_ -port numbers, not just 80 and 443. - -:::info Coming Soon - -Dedicated, static IPs for your domains are coming soon, [request access to the -developer preview](https://dashboard.ngrok.com/developer-preview). - -::: - -## ngrok Managed Domains - -If you don't own a domain that you want to use with ngrok, you can create a -Domain that is a subdomain of an ngrok-managed base domain. The ngrok-managed -base domains are: - -| Domain | Availability | HSTS Global Preload | -| ------------------ | ------------------------------------------------- | ------------------- | -| `ngrok.app` | Available to paying accounts | Yes | -| `ngrok.dev` | Available to paying accounts | Yes | -| `ngrok.pizza` | Available to paying accounts | No | -| `ngrok-free.app` | Used by free accounts | Yes | -| `ngrok-free.dev` | Used by free accounts | Yes | -| `ngrok-free.pizza` | Used by free accounts (coming soon) | No | -| `ngrok.io` | Discontinued and only available to older accounts | No | - -### Public Suffix List - -The ngrok-managed base domains are on the [Public Suffix -List](https://publicsuffix.org/). Browsers use the Public Suffix List to -guarantee that cookies from one subdomain cannot be accessed by other -subdomains. - -### HSTS Preload - -Some of the ngrok-managed base domains are on the global -[HSTS](https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security) preload -list. If the domain of the URL is on the [global HSTS preload -list](https://hstspreload.org/), modern browsers automatically convert requests -with an `http` scheme to `https`. - -If you need to create unencrypted `http` endpoints, you should create them with -hostnames that are not on the HSTS Global Preload like `ngrok.io` and -`ngrok.pizza`. - -ngrok does not prohibit you from creating `http` endpoints with hostnames whose -base domain is on the global HSTS preload list because non-browser clients -(like `curl`) can still be used to make unencrypted HTTP requests to them. - -## API - -Domains are programatically managed via: - -- [`/reserved_domains` API Resource](/api/resources/reserved-domains/) - -## Pricing - -Domains are available on all plans. Some Domain features require upgrades. See -the [Pricing page](https://ngrok.com/pricing) for details. - -| Feature | Plans | -| ---------------------- | --------------------------------------------------------------------------------- | -| Domains | All plans. The Domain name is assigned on Free, you may choose it on other plans. | -| Bring-your-own domains | Personal, Pro, Enterprise, Pay-as-you-go | -| Wildcard Domains | Enterprise | diff --git a/docs/universal-gateway/domains/bring-your-own-domain.mdx b/docs/universal-gateway/domains/bring-your-own-domain.mdx new file mode 100644 index 0000000000..b1000aaa1a --- /dev/null +++ b/docs/universal-gateway/domains/bring-your-own-domain.mdx @@ -0,0 +1,73 @@ +--- +title: How Do I Use A Custom Domain? +sidebar_label: Using Custom Domains +description: Learn how to use your own custom domain with ngrok. +--- + +This guide will show you the steps to use any domain name that you already own with ngrok, e.g. `app.your-domain.com`. + +:::note +ngrok is not a domain registrar; you must already own a domain name to use it +with ngrok. +::: + +## 1. Create a domain in ngrok + +You can create a domain in the ngrok dashboard. [You can do so by going here](https://dashboard.ngrok.com/domains). + +When your domain is created, you'll be given a `CNAME` value such as `exampledata.otherdata.ngrok-cname.com`. Copy it. + +:::info +You can also create a Domain via the [ngrok API](/api/resources/reserved-domains/#request). The `CNAME` will be in the `"cname_target"` field of [the response object](/api/resources/reserved-domains/#response). +::: + +## 2. Add the CNAME record to your domain + +1. In a new browser tab, navigate to your domain hosting provider's dashboard and create a CNAME record. Check your hosting provider's support content or documentation to learn how. + + - Typically, this process includes creating a [DNS record](https://en.wikipedia.org/wiki/List_of_DNS_record_types). + +2. When configuring the record, use the following values: + - Its **type** should be `CNAME` + - Its **name** should be `@` + - Its **value** should be the `CNAME` value you copied from the ngrok dashboard or API response. + +:::tip Test your CNAME record +Using a tool like [`dig`](https://www.digwebinterface.com/) or [`nslookup`](https://www.nslookup.io/), you can test your CNAME record in the terminal. +::: + +## 3. Start an endpoint using your domain: + +To start an agent endpoint at your domain, run the following command in your terminal, replacing `your-domain-here.example.com` with the domain you created in the ngrok dashboard. + + ```bash + ngrok http --url your-domain-here.example.com 8080 + ``` + +## Wildcard domains + +If you bring your own [wildcard domain](/universal-gateway/wildcard-domains), e.g. `*.example.com`, you will need to create a second `CNAME` record with your domain host for [wildcard TLS Certificate provisioning](/universal-gateway/tls-certificates/how-does-ngrok-handle-tls/#wildcard-domains). + +## Apex domains + +Because it's not possible to create `CNAME` records for apex domains, if you want to use an apex domain, e.g. `example.com`, you must use a DNS provider that supports an `ALIAS` record or `CNAME` flattening. + +Because of how `ALIAS`/`CNAME` flattening is implemented, apex domains will not take advantage of the [Global Load Balancer](/universal-gateway/global-load-balancer/#domains). If you're trying to create your apex domain because you need to create endpoints for multiple subdomains, use a [wildcard domain](/universal-gateway/what-are-public-endpoints#wildcard-domains) instead. + +## Using custom domains with TCP endpoints + +Public TCP endpoints are assigned randomly on an ngrok-controlled hostname with a randomly-assigned port. You may not choose the hostname and you may not select the port. + +You may, however, simulate a customized hostname by creating a `CNAME` record to the hostname of your assigned TCP address. If you do so, be aware that all ports on that hostname, even those provisioned to other accounts will then be available on your domain. + +For example if your TCP address is `5.tcp.ngrok.io:12345`, you could create the following `CNAME` record: + +```bash +CNAME tcp.mydomain.com -> 5.tcp.ngrok.io +``` + +And then you can access that TCP endpoint with: + +```bash +telnet tcp.mydomain.com 12345 +``` diff --git a/docs/universal-gateway/domains/what-are-domains.mdx b/docs/universal-gateway/domains/what-are-domains.mdx new file mode 100644 index 0000000000..dcda8386fa --- /dev/null +++ b/docs/universal-gateway/domains/what-are-domains.mdx @@ -0,0 +1,54 @@ +--- +title: How Do Domains Work With ngrok? +description: Learn how to create domains in your ngrok account. +--- + +Domains enable you to create [public endpoints](/universal-gateway/domains/public-endpoints/) with hostnames matching the domain. For example, after you create the domain `your-name.ngrok.app`, you may create the Endpoint `https://your-name.ngrok.app`. + +Valid Domain names include: + +- [ngrok-managed domains](/docs/universal-gateway/domains/what-are-managed-domains), like `foo.ngrok.app`. +- Your own [custom domains](/docs/universal-gateway/domains/bring-your-own-domain/), like `example.your-domain.com`, by creating a `CNAME` DNS record with your domain's DNS provider. + +## Configuration + +Domains also enable you to configure other domain-level behaviors, including: + +- [**Global Load Balancer configuration**](/universal-gateway/global-load-balancer/#domains) - Choose which points of presence handle traffic to a Domain's matching endpoints. + :::info Coming Soon + Per-region global load balancer configuration is coming soon, [request access + to the developer preview](https://dashboard.ngrok.com/developer-preview). + ::: +- [**TLS Certificate management**](/universal-gateway/tls-certificates/how-does-ngrok-handle-tls/) - Configure automatic certificate provisioning or select a certificate you uploaded yourself. +- [**Dedicated IP address configuration**](/universal-gateway/ip-addresses#dedicated-ips) - Attach static, dedicated IPs for a Domain's matching endpoints receive traffic on. + +You can manage Domains on your [ngrok Dashboard](https://dashboard.ngrok.com/domains) or via the [ngrok API](#api). + +## Ownership + +Your account exclusively owns its Domains and all of their nested subdomains +within ngrok. That means: + +- No account may create a Domain with a name that is a subdomain of your Domains. +- No other account may create endpoints with a hostname matching your Domain or any of its nested subdomains. + +For example, if you create a Domain with the name `foo.ngrok.app`: + +- No other account create the Domains `foo.ngrok.app` or `bar.foo.ngrok.app`. +- No other account may create the endpoints `https://foo.ngrok.app` or `https://bar.foo.ngrok.app`. + +## API + +Domains are programatically managed via: + +- [`/reserved_domains` API Resource](/api/resources/reserved-domains/) + +## Pricing + +Domains are available on all plans. Some Domain features require upgrades. See the [Pricing page](https://ngrok.com/pricing) for details. + +| Feature | Plans | +| ---------------------- | --------------------------------------------------------------------------------- | +| Domains | All plans. The Domain name is assigned on Free, you may choose it on other plans. | +| Bring-your-own domains | Personal, Pro, Enterprise, Pay-as-you-go | +| Wildcard Domains | Enterprise | diff --git a/docs/universal-gateway/domains/what-are-managed-domains.mdx b/docs/universal-gateway/domains/what-are-managed-domains.mdx new file mode 100644 index 0000000000..2a230535fd --- /dev/null +++ b/docs/universal-gateway/domains/what-are-managed-domains.mdx @@ -0,0 +1,94 @@ +--- +title: What Are Managed Domains? +sidebar_label: Using ngrok Subdomains +description: Learn about the free and paid domains that ngrok provides. +--- + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; +import { ContentSwitcher } from "@site/src/components/LangSwitcher/ContentSwitcher"; +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +If you don't [already own a Domain](/universal-gateway/bring-your-own-domain) that you want to use with ngrok, you can create a domain that is a subdomain of an ngrok-managed base domain. + +| Domain | Availability | HSTS Global Preload | +| ------------------ | ------------------------------------------------- | ------------------- | +| `ngrok.app` | [Paid accounts](https://ngrok.com/pricing) | Yes | +| `ngrok.dev` | [Paid accounts](https://ngrok.com/pricing) | Yes | +| `ngrok.pizza` | [Paid accounts](https://ngrok.com/pricing) | No | +| `ngrok-free.app` | Free accounts | Yes | +| `ngrok-free.dev` | Free accounts | Yes | +| `ngrok-free.pizza` | Free accounts (coming soon) | No | +| `ngrok.io` | Discontinued and only available to older accounts | No | + +## Public Suffix List + +The ngrok-managed base domains are on the [Public Suffix List](https://publicsuffix.org/). Browsers use the Public Suffix List to guarantee that cookies from one subdomain cannot be accessed by other subdomains. + +## HSTS preload + +Some of the ngrok-managed base domains are on the [global HSTS preload list](https://hstspreload.org/), which means modern browsers automatically convert requests to these domains using an `http` scheme to `https`. + +If you need to create unencrypted `http` endpoints, you should create them with hostnames that are not on the HSTS Global Preload like `ngrok.io` and +`ngrok.pizza`. + +:::tip +ngrok does not prohibit you from creating `http` endpoints with hostnames whose base domain is on the global HSTS preload list. Non-browser clients (like `curl`) can still be used to make unencrypted HTTP requests to them. +::: + +### Randomly assigned hostnames + +If you create a public endpoint without specifying a hostname, ngrok will automatically assign a random one for you.by selecting a random subdomain of one of ngrok's managed Domains to your endpoint. + +The following example creates an HTTPS endpoint on a randomly assigned hostname that forwards to port 8080. + + + +```bash title="Agent CLI" +ngrok http 8080 +``` + +```sh title="SSH example" +ssh -R 443:localhost:80 v2@connect.ngrok-agent.com http +``` + + + + + + :::note + If your [Agent Config file](/docs/traffic-policy/getting-started/agent-endpoints/config-file) doesn't have hostname specified, and you create an endpoint, the hostname will also be randomly assigned. For example, if your Agent Config file looks like this: + + ```yaml + version: 3 + endpoints: + - name: example + url: https:// + upstream: + url: 8080 + ``` + + ::: + + +{/* + + + + + + + + + + + + + + + + + + + + */} diff --git a/docs/universal-gateway/endpoint-pooling.mdx b/docs/universal-gateway/endpoint-pooling.mdx index dd562f735b..656ab7047d 100644 --- a/docs/universal-gateway/endpoint-pooling.mdx +++ b/docs/universal-gateway/endpoint-pooling.mdx @@ -1,13 +1,14 @@ --- -title: Endpoint Pooling -description: Learn how ngrok enables you to load balance traffic to endpoints with endpoint pooling. +title: What Is Endpoint Pooling? +sidebar_label: Using Endpoint Pooling +description: Learn how ngrok enables you to load balance traffic between endpoints with endpoint pooling. --- Endpoint pooling makes load balancing dead simple. Load balancing helps you scale traffic across multiple replicas of your app to increase capacity, -tolerate failures and geo-distribute load. When your create two endpoints with -the same URL (and binding), those endpoints automatically form a "pool" and -share incoming traffic. +tolerate failures and geo-distribute load. When your create two endpoints with the same URL (and binding), those endpoints automatically form a "pool" and share incoming traffic. + +## vs. Other load balancing systems Endpoint pooling is vastly more flexible than comparable load balancing systems: @@ -223,14 +224,9 @@ When a connection or request is balanced to an endpoint in a pool, if that connection or request fails, it is not retried by sending it to another endpoint in the pool. -## Wildcard Endpoints +## Wildcard endpoints -Wildcard endpoints do not pool with non-wildcard URLs. For example, if you have -two endpoints online, `https://foo.example.com` and `https://*.example.com`, -they will not pool together and traffic to `https://foo.example.com` will not -be load balanced. Consult the documentation for [wildcard -endpoints](/universal-gateway/http/#wildcard-endpoints) to understand -the rules for matching and precedence. +[Wildcard endpoints](/universal-gateway/wildcard-domains/wildcard-endpoints) do not pool with non-wildcard URLs. See [the docs on Wildcard Endpoints](/universal-gateway/wildcard-domains/wildcard-endpoints/#wildcard-endpoint-pooling) for more information. ## Protocol, Binding and Type diff --git a/docs/universal-gateway/endpoints.mdx b/docs/universal-gateway/endpoints.mdx index b2359cd956..3113816e59 100644 --- a/docs/universal-gateway/endpoints.mdx +++ b/docs/universal-gateway/endpoints.mdx @@ -1,13 +1,20 @@ --- -sidebar_position: 0 -title: Endpoints +title: What are Endpoints? +description: Learn about how ngrok endpoints enable you to open up your apps and services to network traffic. --- import TypesComparison from "@site/shared/types-comparison.mdx"; An **ngrok Endpoint** is a URL that enables network traffic to reach your services. -You can think of endpoints as a gateway to anything you want to enable access for—whether that's a local development server on your laptop, a production Kubernetes cluster, a database behind a corporate firewall, or a cloud API. Endpoints bridge the gap between your resources and the traffic that needs to reach them. +You can think of endpoints as a gateway for anything you want to enable access to, including but not limited to: + +- A local development server on your laptop +- A production Kubernetes cluster +- A database behind a corporate firewall +- A cloud API + +Endpoints bridge the gap between your resources and the traffic that needs to reach them. ## Why endpoints matter @@ -23,7 +30,7 @@ Endpoints are ngrok's universal gateways, letting you: Endpoints enable traffic flow and management through three core features: -- **URL:** The entry point for traffic to reach your services. This could be any URL, such as `https://your-app.ngrok.io` or `tcp://your-api.internal`. +- **[URL](/universal-gateway/what-are-endpoint-urls):** The entry point for traffic to reach your services. This could be any URL, such as `https://your-app.ngrok.io` or `tcp://your-api.internal`. - **[Binding](#control-access-with-bindings):** The source or origin of incoming traffic. - **[Traffic Policy](/traffic-policy/):** Configuration to manage, manipulate and secure traffic. @@ -69,7 +76,7 @@ ngrok http 8080 This command will start an Agent Endpoint that forwards traffic through the ngrok CLI agent to your locally running application on port 8080. -To learn more, follow ngrok's [Quickstart](/getting-started/). +To learn more, follow the [Quickstart](/getting-started/). ## Load balancing with Endpoint Pooling @@ -98,9 +105,7 @@ Agent Endpoints are also accessible in a read-only capacity via: ## Pricing -Paid plans (Personal, Pro and Enterprise) include a fixed number of -endpoints that you may create based on the number of licenses you have -purchased. +[Paid plans](/pricing-limits/) (Personal, Pro and Enterprise) include a fixed number of endpoints that you may create based on the number of licenses you have purchased. On the Pay-as-you-go plan, there is no limit on the number of endpoints you can create. An endpoint that transmits data in a billing period is counted as an active endpoint for billing purposes. diff --git a/docs/universal-gateway/global-load-balancer.mdx b/docs/universal-gateway/global-load-balancer.mdx deleted file mode 100644 index 6779a5c469..0000000000 --- a/docs/universal-gateway/global-load-balancer.mdx +++ /dev/null @@ -1,208 +0,0 @@ -import TabItem from "@theme/TabItem"; -import Tabs from "@theme/Tabs"; - -import ExplicitRegionAgentCliExample from "/examples/agent-cli/explicit-region.mdx"; -import ExplicitRegionAgentConfigExample from "/examples/agent-config/explicit-region.mdx"; -import ExplicitRegionGoSdkExample from "/examples/go-sdk/explicit-region.mdx"; -import ExplicitRegionJavascriptSdkExample from "/examples/javascript-sdk/explicit-region.mdx"; -import ExplicitRegionKubernetesExample from "/examples/k8s/explicit-region.mdx"; -import ExplicitRegionPythonSdkExample from "/examples/python-sdk/explicit-region.mdx"; -import ExplicitRegionRustSdkExample from "/examples/rust-sdk/explicit-region.mdx"; -import ExplicitRegionSshExample from "/examples/ssh/explicit-region.mdx"; - -# Global Load Balancer - -## Overview - -ngrok's Global Load Balancer improves the performance and resiliency of your -applications by distributing traffic to the nearest healthy point of presence, -measured by latency, from the perspective of the connecting client. Every -application you deliver with ngrok is automatically accelerated with our -always-on, zero-configuration global load balancer. - -Global lobal balancing is sometimes called 'Global Server Load Balancing' or -GSLB. - -Conceptually, a GSLB is simple. A GSLB accelerates traffic by adjusting DNS -resolution so that when clients connect to your endpoints on the internet, they -connect to the nearest point of presence (PoP). A GSLB adds resiliency by -adjusting that same DNS resolution process to steer traffic away from failing -PoPs. - -## vs. Traditional GSLBs - -ngrok operates differently from a traditional GSLB to give you some important -benefits. - -1. In a traditional GSLB deployment, you are responsible for running - geographically redundant copies of your application and configuring networking - technologies to distribute and failover traffic among these deployments. By - contrast, ngrok runs a [global delivery network of - PoPs](/universal-gateway/points-of-presence/) for you. This means that even if you - only deploy your upstream service to a single geography, your apps still get - faster from [Connection Acceleration](#connection-acceleration) and [Module - Acceleration](#module-acceleration). - -2. Unlike a traditional GSLB deployment, when you deploy your application - services to a new geographic location, ngrok automatically routes nearby - traffic to those services without any configuration. Traditional GSLB - deployments require many network configuration updates to bring these new - locations online like IP provisioning and DNS record changes. With ngrok, there - is zero configuration, just start your new application services with their - ngrok agents and you're done. - -3. Unlike a traditional reverse proxy, ngrok forwards traffic to your upstream - services over secure connections established by the [ngrok agent](/agent/), - [Agent SDKs](/agent-sdks) or [Kubernetes Controller](/k8s/). So which PoPs do - those agents connect to? ngrok also applies GSLB principles to those - connections as well to ensure that your agents connect to the geographically - closest PoPs. - -## Endpoints - -ngrok's GSLB improves the performance and resiliency of connections to your -ngrok endpoints (e.g. `https://your-app.ngrok.app`). - -### Connection Acceleration - -When a client (like a web browser) connects to your ngrok endpoint it is routed -to the closest point of presence. DNS resolution of your endpoint's address -returns the IP addresses of ngrok's closest point of presence. The closest point -of presence is determined by the shortest latency from the resolving DNS server -to our points of presence. This ensures that clients are routed to the fastest -point of presence even as internet routing conditions change. - -Connecting to the closest point of presence accelerates your traffic by -reducing the initialization time for TCP and TLS connections. TCP and TLS -connection set up requires network round-trips. ngrok accelerates connections -by reducing the latency of these round-trip times (RTTs) between the client and -your endpoint by routing them to the closest point of presence. - -### Module Acceleration - -In addition to accelerating connection initialization, ngrok also accelerates -the execution of [Modules](/traffic-policy/actions/) that you configure on your -endpoints. Modules execute where the request is first received by the ngrok -edge, at the geographically-closest point of presence. This means that any -behaviors you define in your modules are automatically globally accelerated for -all customers. - -### Geo-Aware Load Balancing - -When you are using a [Tunnel Group Backend](/universal-gateway/edges/#tunnel-group) -with [Edges](/universal-gateway/edges), ngrok can automatically distribute traffic -to the closest upstream if you run geographically distributed copies of your -upstream application service. - -First, consider a case _without_ geo-aware load-balancing. Let's say you have -instances of your application running in Japan. When someone in Belgium makes -a request to your app's endpoint, that request will first be routed to the -closest ngrok point of presence in Europe, like Frankfurt. From Frankfurt, it -will then be routed through ngrok's internal network and finally to your -upstream services in Japan. - -Then let's say you start additional copies of your application service in -France. With zero changes in configuration, those same requests from Belgium -will still be routed to ngrok's point of presence in Frankfurt, but instead of -routing to your upstream services in Japan, they will instead be routed to your -new upstreams in France. That's Geo-Aware Load Balancing. - -### Losing an Upstream {#losing-an-upstream} - -Consider the example in [Geo-Aware Load Balancing](#geo-aware-load-balancing) -where you are running upstream application services in both Japan and France. -Let's then assume that all of your upstream services in Japan fail. Requests -that were being routed to your Japanese upstream services will instead be -routed to your remaining upstream services in France. Requests that were -already being routed to your upstreams in France will be unaffected. - -### Losing a Point of Presence {#endpoints-losing-a-pop} - -In [losing an upstream](#losing-an-upstream), we considered a case where your -upstream services fail. But what if an ngrok point of presence fails? - -If an ngrok point of presence fails, health checks automatically detect that -failure and update our DNS resolution such that clients will attempt to connect -to your endpoints via the next-closest healthy point of presence. - -### Disabling GSLB for an Endpoint {#endpoints-disabling-gslb} - -There is no way to disable GSLB for HTTPS and TLS endpoints. All endpoints you -create in ngrok are available on ngrok's worldwide global delivery network and -inbound requests and connections are routed to the geographically closest point -of presence. - -### TCP Endpoints - -TCP Endpoints do not support GSLB. Unlike domains, TCP addresses are -provisioned for a specific point of presence. When you create a TCP Address, -you must select the point of presence where it will accept traffic. Unlike -ngrok's globally routed domains, traffic to TCP addresses always enters ngrok's -network from that point of presence. - -## Agents - -ngrok's GSLB automatically improves the performance and resiliency of your -ngrok agents, agent SDKs and the Kubernetes Controller. Agents automatically -connect to ngrok's geographically-closest healthy point of presence. - -### Acceleration - -Similar to endpoints, when an ngrok agent connects, DNS resolution returns the -IPs of the closest ngrok point of presence. Connecting to the closest ngrok -point of presence reduces agent initialization time and also reduces the -latency of connections that are routed to that agent. - -### Losing a Point of Presence {#agents-losing-a-pop} - -If an ngrok point of presence fails, health checks automatically detect that -failure and update our DNS resolution such that agents will attempt to connect -to the next-closest healthy point of presence. - -The ngrok agent connects to a single region at a time. If you want the ngrok -agent to simultaneously connect to multiple regions, you must instead run -multiple ngrok agents and [explicitly disable agent -GSLB](#agents-disabling-gslb). - -### Disabling GSLB in the Agent {#agents-disabling-gslb} - -You should always prefer to allow the ngrok agent to use GSLB and connect to -the closest point of presence. However, the ngrok agent does support disabling -GSLB and explicitly choosing which point of presence to connect to. - -If you wish to configure the agent to use a specific point of presence you may -do so with the following configuration: - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### Legacy Agent Behavior - -Beginning with the [ngrok v3 -agent](/agent/changelog#ngrok-agent-300---2022-03-28), the agent uses GSLB to -connect to the lowest-latency point point of presence. Prior to that, v2 ngrok -agents would always connect to the US region by default. diff --git a/docs/universal-gateway/global-load-balancer/gslb-agents.mdx b/docs/universal-gateway/global-load-balancer/gslb-agents.mdx new file mode 100644 index 0000000000..7f9a9a1891 --- /dev/null +++ b/docs/universal-gateway/global-load-balancer/gslb-agents.mdx @@ -0,0 +1,142 @@ +--- +sidebar_label: With ngrok Agents +title: Global Load Balancing for Agents +description: Learn how ngrok's Global Load Balancer improves the resiliency of your ngrok agents, agent SDKs and the Kubernetes Controller. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; +import { LangSwitcher } from "@site/src/components/LangSwitcher"; + +import ExplicitRegionAgentConfigExample from "/examples/agent-config/explicit-region.mdx"; +import ExplicitRegionKubernetesExample from "/examples/k8s/explicit-region.mdx"; + +ngrok's GSLB automatically improves the performance and resiliency of your +ngrok agents, agent SDKs and the Kubernetes Controller. Agents automatically +connect to ngrok's geographically-closest healthy point of presence. + +## Acceleration + +Similar to endpoints, when an ngrok agent connects, DNS resolution returns the IPs of the closest ngrok point of presence. Connecting to the closest ngrok point of presence reduces agent initialization time and also reduces the latency of connections that are routed to that agent. + +## Losing a Point of Presence + +If an ngrok point of presence fails, health checks automatically detect that +failure and update our DNS resolution such that agents will attempt to connect to the next-closest healthy point of presence. + +The ngrok agent connects to a single region at a time. If you want the ngrok +agent to simultaneously connect to multiple regions, you must instead run +multiple ngrok agents and [explicitly disable agent +GSLB](#disabling-gslb-in-the-agent). + +## Disabling GSLB in the Agent + +You should always prefer to allow the ngrok agent to use GSLB and connect to +the closest point of presence. However, the ngrok agent does support disabling +GSLB and explicitly choosing which point of presence to connect to. + +If you wish to configure the agent to use a specific point of presence you may +do so with the following configuration: + + + + + +```bash +ngrok http 80 --region eu +``` + +```ssh tabName="SSH" +ssh -R 0:localhost:80 connect.eu.ngrok-agent.com http +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.HTTPEndpoint(), + ngrok.WithRegion("eu"), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const session = await new ngrok.SessionBuilder() + .authtokenFromEnv() + .serverAddr("connect.eu.ngrok-agent.com:443") + .connect(); + + const listener = await session + .httpEndpoint() + .listenAndForward("http://localhost:8080"); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok, asyncio + +async def create_listener() -> ngrok.Listener: + session: ngrok.Session = ( + await ngrok.SessionBuilder() + .authtoken_from_env() + .server_addr("connect.eu.ngrok-agent.com:443") + .connect() + ) + + return (await session.http_endpoint() + .listen_and_forward("http://localhost:8080")) + +listener = asyncio.run(create_listener()) + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; + +async fn listen_ngrok() -> anyhow::Result { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .server_addr("connect.eu.ngrok-agent.com:443"), + .connect() + .await?; + + let tun = sess + .http_endpoint() + .listen() + .await?; + + println!("Listening on URL: {:?}", tun.url()); + + Ok(tun) +} +``` + + + + + + + + + + + + + +## Legacy Agent Behavior + +Beginning with the [ngrok v3 agent](/agent/changelog#ngrok-agent-300---2022-03-28), the agent uses GSLB to connect to the lowest-latency point point of presence. Prior to that, v2 ngrok agents would always connect to the US region by default. diff --git a/docs/universal-gateway/global-load-balancer/gslb-endpoints.mdx b/docs/universal-gateway/global-load-balancer/gslb-endpoints.mdx new file mode 100644 index 0000000000..ae6ad2f507 --- /dev/null +++ b/docs/universal-gateway/global-load-balancer/gslb-endpoints.mdx @@ -0,0 +1,76 @@ +--- +sidebar_label: With Endpoints +title: Global Load Balancing for Endpoints +description: Learn how ngrok's Global Load Balancer improves connection performance to your endpoints. +--- + +ngrok's GSLB improves the performance and resiliency of connections to your +endpoints. + +When a client (such as a web browser) connects to your endpoint, it's routed to the closest [point of presence](/universal-gateway/points-of-presence/). The closest point of presence is the one with the shortest latency to the resolving DNS server for the connection. This ensures that clients are routed to the fastest point of presence even as internet routing conditions change. + +## Connection Acceleration + +Connecting to the closest point of presence accelerates your traffic by +reducing the initialization time for TCP and TLS connections. TCP and TLS +connection set up requires network round-trips. ngrok accelerates connections +by reducing the latency of these round-trip times (RTTs) between the client and your endpoint by routing them to the closest point of presence. + +### Module Acceleration + +In addition to accelerating connection initialization, ngrok also accelerates the execution of [Modules](/traffic-policy/actions/) that you configure on your endpoints. Modules execute where the request is first received by the ngrok edge, at the geographically-closest point of presence. This means that any behaviors you define in your modules are automatically globally accelerated for all customers. + +## Geo-Aware Load Balancing + +When you are using a [Tunnel Group Backend](/universal-gateway/edges/#tunnel-group) +with [Edges](/universal-gateway/edges), ngrok can automatically distribute traffic +to the closest upstream if you run geographically distributed copies of your +upstream application service. + +### Example scenario + +Let's say you have instances of your application running in Japan. When someone in Belgium makes a request to your app's endpoint, they will: + +1. First, be routed to the + closest ngrok point of presence in Europe, such as Germany +1. Then, be routed through ngrok's internal network and finally to your + upstream services in Japan + +If you were to deploy additional copies of your application in +France, those same requests from Belgium would: + +1. First, be routed to ngrok's nearest point of presence in Europe, which would be Germany +1. Then, be routed to your new upstreams in France rather than Japan + +That's Geo-Aware Load Balancing. + +### Upstream failover + +When upstream services fail, ngrok's GSLB will automatically route traffic to the next-closest running upstream service. + +### Losing a Point of Presence + +If an ngrok point of presence fails, health checks automatically detect that +failure and update our DNS resolution such that clients will attempt to connect to your endpoints via the next-closest healthy point of presence. + +## Disabling GSLB for an endpoint + +**There is no way to disable GSLB for HTTP/S and TLS endpoints**. TCP endpoints do not support GSLB. + +## GSLB for TCP endpoints + +ngrok does not support global load balancing for TCP Addresses, but you can connect TCP Addresses to [Agent Endpoints](/agent/) in different [Points of Presence](/universal-gateway/points-of-presence). This allows you to accept traffic to a TCP Address in one region, then forward it to an Agent in a different region. + +The following example [CLI command](/agent/cli) creates an agent in the `jp` region that connects to a TCP address in the `eu` region: + +```sh +ngrok tcp 3389 --region jp --url tcp://1.tcp.eu.ngrok.io:12345 +``` + +## Domains + +[Domains](/universal-gateway/domains/what-are-domains) allow you to configure which points of presence the Global Load +Balancer may resolve clients to. This allows you to select which points of +presence will receive traffic for the Domain's matching endpoints. To disable +the Global Load Balancer, you may configure a domain to only resolve a single +point of presence. diff --git a/docs/universal-gateway/global-load-balancer/index.mdx b/docs/universal-gateway/global-load-balancer/index.mdx new file mode 100644 index 0000000000..637494ccbf --- /dev/null +++ b/docs/universal-gateway/global-load-balancer/index.mdx @@ -0,0 +1,37 @@ +--- +title: What is the Global Load Balancer? +description: Learn about how ngrok's Global Load Balancer and how it improves the performance and resiliency of your applications. +--- + +ngrok's Global Load Balancer improves the performance and resiliency of your +applications by distributing traffic to the point of presence with the least latency from the client, and away from failing points of presence and upstream services. + +Every application you deliver with ngrok is automatically accelerated with our always-on, zero-configuration global load balancer. + +:::tip Remember +Global lobal balancing (or GSLB), balances traffic *to* endpoints. This is distinct from [endpoint pool load balancing](/universal-gateway/pooling/pool-load-balancing/), which balances traffic *between* your endpoints. +::: + +## vs. Traditional GSLBs + +ngrok operates differently from a traditional GSLB to give you some important +benefits. + +### Automatic geo-aware failover + +Traditional GSLBs require you to: + +- Run geographically redundant copies of your application +- Configure networking technologies to distribute and failover traffic among these deployments + +By contrast, ngrok runs a [global delivery network of PoPs](/universal-gateway/points-of-presence/) for you. This means that even if you only deploy your upstream service to a single geography, your apps still get faster from [Connection Acceleration](/universal-gateway/global-load-balancer/gslb-endpoints/#connection-acceleration) and [Module Acceleration](/universal-gateway/global-load-balancer/gslb-endpoints/#module-acceleration). + +### Zero configuration + +Traditional GSLB deployments require network configuration updates, such as IP provisioning and DNS record changes, to bring new applications and services online. + +With ngrok, when you deploy your applications and services to a new geographic location, nearby traffic is automatically routed to those services. + +### Secure connections + +Unlike a traditional reverse proxy, ngrok forwards traffic to your upstream services over secure connections established by the [ngrok agent](/agent/), [Agent SDKs](/agent-sdks) or [Kubernetes Controller](/k8s/). So which PoPs do those agents connect to? ngrok also applies GSLB principles to those connections, ensuring that your agents connect to the geographically closest PoPs. diff --git a/docs/universal-gateway/http-s/endpoint-url-defaults.mdx b/docs/universal-gateway/http-s/endpoint-url-defaults.mdx new file mode 100644 index 0000000000..2b790b33ee --- /dev/null +++ b/docs/universal-gateway/http-s/endpoint-url-defaults.mdx @@ -0,0 +1,31 @@ +--- +sidebar_label: Default Endpoint URL Values +title: How are Endpoint URLs Constructed? +description: Learn what default values ngrok uses to construct endpoint URLs. +--- + +When you create an agent endpoint, if you do not specify a complete URL, the following defaults are used to construct an endpoint URL. When you create a cloud endpoint, you must always specify both a scheme and hostname. + +| URL Part | Default | +| -------- | --------------------------------------------------------- | +| Scheme | `https` | +| Hostname | randomly selected | +| Port | `443` if scheme is `https`
`80` if scheme is `http` | + +## Examples + +Consult the following table of examples of URL defaulting: + +| Value | Endpoint URL | +| ------------------------------- | -------------------------------------------------------- | +| `https://example.ngrok.app` | `https://example.ngrok.app` | +| `http://example.ngrok.app` | `http://example.ngrok.app` | +| `example.ngrok.app` | `https://example.ngrok.app` | +| `app.example.com` | `https://app.example.com` | +| `https://example.internal` | `https://example.internal` | +| `https://example.internal:1234` | `https://example.internal:1234` | +| `http://example.internal` | `http://example.internal` | +| `foo.internal` | `https://foo.internal` | +| `{empty}` | `https://1eb2-181-80-12-3.ngrok.app` (randomly selected) | + +If you would like to listen for both http and https traffic, create two endpoints. diff --git a/docs/universal-gateway/http-s/http-s-endpoints.mdx b/docs/universal-gateway/http-s/http-s-endpoints.mdx new file mode 100644 index 0000000000..1adfebf921 --- /dev/null +++ b/docs/universal-gateway/http-s/http-s-endpoints.mdx @@ -0,0 +1,55 @@ +--- +title: How HTTP/S Endpoints Work +description: Learn the technical details of how ngrok's HTTP/S endpoints work. +--- + +[HTTP/S endpoints](/universal-gateway/https-s) are standards-compliant HTTP reverse proxies. + +## Supported versions + +- HTTP/S endpoints support HTTP/1.1. +- HTTPS endpoints support HTTP/1.1 and HTTP/2. +- HTTP/1.0, HTTP/3 and QUIC are **not** supported. + +## HTTP/2 support + +HTTP/2 is a newer version of HTTP that offers improved performance by enabling multiple requests and responses over a single connection, among [other benefits](https://en.wikipedia.org/wiki/HTTP/2). + +ngrok's HTTPS endpoints automatically use HTTP/2 for all connections if the client +supports it. Client support is determined via standard [ALPN](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation). + +HTTP/2 is used between the client and your endpoint even if your upstream +service does not support HTTP/2. + +See the [HTTP/2 agent forwarding](/universal-gateway/agent-forwarding/#http2-forwarding) documentation to learn how to use HTTP/2 when sending traffic to an upstream service. + +## Websocket support + +Websocket connections are supported out-of-the-box with no configuration required. + +## Hop by hop headers + +ngrok does not forward any [hop-by-hop +headers](https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1) to upstream services other than `Connection: upgrade`, which are forwarded +to support [websockets](#websocket-support). + +For information on headers added automatically by ngrok, see +[the docs on upstream headers for HTTP/S endpoints](/universal-gateway/http-s/#upstream-headers). + +## Persistent connections + +When a connection is made to HTTP/S ngrok endpoints with HTTP/1.1, ngrok may +choose to use [persistent connections](https://en.wikipedia.org/wiki/HTTP_persistent_connection), or HTTP keep-alive, to improve the +performance of future requests from the same client (if the client supports it). + +This behavior is not guaranteed and it is not configurable. + +See [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-6.3) for +additional details. + +## Well Known URIs + +ngrok handles the `/.well-known/acme-challenge` path of any HTTP endpoint matching a +[domain](/universal-gateway/domains/what-are-domains) with [automated certificate management](/universal-gateway/tls-certificatesautomatic-certificate-management/) +enabled. You may disable this behavior by [uploading your own certificate](/universal-gateway/tls-certificates/custom-certificates/) on the +matching domain. diff --git a/docs/universal-gateway/http-s/index.mdx b/docs/universal-gateway/http-s/index.mdx new file mode 100644 index 0000000000..babb52ab2c --- /dev/null +++ b/docs/universal-gateway/http-s/index.mdx @@ -0,0 +1,178 @@ +--- +title: How Do I Handle HTTP/S traffic? +description: Learn how to create HTTP/S endpoints with ngrok. +--- + +import StaticDomainAgentConfigExample from "/examples/agent-config/http-static-domain.mdx"; +import StaticDomainKubernetesExample from "/examples/k8s/http-static-domain.mdx"; + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; + +You can create HTTP/S endpoints to serve web services like REST APIs, web applications, websites and websocket servers. + +## Quickstart + + + + [Agent Endpoints](/agent/) are the easiest way to create an HTTP/S endpoint. You can start agent endpoints on your local machine. The endpoint wil llive for the lifetime of the process and forward traffic to a port or URL of your choosing. + + The following example creates the endpoint `https://example.ngrok.app` and forwards its traffic to a local port. + + + ```bash + ngrok http 8080 --url https://example.ngrok.app + ``` + ```sh tabName="SSH" + ssh -R example.ngrok.app:443:localhost:8080 v2@connect.ngrok-agent.com http + ``` + ```go + import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" + + ) + + func ngrokListener(ctx context.Context) (net.Listener, error) { + upstreamURL, \_ := url.Parse("http://localhost:8080") + return ngrok.ListenAndForward(ctx, + upstreamURL, + config.HTTPEndpoint( + config.WithURL("https://example.ngrok.app"), + ), + ngrok.WithAuthtokenFromEnv(), + ) + } + + ``` + ```jsx + const ngrok = require("@ngrok/ngrok"); + + (async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + domain: "example.ngrok.app", + }); + + console.log(`Ingress established at: ${listener.url()}`); + })(); + ``` + + ```python + import ngrok + + listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + domain="example.ngrok.app") + + print(f"Ingress established at: {listener.url()}"); + ``` + + ```rust + use ngrok::prelude::*; + + async fn listen_ngrok() -> anyhow::Result { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + + let tun = sess + .http_endpoint() + .domain("example.ngrok.app") + .listen() + .await?; + + println!("Listening on URL: {:?}", tun.url()); + + Ok(tun) + } + ``` + + + + + + +[Cloud endpoints](/universal-gateway/cloud-endpoints/) are created via [the ngrok Dashboard](https://dashboard.ngrok.com/endpoints/new) or [API](/api/). They are persistent and live until they are deleted. [Traffic Policy](/traffic-policy/) controls how a cloud endpoint handles traffic. + +To create an HTTPS cloud endpoint which returns a `Hello world!` `200 OK` response, you can add the following to your Cloud Endpoint's Traffic Policy in the ngrok Dashboard: + +```yaml +on_http_request: + - actions: + - type: custom-response + config: + status_code: 200 + headers: + content-type: text/plain + content: "Hello world!" +``` + +If you want to add it with the API instead, you can save that policy to a local file, then run the following command in your terminal, referencing the file you created: + +```sh title="Command line" +ngrok api endpoints create \ + --url https://example.ngrok.app \ + --traffic-policy "$( + + + Follow the [ngrok Kubernetes Controller documentation](https://ngrok.com/docs/k8s/guides/quickstart/) to get started using ngrok with Kubernetes. You can use the following service definition to create an HTTP endpoint: + + + + + + + + You can create an HTTP/S endpoint using the [ngrok agent configuration file](/docs/traffic-policy/getting-started/agent-endpoints/config-file). You can edit the file with the following terminal command: + + ```bash + ngrok config edit + ``` + + Specify the endpoint URL in your configuration as shown in the following example: + + + + Then, start the agent with the following command: + + ```bash + ngrok http 8080 + ``` + + + + +## Learn more + +- **URL Validation** — URLs are validated differently depending on their [binding](/universal-gateway/bindings). To learn more about valid URLs for HTTP/S endpoints, see [the Endpoint URLs documentation](/docs/universal-gateway/what-are-endpoint-urls/#http). +- **Domains** — Public HTTP/S endpoints must match a domain on your account. See [the domains documentation](/universal-gateway/domains/what-are-domains/) for more information. +- **Bring your own domain** — To use your own domain with HTTP/S endpoints, see [the guide on the subject](/universal-gateway/bring-your-own-domain). +- **Wildcard Endpoints** — You can create HTTP/S endpoints that receive traffic from all of the subdomains matching a given wildcard domain. See [the wildcard domain docs](/universal-gateway/wildcard-domains/) for more information. +- **Traffic Policy** — Attach [Traffic Policy](/traffic-policy/) to endpoints to route, authenticate and transform the traffic through the endpoint. +- **Agent Forwarding** — The [ngrok agent](/agent/) and [Agent SDKs](/agent-sdks/) forward traffic that your endpoints receive to upstream services. See [the agent forwarding documentation](/universal-gateway/agent-forwarding/) for more information. +- **Traffic Observability** — [Traffic Inspector](/obs/traffic-inspection/) gives you a real-time view in the ngrok dashboard of the HTTP traffic flowing through your HTTP/S endpoints. You can even [export traffic logs with the Traffic Events system](/docs/obs/events/reference/#traffic-events). +- **TLS** — Learn how [ngrok automatically handles TLS](/universal-gateway/tls-certificates/how-does-ngrok-handle-tls/) and [TLS termination](/universal-gateway/tls/tls-termination/) for HTTP/S endpoints for you. + +## Errors + +Learn how ngrok handles errors for HTTP/S endpoints in the [Errors documentation](/errors/#http-errors). + +## API + +HTTP/S Endpoints can be created programatically. Consult the documentation on [Endpoint APIs](/api/resources/endpoints/). + +## Limits & pricing + +HTTP/S endpoints are available on all plans. Consult the [pricing](/pricing-limits/) documentation for general billing details. + +For HTTP/S limits, see the [endpoint Limits documentation](/pricing-limits/endpoint-limits/). diff --git a/docs/universal-gateway/http-s/upstream-headers.mdx b/docs/universal-gateway/http-s/upstream-headers.mdx new file mode 100644 index 0000000000..ab4093720f --- /dev/null +++ b/docs/universal-gateway/http-s/upstream-headers.mdx @@ -0,0 +1,19 @@ +--- +title: Forwarded Headers Reference +description: ngrok adds headers to each HTTP request with information about the upstream client. +--- + +ngrok adds headers to each [HTTP request](/universal-gateway/http-s/) with information about the original +client IP, request scheme and request `host` header value. + +| Header | Description | +| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `x-forwarded-for` | The IP address of the client who initiated the request. If this header exists on the original request, ngrok will append a new value. | +| `x-forwarded-proto` | The scheme of the original request, either `http` or `https`. If this header exists on the original request, ngrok will append a new value. | +| `x-forwarded-host` | The header from the client's request if it existed, otherwise is set to the request's `Host` header value. | + +Because ngrok appends values to `x-forwarded-for` and `x-forwarded-proto`, be +sure to use the last value of the header in your application code to read the +values injected by ngrok. + +You may remove these headers with the [Remove Headers](/traffic-policy/actions/remove-headers/) Traffic Policy action. diff --git a/docs/universal-gateway/http.mdx b/docs/universal-gateway/http.mdx deleted file mode 100644 index b3d232a8ad..0000000000 --- a/docs/universal-gateway/http.mdx +++ /dev/null @@ -1,949 +0,0 @@ ---- -title: HTTP/S Endpoints ---- - -import TabItem from "@theme/TabItem"; -import Tabs from "@theme/Tabs"; - -import TlsLimits from "./_tls_limits.mdx"; - -import RandomAgentCliExample from "/examples/agent-cli/http-random.mdx"; -import RandomAgentConfigExample from "/examples/agent-config/http-random.mdx"; -import RandomGoSdkExample from "/examples/go-sdk/http-random.mdx"; -import RandomJavascriptSdkExample from "/examples/javascript-sdk/http-random.mdx"; -import RandomPythonSdkExample from "/examples/python-sdk/http-random.mdx"; -import RandomRustSdkExample from "/examples/rust-sdk/http-random.mdx"; -import RandomSshExample from "/examples/ssh/http-random.mdx"; - -import StaticDomainAgentCliExample from "/examples/agent-cli/http-static-domain.mdx"; -import StaticDomainAgentConfigExample from "/examples/agent-config/http-static-domain.mdx"; -import StaticDomainGoSdkExample from "/examples/go-sdk/http-static-domain.mdx"; -import StaticDomainJavascriptSdkExample from "/examples/javascript-sdk/http-static-domain.mdx"; -import StaticDomainKubernetesExample from "/examples/k8s/http-static-domain.mdx"; -import StaticDomainPythonSdkExample from "/examples/python-sdk/http-static-domain.mdx"; -import StaticDomainRustSdkExample from "/examples/rust-sdk/http-static-domain.mdx"; -import StaticDomainSshExample from "/examples/ssh/http-static-domain.mdx"; - -import BrandedDomainAgentCliExample from "/examples/agent-cli/http-branded-domain.mdx"; -import BrandedDomainAgentConfigExample from "/examples/agent-config/http-branded-domain.mdx"; -import BrandedDomainGoSdkExample from "/examples/go-sdk/http-branded-domain.mdx"; -import BrandedDomainJavascriptSdkExample from "/examples/javascript-sdk/http-branded-domain.mdx"; -import BrandedDomainKubernetesExample from "/examples/k8s/http-branded-domain.mdx"; -import BrandedDomainPythonSdkExample from "/examples/python-sdk/http-branded-domain.mdx"; -import BrandedDomainRustSdkExample from "/examples/rust-sdk/http-branded-domain.mdx"; -import BrandedDomainSshExample from "/examples/ssh/http-branded-domain.mdx"; - -import BasicAuthAgentCliExample from "/examples/agent-cli/http-basic-auth.mdx"; -import BasicAuthAgentConfigExample from "/examples/agent-config/http-basic-auth.mdx"; -import BasicAuthGoSdkExample from "/examples/go-sdk/http-basic-auth.mdx"; -import BasicAuthJavascriptSdkExample from "/examples/javascript-sdk/http-basic-auth.mdx"; -import BasicAuthKubernetesExample from "/examples/k8s/http-basic-auth.mdx"; -import BasicAuthPythonSdkExample from "/examples/python-sdk/http-basic-auth.mdx"; -import BasicAuthRustSdkExample from "/examples/rust-sdk/http-basic-auth.mdx"; -import BasicAuthSshExample from "/examples/ssh/http-basic-auth.mdx"; - -import OAuthAgentCliExample from "/examples/agent-cli/http-oauth-authn.mdx"; -import OAuthAgentConfigExample from "/examples/agent-config/http-oauth-authn.mdx"; -import OAuthGoSdkExample from "/examples/go-sdk/http-oauth-authn.mdx"; -import OAuthJavascriptSdkExample from "/examples/javascript-sdk/http-oauth-authn.mdx"; -import OAuthKubernetesExample from "/examples/k8s/http-oauth-authn.mdx"; -import OAuthPythonSdkExample from "/examples/python-sdk/http-oauth-authn.mdx"; -import OAuthRustSdkExample from "/examples/rust-sdk/http-oauth-authn.mdx"; -import OAuthSshExample from "/examples/ssh/http-oauth-authn.mdx"; - -import ForwardHttpsAgentCliExample from "/examples/agent-cli/http-forward-https.mdx"; -import ForwardHttpsAgentConfigExample from "/examples/agent-config/http-forward-https.mdx"; -import ForwardHttpsGoSdkExample from "/examples/go-sdk/http-forward-https.mdx"; -import ForwardHttpsJavascriptSdkExample from "/examples/javascript-sdk/http-forward-https.mdx"; -import ForwardHttpsKubernetesExample from "/examples/k8s/http-forward-https.mdx"; -import ForwardHttpsPythonSdkExample from "/examples/python-sdk/http-forward-https.mdx"; -import ForwardHttpsRustSdkExample from "/examples/rust-sdk/http-forward-https.mdx"; -import ForwardHttpsSshExample from "/examples/ssh/http-forward-https.mdx"; - -import HostHeaderAgentCliExample from "/examples/agent-cli/http-rewrite-host-header.mdx"; -import HostHeaderAgentConfigExample from "/examples/agent-config/http-rewrite-host-header.mdx"; -import HostHeaderGoSdkExample from "/examples/go-sdk/http-rewrite-host-header.mdx"; -import HostHeaderJavascriptSdkExample from "/examples/javascript-sdk/http-rewrite-host-header.mdx"; -import HostHeaderKubernetesExample from "/examples/k8s/http-rewrite-host-header.mdx"; -import HostHeaderPythonSdkExample from "/examples/python-sdk/http-rewrite-host-header.mdx"; -import HostHeaderRustSdkExample from "/examples/rust-sdk/http-rewrite-host-header.mdx"; -import HostHeaderSshExample from "/examples/ssh/http-rewrite-host-header.mdx"; - -import WildcardAgentCliExample from "/examples/agent-cli/http-wildcard-domain.mdx"; -import WildcardAgentConfigExample from "/examples/agent-config/http-wildcard-domain.mdx"; -import WildcardGoSdkExample from "/examples/go-sdk/http-wildcard-domain.mdx"; -import WildcardJavascriptSdkExample from "/examples/javascript-sdk/http-wildcard-domain.mdx"; -import WildcardKubernetesExample from "/examples/k8s/http-wildcard-domain.mdx"; -import WildcardPythonSdkExample from "/examples/python-sdk/http-wildcard-domain.mdx"; -import WildcardRustSdkExample from "/examples/rust-sdk/http-wildcard-domain.mdx"; -import WildcardSshExample from "/examples/ssh/http-wildcard-domain.mdx"; - -import NonLocalAgentCliExample from "/examples/agent-cli/http-nonlocal.mdx"; -import NonLocalAgentConfigExample from "/examples/agent-config/http-nonlocal.mdx"; -import NonLocalGoSdkExample from "/examples/go-sdk/http-nonlocal.mdx"; -import NonLocalJavascriptSdkExample from "/examples/javascript-sdk/http-nonlocal.mdx"; -import NonLocalKubernetesExample from "/examples/k8s/http-nonlocal.mdx"; -import NonLocalPythonSdkExample from "/examples/python-sdk/http-nonlocal.mdx"; -import NonLocalRustSdkExample from "/examples/rust-sdk/http-nonlocal.mdx"; -import NonLocalSshExample from "/examples/ssh/http-nonlocal.mdx"; - -import AbsPathFileserverAgentCliExample from "/examples/agent-cli/http-fileserver-abs-path.mdx"; -import AbsPathFileserverAgentConfigExample from "/examples/agent-config/http-fileserver-abs-path.mdx"; -import AbsPathFileserverGoSdkExample from "/examples/go-sdk/http-fileserver-abs-path.mdx"; -import AbsPathFileserverJavascriptSdkExample from "/examples/javascript-sdk/http-fileserver-abs-path.mdx"; -import AbsPathFileserverKubernetesExample from "/examples/k8s/http-fileserver-abs-path.mdx"; -import AbsPathFileserverPythonSdkExample from "/examples/python-sdk/http-fileserver-abs-path.mdx"; -import AbsPathFileserverRustSdkExample from "/examples/rust-sdk/http-fileserver-abs-path.mdx"; -import AbsPathFileserverSshExample from "/examples/ssh/http-fileserver-abs-path.mdx"; - -import WorkingDirFileserverAgentCliExample from "/examples/agent-cli/http-fileserver-working-dir.mdx"; -import WorkingDirFileserverAgentConfigExample from "/examples/agent-config/http-fileserver-working-dir.mdx"; -import WorkingDirFileserverGoSdkExample from "/examples/go-sdk/http-fileserver-working-dir.mdx"; -import WorkingDirFileserverJavascriptSdkExample from "/examples/javascript-sdk/http-fileserver-working-dir.mdx"; -import WorkingDirFileserverKubernetesExample from "/examples/k8s/http-fileserver-working-dir.mdx"; -import WorkingDirFileserverPythonSdkExample from "/examples/python-sdk/http-fileserver-working-dir.mdx"; -import WorkingDirFileserverRustSdkExample from "/examples/rust-sdk/http-fileserver-working-dir.mdx"; -import WorkingDirFileserverSshExample from "/examples/ssh/http-fileserver-working-dir.mdx"; - -import WindowsFileserverAgentCliExample from "/examples/agent-cli/http-fileserver-windows.mdx"; -import WindowsFileserverAgentConfigExample from "/examples/agent-config/http-fileserver-windows.mdx"; -import WindowsFileserverGoSdkExample from "/examples/go-sdk/http-fileserver-windows.mdx"; -import WindowsFileserverJavascriptSdkExample from "/examples/javascript-sdk/http-fileserver-windows.mdx"; -import WindowsFileserverKubernetesExample from "/examples/k8s/http-fileserver-windows.mdx"; -import WindowsFileserverPythonSdkExample from "/examples/python-sdk/http-fileserver-windows.mdx"; -import WindowsFileserverRustSdkExample from "/examples/rust-sdk/http-fileserver-windows.mdx"; -import WindowsFileserverSshExample from "/examples/ssh/http-fileserver-windows.mdx"; - -HTTP/S endpoints enable you to serve web services like REST APIs, web -applications, websites and websocket servers. Serving a web application is as -simple as `ngrok http 80`. - -Once your endpoint is running, check out: - -- [Traffic Policy](/traffic-policy/) - Add routing, authentication and traffic transformation -- [Traffic Inspector](https://dashboard.ngrok.com/traffic-inspection/) - Real-time observability with request/response introspection -- [Endpoint Pooling](/universal-gateway/endpoint-pooling/) - Load balancing - -## Quickstart - -### Agent Endpoint - -Agent Endpoints are the easiest way to get started with ngrok. An [agent -endpoint](/universal-gateway/cloud-endpoints/) is started by a -[Secure Tunnels](/agent/) agent. The endpoint lives for the lifetime of the -process and forwards traffic to a port or URL of your choosing. - -Create the endpoint `https://example.ngrok.app` and forward its traffic to a -local port. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -### Cloud Endpoint - -[Cloud endpoints](/universal-gateway/cloud-endpoints/) are created via the -ngrok Dashboard or [API](/api/). They are persistent and live until they are -deleted. [Traffic Policy](/traffic-policy/) controls how a cloud endpoint -handles traffic. - -[Create an HTTPS cloud endpoint](https://dashboard.ngrok.com/endpoints/new) -which returns a `Hello world!` 200 OK response. - - - - -```sh title="Command line" -ngrok api endpoints create \ - --url https://example.ngrok.app \ - --traffic-policy "$( - - - -## URL - -URLs are validated differently depending on their -[binding](/universal-gateway/bindings). Consult the -following documentation for details on valid URLs for TCP endpoints: - -- [Public Endpoint URLs](/universal-gateway/public-endpoints/#urls) -- [Internal Endpoint URLs](/universal-gateway/internal-endpoints/#urls) -- [Kubernetes Endpoint URLs](/universal-gateway/kubernetes-endpoints/#urls) - -#### Public - -###### HTTP - -- The hostname must be a domain with a valid [public suffix](https://publicsuffix.org/). -- The port must be `80`. If you do not specify a port, the default `80` will be used for you. - -**Examples** - -- `http://example.ngrok.app` -- `http://example.ngrok.app:80` -- `http://example.party` -- `http://example.ngrok.app:81` - invalid port: port number must be `80`, not `81` -- `http://example.doesnotexist` - invalid hostname: `.doesnotexist` is not a public suffix domain -- `http://example.internal` - invalid hostname: `.internal` is not a public suffix domain - -###### HTTPS - -- The hostname must be a domain with a valid [public suffix](https://publicsuffix.org/). -- The port must be `443`. If you do not specify a port, the default `443` will be used for you. - -#### Internal - -#### Kubernetes - -##### Valid URLs - -- https://example.ngrok.app -- https://example.ngrok.app:443 -- https://example.party - -##### Invalid URLs - -- https://example.ngrok.app:8443 -- https://example.nosuchtld -- https://example.internal - -### Validation - -When you create an agent endpoint, if you do not specify a complete URL, -following defaults are used to construct an endpoint URL. When you create a -cloud endpoint, you must always specify both a scheme and hostname. - -| URL Part | Default | -| -------- | --------------------------------------------------------- | -| Scheme | `https` | -| Hostname | randomly selected | -| Port | `443` if scheme is `https`
`80` if scheme is `http` | - -Consult the following table of examples of URL defaulting: - -| Value | Endpoint URL | -| ------------------------------- | -------------------------------------------------------- | -| `https://example.ngrok.app` | `https://example.ngrok.app` | -| `http://example.ngrok.app` | `http://example.ngrok.app` | -| `example.ngrok.app` | `https://example.ngrok.app` | -| `app.example.com` | `https://app.example.com` | -| `https://example.internal` | `https://example.internal` | -| `https://example.internal:1234` | `https://example.internal:1234` | -| `http://example.internal` | `http://example.internal` | -| `foo.internal` | `https://foo.internal` | -| `{empty}` | `https://1eb2-181-80-12-3.ngrok.app` (randomly selected) | - -If you would like to listen for both http and https traffic, create two endpoints. - -#### Domains - -When you create a public endpoint, it must match a -[Domain](/universal-gateway/domains) on your account. Domains help you set up -branded domains and manage TLS certificates. You may create endpoints with -wildcard domains as well. - -Endpoints with randomly-assigned hostnames are an exception and won't match an -existing Domain object. - -### Bring your own domain {#bring-your-own-domain} - -If you want to bring your own domain, first [create a Domain record and set up -a DNS CNAME record](/universal-gateway/domains/#branded-domains). Then -create an endpoint on that domain by specifying a URL with a matching hostname. - -For example, to create an HTTPS endpoint on `https://app.example.com`, [create -a Domain](https://dashboard.ngrok.com/domains) and follow the instructions to -set up a CNAME record. Then use the following example to start an endpoint on -your domain: - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### Wildcard endpoints - -You can create an endpoint which will receive traffic for all of the subdomains -matching a given wildcard domain like `*.example.com`. You must create a -[wildcard domain](/universal-gateway/domains/#wildcard-domains) to create a -public wildcard endpoint. - -For example, if you create the wildcard endpoint `https://*.example.com`, it -will receive traffic for `https://foo.example.com` and -`https://bar.example.com`. - -- Connections to URLs which match an online wildcard endpoint will be routed to - it. For example, if you have created a wildcard endpoint - `https://*.example.com`, connections to `https://foo.bar.baz.example.com` will - route to it. -- Connections are routed to the most specific online endpoint. For example, if - the endpoints `https://*.example.com` and `https://app.example.com` are both - online, a connection to `https://app.example.com` will not be routed to the - wildcard endpoint. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### Use multiple endpoints with wildcard subdomains - -With the [Agent CLI](/agent/cli), you can create separate public endpoints for subdomains of a wildcard domain no matter where the upstream services are running. See [the Domains docs](/docs/universal-gateway/domains/#wildcard-domains) for more information. - -For example, if you reserve `*.example.com` and want to route requests to `api1.example.com` and `api2.example.com`, you can specify subdomains via the CLI. ngrok will handle routing requests to the correct endpoint, even if they're on different ports. - -The first one might be at port `80`: - -```bash -ngrok http 80 --url https://api1.example.com -``` - -While the second is at port `81`: - -```bash -ngrok http 81 --url https://api2.example.com -``` - -:::tip -This is only necessary for creating _public_ endpoints to subdomains. Internal endpoints don't require a domain. -::: - -### Randomly assigned hostnames - -If you run create a public endpoint without specifying a hostname, ngrok will -automatically assign a random one for you.by selecting a random subdomain of one of our [ngrok-managed -Domains](/universal-gateway/domains#ngrok-managed-domains) to your endpoint. -For example, the command `ngrok http 80` may create an endpoint like -`https://1eb2-181-80-12-3.ngrok.app`. - -The following example create an HTTPS endpoint on a randomly assigned hostname -that forwards to port 8080. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Traffic Policy - -Attach [Traffic Policy](/traffic-policy/) to endpoints to route, authenticate and transform the traffic through the endpoint. - -### Authentication - -Public endpoints are accessible to the public internet unless you secure them -with authentication. That's desirable if you're hosting a public website but -most often you want to add authentication. You can secure your endpoints with -[Traffic Policy](/traffic-policy) with any of the following actions: - -- [Basic Auth](/traffic-policy/actions/basic-auth) -- [OAuth](/traffic-policy/actions/oauth) -- [IP Restriction](/traffic-policy/actions/restrict-ips/) -- [Webhook Verification](/traffic-policy/actions/verify-webhook/) -- [JWT](/traffic-policy/actions/jwt-validation/) -- [Mutual TLS](/traffic-policy/actions/terminate-tls/) -- [OpenID Connect](/traffic-policy/actions/oidc/) -- [SAML](/traffic-policy/actions/saml/) - -#### Basic Auth Example - -Adds a username and password with the [Basic -Auth](/traffic-policy/actions/basic-auth) Traffic Policy action. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -#### Google OAuth Example - -The following example enforces a browser-based OAuth redirect flow in front of -your endpoint using Google as the identity provider by using the -[OAuth](/traffic-policy/actions/oauth) Traffic Policy action. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#### Rewriting the `host` header {#rewrite-host-header} - -Some application servers expect the `host` header to match a specific value -when they receive requests and some use the `host` header to determine which of -many sites to display. ngrok can rewrite the `host` header of incoming requests -so that your application behaves correctly. - -When you rewrite the `host` header, ngrok also rewrites the `location` header of -HTTP responses automatically to match the hostname of your Endpoint URL. - -The following example rewrites the `host` header to the value `localhost` using -the [`add-headers`](/traffic-policy/actions/add-headers) Traffic Policy action. -Adding the `Host` header [is a special -case](/traffic-policy/actions/add-headers/#special-cases) that replaces the existing -`Host` header instead of appending a second value. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Agent Forwarding - -The [ngrok agent](/agent/) and [Agent -SDKs](/agent-sdks/) forward traffic that your endpoints receive -to upstream services. You specify a URL or port number to instruct the ngrok -agent where and how to forward traffic. - -### HTTPS forwarding - -The scheme in your upstream URL is used to determine whether to forward HTTP or -HTTPS traffic to the upstream service. If you do not specify a scheme, the -default `http` scheme is chosen _unless_ you forward to port `443`, in which -case ngrok will use `https`. Consult the following table of examples. - -| Upstream URL | Normalized Value | -| ------------------------ | ------------------------ | -| `http://localhost:1234` | `http://localhost:1234` | -| `https://localhost:1234` | `https://localhost:1234` | -| `localhost:1234` | `http://localhost:1234` | -| `1234` | `http://localhost:1234` | -| `localhost:443` | `https://localhost:443` | -| `443` | `https://localhost:443` | - -ngrok assumes that the network you run the agent on is private and it does not -verify the TLS certificate presented by the upstream service. You may change -this behavior with the [flags `--upstream-tls-verify` and -`upstream-tls-verify-cas`](/agent/cli/#ngrok-http). - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### Non-local forwarding - -Agents don't just forward to ports on your localhost. You can forward traffic -to any address or URL reachable from the agent. For example, if you want to -forward traffic to a HTTP server running on your network at `192.168.1.2:80`: - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### HTTP/2 forwarding - -When agents forward to upstream http/2 services, connections use HTTP/1.1 by -default. - -You can configure the agent, SDKs and Kubernetes Operator to instead use HTTP/2 -when forwarding to your upstream service. - -| Forwarder | Option | Docs | -| ------------------- | --------------------------------- | ----------------------------------------- | -| Agent | `--upstream-protocol` | [Agent CLI flags](/agent/cli/#ngrok-http) | -| Agent SDKs | language-dependent | [Agent SDKs](/agent-sdks) | -| Kubernetes Operator | `appProtocol` on the `Tunnel` CRD | [Kubernetes Operator](/k8s) | - -When http2 forwarding is enabled, all requests to your upstream service will be -transmitted over HTTP/2 Cleartext since TLS was already terminated at the ngrok -cloud service. We cannot use -[TLS-ALPN](https://httpwg.org/specs/rfc7540.html#TLS-ALPN) at this time. We -rely on [HTTP/2 with Prior -Knowledge](https://httpwg.org/specs/rfc7540.html#known-http) currently. - -### Serving file directories - -The ngrok agent supports the `file://` scheme in a forwarding URL. When you use -the `file://` scheme, the ngrok agent serves local file system directories by -using its own built-in file server, no separate server needed. It works just -like `python3 -m http.server` but it is built directly into the ngrok agent. - -Paths in `file://` URLs must be specified as absolute paths. - -#### Serve files in `/var/log` - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -#### Serve files on Windows - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -#### Serve files in your current working directory - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Traffic Observability - -### Traffic Inspector - -[Traffic Inspector](/obs/traffic-inspection/) gives you a real-time view in the -ngrok dashboard of the HTTP traffic flowing through your HTTP/S endpoints. You -can choose whether Traffic Inspector captures only request metadata or full -request and response bodies. - -### Log Export Events - -You can export logs of traffic to HTTP/S endpoints with [ngrok's events -system](/obs/). The following events are published for log exporting: - -| Event | When | -| ------------------------------------------------------------------------ | ----------------------------------------------------------------- | -| [http_request_complete.v0](/obs/events/reference/#http-request-complete) | Published when an HTTP request to an HTTP/S endpoints completes. | -| [tcp_connection_closed.v0](/obs/events/reference/#tcp-connection-closed) | Published when a TCP connection to an HTTP/S endpoints completes. | - -## Advanced - -HTTP/S endpoints are standards-compliant HTTP reverse proxies. - -### Versions - -- HTTP/S endpoints support HTTP/1.1. -- HTTPS endpoints support HTTP/1.1 and HTTP/2. -- HTTP/1.0, HTTP/3 and QUIC are **not** supported. - -### HTTP/2 - -HTTPS endpoints will automatically use HTTP/2 for all connections if the client -supports it. Client support is determined via standard ALPN negotiation. - -HTTP/2 is used between the client and your endpoint even even if your upstream -service does not support HTTP/2. - -The section on [HTTP/2 agent forwarding](#http2-forwarding) has details on how to -configure the use of HTTP/2 when sending traffic to an upstream service. - -### Websockets - -Websocket connections are supported out-of-the-box. No configuration is required. - -### Hop by hop headers - -ngrok does not forward any [hop-by-hop -headers](https://datatracker.ietf.org/doc/html/rfc2616#section-13.5.1) to the -upstream service. As an exception, `Connection: upgrade` headers are forwarded -to support [websockets](#websockets). - -For information on headers added automatically by ngrok, see -[Upstream Headers](#upstream-headers). - -### Persistent connections - -When a connection is made to HTTP/S ngrok endpoints with HTTP/1.1, ngrok may -choose to use persistent connections (aka HTTP keep-alive) to improve the -performance of future requests from the same client if the client supports it. - -This behavior is not guaranteed and it is not configurable. - -See [RFC 7230](https://datatracker.ietf.org/doc/html/rfc7230#section-6.3) for -additional details. - -### Well Known URIs - -#### `/.well-known/acme-challenge` - -ngrok takes over handling of this path of any HTTP endpoint matching a -[Domain](/universal-gateway/domains) with automated certificate management -enabled. You may disable this behavior by uploading your own certificate on the -matching Domain. - -## TLS - -ngrok automatically handles TLS (SSL) certificate management and termination for you. -There is nothing to setup, configure or manage. - -TLS connections to `https` endpoints are terminated at ngrok's cloud service. -If you wish to terminate TLS traffic at the ngrok agent or in your upstream -application, use a [TLS Endpoint](/universal-gateway/tls) instead. - -Consult the following documentation for additional details on how ngrok handles -TLS termination and certificiate management: - -- [TLS Certificates](/universal-gateway/tls-certificates) -- [TLS Termination](/universal-gateway/tls-termination) - -## Upstream Headers - -ngrok adds headers to each HTTP request with information about the original -client IP, request scheme and request `host` header value. - -| Header | Description | -| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -| `x-forwarded-for` | The IP address of the client who initiated the request. If this header exists on the original request, ngrok will append a new value. | -| `x-forwarded-proto` | The scheme of the original request, either `http` or `https`. If this header exists on the original request, ngrok will append a new value. | -| `x-forwarded-host` | The header from the client's request if it existed, otherwise is set to the request's `Host` header value. | - -Because ngrok appends values to `x-forwarded-for` and `x-forwarded-proto`, be -sure to use the last value of the header in your application code to read the -values injected by ngrok. - -You may remove these headers with the [Remove -Headers](/traffic-policy/actions/remove-headers/) Traffic Policy action. - -## Limits & Timeouts - -[Contact us](mailto:support@ngrok.com) if you need to configure limits and -timeouts on connections to HTTP endpoints. - -#### Connection - -| Limit | Name | Notes | -| --------- | ------------------- | ------------------------------------------------------------ | -| 5 minutes | Client Idle Timeout | Time since data was last transmitted by the upstream service | -| 5 minutes | Server Idle Timeout | Time since data was last transmitted by the upstream service | -| No limit | Data transmitted | Data transmitted by the client or upstream service | - -#### TLS - - - -#### HTTP - -| Limit | Name | Notes | -| ---------- | ------------------ | --------------------------------------------- | -| No timeout | Round Trip Timeout | Time for the entire HTTP request and response | - -#### HTTP Request - -| Limit | Name | Notes | -| ---------- | ---------------------- | ---------------------------------------------------- | -| 1 MB | Request Header Size | Includes method, URI and headers | -| 1 MB | Request URI Length | Limited by the size of the request header | -| No timeout | Request Timeout | Time to read the entire HTTP request from the client | -| No timeout | Request Header Timeout | Time to read the HTTP request header from the client | -| No limit | Request Body Size | | - -#### HTTP Response - -| Limit | Name | Notes | -| ---------- | ----------------------- | ----------------------------------------------------- | -| 1 MB | Response Header Size | Includes method, URI and headers | -| No timeout | Response Timeout | Time to read the entire HTTP response from the server | -| No timeout | Response Header Timeout | Time to read the HTTP response header from the server | -| No limit | Response Body Size | | - -## Errors - -If ngrok fails to handle an HTTP request it will set the `ngrok-error-code` -header in the HTTP response with a [unique ngrok Error Code](/errors/) -describing the failure. - -ngrok guarantees that the upstream service may never set the `ngrok-error-code` -HTTP response header so you know reliably that it was set by ngrok. - -ngrok may return an error under the following conditions: - -- Your upstream service timed out or rejected the connection -- Your upstream service returned a response that was not valid HTTP -- A [Traffic Policy](/traffic-policy) action rejected the request. -- [Traffic Policy](/traffic-policy) execution encountered a runtime error. -- ngrok encountered an internal error - -## API - -HTTP/S Endpoints can be created programatically. Consult the documentation on -[Endpoint APIs](/api/resources/endpoints/). - -## Pricing - -HTTP/S endpoints are available on all plans. Consult the [Endpoints -Pricing](/universal-gateway/endpoints/#pricing) documentation for -billing details. - -See [Domains pricing](/universal-gateway/domains/#pricing) for details on -pricing for custom domains, wildcard domains and more. diff --git a/docs/universal-gateway/internal-endpoints.mdx b/docs/universal-gateway/internal-endpoints.mdx deleted file mode 100644 index 618c0e0f84..0000000000 --- a/docs/universal-gateway/internal-endpoints.mdx +++ /dev/null @@ -1,125 +0,0 @@ ---- -title: Internal Endpoints -description: Learn about staging internal services and applications using internal endpoints. ---- - -**Internal Endpoints** are private endpoints that only receive traffic when forwarded through the [`forward-internal` traffic policy action](/docs/traffic-policy/actions/forward-internal/). This allows you to route traffic to an application through ngrok without making it publicly addressable. - -Internal endpoint URLs must: - -- End with the `.internal` domain extension -- Use the `internal` [binding](/docs/universal-gateway/bindings/) - -A common practice is to use a [public](/docs/universal-gateway/public-endpoints) [cloud endpoints](/docs/universal-gateway/cloud-endpoints/) to manage a centralized Traffic Policy, then forward traffic to one or more internal [endpoints](/docs/universal-gateway/endpoints/). See [the guide on using cloud endpoints with internal endpoints](/docs/guides/other-guides/forwarding-and-load-balancing-with-cloud-endpoints/) to learn more. - -## Quickstart - -### Agent Endpoint - -Create an internal agent endpoint by specifying a binding of `internal` when -you create an endpoint. - -```bash -ngrok http 8080 --url "https://example.internal" --binding internal -``` - -### Cloud Endpoint - -Instead of an agent endpoint, you can create an internal cloud endpoint. - -Specify a binding of `internal` when you create the cloud endpoint. - -```bash -ngrok api create \ - --type cloud \ - --binding internal \ - --url "https://example.internal" \ - --traffic-policy "$(cat traffic-policy.yml)" -``` - -##### `traffic-policy.yml` - -```yaml -on_http_request: - - actions: - - type: custom-response - config: - status_code: 200 - headers: - content-type: text/plain - content: "Hello world!" -``` - -### Forwarding - -Internal endpoints aren’t directly accessible. To send traffic to an Internal Endpoint, you must create an endpoint that uses the Traffic Policy to forward traffic using the [`forward-internal` action](/docs/traffic-policy/actions/forward-internal/). - -For example, to route public traffic to your internal endpoint, use the following command and traffic policy to create a Public Cloud Endpoint that forwards requests to your Internal Endpoint: - -```bash -ngrok api create \ - --type cloud \ - --url "https://your-name.ngrok.app" \ - --traffic-policy "$(cat traffic-policy.yml)" -``` - -##### `traffic-policy.yml` - -```yaml -on_http_request: - - actions: - - type: forward-internal - config: - url: https://example.internal -``` - -Now, when you make a request to `https://your-name.ngrok.app`, ngrok applies the specified traffic policy. This policy instructs ngrok to use the forward-internal action, routing the incoming HTTP request directly to your internal endpoint at `https://example.internal`. - -This configuration lets you manage how traffic reaches your service without requiring it to be directly accessible on the public internet. - -## Inferred Binding - -ngrok automatically infers an `internal` binding for any endpoint created with a `.internal` hostname, so you can omit the `binding` property in most cases. - -For example, the following command creates an endpoint with an internal binding: - -```bash -ngrok http 8080 --url "https://example.internal" -``` - -## URLs - -- **Scheme** - Internal endpoints support all [Endpoint Protocols](/universal-gateway/protocols) (`http`, `https`, `tcp` and `tls`). -- **Hostname** - Hostnames **must** end with `.internal` and may contain up to 5 subdomains. You must specify a URL with a hostname, randomly-assigned hostnames are not supported. You may specify wildcard hostnames. -- **Port** - All port numbers [1-65535] are valid. For `tcp` endpoints, you **must** specify a port. -- **Namespacing** - Internal endpoints are namespaced on a per-account basis. - This means that, two different accounts may have internal endpoints with the same URL (e.g. `https://api.internal`) without conflict or interference in [endpoint pooling](/universal-gateway/endpoint-pooling). - -#### Examples - -- `https://example.internal` -- `https://example.foo.bar.internal` -- `https://example.internal:12345` -- `tls://example.internal` -- `tls://example.internal:12345` -- `tcp://example.internal:12345` - -## Type and Pooling - -- Internal endpoints support both [Endpoint Types](/universal-gateway/types): `agent` and `cloud`. -- Internal endpoints support [Endpoint Pooling](/universal-gateway/endpoint-pooling). - -## HTTP/S `on_tcp_connect` phase - -For internal `http` and `https` endpoints, the `on_tcp_connect` [Traffic Policy](/traffic-policy/) phase is not applicable and never triggers. - -This is because when you use the [`forward-internal` action](/docs/traffic-policy/actions/forward-internal/) to forward traffic to an `http` or `https` endpoint, no new TCP connection is established. For additional details, see the [`forward-internal` documentation](/traffic-policy/actions/forward-internal/). - -## API - -Internal endpoints can be managed programatically. To get started, consult the -[Endpoints API documentation](/api/resources/endpoints/). - -## Pricing - -Internal endpoints are available on the Pay-as-you-go plan. Consult the [Endpoints Pricing](/universal-gateway/endpoints/#pricing) documentation for billing details. diff --git a/docs/universal-gateway/internal-endpoints/index.mdx b/docs/universal-gateway/internal-endpoints/index.mdx new file mode 100644 index 0000000000..19a7793f62 --- /dev/null +++ b/docs/universal-gateway/internal-endpoints/index.mdx @@ -0,0 +1,41 @@ +--- +sidebar_label: Internal Binding +title: What are Internal Endpoints? +description: Learn about staging internal services and applications using internal endpoints. +--- + +**Internal Endpoints** are private endpoints that only receive traffic when forwarded through the [`forward-internal` traffic policy action](/docs/traffic-policy/actions/forward-internal/). This allows you to route traffic to an application through ngrok without making it publicly addressable. + +Internal endpoint URLs must: + +- End with the `.internal` domain extension +- Use the `internal` [binding](/docs/universal-gateway/bindings/) + +:::tip +A common practice is to use a [public](/docs/universal-gateway/public-endpoints) [cloud endpoints](/docs/universal-gateway/cloud-endpoints/) to manage a centralized Traffic Policy, then forward traffic to one or more internal [endpoints](/docs/universal-gateway/endpoints/). See [the guide on using cloud endpoints with internal endpoints](/docs/guides/other-guides/forwarding-and-load-balancing-with-cloud-endpoints/) to learn more. +::: + +## Get started + +See [the quickstart](/docs/universal-gateway/internal-endpoints/create-internal-endpoints) to create your first Internal Endpoint. + +## Type and Pooling + +Internal endpoints support: + +- Both [Endpoint Types](/universal-gateway/types): `agent` and `cloud`. +- [Endpoint Pooling](/universal-gateway/endpoint-pooling). + +## HTTP/S `on_tcp_connect` phase + +For internal `http` and `https` endpoints, the `on_tcp_connect` [Traffic Policy](/traffic-policy/) phase is not applicable and never triggers. + +This is because when you use the [`forward-internal` action](/docs/traffic-policy/actions/forward-internal/) to forward traffic to an `http` or `https` endpoint, no new TCP connection is established. For additional details, see the [`forward-internal` documentation](/traffic-policy/actions/forward-internal/). + +## API + +Internal endpoints can be managed programatically. To get started, consult the [Endpoints API documentation](/api/resources/endpoints/). + +## Pricing + +Internal endpoints are available on the Pay-as-you-go plan. Consult the [Endpoints Pricing](/universal-gateway/endpoints/#pricing) documentation for billing details. diff --git a/docs/universal-gateway/internal-endpoints/quickstart.mdx b/docs/universal-gateway/internal-endpoints/quickstart.mdx new file mode 100644 index 0000000000..f5d68933cd --- /dev/null +++ b/docs/universal-gateway/internal-endpoints/quickstart.mdx @@ -0,0 +1,73 @@ +--- +title: Internal Endpoint Quickstart +--- + +## Agent Endpoints + +When you create an [agent endpoint](/docs/universal-gateway/agent-endpoints), you can set the binding to `internal` to make it an internal endpoint. + +```bash +ngrok http 8080 --url "https://example.internal" --binding internal +``` + +### Inferred Binding + +ngrok automatically infers an `internal` binding for any endpoint created with a `.internal` hostname, so you can omit the `binding` property in most cases. + +For example, the following command creates an endpoint with an internal binding: + +```bash +ngrok http 8080 --url "https://example.internal" +``` + +## Cloud Endpoints + +You can also create internal [cloud endpoints](/docs/universal-gateway/cloud-endpoints/). + +Specify a binding of `internal` when you create the cloud endpoint. + +```bash +ngrok api create \ + --type cloud \ + --binding internal \ + --url "https://example.internal" \ + --traffic-policy "$(cat traffic-policy.yml)" +``` + +#### `traffic-policy.yml` + +```yaml +on_http_request: + - actions: + - type: custom-response + config: + status_code: 200 + headers: + content-type: text/plain + content: "Hello world!" +``` + +## Forwarding + +Internal endpoints aren’t directly accessible. To send traffic to an Internal Endpoint, you must create an endpoint that uses the [`forward-internal` Traffic Policy action](/docs/traffic-policy/actions/forward-internal/). + +For example, to route public traffic to your internal endpoint, you can use the following traffic policy: + +```yaml +on_http_request: + - actions: + - type: forward-internal + config: + url: https://example.internal +``` + +And you can add it to a Cloud Endpoint with the following terminal command: + +```bash +ngrok api create \ + --type cloud \ + --url "https://your-name.ngrok.app" \ + --traffic-policy "$(cat traffic-policy.yml)" +``` + +This configuration lets you manage how traffic reaches your service without requiring it to be directly accessible on the public internet. diff --git a/docs/universal-gateway/ip-addresses.mdx b/docs/universal-gateway/ip-addresses.mdx index 87ccc460ca..0235c63dbd 100644 --- a/docs/universal-gateway/ip-addresses.mdx +++ b/docs/universal-gateway/ip-addresses.mdx @@ -1,9 +1,9 @@ --- -title: IP Addresses +sidebar_label: How IP Addresses Work +title: How Do IP Addresses Work With ngrok? +description: Learn how ngrok assigns IPs for endpoints, agent connections, and the dashboard API. --- -# IP Addresses {#ip-addresses} - ngrok's cloud service uses a dynamic, rotating set of multitenant IPs to serve your public Endpoints. Endpoint IPs may change frequently **_and without notice_**. If you hardcode any of ngrok's IPs or rely on DNS answers past their @@ -17,15 +17,22 @@ Global Load Balancing. ## Dedicated IPs If you need a static IP for your public endpoints, you may attach static, -[dedicated IPs for Domains](/universal-gateway/domains/#dedicated-ips). You may -also set up dedicated IPs for [Agent Connect -URLs](/agent/ingress/#dedicated-ips). +dedicated IPs for: -:::info Coming Soon +- [Domains](#domains) +- [Agent Connect URLs](/agent/ingress/#dedicated-ips). -Dedicated, static IPs for public endpoints coming soon, [request access to the -developer preview](https://dashboard.ngrok.com/developer-preview). +### Domains + +By default, a [Domain's](/universal-gateway/domains/what-are-domains/) matching Endpoints receive traffic on a set of +multi-tenant IP addresses that are shared among all ngrok accounts. You may instead configure a Domain's matching endpoints to receive traffic on IP addresses that are dedicated to your account. +If your Domain uses dedicated IPs, you may create public endpoints on _any_ +port numbers, not just `80` and `443`. + +:::info Coming Soon +Dedicated, static IPs for your domains are coming soon, [request access to the +developer preview](https://dashboard.ngrok.com/developer-preview). ::: ## IPv6 diff --git a/docs/universal-gateway/kubernetes-endpoints.mdx b/docs/universal-gateway/kubernetes-endpoints.mdx deleted file mode 100644 index fdc51e0cf4..0000000000 --- a/docs/universal-gateway/kubernetes-endpoints.mdx +++ /dev/null @@ -1,176 +0,0 @@ -# Kubernetes Endpoints - -:::info Coming Soon - -Kubernetes endpoints are not available yet, [request access to the developer -preview](https://dashboard.ngrok.com/developer-preview) for early access. - -::: - -## Overview - -Kubernetes endpoints are secure, private endpoints that are only addressable -inside of Kubernetes clusters where you install the [Kubernetes -operator](/k8s/). They enable you to connect to ngrok endpoints without making -them publicly addressable. - -Kubernetes endpoints have a -[binding](/universal-gateway/bindings) of `kubernetes`. - -## Quickstart - -Create a Kubernetes endpoint by specifying binding of `kubernetes` when you -create an endpoint. - -#### Step 1: Install the ngrok Kubernetes Operator - -```bash -helm install ngrok-operator ngrok/ngrok-operator \ - --namespace ngrok-operator \ - --create-namespace \ - --set description="example operator" \ - --set bindings.enabled=true \ - --set credentials.apiKey=$NGROK_API_KEY \ - --set credentials.authtoken=$NGROK_AUTHTOKEN -``` - -#### Step 2: Create a new namespace - -```bash -kubectl create ns prod -``` - -#### Step 3: Create an ngrok endpoint - -Run the following command in the same ngrok account to create the kubernetes -bound endpoint. After the command completes, the ngrok operator will [create -`Service` objects](#service-creation) in the kubernetes cluster matching the -endpoint's URL. - -```bash -ngrok http 80 --url http://customer-2.prod --binding kubernetes -``` - -#### Step 4: Connect to the endpoint - -Other pods in the Kubernetes cluster where the ngrok operator is running can -connect to the bound endpoint. - -```bash -$ kubectl run -i --tty --rm debug --restart=Never --image=appropriate/curl -- /bin/sh -# curl http://customer-2.prod -``` - -Congraulations, you just connected to your application via a private kubernetes -endpoint! - -## URLs - -Kubernetes endpoint URL hostnames must be in the following format: - -- `[http|tcp]://name.namespace[:port]` - -The following restrictions are enforced: - -- **Scheme** - Must be `http` or `tcp`. `https` and `tls` are not supported. -- **Hostname** - Hostnames must always be two parts separated by a single dot, - e.g. `foo.bar`. Wildcard hostnames are not allowed. -- **Port** - All port numbers [1-65535] are valid. Port must be specified for - `tcp` endpoints. -- **Namespacing** - Kubernetes endpoints are namespaced on a per-account basis. - Two accounts may have kubernetes endpoints with the same URL (e.g. - http://api.internal). Those endpoints will not conflict or - [pool](/universal-gateway/endpoint-pooling). - -#### Examples - -- `http://app.example` -- `http://app.example:12345` -- `tcp://app.example:443` -- `tcp://app.example:12345` -- `https://app.example` - invalid scheme `https` -- `tls://app.example:12345` - invalid scheme `tls` -- `http://app.foo.bar` - invalid hostname, must have only two parts -- `tcp://app.example` - tcp endpoint must specify port number - -## Type and Pooling - -- Kubernetes endpoints support all [Endpoint - Types](/universal-gateway/types) (`agent` and `cloud`). -- Kubernetes endpoints support [Endpoint - Pooling](/universal-gateway/endpoint-pooling). - -## `Service` Creation - -After a kubernetes-bound endpoint is created, the ngrok cloud service notifies -Kubernetes Operators that a new kubernetes-bound endpoint exists. Kubernetes -Operators create `v1.Service` objects in their Kubernetes clusters which -forward traffic they receive to the operators' pods. - -#### `ClusterIP` Service - -A Cluster IP service is created in the operator's namespace. - -```yaml -apiVersion: v1 -kind: Service -metadata: - name: # the endpoint's ID - namespace: ngrok-operator -spec: - selector: - app.kubernetes.io/name: ngrok-operator-forwarder - ports: - - protocol: TCP - port: 80 # the endpoint url's port - targetPort: # assigned by operator to target the ngrok-operator-forwarder container -``` - -#### `ExternalName` Service - -An ExternalName service is created in the namespace targeted by the second part -of the URL's hostname. - -```yaml -apiVersion: v1 -kind: Service -metadata: - name: customer-2 # first part of the URL's hostname - namespace: prod ## second part of the URL's hostname -spec: - # Point service at the Operator Forwarder - type: ExternalName - externalName: .ngrok-operator.svc.cluster.local -``` - -## How do I update endpoint selectors? - -If you don't want all kubernetes endpoints in your account to appear inside of -a cluster, you may specify an Endpoint Selector which filters which Kubernetes -endpoints are projected into the cluster it runs in. Endpoint Selectors are a -CEL expression which is evaluated against each Kubernetes Endpoint in your -account. The operator will only projects endpoints that the selector returns -`true` for. - -See [the docs on enabling bindings](/docs/k8s/guides/bindings/#enable-bindings-for-the-operator) to learn more. - -## How do I enable or disable Kubernetes endpoints on an existing installation? - -By default, if you don't change the default endpoint selector, all endpoints with a Kubernetes binding will be bound to the cluster the Operator is installed on. Changing the binding allows you to restrict which endpoints that operator will handle. - -See [the docs on enabling bindings](/docs/k8s/guides/bindings/#enable-bindings-for-the-operator) to learn more. - -## Coming Soon - -This feature is in developer preview, more documentation is coming soon. - -## API - -Kubernetes endpoints can be created programatically. Consult the documentation -on [Endpoint APIs](/api/resources/endpoints/). - -## Pricing - -Kubernetes endpoints are available on the Pay-as-you-go plan. Consult the -[Endpoints Pricing](/universal-gateway/endpoints/#pricing) -documentation for billing details. diff --git a/docs/universal-gateway/kubernetes-endpoints/index.mdx b/docs/universal-gateway/kubernetes-endpoints/index.mdx new file mode 100644 index 0000000000..fac247ce64 --- /dev/null +++ b/docs/universal-gateway/kubernetes-endpoints/index.mdx @@ -0,0 +1,26 @@ +--- +sidebar_label: Kubernetes Binding +title: What are Kubernetes Endpoints? +description: Learn about connecting your Kubernetes clusters with ngrok's Kubernetes endpoints. +--- + +Kubernetes endpoints are secure, private endpoints that are only addressable +inside of Kubernetes clusters where you install the [Kubernetes +Operator](/k8s/). They enable you to connect to ngrok endpoints without making them publicly addressable. + +Kubernetes endpoints have a [binding](/universal-gateway/bindings) of `kubernetes`. + +## Get started + +Follow the [installation instructions](/docs/k8s/installation/install/) to set up the ngrok Kubernetes Operator. + +## Learn more + +See [the docs on using bindings with the Kubernetes Operator](/docs/k8s/guides/bindings/#kubernetes-binding) to learn more. +oints/). + +## Pricing + +Kubernetes endpoints are available on the Pay-as-you-go plan. Consult the +[Endpoints Pricing](/universal-gateway/endpoints/#pricing) +documentation for billing details. diff --git a/docs/universal-gateway/kubernetes-endpoints/services.mdx b/docs/universal-gateway/kubernetes-endpoints/services.mdx new file mode 100644 index 0000000000..f63ede3d7c --- /dev/null +++ b/docs/universal-gateway/kubernetes-endpoints/services.mdx @@ -0,0 +1,46 @@ +--- +sidebar_label: Kubernetes Services +title: How ngrok Creats Kubernetes Services +description: Learn how ngrok creates Kubernetes Services for kubernetes-bound endpoints. +--- + +After a kubernetes-bound endpoint is created, the ngrok cloud service notifies +Kubernetes Operators that a new kubernetes-bound endpoint exists. Kubernetes +Operators create `v1.Service` objects in their Kubernetes clusters which +forward traffic they receive to the operators' pods. + +### `ClusterIP` Service + +A Cluster IP service is created in the operator's namespace. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: # the endpoint's ID + namespace: ngrok-operator +spec: + selector: + app.kubernetes.io/name: ngrok-operator-forwarder + ports: + - protocol: TCP + port: 80 # the endpoint url's port + targetPort: # assigned by operator to target the ngrok-operator-forwarder container +``` + +### `ExternalName` Service + +An ExternalName service is created in the namespace targeted by the second part +of the URL's hostname. + +```yaml +apiVersion: v1 +kind: Service +metadata: + name: customer-2 # first part of the URL's hostname + namespace: prod ## second part of the URL's hostname +spec: + # Point service at the Operator Forwarder + type: ExternalName + externalName: .ngrok-operator.svc.cluster.local +``` diff --git a/docs/universal-gateway/migrate-from-tunnels.mdx b/docs/universal-gateway/migrate-from-tunnels.mdx new file mode 100644 index 0000000000..a69a053c1d --- /dev/null +++ b/docs/universal-gateway/migrate-from-tunnels.mdx @@ -0,0 +1,3 @@ +--- +title: How Do I Migrate from Tunnels to Endpoints? +--- diff --git a/docs/universal-gateway/mock-api.mdx b/docs/universal-gateway/mock-api.mdx new file mode 100644 index 0000000000..58cdbebecb --- /dev/null +++ b/docs/universal-gateway/mock-api.mdx @@ -0,0 +1,115 @@ +--- +sidebar_label: Mocking API Responses With Endpoints +title: How Do I Mock API Responses With Endpoints? +description: Learn how to mock API responses using ngrok Endpoints and Traffic Policy. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; +import ConfigExample from "/src/components/ConfigExample.tsx"; + +You can mock API responses using ngrok [Endpoints](/docs/universal-gateway/endpoints). This enables you to test your application's functionality without having to stand up a full backend service or make requests to real APIs. + +The following steps will walk you through using [Traffic Policy](/traffic-policy/) to mock API responses. + +## 1. Create a Traffic Policy + +When requests are made to an Endpoint with a Traffic Policy, the policy can execute certain actions before returning a response or forwarding the traffic to downstream services. Using [request variables](/docs/traffic-policy/variables/req/), you can check many aspects of a request before sending a response, such as the value of its headers, the scheme, the user agent, and more. + +The following example Traffic Policy checks the URL path of all incoming requests, then returns a custom response if the path matches `/api/example`: + + + +## 2. Apply the Traffic Policy to an Endpoint + +There are multiple ways to apply the Traffic Policy from the previous section to your Endpoints. How you should do so depends on the type of Endpoint you're using. + +### Agent Endpoints + + + + +Run the following terminal command to create an Agent Endpoint with a Traffic Policy file: + +```bash + ngrok http 8080 --traffic-policy "policy-file-here.yml" +``` + +See [the guide on using Traffic Policy with CLI flags](/docs/traffic-policy/getting-started/agent-endpoints/cli/) for more information. + + + + +Use the following terminal command to edit your ngrok config file: + +```bash +ngrok config edit +``` + +See [the guide on using Traffic Policy with a config file](/docs/traffic-policy/getting-started/agent-endpoints/config-file/) for more information. + + + + +### Cloud Endpoints + + + + + 1. Navigate to the [Endpoints](https://dashboard.ngrok.com/endpoints/) page. + 1. Select the Cloud Endpoint you want to use. You'll be taken to a page where you can edit the Traffic Policy directly. + + + + With the ngrok CLI `api` command, you can add a Traffic Policy file to your Cloud Endpoint with the following command options: + ```bash + ngrok api endpoints create \ + --url https:// \ + --traffic-policy "policy-file-here.yml" + ``` + See [the guide on using Traffic Policy with Cloud Endpoints](/docs/traffic-policy/getting-started/cloud-endpoints/api/) for more information. + + + +## 3. Test the Traffic Policy + +To test the Traffic Policy defined in this guide, send a request to your endpoint like this: + +```shell +$ curl https://example.ngrok.app/api/example +``` + +The response should look like this: + +```http +HTTP/2 200 OK +content-type: application/json + +{ + "hello": "world" +} +``` diff --git a/docs/universal-gateway/overview.mdx b/docs/universal-gateway/overview.mdx index 200cd6a1dd..467eff58b9 100644 --- a/docs/universal-gateway/overview.mdx +++ b/docs/universal-gateway/overview.mdx @@ -1,10 +1,8 @@ --- -title: Overview -pagination_next: universal-gateway/domains +title: What is a Universal Gateway? +pagination_next: universal-gateway/domains/what-are-domains --- -# Universal Gateway - ngrok's Universal Gateway is a globally distributed API Gateway. It secures, accelerates and protects and accelerates your applications. We call it a Universal Gateway because it also supports @@ -18,10 +16,9 @@ Bindings, Pools and Domains to understand how they work. Learn more about Universal Gateway Concepts: -- [Domains →](/universal-gateway/domains/) +- [Domains →](/universal-gateway/domains/what-are-domains/) - [TCP Addresses →](/universal-gateway/tcp-addresses/) -- [TLS Certificates →](/universal-gateway/tls-certificates/) -- [Edges →](/universal-gateway/edges/) +- [TLS Certificates →](/universal-gateway/tls-certificates/how-does-ngrok-handle-tls/) ## Endpoints @@ -47,8 +44,8 @@ and traffic to their URL is balanced among them. ngrok automatically handles TLS (SSL) termination and certificate management for you. There is typically nothing to setup, configure or manage. -- [Learn more about TLS Certificates →](/universal-gateway/tls-certificates/) -- [Learn more about the TLS Termination →](/universal-gateway/tls-termination/) +- [Learn more about TLS Certificates →](/universal-gateway/tls-certificates/how-does-ngrok-handle-tls/) +- [Learn more about the TLS Termination →](/universal-gateway/tls/tls-termination/) ## Global Load Balancer diff --git a/docs/universal-gateway/points-of-presence.mdx b/docs/universal-gateway/points-of-presence.mdx index f7e54c4227..6480db5197 100644 --- a/docs/universal-gateway/points-of-presence.mdx +++ b/docs/universal-gateway/points-of-presence.mdx @@ -1,17 +1,17 @@ --- -title: Points of Presence +sidebar_label: Global Points of Presence +title: Where Are ngrok's Points of Presence? +description: Learn about ngrok's globally distributed points of presence. --- -# Points of Presence - ngrok's globally distributed cloud service runs on points of presence all -around the world to enable fast, low latency traffic to your applications. +around the world to enable low-latency traffic to your applications. We continuously expand our regional points of presence. As we add each new point of presence, your applications become faster for global customers without any changes. -## Reference +## Regions The current points of presence are: @@ -26,9 +26,9 @@ The current points of presence are: | us | United States (Ohio) | | us-cal-1 | United States (California) | -## Usage +### Usage -The table of region codes above are used throughout the product to communicate +The table of region codes on this page are used throughout the product to communicate which points of presence are being used by a particular feature and to allow you to configure pieces of the product to use specific points of presence. Region codes are used by the following features: @@ -36,7 +36,7 @@ Region codes are used by the following features: - [Global Load Balancer](/universal-gateway/global-load-balancer/) - [`conn.server_region` Traffic Policy variable](/traffic-policy/variables/connection/#connserver_region) - [`region` Agent Configuration property](/agent/config/v2/#region) -- [Domain Global Load Balancer configuration](/universal-gateway/domains#global-load-balancer) +- [Domain Global Load Balancer configuration](/universal-gateway/global-load-balancer) They are correspondingly used in the following APIs: diff --git a/docs/universal-gateway/pooling/index.mdx b/docs/universal-gateway/pooling/index.mdx new file mode 100644 index 0000000000..91d5b1237e --- /dev/null +++ b/docs/universal-gateway/pooling/index.mdx @@ -0,0 +1,49 @@ +--- +title: Endpoint Pooling +description: Learn how ngrok enables you to load balance traffic with endpoint pools. +--- + +When you create two endpoints with the same URL and binding, they automatically form a "pool" that load balances traffic between them. Load balancing helps you scale traffic across multiple replicas of your app to increase capacity, tolerate failures, and geo-distribute load. + +Endpoint pooling is vastly more flexible than comparable load balancing +systems: + +- Endpoints join and leave pools automatically as they are created and + destroyed, there is no need to register your upstreams ahead of time. +- You can define your own _dyanmic_ load balancing strategies. For example, you can define strategies that adjust traffic distribution based on the performance of upstream services or properties of the incoming requests. +- You can pool endpoints with different Traffic Policies. This means that not only can you blue-green and canary deploy your own apps, you can also do that with the Traffic Policies themselves. This helps you dramatically mitigate the risk of gateway changes that so often cause site-wide outages. + +## When to use Endpoint Pooling + +Endpoint pooling is a good choice when you want to: + +- Load balance among multiple replicas of the same application, even running in different cloud providers, on-prem, etc. +- Switch from agent endpoints to cloud endpoints with no downtime (or vice-versa) +- Implement [blue-green deployments](https://en.wikipedia.org/wiki/Blue%E2%80%93green_deployment) to reduce risk and rollback times +- A/B test different versions of your apps with blue-green deployments +- Deploy canary version of your application +- Gradually roll out changes to an endpoint's Traffic Policy + +## Enabling Pooling + +Endpoint pooling is disabled by default, and can be enabled on a per-endpoint basis. You must enable pooling on each endpoint you want to pool by setting `pooling_enabled` to `true`. + +## Getting started + +To try out endpoint pooling, see [the endpoint pooling quickstart guide](/universal-gateway/pooling/pooling-quickstart). + +## Using pooling with wildcard endpoints + +[Wildcard endpoints](/universal-gateway/wildcard-domains/wildcard-endpoints) do not pool with non-wildcard URLs. See [the docs on Wildcard Endpoints](/universal-gateway/wildcard-domains/wildcard-endpoints/#wildcard-endpoint-pooling) for more information. + +## API + +Because endpoint pools are created on-demand when two endpoints share the same URL and binding, there is no API resource for endpoint pools. Instead, each [Endpoint API Resource](/api/resources/endpoints/) has a read-only `pools` field which lists the other endpoints in the same pool as the requested endpoint. + +## Limits & pricing + +Endpoint pooling is available on the Pay-As-You-Go plan. Each endpoint in a pool is billed separately. + +See the [pooling limits documentation](/pricing-limits/pooling-limits/) for limits on pooling. + +See the [pricing](/pricing-limits/) documentation for general billing details. diff --git a/docs/universal-gateway/pooling/pool-load-balancing.mdx b/docs/universal-gateway/pooling/pool-load-balancing.mdx new file mode 100644 index 0000000000..399bcaf1d6 --- /dev/null +++ b/docs/universal-gateway/pooling/pool-load-balancing.mdx @@ -0,0 +1,90 @@ +--- +sidebar_label: How Load Balancing Works +title: How Does ngrok Load Balance My Endpoint Pools? +description: Learn about the different load balancing strategies available for endpoint pools with ngrok. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +[Endpoint pools](/universal-gateway/pooling) automatically load balance traffic between their endpoints. Load balancing is applied when: + +- Pooled **public and kubernetes** endpoints load balance traffic received from external clients. +- Pooled **internal** endpoints receive traffic that is forwarded to them via the `forward-internal` Traffic Policy action. + +:::tip Remember +Load balancing in endpoint pools balances traffic *between* endpoints. This is distinct from the [global load balancer](/universal-gateway/global-load-balancer/), which balances traffic *to* endpoints. +::: + +## Granularity + +ngrok intelligently chooses the load balancing layer automatically for you. + + + + +Traffic to TCP and TLS endpoints is balanced on a per-connection basis (layer 4). + + + + +Traffic to HTTP and HTTPS endpoints balanced on a per-request basis (layer 7). If multiple endpoints in a pool have different `on_tcp_connect` phases in their Traffic Policy, load balancing is instead done on a per-connection basis (layer 4). + + + + +## Default load balancing strategy + +ngrok's default balancing strategy attempts to strike a balance between +performance and faireness by prioritizing the following: + +1. Identify all endpoints in the pool which are in the [point of presence](/universal-gateway/points-of-presence/) closest to where a connection is received. +1. Balance the connections in a random distribution among those endpoints. + +For the purposes of the first step, [cloud endpoints](/universal-gateway/cloud-endpoints) are considered to be online in +all points of presence. + +### Example + +If an endpoint pool consist of the following endpoints: + +- **Endpoint A**: Agent Endpoint connected to `eu` +- **Endpoint B**: Agent Endpoint connected `eu` +- **Endpoint C**: Agent Endpoint connected `us` +- **Endpoint D**: Cloud Endpoint + +Then: + +- A connection received in `eu` will be balanced among endpoints A, B, D +- A connection received in `us` will be balanced among endpoints C, D +- A connection received in `jp` will be balanced among endpoints D + +### Connection retries with load balancing + +Currently, there's no support for [connection failover](https://en.wikipedia.org/wiki/Failover) with endpoint pools. Failed connections to an endpoint in a pool are neither retried not sent to other endpoints in the pool. + +## Custom Strategies + +:::info Coming Soon + +Custom load balancing strategies are not yet generally available. [Request access to the developer preview](mailto:support@ngrok.com). + +::: + +When balancing traffic to internal endpoints, you may define your own balancing strategy by setting the `endpoint_selectors` and `endpoint_weights` fields on the `forward-internal` Traffic Policy action configuration. + +## Using Traffic Policy with pools + +Endpoints in a pool may have different Traffic Policies. This lets you run old and new Traffic Policies side-by-side when transitioning endpoints into and out of a pool, so you can control and monitor traffic as you make changes. + +It also enables you to roll out new Traffic Policy changes without risking an all-or-nothing deployment, because you can apply changes to endpoints individually rather than being forced to apply them to all endpoints in a pool at once + +### Example scenario + +You might want to transition from using one data center to a different data center for request handling, and the new data center might require a different Traffic Policy configuration. Because traffic policy is applied on a per-endpoint basis in endpoint pools, you could add your new endpoints associated with your new data center to the pool of old endpoints on by one, while gradually removing the old endpoints. + +Such a transition would be easier to monitor and control than if you had to change the traffic policy for all endpoints in the pool at once. You could also use this strategy to roll out a new Traffic Policy to a subset of your endpoints, and then gradually roll it out to the rest of your endpoints. + +### How it works + +When traffic is balanced among endpoints with different Traffic Policies, ngrok first chooses an endpoint to balance to, then executes the Traffic Policy of the chosen endpoint. diff --git a/docs/universal-gateway/pooling/pooling-quickstart.mdx b/docs/universal-gateway/pooling/pooling-quickstart.mdx new file mode 100644 index 0000000000..f115d68e47 --- /dev/null +++ b/docs/universal-gateway/pooling/pooling-quickstart.mdx @@ -0,0 +1,89 @@ +--- +title: Endpoint Pooling Quickstart +sidebar_label: Quickstart +description: Get started using endpoint pooling to load balance traffic with ngrok. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +Endpoint pooling allows you to load balance traffic across multiple endpoints. See the [Endpoint Pooling documentation](/universal-gateway/pooling/) for more details. + +The following instructions will help you get started with endpoint pooling using both agent and cloud endpoints. + + + + +Create two endpoints with the same URL forwarding to two different ports. They will automatically be pooled together. + +``` +ngrok http 8080 --url https://your-domain.ngrok.app --pooling-enabled true +``` + +``` +ngrok http 9090 --url https://your-domain.ngrok.app --pooling-enabled true +``` + +When you make requests to the endpoints' URL, you will see responses balanced +among each endpoint in the pool. + +``` +curl https://your-domain.ngrok.app + + +curl https://your-domain.ngrok.app + +``` + + + + +Create two endpoints with the same URL and two different traffic policies. They will automatically be pooled together. + +First, create two traffic policy files, `policy-a.yml` and `policy-b.yml`. + +```yaml title="policy-a.yml" mode=traffic-policy +on_http_request: + - actions: + - type: custom-response + config: + status_code: 200 + content: Policy A +``` + +```yaml title="policy-b.yml" mode=traffic-policy +on_http_request: + - actions: + - type: custom-response + config: + status_code: 200 + content: Policy B +``` + +Then create two cloud endpoints, one with each policy: + +```sh title="Command line" +ngrok api endpoints create \ + --url https://your-domain.ngrok.app \ + --traffic-policy "$(cat policy-a.yml)" \ + --pooling-enabled=true + +ngrok api endpoints create \ + --url https://your-domain.ngrok.app \ + --traffic-policy "$(cat policy-b.yml)" \ + --pooling-enabled=true +``` + +When you make requests to the endpoints' URL, you will see responses balanced +among each endpoint in the pool. + +```sh title="Command line" +curl https://your-domain.ngrok.app + + +curl https://your-domain.ngrok.app + +``` + + + diff --git a/docs/universal-gateway/public-endpoints.mdx b/docs/universal-gateway/public-endpoints.mdx deleted file mode 100644 index 37fd6ed878..0000000000 --- a/docs/universal-gateway/public-endpoints.mdx +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: Public Endpoints -description: Learn about enabling internet traffic to your services with public endpoints. ---- - -Public endpoints enable your services to receive geo-balanced internet traffic using [ngrok's global points of presence](/docs/universal-gateway/edges/). - -Public endpoints enable you to receive traffic from the internet via ngrok’s [global points of presence](/docs/universal-gateway/edges/). This is the most common type of endpoint and the easiest way to start. - -Public endpoint URLs must: - -- Use either a [Domain](/universal-gateway/domains/) or [TCP Address](/universal-gateway/tcp-addresses/) -- Use the `public` [binding](/docs/universal-gateway/bindings/) - -## Get started - -You can create a public endpoint using: - -- [The dashboard](https://dashboard.ngrok.com/endpoints) -- [The API](/docs/api/resources/endpoints/#create-endpoint). - -Follow the [Getting Started](/docs/getting-started/) guide to set up an ngrok account and create your first public endpoint. - -## Authentication - -Public endpoints are useful out of the box for content you don’t want to restrict access to, such as blogs or marketing sites; but they can also be used for services that require strict access control such as dashboards or private APIs. - -To keep such services both public and secure, you can add a Traffic Policy to your endpoint for authentication and authorization. Traffic Policy actions enable you to do the following with your endpoints: - -- [JWT Validation](/docs/traffic-policy/actions/jwt-validation/) -- [OAuth](/docs/traffic-policy/actions/oauth/) -- [OIDC](/docs/traffic-policy/actions/oidc/) -- [IP restrictions](/docs/traffic-policy/actions/restrict-ips/) -- [Mutual TLS](/docs/traffic-policy/actions/terminate-tls/#example-traffic-policy-document) - -## URLs - -When you create a public endpoint, the URL you create it with is validated -differently based on the protocol of the URL. - -### `http` - -- The hostname must match a [Domain](/universal-gateway/domains/) in your account. -- The hostname must be a domain with a valid [public suffix](https://publicsuffix.org/). -- The port must be `80`. If you do not specify a port, the default `80` will be used for you. - -**Examples** - -- `http://example.ngrok.app` -- `http://example.ngrok.app:80` -- `http://example.party` -- `http://example.ngrok.app:81` - invalid port, must be `80`, not `81` -- `http://example.doesnotexist` - invalid hostname: `.doesnotexist` is not a public suffix domain -- `http://example.internal` - invalid hostname: `.internal` is not a public suffix domain - -### `https`, `tls` - -- The hostname must match a [Domain](/universal-gateway/domains/) in your account. -- The hostname must be a domain with a valid [public suffix](https://publicsuffix.org/). -- The port must be `443`. If you do not specify a port, the default `443` will be used for you. - -**Examples** - -- `https://example.ngrok.app` -- `https://example.ngrok.app:443` -- `https://example.party` -- `https://example.ngrok.app:8443` - invalid port, must be `443` -- `https://example.nosuchtld` - invalid hostname, `.nosuchtld` is not a public suffix domain -- `https://example.internal` - invalid hostname, public endpoints cannot use `.internal` - -### `tcp` - -- You must specify a port number in TCP URLs. -- The hostname and port must match the address of a [TCP - Address](/universal-gateway/tcp-addresses) in your account. - -**Examples** - -- `tcp://1.tcp.ngrok.io:12345` -- `tcp://1.tcp.eu.ngrok.io:12345` -- `tcp://1.tcp.ngrok.io` - invalid, does not specify a port number -- `tcp://example.ngrok.app:12345` - invalid, does not match a TCP Address -- `tcp://your-domain.com:12345` - invalid, does not match a TCP Address - -## API - -Public endpoints can be created programatically. Consult the documentation on -[Endpoint APIs](/api/resources/endpoints/). - -## Pricing - -Public endpoints are available on all plans. Consult the [Endpoints -Pricing](/universal-gateway/endpoints/#pricing) documentation for -billing details. diff --git a/docs/universal-gateway/public-endpoints/index.mdx b/docs/universal-gateway/public-endpoints/index.mdx new file mode 100644 index 0000000000..9f3bcb4755 --- /dev/null +++ b/docs/universal-gateway/public-endpoints/index.mdx @@ -0,0 +1,57 @@ +--- +sidebar_label: Public Binding +title: What are Public Endpoints? +description: Learn about enabling internet traffic to your services with public endpoints. +--- + +Public endpoints enable your services to receive geo-balanced internet traffic using [ngrok's global points of presence](/docs/universal-gateway/edges/). This is the most common type of endpoint and the easiest way to start. + +[Public endpoint URLs](/docs/universal-gateway/what-are-endpoint-urls/) must: + +- Use either a [Domain](/universal-gateway/domains/what-are-domains/) or [TCP Address](/universal-gateway/tcp-addresses/) +- Use the `public` [binding](/docs/universal-gateway/bindings/) + +## Get started + +You can create a public endpoint using: + +- [The dashboard](https://dashboard.ngrok.com/endpoints) +- [The API](/docs/api/resources/endpoints/#create-endpoint). + +Follow the [Getting Started](/docs/getting-started/) guide to set up an ngrok account and create your first public endpoint. + +## Authentication + +Public endpoints are useful out of the box for content you don't want to restrict access to, such as blogs or marketing sites; but they can also be used for services that require strict access control such as dashboards or private APIs. + +To keep such services both public and secure, you can add a Traffic Policy to your endpoint for authentication and authorization. Traffic Policy actions enable you to do the following with your endpoints: + +- [JWT Validation](/docs/traffic-policy/actions/jwt-validation/) +- [OAuth](/docs/traffic-policy/actions/oauth/) +- [OIDC](/docs/traffic-policy/actions/oidc/) +- [IP restrictions](/docs/traffic-policy/actions/restrict-ips/) +- [Mutual TLS](/docs/traffic-policy/actions/terminate-tls/#example-traffic-policy-document) + +## Matching endpoints + +A matching endpoint is a public endpoint with a [hostname](https://en.wikipedia.org/wiki/Hostname.) matching a [Domain](/universal-gateway/what-are-domains) or [TCP Address](/universal-gateway/) you've configured with ngrok. + +Matching endpoints are subject to the following restrictions: + +| Endpoint Protocol | Required Port | +| ----------------- | ------------- | +| `http` | `80` | +| `https` | `443` | +| `tls` | `443` | +| `tcp` | Any | + +## API + +Public endpoints can be created programatically. Consult the documentation on +[Endpoint APIs](/api/resources/endpoints/). + +## Pricing + +Public endpoints are available on all plans. Consult the [Endpoints +Pricing](/universal-gateway/endpoints/#pricing) documentation for +billing details. diff --git a/docs/universal-gateway/tcp-addresses.mdx b/docs/universal-gateway/tcp-addresses.mdx deleted file mode 100644 index 10ea6b6562..0000000000 --- a/docs/universal-gateway/tcp-addresses.mdx +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: Universal Gateway > TCP Addresses ---- - -# TCP Addresses - -## Overview - -TCP Addresses enable you to create public [TCP -Endpoints](/universal-gateway/tcp/) on a fixed address. TCP Addresses -are a host and port tuple, for example `1.tcp.eu.ngrok.io:12345`. - -You can manage TCP Addresses on your [ngrok -Dashboard](https://dashboard.ngrok.com/tcp-addresses) or via the [ngrok -API](#api). - -## Public endpoint creation - -A TCP Address's primary responsibility is to enable you to create public TCP -endpoints with a hostname and port matching the address. These are called -"matching endpoints". For example, after you create the TCP Address -`1.tcp.jp.ngrok.io:12345`, you can create the Endpoint -`tcp://1.tcp.jp.ngrok.io:12345`. - -Only TCP endpoints may be created on TCP Addresses. To create other endpoint -types, create a [Domain](/universal-gateway/domains/). - -## Address assignment - -The hostname and port of the TCP Address are randomly assigned when you create -it, after which it will not change. You may not choose the hostname or port. -If you delete a TCP Address, there is no way to provision the same one again. -TCP Addresses may be managed via the dashboard and via API. - -The port of your TCP Address is uniquely assigned to your account, but other -ports on that same hostname may be assigned to other accounts. While the -hostname and port of a TCP Address is fixed, they do not have static IPs. - -## Global Load Balancer - -TCP Addresses are not supported by the [global load -balancer](/universal-gateway/global-load-balancer). - -You must select a [Point of -Presence](/universal-gateway/points-of-presence) when you create a TCP -Address. Connections to matching TCP Endpoints on a TCP Address will always -route to the TCP Address's point of presence, no matter where those connections -originated in the world. - -You may create Agent Endpoints from an agent connected to a different point of -presence than the matching TCP Address. For example, the following will work -properly: - -```sh -ngrok tcp 3389 --region jp --url tcp://1.tcp.eu.ngrok.io:12345 -``` - -## API - -TCP Addresses are programatically managed via: - -- [`/reserved_addrs` API Resource](/api/resources/reserved-addrs/) - -## Pricing - -TCP Addresses are available on paid plans only, they are not available on the -free plan. diff --git a/docs/universal-gateway/tcp-addresses/how-are-tcp-addresses-assigned.mdx b/docs/universal-gateway/tcp-addresses/how-are-tcp-addresses-assigned.mdx new file mode 100644 index 0000000000..b9e56384e2 --- /dev/null +++ b/docs/universal-gateway/tcp-addresses/how-are-tcp-addresses-assigned.mdx @@ -0,0 +1,14 @@ +--- +sidebar_label: Creating TCP Addresses +title: How Are TCP Addresses Assigned? +description: Learn how ngrok assignes TCP Addresses. +--- + +You can create TCP Addresses in [the dashboard](https://dashboard.ngrok.com/tcp-addresses) or via [the API](/api/resources/reserved-addrs/). The following limitations apply: + +- When you create a TCP Address, the hostname and port are randomly assigned. Both are permanent. + - You may not choose the hostname or port. +- If you delete a TCP Address, there is no way to provision the same one again. +- TCP Addresses may be managed via the dashboard or API. +- The port of your TCP Address is uniquely assigned to your account, but other ports on that same hostname may be assigned to other accounts. +- While the hostname and port of a TCP Address is fixed, they do not have static IPs. diff --git a/docs/universal-gateway/tcp-addresses/index.mdx b/docs/universal-gateway/tcp-addresses/index.mdx new file mode 100644 index 0000000000..91625eeea1 --- /dev/null +++ b/docs/universal-gateway/tcp-addresses/index.mdx @@ -0,0 +1,27 @@ +--- +sidebar_label: Using TCP Addresses +title: What are TCP Addresses? +description: Learn how to use TCP Addresses with ngrok. +--- + +[TCP](https://en.wikipedia.org/wiki/Transmission_Control_Protocol) Addresses enable you to create public [TCP Endpoints](/universal-gateway/tcp/) on static addresses. All TCP Addresses contain both their hostname and port, such as `1.tcp.eu.ngrok.io:12345`. + +You can manage TCP Addresses with: + +- [The Dashboard](https://dashboard.ngrok.com/tcp-addresses) + - Learn [how TCP Addresses are assigned](/universal-gateway/tcp-addresses/how-are-tcp-addresses-assigned/). +- [The API](/api/resources/reserved-addrs/). + +:::note +Only TCP Endpoints may be created on TCP Addresses. For other endpoint +types, create a [Domain](/universal-gateway/domains/what-are-domains/). +::: + +## TCP address load balancing + +Global load balancing is not supported for TCP Addresses. See the [Load Balancing documentation](/universal-gateway/global-load-balancer/#gslb-for-tcp-endpoints) for more information. + +## Pricing + +TCP Addresses are available on paid plans only, they are not available on the +free plan. See [the pricing page](https://ngrok.com/pricing) for more information. diff --git a/docs/universal-gateway/tcp.mdx b/docs/universal-gateway/tcp.mdx deleted file mode 100644 index 27591fd0d7..0000000000 --- a/docs/universal-gateway/tcp.mdx +++ /dev/null @@ -1,321 +0,0 @@ ---- -title: TCP Endpoints ---- - -import TabItem from "@theme/TabItem"; -import Tabs from "@theme/Tabs"; - -import RandomAgentCliExample from "/examples/agent-cli/tcp-random.mdx"; -import RandomAgentConfigExample from "/examples/agent-config/tcp-random.mdx"; -import RandomGoSdkExample from "/examples/go-sdk/tcp-random.mdx"; -import RandomJavascriptSdkExample from "/examples/javascript-sdk/tcp-random.mdx"; -import RandomKubernetesExample from "/examples/k8s/tcp-random.mdx"; -import RandomPythonSdkExample from "/examples/python-sdk/tcp-random.mdx"; -import RandomRustSdkExample from "/examples/rust-sdk/tcp-random.mdx"; -import RandomSshExample from "/examples/ssh/tcp-random.mdx"; - -import FixedAgentCliExample from "/examples/agent-cli/tcp-fixed.mdx"; -import FixedAgentConfigExample from "/examples/agent-config/tcp-fixed.mdx"; -import FixedGoSdkExample from "/examples/go-sdk/tcp-fixed.mdx"; -import FixedJavascriptSdkExample from "/examples/javascript-sdk/tcp-fixed.mdx"; -import FixedKubernetesExample from "/examples/k8s/tcp-fixed.mdx"; -import FixedPythonSdkExample from "/examples/python-sdk/tcp-fixed.mdx"; -import FixedRustSdkExample from "/examples/rust-sdk/tcp-fixed.mdx"; -import FixedSshExample from "/examples/ssh/tcp-fixed.mdx"; - -import NonLocalAgentCliExample from "/examples/agent-cli/tcp-nonlocal.mdx"; -import NonLocalAgentConfigExample from "/examples/agent-config/tcp-nonlocal.mdx"; -import NonLocalGoSdkExample from "/examples/go-sdk/tcp-nonlocal.mdx"; -import NonLocalJavascriptSdkExample from "/examples/javascript-sdk/tcp-nonlocal.mdx"; -import NonLocalKubernetesExample from "/examples/k8s/tcp-nonlocal.mdx"; -import NonLocalPythonSdkExample from "/examples/python-sdk/tcp-nonlocal.mdx"; -import NonLocalRustSdkExample from "/examples/rust-sdk/tcp-nonlocal.mdx"; -import NonLocalSshExample from "/examples/ssh/tcp-nonlocal.mdx"; - -import ProxyProtoAgentCliExample from "/examples/agent-cli/tcp-proxyproto.mdx"; -import ProxyProtoAgentConfigExample from "/examples/agent-config/tcp-proxyproto.mdx"; -import ProxyProtoGoSdkExample from "/examples/go-sdk/tcp-proxyproto.mdx"; -import ProxyProtoJavascriptSdkExample from "/examples/javascript-sdk/tcp-proxyproto.mdx"; -import ProxyProtoKubernetesExample from "/examples/k8s/tcp-proxyproto.mdx"; -import ProxyProtoPythonSdkExample from "/examples/python-sdk/tcp-proxyproto.mdx"; -import ProxyProtoRustSdkExample from "/examples/rust-sdk/tcp-proxyproto.mdx"; -import ProxyProtoSshExample from "/examples/ssh/tcp-proxyproto.mdx"; - -# TCP Endpoints - -## Overview - -TCP endpoints enable you to deliver any network service with a TCP-based -protocol. They are commonly used to create connectivity for: - -- Remote access protocols like SSH, VNC and RDP -- Databases like MySQL, Postgres, MSSQL and SQLite -- IoT protocols like MQTT -- Gaming servers like Minecraft - -If you are accepting TLS traffic, you may prefer to create a [TLS Endpoint](/universal-gateway/tls/). - -::::info Free Plan Usage -TCP endpoints are only available on a free plan after [adding a valid payment method](https://dashboard.ngrok.com/settings#id-verification) to your account. -:::: - -## Quickstart - -Agent Endpoints are the easiest way to get started with ngrok. An [agent -endpoint](/universal-gateway/cloud-endpoints/) is started by a -[Secure Tunnels](/agent/) agent. The endpoint lives for the lifetime -of the process and forwards traffic to a port or URL of your choosing. - -This example creates a TCP endpoint on a randomly-assigned URL - e.g. -`tcp://1.tcp.ngrok.io:12345` and forwards its traffic to a local port. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## URLs - -URLs are validated differently depending on their -[binding](/universal-gateway/bindings). Consult the -following documentation for details on valid URLs for TCP endpoints: - -- [Public Endpoint URLs](/universal-gateway/public-endpoints/#tcp) -- [Internal Endpoint URLs](/universal-gateway/internal-endpoints/#urls) -- [Kubernetes Endpoint URLs](/universal-gateway/kubernetes-endpoints/#urls) - -There is no standard scheme for TCP URLs so ngrok renders them as `tcp://`. - -### Static URLs - -If you would like a public TCP endpoint to have a static URL, you must first -create a [TCP Address](/universal-gateway/tcp-addresses). When you create a TCP -address, a random hostname and port will be assigned to you, e.g. -`1.tcp.ngrok.io:12345`. - -A TCP address is only needed to make a public TCP endpoint have a static URL. -They are not needed for TCP endpoints on other bindings, like `internal` or -`kubernetes`. - -After you have created a TCP Address, specify the address (e.g. -`1.tcp.eu.ngrok.io:12345`) in the URL when you create the endpoint. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### Custom domains - -Public TCP endpoints are assigned randomly on an ngrok-controlled hostname with -a randomly-assigned port. You may not choose the hostname and you may not -select the port. - -You may, however, simulate a customized hostname by creating a CNAME record to -the hostname of your assigned TCP address. If you do so, be aware that all -ports on that hostname, even those provisioned to other accounts will then be -available on your domain. - -For example if your TCP address is `5.tcp.ngrok.io:12345`, you could create the -following CNAME record: - -``` -CNAME tcp.mydomain.com -> 5.tcp.ngrok.io -``` - -And then you can access that TCP endpoint with - -``` -telnet tcp.mydomain.com 12345 -``` - -## Traffic Policy - -Attach [Traffic Policy](/traffic-policy/) to endpoints to route, authenticate -and transform the traffic through the endpoint. - -### Authentication - -When you create public TCP endpoints, you often want to secure them with -authentication. You can secure your TCP endpoints with the following [Traffic -Policy](/traffic-policy/) actions. There is a limited set of actions available -to authenticate TCP traffic because the TCP protocol is low-level. - -- [IP Restriction](/traffic-policy/actions/restrict-ips/) -- [Mutual TLS](/traffic-policy/actions/terminate-tls/) - -## Agent Forwarding - -The [ngrok agent](/agent/) and [Agent -SDKs](/agent-sdks/) forward traffic that your endpoints receive -to upstream services. You specify a URL or port number to instruct the ngrok -agent where and how to forward traffic. - -### Forward to non-local service - -Agents don't just forward to ports on your localhost. You can forward traffic -to any address or URL reachable from the agent. For example, if you want to -forward traffic to a Postgres server running on your network at -`192.168.1.2:5432`: - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### PROXY Protocol - -When you forward traffic to an upstream TCP service, becuase traffic is coming -from the ngrok agent, it won't know the client's original IP address. You can -add the [PROXY -protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) header -on connections to your upstream service to send connection information like the -original client IP address to your upstream service. You will need to configure -your upstream service to handle the PROXY protocol header. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Observability - -### Traffic Inspector - -[Traffic Inspector](/obs/traffic-inspection) does not support TCP endpoints. - -### Log Export Events - -You can export logs of traffic to TCP endpoints with [ngrok's events -system](/obs/events/). The following events are published for log exporting: - -| Event | When | -| ------------------------------------------------------------------------ | ------------------------------------------------------------ | -| [tcp_connection_closed.v0](/obs/events/reference/#tcp-connection-closed) | Published when a TCP connection to a TCP endpoint completes. | - -## Limits & Timeouts - -[Contact us](mailto:support@ngrok.com) if you need to configure limits and timeouts on -connections to TCP endpoints. - -| Limit | Name | Notes | -| --------- | ------------------- | ------------------------------------------------------------ | -| 5 minutes | Client Idle Timeout | Time since data was last transmitted by the upstream service | -| 5 minutes | Server Idle Timeout | Time since data was last transmitted by the upstream service | -| No limit | Data transmitted | Data transmitted by the client or upstream service | - -## Errors - -If an error is encountered while handling connections to a TCP endpoint for any -reason (e.g. traffic policy action error, internal server error), the -connection will be closed. Because of the low-level nature of the TCP protocol, -there is no mechanism used to transmit information about what error code was -encountered. - -Use the [observability](#observability) features to understand connection -handling errors. - -## API - -TCP Endpoints can be created programatically. Consult the documentation on -[Endpoint APIs](/api/resources/endpoints/). - -## Pricing - -TCP endpoints are available on all plans. Consult the [Endpoints -Pricing](/universal-gateway/endpoints/#pricing) documentation for -billing details. - -TCP endpoints are only available on a free plan after [adding a valid payment -method](https://dashboard.ngrok.com/settings#id-verification) to your account. - -See [TCP Addresses pricing](/universal-gateway/tcp-addresses/#pricing) for -details on pricing for fixed TCP Addresses. diff --git a/docs/universal-gateway/tcp/index.mdx b/docs/universal-gateway/tcp/index.mdx new file mode 100644 index 0000000000..f16192c0de --- /dev/null +++ b/docs/universal-gateway/tcp/index.mdx @@ -0,0 +1,146 @@ +--- +title: How Do I Handle TCP Traffic? +description: Learn how to handle TCP traffic with ngrok. +--- + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +import RandomAgentConfigExample from "/examples/agent-config/tcp-random.mdx"; +import RandomKubernetesExample from "/examples/k8s/tcp-random.mdx"; + +TCP endpoints enable you to deliver any network service with a TCP-based +protocol. They are commonly used to create connectivity for: + +- Remote access protocols like SSH, VNC and RDP +- Databases like MySQL, Postgres, MSSQL and SQLite +- IoT protocols like MQTT +- Gaming servers like Minecraft + +If you are accepting TLS traffic, consider using a [TLS Endpoint](/universal-gateway/tls/). + +::::info Free Plan Usage +TCP endpoints are only available on a free plan after [adding a valid payment method](https://dashboard.ngrok.com/settings#id-verification) to your account. +:::: + +## Quickstart + +Agent Endpoints are the easiest way to get started with ngrok. An [agent +endpoint](/universal-gateway/cloud-endpoints/) is started by a +[Secure Tunnels](/agent/) agent. The endpoint lives for the lifetime +of the process and forwards traffic to a port or URL of your choosing. + +This example creates a TCP endpoint on a randomly-assigned URL - e.g. +`tcp://1.tcp.ngrok.io:12345` and forwards its traffic to a local port. + + + + +```bash +ngrok tcp 22 +``` + +```ssh tabName="SSH" +ssh -R 0:localhost:22 v2@connect.ngrok-agent.com tcp +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.TCPEndpoint(), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + proto: "tcp", + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + proto="tcp") + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; + +async fn listen_ngrok() -> anyhow::Result { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + + let tun = sess + .tcp_endpoint() + .listen() + .await?; + + println!("Listening on URL: {:?}", tun.url()); + + Ok(tun) +} +``` + + + + + + + + + + + + +## Learn more + +- **URL Validation** — URLs are validated differently depending on their [binding](/universal-gateway/bindings). To learn more about valid URLs for TCP endpoints, see [the Endpoint URLs documentation](/docs/universal-gateway/what-are-endpoint-urls/#tcp). +- **Static URLs** — To create a public TCP endpoint with a static URL, you must first create a [TCP Address](/universal-gateway/tcp-addresses/). See [the documentation on static TCP URLs](/universal-gateway/tcp/static-tcp-urls/) for more information. +- **Authentication** — You can secure your TCP endpoints with the [IP Restriction](/traffic-policy/actions/restrict-ips/) and [Mutual TLS](/docs/guides/other-guides/how-to-terminate-traffic-with-ngrok-configs/#mutual-tls-example) Traffic Policy actions. There is a limited set of actions available to authenticate TCP traffic because the protocol is low-level. +- **Bring your own domain** — To use your own domain with TCP endpoints, see [the guide on the subject](/universal-gateway/bring-your-own-domain/#using-custom-domains-with-tcp-endpoints). +- **Traffic Observability** — [Traffic Inspector](/obs/traffic-inspection/) gives you a real-time view in the ngrok dashboard of the traffic flowing through your TLS endpoints. You can even [export traffic logs with the Traffic Events system](/docs/obs/events/reference/). + +## Errors + +Learn how ngrok handles errors for TCP endpoints in the [Errors documentation](/errors/#tcp-errors). + +## API + +TCP Endpoints can be created programatically. Consult the documentation on +[Endpoint APIs](/api/resources/endpoints/). + +## Limits & pricing + +TCP endpoints are available on all plans. To access them on the free plan, [add a payment method to your ngrok account](https://dashboard.ngrok.com/settings#id-verification). Consult the [pricing](/pricing-limits/) documentation for general billing details. + +For TCP limits, see the [endpoint Limits documentation](/pricing-limits/endpoint-limits/#tcp-timeout-limits). + +:::tip +See [TCP Addresses pricing](/universal-gateway/tcp-addresses/#pricing) for +details on pricing for fixed TCP Addresses. +::: diff --git a/docs/universal-gateway/tcp/static-tcp-url.mdx b/docs/universal-gateway/tcp/static-tcp-url.mdx new file mode 100644 index 0000000000..ccd98831ad --- /dev/null +++ b/docs/universal-gateway/tcp/static-tcp-url.mdx @@ -0,0 +1,111 @@ +--- +title: Static URLs for TCP Endpoints +description: Learn how to create TCP endpoints with URLs. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; +import { LangSwitcher } from "@site/src/components/LangSwitcher"; +import { ContentSwitcher } from "@site/src/components/LangSwitcher/ContentSwitcher"; +import FixedAgentConfigExample from "/examples/agent-config/tcp-fixed.mdx"; +import FixedKubernetesExample from "/examples/k8s/tcp-fixed.mdx"; + +If you would like a public TCP endpoint to have a static URL, you must first +create a [TCP Address](/universal-gateway/tcp-addresses/). When you create a TCP +address, a random hostname and port will be assigned to you, e.g. +`1.tcp.ngrok.io:12345`. + +A TCP address is only needed to make a public TCP endpoint have a static URL. +They are not needed for TCP endpoints on other bindings, like `internal` or +`kubernetes`. + +After you have created a TCP Address, specify the address (e.g. +`1.tcp.eu.ngrok.io:12345`) in the URL when you create the endpoint. + + + + + +```bash +ngrok tcp 3389 --url tcp://1.tcp.eu.ngrok.io:12345 +``` + +```sh tabName="SSH" +ssh -R 1.tcp.eu.ngrok.io:12345:localhost:3389 connect.eu.ngrok-agent.com tcp +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.TCPEndpoint( + config.WithRemoteAddr("1.tcp.ngrok.io:12345"), + ), + ngrok.WithRegion("eu"), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + proto: "tcp", + remote_addr: "1.tcp.eu.ngrok.io:12345", + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + proto="tcp", + remote_addr="1.tcp.eu.ngrok.io:12345") + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; + +async fn listen_ngrok() -> anyhow::Result { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + + let tun = sess + .tcp_endpoint() + .remote_addr("1.tcp.eu.ngrok.io:12345") + .listen() + .await?; + + println!("Listening on URL: {:?}", tun.url()); + + Ok(tun) +} +``` + + + + + + + + + + diff --git a/docs/universal-gateway/tls-certificates.mdx b/docs/universal-gateway/tls-certificates.mdx deleted file mode 100644 index b6d8dafcec..0000000000 --- a/docs/universal-gateway/tls-certificates.mdx +++ /dev/null @@ -1,186 +0,0 @@ -# TLS Certificates - -ngrok automatically handles TLS (SSL) certificate management and termination -for you. There is typically nothing to setup, configure or manage. - -You can manage TLS certificates on your [ngrok -dashboard](https://dashboard.ngrok.com/tls-certs) or via the [ngrok API](#api). - -## Overview - -TLS certificates are a tuple of a private key and certificate that are -presented by the ngrok cloud service during a TLS handshakes to terminate TLS -connections to [HTTPS endpoints](/universal-gateway/http) and [TLS -endpoints](/universal-gateway/tls). TLS certificates are attached to -[domains](/universal-gateway/domains/) for termination of TLS connections to -endpoints whose URLs match that domain. ngrok can automatically provision -certificates for you or you can upload your own. - -See the [TLS Termination](/universal-gateway/tls-termination/) -documentation for details on how and when ngrok terminates TLS connections. - -## Certificate Selection - -When TLS connections to an endpoint are terminated, ngrok uses the TLS -Certificate attached to the [domain](/universal-gateway/domains) matching the -endpoint's URL for termination. - -Each [domain](/universal-gateway/domains/) has an attached TLS certificate that -is referenced by its [`certificate_id` field](/api/resources/reserved-domains). -If the domain object does reference any certificate, or if there is no matching -domain object for an endpoint's URL, ngrok selects its own TLS certificate for -termination. - -You may override the certificate used for TLS termination by explicitly -terminating TLS yourself with the [`terminate-tls` traffic policy -action](/traffic-policy/actions/terminate-tls/). - -## Certificate Provisioning - -Whenever you create a [domain](/universal-gateway/domains/) you choose how -a TLS certificate will be provisioned. Either: - -- [Automatic TLS certificates](#automated) (default) - ngrok automatically - provisions a TLS certificate from an ACME provider like Let's Encrypt. -- [Bring your own TLS certificates](#custom) - Upload your own TLS certificate - -It is recommended that you choose automatic TLS certificates unless you have -special requirements. - -## Automatic Provisioning {#automated} - -When you choose automatic TLS certificate management for a domain (this is the -default), ngrok automatically provisions **and renews** TLS certificates from -an ACME-compliant certificate authority like Let's Encrypt. - -ngrok uses an HTTP01 challenge for TLS certificate provisioning of most -domains. When you create a [wildcard domain](#wildcard-domains) ngrok uses a -DNS01 challenge instead. - -ngrok is a [Let's Encrypt sponsor](https://letsencrypt.org/sponsors/). - -### Status - -TLS certificates are provisioned asynchronously. Depending on the speed of the -ACME certificate authority, it can take anywhere between a few seconds to 10 -minutes for your certificate to be provisioned. The domain's -`certificate_management_status` field on the [TLS Certificate API -Resource](/api/resources/tls-certificates/) contains the status of the -provisioning job. - -### Bring your own domain - -When you [bring your own domain](/universal-gateway/domains/#branded-domains) -(e.g. `api.your-domain.com`) you must create a CNAME DNS record in your DNS -provider. Certificate provisioning will not begin until your create this CNAME -DNS record. - -### Wildcard Domains - -When you bring your own wildcard domain (e.g. `*.app.example.com`), ngrok uses -a DNS01 challenge for TLS certificate provisioning which means that you must -create two CNAME records when creating branded wildcard domains instead of just -one. - -For example, If your domain is `*.app.example.com` you will be required to create the -following two CNAME records: - -- `*.app.example.com` -- `_acme-challenge.app.example.com` - -Certificate provisioning will not begin until you have created both DNS -records. - -### Private Keys - -When using automatic TLS certificates, ngrok generates a private key for your -domain and encrypts it at rest with with [NaCL](https://nacl.cr.yp.to/). - -When you configure a domain to use automated certificates, you may electively -choose whether ngrok will create an ECDSA private key (the default) or RSA -private key. If you choose an RSA private key, it is created with a size of -4096 bits. - -## Bring your own certificates {#custom} - -You may upload your own TLS certificates if you don't want to use the TLS -certificates that ngrok automatically provisions for you. Uploading your own -certificates may be the right choice if you are issuing certificates from your -own certificate authority or if you are using an EV certificate. - -To bring your own TLS certificate, upload a [certificate -bundle](#certificate-bundles) and a [private key](#private-keys). Keep in mind -that after you create your TLS certificate, you must attach it to one or more -domains before it will be used for termination. When working with the API, this -is done by updating the `certificate_id` property of the [Domain API -Resource](/api/resources/reserved-domains). - -Unlike automatic TLS certificates, when you are using custom TLS certificates, -you are responsible for managing the renewal and rotation of new certificates. - -### Certificate Bundles {#certificate-bundles} - -When uploading your own TLS certificates to ngrok, you are expected to provide -a certificate bundle of all certificates necessary to establish a chain of -trust to a trusted root certificate authority. Many TLS certificate vendors -will provide you with a constructed certificate bundle, but some will return -the leaf certificate and the intermediate certificates separately and you must -concatenate them to construct the bundle yourself. This is the -`certificate_pem` field in the [TLS Certificate Create -API](/api/resources/tls-certificates/). - -Certificate bundles are a series of PEM-encoded X.509 certificates that have -been concatenated together. **The order of this bundle is significant.** - -The first certificate in the bundle must be the leaf certificate. The leaf -certificate is the one which is signed for your domain and [the private -key](#private-keys) you will upload. - -After the leaf certificate are the intermediates certificates, if any. Each -intermediate certificate signs the certificate preceding it in the bundle. As -an example, the first intermediate will sign the leaf, and that signature is -part of the leaf certificate itself. The final certificate will be signed by -the root certificate authority. You may also included the root certificate in -the bundle as well, but it is not necessary or common practice to do so. - -A certificate bundle will look like the following: - -```pem ------BEGIN CERTIFICATE----- -... ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -... ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -... ------END CERTIFICATE----- -``` - -### Private Keys {#private-keys} - -ngrok accepts the following formats for the private key of an uploaded TLS -certificate. This is the `private_key_pem` field in the [TLS Certificate Create -API](/api/resources/tls-certificates/). - -- RSA, in either PKCS#1 or PKCS#8 form. -- ECDSA, in either SEC 1 or PKCS#8 form. -- Ed25519, in PKCS#8 form. - -Regardless of the format you choose, the private key must be formatted as ASN.1 -DER, encoded as PEM. ngrok will not accept any private keys that are encrypted -(e.g. with DES). - -ngrok encrypts your uploaded private keys at rest with -[NaCL](https://nacl.cr.yp.to/). - -## API - -TLS certificates are managed programatically via: - -- [`/tls_certificates` API Resource](/api/resources/tls-certificates/) - -## Pricing - -TLS certificates are available on all plans. Bringing your own certificates is -available on the Enterprise plan. diff --git a/docs/universal-gateway/tls-certificates/automatic-certificate-management.mdx b/docs/universal-gateway/tls-certificates/automatic-certificate-management.mdx new file mode 100644 index 0000000000..5d99e14dfa --- /dev/null +++ b/docs/universal-gateway/tls-certificates/automatic-certificate-management.mdx @@ -0,0 +1,50 @@ +--- +sidebar_label: Automatic Certificate Management +title: What Is Automatic Certificate Management? +description: Learn how ngrok provisions TLS certificates. +--- + +Whenever you create a [domain](/universal-gateway/domains/what-are-domains/), ngrok automatically provisions and manages your TLS certificates by default. Your TLS certificates will be automatically provisioned **and renewed** with [Let's Encrypt](https://letsencrypt.org/about/), an ACME-compliant certificate authority. Others may be supported in the future. + +Alternatively, you can [bring your own TLS certificates](/universal-gateway/tls-certificates/custom-certificates) and [use your own certificate authority](/api/resources/certificate-authorities/). + +:::tip +It is recommended that you choose automatic TLS certificate management unless you have special requirements. +::: + +## Let's Encrypt provisioning + +ngrok is a [Let's Encrypt sponsor](https://letsencrypt.org/sponsors/). + +When provisioning TLS certificates with Let's Encrypt, ngrok uses a [HTTP01 challenge](https://letsencrypt.org/docs/challenge-types/#http-01-challenge) for most domains. When you create a [wildcard domain](#using-wildcard-domains), ngrok uses a [DNS01 challenge](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge) instead. + +### How long does provisioning take? + +TLS certificates are provisioned asynchronously. Depending on the speed of the ACME certificate authority, it can take anywhere between a few seconds to 10 minutes for your certificate to be provisioned. + +You can check the status of a certificate provisioning job by [requesting the domain with ngrok's API](/api/resources/reserved-domains/#get-reserved-domain). Each domain object contains a `certificate_management_status` property. + +## Configuring automatic management + +You can use the API to configure automatic TLS certificate management for a domain by sending a request with the `"certificate_management_policy"` property to [`/reserved_domains/{id}`](https://ngrok.com/docs/api/resources/reserved-domains/#update-reserved-domain). + +```bash +curl \ +-X PATCH \ +-H "Authorization: Bearer {API_KEY}" \ +-H "Content-Type: application/json" \ +-H "Ngrok-Version: 2" \ +-d '{"certificate_management_policy":{"authority":"letsencrypt"},"description":"point-of-sale new york #302","http_endpoint_configuration_id":"ec_2uBNwE5PEQsAgI7WQkwC8mL1a2x","https_endpoint_configuration_id":"ec_2uBNwBytfQIshIWu9bdcD0Buy78","metadata":"{env: \"staging\", \"connector_id\":\"64698fcc-5f5c-4b63-910e-8669d04bd943\"}"}' \ +https://api.ngrok.com/reserved_domains/rd_2uBNwCkQlImhoyji1BWWiMGAHwc +``` + +### Private Keys + +When using automatic TLS certificates, ngrok generates a private key for your +domain and encrypts it [at rest](https://en.wikipedia.org/wiki/Data_at_rest) with [NaCL](https://nacl.cr.yp.to/). + +When you configure a domain to use automated certificates, you can choose which type of private key will be generated for it. Options include: + +- [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm) (default) +- [RSA]() + - If you choose an RSA private key, it will be created with a size of `4096` bits. diff --git a/docs/universal-gateway/tls-certificates/custom-certificates.mdx b/docs/universal-gateway/tls-certificates/custom-certificates.mdx new file mode 100644 index 0000000000..86b5c241b4 --- /dev/null +++ b/docs/universal-gateway/tls-certificates/custom-certificates.mdx @@ -0,0 +1,46 @@ +--- +title: Using Your Own Certificates +description: Learn how to use your own TLS certificates rather than automatic certificate management. +--- + +ngrok [manages TLS certificates for your domains automatically](/universal-gateway/tls-certificatesautomatic-certificate-management) by default, and in general automatic management is recommended. However, you may also upload and manage the renewal and rotation of your TLS certificates yourself. + +:::warning +You cannot use your own certificates with [ngrok's managed domains](/universal-gateway/domains/what-are-managed-domains). +::: + +Uploading your own certificates may be the right choice if you are: + +- Issuing certificates from your own preferred certificate authority +- Using an [EV certificate](https://en.wikipedia.org/wiki/Extended_Validation_Certificate) + +## Using your own certificate + +To use your own TLS certificates with ngrok, you first need to upload the certificate, then attach it to a domain. To do so: + +1. Upload a [certificate bundle](/universal-gateway/tls-certificates/what-is-a-certificate-bundle/) and a [private key](/universal-gateway/tls-certificates/what-are-private-tls-keys). You can do this with one of the following: + - [The TLS section of the Dashboard](https://dashboard.ngrok.com/tls-certs) + - [The API](/api/resources/tls-certificates/#create-tls-certificate): + ```bash + curl \ + -X POST \ + -H "Authorization: Bearer {API_KEY}" \ + -H "Content-Type: application/json" \ + -H "Ngrok-Version: 2" \ + -d '{"certificate_pem":"-----BEGIN CERTIFICATE-----\ncertificate-here\n-----END CERTIFICATE-----","private_key_pem":"-----BEGIN PRIVATE KEY-----\nprivate-key-here\n-----END PRIVATE KEY-----"}' \ + https://api.ngrok.com/tls_certificates + ``` +1. After you create your TLS certificate, you must attach it to one or more domains on ngrok before it can be used for termination. You can do so with one of the following: + - [The Domains section of the dashboard](https://dashboard.ngrok.com/domains) + 1. Select your domain. + 1. Expand the dropdown that says "Automated TLS Certificates" to choose the "Use an uploaded certificate" option. + - [With the Domains API resource](/api/resources/reserved-domains/#update-reserved-domain), using the `certificate_id` property in the request body. You must have already uploaded your TLS certificate with the API or dashboard. + ```bash + curl \ + -X PATCH \ + -H "Authorization: Bearer {API_KEY}" \ + -H "Content-Type: application/json" \ + -H "Ngrok-Version: 2" \ + -d '{"certificate_id":"id-for-certificate-here' \ + https://api.ngrok.com/reserved_domains/rd_2uBNwCkQlImhoyji1BWWiMGAHwc + ``` diff --git a/docs/universal-gateway/tls-certificates/how-are-certificates-selected.mdx b/docs/universal-gateway/tls-certificates/how-are-certificates-selected.mdx new file mode 100644 index 0000000000..41de6d79bf --- /dev/null +++ b/docs/universal-gateway/tls-certificates/how-are-certificates-selected.mdx @@ -0,0 +1,17 @@ +--- +sidebar_label: How ngrok Selects TLS Certificates +title: How Are TLS Certificates Selected? +description: Learn how ngrok selects certificates for TLS termination. +--- + +When TLS connections to an endpoint are terminated, ngrok uses the TLS certificate attached to the [Domain](/universal-gateway/domains/what-are-domains) matching the endpoint's URL. + +Each [domain](/universal-gateway/domains/what-are-domains/) on ngrok has an attached TLS certificate, which you can find by: + +- [Fetching the domain object from the API](/api/resources/reserved-domains#request-2) + - Or [listing all TLS Certificates](/api/resources/tls-certificates/#list-tls-certificates) +- [Viewing your TLS Certificates in the dashboard](https://dashboard.ngrok.com/tls-certs) + +If the domain object doesn't reference any certificate, or if there is no matching domain object for an endpoint's URL, ngrok selects its own TLS certificate for termination. + +You may override the certificate used for TLS termination by explicitly terminating TLS yourself with the [`terminate-tls` traffic policy action](/traffic-policy/actions/terminate-tls/). diff --git a/docs/universal-gateway/tls-certificates/how-does-ngrok-handle-tls.mdx b/docs/universal-gateway/tls-certificates/how-does-ngrok-handle-tls.mdx new file mode 100644 index 0000000000..135253aee5 --- /dev/null +++ b/docs/universal-gateway/tls-certificates/how-does-ngrok-handle-tls.mdx @@ -0,0 +1,42 @@ +--- +title: How Does ngrok Handle TLS Certificates? +description: Learn how ngrok handles TLS certificates. +--- + +ngrok [automatically handles](/universal-gateway/tls-certificatesautomatic-certificate-management) TLS (SSL) certificate management and termination for you out of the box, but you can also [customize how termination works](/traffic-policy/actions/terminate-tls/) and [use your own certificates](/universal-gateway/tls-certificates/custom-certificates). + +You can manage TLS certificates with: + +- [The Dashboard](https://dashboard.ngrok.com/tls-certs) +- [The API](/api/resources/tls-certificates/). +- [The `terminate-tls` Traffic Policy action](/traffic-policy/actions/terminate-tls/) + +You can also [specify the local path to a certificate file](/agent/cli/#example-10) when starting a TLS endpoint with the Agent CLI. + +## How certificates work + +TLS certificates are composed of a private key and a certificate. These are presented by the ngrok cloud service during [TLS handshakes](https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_handshake) to terminate TLS connections to [HTTPS endpoints](/universal-gateway/http-s/) and [TLS endpoints](/universal-gateway/tls). + +## Certificates with domains + +TLS certificates are attached to [domains](/universal-gateway/domains/what-are-domains/) for [termination of TLS connections to endpoints](/universal-gateway/tls/tls-termination/) whose URLs match that domain. + +## Wildcard domains + +See the [wildcard domains](/universal-gateway/wildcard-domains/#tls-provisioning) docs for more information about how TLS certificates are managed for wildcard domains. + +## Mutual TLS + +Mutual TLS is supported when terminating TLS at ngrok's cloud service via the `mutual_tls_certificate_authorities` field of the [`terminate-tls`](/traffic-policy/actions/terminate-tls) traffic policy action. + +You can also enable mutual TLS when terminating TLS at the agent via the `mutual_tls_certificate_authorities` property of the [`agent_tls_termination`](/agent/config/v3/#endpoint-configuration-options) section of an endpoint configuration in the [agent configuration](/agent/config/v3/) file. + +## API + +TLS certificates are managed programatically via: + +- [`/tls_certificates` API Resource](/api/resources/tls-certificates/) + +## Pricing + +TLS certificates are available on all plans. Bringing your own certificates is available on the Enterprise plan. See the [pricing page](https://ngrok.com/pricing) for details. diff --git a/docs/universal-gateway/tls-certificates/what-are-private-tls-keys.mdx b/docs/universal-gateway/tls-certificates/what-are-private-tls-keys.mdx new file mode 100644 index 0000000000..c5fcc497ad --- /dev/null +++ b/docs/universal-gateway/tls-certificates/what-are-private-tls-keys.mdx @@ -0,0 +1,34 @@ +--- +title: Uploading Private TLS Keys +description: Learn what a TLS Certificate private key is and how to upload one to ngrok. +--- + +When [uploading your own TLS certificates to ngrok](/universal-gateway/tls-certificates/custom-certificates), you must also upload a private key. + +You can do so with the `private_key_pem` field when uploading a TLS certificate [with the API](/api/resources/tls-certificates/). + +```bash +curl \ +-X POST \ +-H "Authorization: Bearer {API_KEY}" \ +-H "Content-Type: application/json" \ +-H "Ngrok-Version: 2" \ +-d '{"certificate_pem":"-----BEGIN CERTIFICATE-----\nMIIDDTCCAfWgAwIBAgIUBUunDdA4gjgtEbZA8w9Ljhvl3bEwDQYJKoZIhvcNAQEL\nBQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMjAwMzI0MTgxODE5WhcNMjAw\nNDIzMTgxODE5WjAWMRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAPKVkkKYNl3d9cqrz4tIFlwsohED5W4y1dcBixy4\nGANFFnw43nc2wPyKwYXumJqJIFrcW/NkUZL07bd+dou6mT6Gh/zbaTW91IkREPXL\n7b3KfVu4XkFosVXpWs0U6o4GrZ81CLiKBWI+H03x/ij5OSiJ1l71pqLeTJLOydAR\nAl8kpp7axeHU4UbDrAZkW5SnuZTjIKwVg0UNsBg1yNfUOu1Uah3BYaqPgQitC0Yg\nLW+NUGu/T91bkD7tLsVInkQXeQGdXBAqOycfJ7wj8OlIpyuXjTnGFA0izVmbQw5f\nrQnZ0geGyhLamvz9Gcd7mIlD/+/AEN9Lht82tAOzKG98/O8CAwEAAaNTMFEwHQYD\nVR0OBBYEFKv6RsvEC6T+zCtJZwB0FCR1sEkhMB8GA1UdIwQYMBaAFKv6RsvEC6T+\nzCtJZwB0FCR1sEkhMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB\nAC5fBrouinespo5+9AipjhY/HOKTg+OCnppFnSnqeU1eXZZJ0oakdHTpTNxtbQP9\ntOJTA2f3KWvmpNDMohEQXZz8wHDkdbrIXJKVp6zs1pEp+0BIjA4y9mSywa5xuyk0\noGeChRgGqp2JujDyPCb7LEaKKQEEdMqy73QG+jEAh14+wKixlAf1nATBdeCUvssK\n2x1uZMyqjJFB5y/5EdnWQzD4WJkrsCkxsZHVMN1d+dqf2sf3dTRV8fzsFGOG17NS\n6u2n9iGcFdBA82XN8yeLIWhy1t3GWutG1sdxENbFRRXea+iUqzDsmRtkaBma2GLQ\nd6JTpFbsCtwDjP23UEi7SZo=\n-----END CERTIFICATE-----","private_key_pem":"-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDylZJCmDZd3fXK\nq8+LSBZcLKIRA+VuMtXXAYscuBgDRRZ8ON53NsD8isGF7piaiSBa3FvzZFGS9O23\nfnaLupk+hof822k1vdSJERD1y+29yn1buF5BaLFV6VrNFOqOBq2fNQi4igViPh9N\n8f4o+TkoidZe9aai3kySzsnQEQJfJKae2sXh1OFGw6wGZFuUp7mU4yCsFYNFDbAY\nNcjX1DrtVGodwWGqj4EIrQtGIC1vjVBrv0/dW5A+7S7FSJ5EF3kBnVwQKjsnHye8\nI/DpSKcrl405xhQNIs1Zm0MOX60J2dIHhsoS2pr8/RnHe5iJQ//vwBDfS4bfNrQD\nsyhvfPzvAgMBAAECggEBALLv7YE98exvi5zB+0fMFuJK8gkHDLequ93q/4hhqyTO\nU3WyJTdepiAi4fk/NEXZnIopPZJdj2aNUMQnfp43OE7MwYac+hBwRFQOyKnmkSmM\nMcf0SWKKLTUn+piIMzQsbOmhHxuwg6QiGslOFaJ3o9fpRL2rCg3dWDJ6Ypcd1NgE\nK0uy7gg+DwIpU6MeG6lA+HbxbGi+yd2x88Gjn9dGr7FZK34RUDooH60BCX9P8N9X\nT+n10MzzX7ZQOsLfe8FKc1/X8AybI5SYm1GMyfKD4QBt6JG4HKAjPHzBzcIpfN3d\n7BM11Imkrz7LcbUG+F23NVsi6n5IIGT1WqwCRIH2PpECgYEA/SJ5Ra4d0hUS5RYB\nzABquM3sp7JsKxCn7O5PqNLB4TgH9dXtWFhaFVB6juMGyHbvktVH0j4lps/Te0rk\nVU2zU1XxvCTFhtcCYUtNk0cRw6LH8feKiorXHdDRB33t0c47QSD/6AGOjBtxqD7B\n3ZxyR3P+7RdQopLLRFN+FHAnmzsCgYEA9VSGZDFSK+fbg4CgwkWdzuHrAXaUEv0U\novqqWd/yXB9wauEvRHnOrSgW6hFZQiatJOXx0KnalJQzohz/SLGO0MqGtwQbYWVT\nWiJgjUbNeiPEHBeUA6U55lVQr26kQSUWdXEtRbDz+hqV1K+6tTEMzaSPmJiHNgki\nlNMO2gqGQd0CgYBJ268qx5zn2UJEGWG41j5NYbg1TfgFsLxugzI2/heX0TNxZVP1\nPQI7ydmYq2ElSJ6qZxSnoX5255i7FqT8xskV/bOkw83mhAGrxb8Cw+/I90wDq8h+\nl/ggOPdkijfDybq8TBae6SVgd/l3r6f9M1KcypmNMApVBSPN8daNvBOyVQKBgQDo\nsj2utyFrx8Xsm4rf+kxOuPbBMooM4MQ8OmpuSP6G5sMofWLqHmcs0sO5TK9PEYRV\nZU3ST+ml2FSJRdvWRaRi4laZLWoTHZrL+aN/HVM0sMwIoUyhkIy0ruOTIuzlZZpB\n1xHL8qXX6nOHgw8jYdz1CUuyv6owVMXaR77kjer+eQKBgByYZlR/eNTzlot0SdFl\nIbgQ9bV7VLIo+vKzOXE3trfzRJMgUosLTp+5wdSVSW/VBdYZ7Ir3n0bbpY/dGinI\nVShxPbChhCZnhvG2lEEiekI44m5jHSA6hhtRdt/CrhL65Rw2SE5lMEe8htg1UGus\nwzLHWHBl72FjbjdhvEgrq60W\n-----END PRIVATE KEY-----"}' \ +https://api.ngrok.com/tls_certificates +``` + +## Accepted formats + +ngrok accepts the following private key formats: + +- [RSA](), in either `PKCS#1` or `PKCS#8` form. +- [ECDSA](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm), in either `SEC 1` or `PKCS#8` form. +- [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519), in PKCS#8 form. + +Regardless of the format you choose, the private key must be formatted as [`ASN.1 DER`](https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/), encoded as `PEM`. + +## Encryption + +ngrok will not accept any private keys that are encrypted (e.g. with `DES`). + +ngrok encrypts your uploaded private keys [at rest](https://en.wikipedia.org/wiki/Data_at_rest) with [NaCL](https://nacl.cr.yp.to/). diff --git a/docs/universal-gateway/tls-certificates/what-is-a-certificate-bundle.mdx b/docs/universal-gateway/tls-certificates/what-is-a-certificate-bundle.mdx new file mode 100644 index 0000000000..7e87b63462 --- /dev/null +++ b/docs/universal-gateway/tls-certificates/what-is-a-certificate-bundle.mdx @@ -0,0 +1,61 @@ +--- +sidebar_label: Certificate Bundles +title: How Do I Use a Certificate Bundle? +description: Learn what a certificate bundle is and how to upload one to ngrok. +--- + +When [uploading your own TLS certificates to ngrok](/universal-gateway/tls-certificates/custom-certificates), you must also upload a certificate bundle. + +Certificate bundles are a combination of all TLS certificates necessary to establish a [chain of trust](https://letsencrypt.org/certificates/) to a trusted root certificate authority. They consist of a series of [PEM-encoded X.509](https://en.wikipedia.org/wiki/X.509) certificates that have been concatenated together. **The certificates must be arranged in the proper order.** + +## Creating a certificate bundle + +You can construct a bundle by pasting each certificate in order into a single file. + +A certificate bundle will look like the following, with the leaf certificate first, followed by any intermediate certificates, and, optionally, the root certificate: + +```bash +-----BEGIN CERTIFICATE----- +... +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +... +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +... +-----END CERTIFICATE----- +``` + +### Using the API + +When uploading a certificate bundle [with the API](/api/resources/tls-certificates#create-tls-certificate), you can use the `certificate_pem` field to provide the certificate bundle. + +```bash +curl \ +-X POST \ +-H "Authorization: Bearer {API_KEY}" \ +-H "Content-Type: application/json" \ +-H "Ngrok-Version: 2" \ +-d '{"certificate_pem":"-----BEGIN CERTIFICATE-----\nMIIDDTCCAfWgAwIBAgIUBUunDdA4gjgtEbZA8w9Ljhvl3bEwDQYJKoZIhvcNAQEL\nBQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMjAwMzI0MTgxODE5WhcNMjAw\nNDIzMTgxODE5WjAWMRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcN\nAQEBBQADggEPADCCAQoCggEBAPKVkkKYNl3d9cqrz4tIFlwsohED5W4y1dcBixy4\nGANFFnw43nc2wPyKwYXumJqJIFrcW/NkUZL07bd+dou6mT6Gh/zbaTW91IkREPXL\n7b3KfVu4XkFosVXpWs0U6o4GrZ81CLiKBWI+H03x/ij5OSiJ1l71pqLeTJLOydAR\nAl8kpp7axeHU4UbDrAZkW5SnuZTjIKwVg0UNsBg1yNfUOu1Uah3BYaqPgQitC0Yg\nLW+NUGu/T91bkD7tLsVInkQXeQGdXBAqOycfJ7wj8OlIpyuXjTnGFA0izVmbQw5f\nrQnZ0geGyhLamvz9Gcd7mIlD/+/AEN9Lht82tAOzKG98/O8CAwEAAaNTMFEwHQYD\nVR0OBBYEFKv6RsvEC6T+zCtJZwB0FCR1sEkhMB8GA1UdIwQYMBaAFKv6RsvEC6T+\nzCtJZwB0FCR1sEkhMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB\nAC5fBrouinespo5+9AipjhY/HOKTg+OCnppFnSnqeU1eXZZJ0oakdHTpTNxtbQP9\ntOJTA2f3KWvmpNDMohEQXZz8wHDkdbrIXJKVp6zs1pEp+0BIjA4y9mSywa5xuyk0\noGeChRgGqp2JujDyPCb7LEaKKQEEdMqy73QG+jEAh14+wKixlAf1nATBdeCUvssK\n2x1uZMyqjJFB5y/5EdnWQzD4WJkrsCkxsZHVMN1d+dqf2sf3dTRV8fzsFGOG17NS\n6u2n9iGcFdBA82XN8yeLIWhy1t3GWutG1sdxENbFRRXea+iUqzDsmRtkaBma2GLQ\nd6JTpFbsCtwDjP23UEi7SZo=\n-----END CERTIFICATE-----","private_key_pem":"-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDylZJCmDZd3fXK\nq8+LSBZcLKIRA+VuMtXXAYscuBgDRRZ8ON53NsD8isGF7piaiSBa3FvzZFGS9O23\nfnaLupk+hof822k1vdSJERD1y+29yn1buF5BaLFV6VrNFOqOBq2fNQi4igViPh9N\n8f4o+TkoidZe9aai3kySzsnQEQJfJKae2sXh1OFGw6wGZFuUp7mU4yCsFYNFDbAY\nNcjX1DrtVGodwWGqj4EIrQtGIC1vjVBrv0/dW5A+7S7FSJ5EF3kBnVwQKjsnHye8\nI/DpSKcrl405xhQNIs1Zm0MOX60J2dIHhsoS2pr8/RnHe5iJQ//vwBDfS4bfNrQD\nsyhvfPzvAgMBAAECggEBALLv7YE98exvi5zB+0fMFuJK8gkHDLequ93q/4hhqyTO\nU3WyJTdepiAi4fk/NEXZnIopPZJdj2aNUMQnfp43OE7MwYac+hBwRFQOyKnmkSmM\nMcf0SWKKLTUn+piIMzQsbOmhHxuwg6QiGslOFaJ3o9fpRL2rCg3dWDJ6Ypcd1NgE\nK0uy7gg+DwIpU6MeG6lA+HbxbGi+yd2x88Gjn9dGr7FZK34RUDooH60BCX9P8N9X\nT+n10MzzX7ZQOsLfe8FKc1/X8AybI5SYm1GMyfKD4QBt6JG4HKAjPHzBzcIpfN3d\n7BM11Imkrz7LcbUG+F23NVsi6n5IIGT1WqwCRIH2PpECgYEA/SJ5Ra4d0hUS5RYB\nzABquM3sp7JsKxCn7O5PqNLB4TgH9dXtWFhaFVB6juMGyHbvktVH0j4lps/Te0rk\nVU2zU1XxvCTFhtcCYUtNk0cRw6LH8feKiorXHdDRB33t0c47QSD/6AGOjBtxqD7B\n3ZxyR3P+7RdQopLLRFN+FHAnmzsCgYEA9VSGZDFSK+fbg4CgwkWdzuHrAXaUEv0U\novqqWd/yXB9wauEvRHnOrSgW6hFZQiatJOXx0KnalJQzohz/SLGO0MqGtwQbYWVT\nWiJgjUbNeiPEHBeUA6U55lVQr26kQSUWdXEtRbDz+hqV1K+6tTEMzaSPmJiHNgki\nlNMO2gqGQd0CgYBJ268qx5zn2UJEGWG41j5NYbg1TfgFsLxugzI2/heX0TNxZVP1\nPQI7ydmYq2ElSJ6qZxSnoX5255i7FqT8xskV/bOkw83mhAGrxb8Cw+/I90wDq8h+\nl/ggOPdkijfDybq8TBae6SVgd/l3r6f9M1KcypmNMApVBSPN8daNvBOyVQKBgQDo\nsj2utyFrx8Xsm4rf+kxOuPbBMooM4MQ8OmpuSP6G5sMofWLqHmcs0sO5TK9PEYRV\nZU3ST+ml2FSJRdvWRaRi4laZLWoTHZrL+aN/HVM0sMwIoUyhkIy0ruOTIuzlZZpB\n1xHL8qXX6nOHgw8jYdz1CUuyv6owVMXaR77kjer+eQKBgByYZlR/eNTzlot0SdFl\nIbgQ9bV7VLIo+vKzOXE3trfzRJMgUosLTp+5wdSVSW/VBdYZ7Ir3n0bbpY/dGinI\nVShxPbChhCZnhvG2lEEiekI44m5jHSA6hhtRdt/CrhL65Rw2SE5lMEe8htg1UGus\nwzLHWHBl72FjbjdhvEgrq60W\n-----END PRIVATE KEY-----"}' \ +https://api.ngrok.com/tls_certificates +``` + +## Structure + +Many TLS certificate vendors will provide you with a constructed certificate bundle, but some provide the [leaf certificate](https://letsencrypt.org/docs/glossary/#def-certificate) and the [intermediate certificates](https://letsencrypt.org/docs/glossary/#def-intermediate) separately. + +### Leaf certificates + +The first certificate in the bundle must be the leaf certificate. The leaf certificate is the one which is signed for your domain and [the private key](#private-keys) you will upload. + +### Intermediate certificates + +After the leaf certificate are the intermediate certificates, if any. Each intermediate certificate signs the certificate preceding it in the bundle. As an example, the first intermediate will sign the leaf, and that signature is part of the leaf certificate itself. + +### Root certificates + +The final certificate will be signed by the root certificate authority. You may include the root certificate in the bundle as well, but it is not necessary or common practice to do so. + +``` + +``` diff --git a/docs/universal-gateway/tls-termination.mdx b/docs/universal-gateway/tls-termination.mdx deleted file mode 100644 index 655016577d..0000000000 --- a/docs/universal-gateway/tls-termination.mdx +++ /dev/null @@ -1,307 +0,0 @@ ---- -title: TLS Termination ---- - -import TabItem from "@theme/TabItem"; -import Tabs from "@theme/Tabs"; - -import TlsLimits from "./_tls_limits.mdx"; - -import AtAgentAgentCliExample from "/examples/agent-cli/tls-terminate-at-agent.mdx"; -import AtAgentAgentConfigExample from "/examples/agent-config/tls-terminate-at-agent.mdx"; -import AtAgentGoSdkExample from "/examples/go-sdk/tls-terminate-at-agent.mdx"; -import AtAgentJavascriptSdkExample from "/examples/javascript-sdk/tls-terminate-at-agent.mdx"; -import AtAgentKubernetesExample from "/examples/k8s/tls-terminate-at-agent.mdx"; -import AtAgentPythonSdkExample from "/examples/python-sdk/tls-terminate-at-agent.mdx"; -import AtAgentRustSdkExample from "/examples/rust-sdk/tls-terminate-at-agent.mdx"; -import AtAgentSshExample from "/examples/ssh/tls-terminate-at-agent.mdx"; - -import AtUpstreamAgentCliExample from "/examples/agent-cli/tls-terminate-at-upstream.mdx"; -import AtUpstreamAgentConfigExample from "/examples/agent-config/tls-terminate-at-upstream.mdx"; -import AtUpstreamGoSdkExample from "/examples/go-sdk/tls-terminate-at-upstream.mdx"; -import AtUpstreamJavascriptSdkExample from "/examples/javascript-sdk/tls-terminate-at-upstream.mdx"; -import AtUpstreamKubernetesExample from "/examples/k8s/tls-terminate-at-upstream.mdx"; -import AtUpstreamPythonSdkExample from "/examples/python-sdk/tls-terminate-at-upstream.mdx"; -import AtUpstreamRustSdkExample from "/examples/rust-sdk/tls-terminate-at-upstream.mdx"; -import AtUpstreamSshExample from "/examples/ssh/tls-terminate-at-upstream.mdx"; - -import CustomDomainAgentCliExample from "/examples/agent-cli/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainAgentConfigExample from "/examples/agent-config/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainGoSdkExample from "/examples/go-sdk/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainJavascriptSdkExample from "/examples/javascript-sdk/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainKubernetesExample from "/examples/k8s/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainPythonSdkExample from "/examples/python-sdk/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainRustSdkExample from "/examples/rust-sdk/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainSshExample from "/examples/ssh/tls-terminate-at-edge-custom-domain.mdx"; - -# TLS Termination - -ngrok automatically handles TLS (SSL) termination and certificate management -for you. There is typically nothing to setup, configure or manage. - -## Overview - -ngrok's TLS termination behavior is determined by an endpoint's protocol and -traffic policy. You may customize each endpoint to choose where TLS is -terminated, how it is terminated and even whether it is terminated at all. When -ngrok's cloud service terminates TLS, it: - -- Uses latest and most secure version of TLS -- Uses the [TLS - Certificate](/universal-gateway/tls-certificates/) attached to the - [Domain](/universal-gateway/domains/) which matches the Endpoint URL's - hostname -- Accelerates your traffic by using the global load balancer to terminate at its - closest point of presence - -ngrok supports [end-to-end encryption](#end-to-end-encryption) where the ngrok -cloud service does not terminate TLS connections and only sees enciphered -traffic. When configured this way, you are responsible for configuring TLS -termination in your upstream service or at the ngrok agent. - -## Termination Location - -TLS connections to your ngrok endpoints are terminated at one of three -locations. - -- **ngrok's cloud service**: This is the easiest and most common. All HTTPS - endpoints terminate TLS at ngrok's cloud service. When connections are - terminated by ngrok's cloud service, they are re-encrypted before they are - transmitted over a Secure Tunnel to an agent. -- **ngrok agent**: This is a form of [end-to-end - encryption](#end-to-end-encryption) where the ngrok cloud service does not - terminate TLS and you instead configure the ngrok agent to terminate TLS - connections for you. -- **your upstream service**: This is another form of [end-to-end - encryption](#end-to-end-encryption) where neither the cloud service nor an - agent terminates TLS connections. Instead, your upstream application service is - responsible for TLS termination. - -An endpoint's protocol determines the ngrok cloud service's default TLS -termination behavior. - -| Endpoint Protocol | TLS Termination | -| --------------------------------- | --------------------------------------------------------- | -| [HTTP](/universal-gateway/http/) | None | -| [HTTPS](/universal-gateway/http/) | Always at ngrok's cloud service. | -| [TLS](/universal-gateway/tls/) | Default no termination, configurable with `terminate-tls` | -| [TCP](/universal-gateway/tcp/) | Default no termination, configurable with `terminate-tls` | - -### Examples - -#### Cloud Service - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -#### Terminate at Agent - -See [Zero-Knowledge TLS at the Agent](/agent/agent-tls-termination/) for additional details. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -#### Terminate at Upstream - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## `terminate-tls` - -The [`terminate-tls` Traffic Policy -Action](/traffic-policy/actions/terminate-tls) enables you to terminate TLS -connections at ngrok's cloud service for TCP and TLS endpoints. - -You may also use this action on HTTPS endpoints to customize how TLS is -terminated. When you use the `terminate-tls` action on an HTTPS endpoint, ngrok -will skip the default TLS termination step that it runs for all HTTPS endpoints -so as not to terminate TLS twice. - -## Acceleration - -The ngrok cloud service improves the performance of your endpoints by -accelerating TLS termination using ngrok's [global points -of presence](/universal-gateway/points-of-presence). - -TLS connection set up requires multiple network round-trips. When round-trip -times (RTTs) are long, TLS connection establishment slows down. ngrok reduces -the latency of these round-trip times between the client and your endpoint by -terminating connections at the closest [point of -presence](/universal-gateway/points-of-presence/) via its [global load -balancer](/universal-gateway/global-load-balancer). - -## Certificates - -When the ngrok cloud service terminates TLS connections, it does so with the -[TLS Certificate](/universal-gateway/tls-certificates/) attached to the -[Domain](/universal-gateway/domains/) which matches the Endpoint URL's -hostname. See the documentation on [TLS -Certificates](/universal-gateway/tls-certificates/) for more details on -how they are -[selected](/universal-gateway/tls-certificates/#certificate-selection), -managed, provisioned and renewed. - -You may customize which TLS certificate is chosen for termination with the -[`terminate-tls`](/traffic-policy/actions/terminate-tls) traffic policy action. - -## Mutual TLS - -Mutual TLS is supported when terminating TLS at ngrok's cloud service via the -`mutual_tls_certificate_authorities` field of the -[`terminate-tls`](/traffic-policy/actions/terminate-tls) traffic policy action. - -Mutual TLS is supported when terminating TLS at the agent via the -`mutual_tls_certificate_authorities` property of the [`agent_tls_termination` -section of an endpoint -configuration](/agent/config/v3/#endpoint-configuration-options) in the agent -configuration file. - -## Handshake - -### TLS Version - -ngrok uses TLS 1.3 (the latest version) by default. If a client does not -support TLS 1.3, ngrok will use the highest possible version that the client -supports, down to TLS 1.1. - -You may customize the minimum and maximum supported versions of TLS with the -[`terminate-tls`](/traffic-policy/actions/terminate-tls) traffic policy action. - -### ALPN - -`https` endpoints negotiate the next protocol via ALPN with the following -default list in order of preference: - -``` -['h2', 'http/1.1'] -``` - -### SNI - -ngrok endpoints do not support legacy clients which do not set the SNI -extension. For example, the following clients (and others) will fail to work -with ngrok endpoints: - -- Microsoft Internet Explorer 6.0 -- Microsoft Internet Explorer 7 & 8 on Windows XP or earlier -- Native browser on Android 2.X -- Java <=1.6 -- [Python 2.X, 3.0, 3.1 if required modules are not installed](https://stackoverflow.com/questions/18578439/using-requests-with-tls-doesnt-give-sni-support/18579484#18579484) - -### Encrypted Client Hello - -ngrok endpoints do not yet support the draft implementation of [Encrypted -Client Hello](https://datatracker.ietf.org/doc/draft-ietf-tls-esni/). - -## FIPS Compliance - -ngrok does not use a FIPS-compliant TLS implementation by default, but one can -be enabled for your endpoints. - -[Contact us](mailto:support@ngrok.com) if you require a FIPS-compliant TLS -implementation. - -## End-to-end encryption - -You may choose to terminate TLS at your upstream service or at the ngrok agent -to achieve end-to-end encryption (E2EE), often referred to as Zero-knowledge TLS. When your endpoints operate in this -mode, the ngrok cloud service can not see the payloads that transfer through -your endpoints. - -Creating an endpoint with end-to-end encryption is simple: - -- Create a TLS or TCP endpoint -- **Do not** add a `terminate-tls` action to its traffic policy. - -That's it! Read the [Agent TLS Termination -Guide](/agent/agent-tls-termination/) for a step by step approach to set it up. - -To set up the agent to terminate TLS for you, consult the following table -because the configuration depends on which kind of agent you are using. - -| Agent | Documentation | -| ------------------- | ------------------------------------------------------------------------------------------------------- | -| Agent Config File | [`agent_tls_termination`](/agent/config/v3/#endpoint-configuration-options) | -| Go SDK | [WithTLSTerminationKeyPair](https://pkg.go.dev/golang.ngrok.com/ngrok/config#WithTLSTerminationKeyPair) | -| Other SDKs | not supported | -| Kubernetes Operator | not supported | - -## Limits and Timeouts - - diff --git a/docs/universal-gateway/tls.mdx b/docs/universal-gateway/tls.mdx deleted file mode 100644 index 6443f9ff5c..0000000000 --- a/docs/universal-gateway/tls.mdx +++ /dev/null @@ -1,408 +0,0 @@ ---- -title: TLS Endpoints ---- - -import TabItem from "@theme/TabItem"; -import Tabs from "@theme/Tabs"; - -import TlsLimits from "./_tls_limits.mdx"; - -import AtAgentAgentCliExample from "/examples/agent-cli/tls-terminate-at-agent.mdx"; -import AtAgentAgentConfigExample from "/examples/agent-config/tls-terminate-at-agent.mdx"; -import AtAgentGoSdkExample from "/examples/go-sdk/tls-terminate-at-agent.mdx"; -import AtAgentJavascriptSdkExample from "/examples/javascript-sdk/tls-terminate-at-agent.mdx"; -import AtAgentKubernetesExample from "/examples/k8s/tls-terminate-at-agent.mdx"; -import AtAgentPythonSdkExample from "/examples/python-sdk/tls-terminate-at-agent.mdx"; -import AtAgentRustSdkExample from "/examples/rust-sdk/tls-terminate-at-agent.mdx"; -import AtAgentSshExample from "/examples/ssh/tls-terminate-at-agent.mdx"; - -import AtUpstreamAgentCliExample from "/examples/agent-cli/tls-terminate-at-upstream.mdx"; -import AtUpstreamAgentConfigExample from "/examples/agent-config/tls-terminate-at-upstream.mdx"; -import AtUpstreamGoSdkExample from "/examples/go-sdk/tls-terminate-at-upstream.mdx"; -import AtUpstreamJavascriptSdkExample from "/examples/javascript-sdk/tls-terminate-at-upstream.mdx"; -import AtUpstreamKubernetesExample from "/examples/k8s/tls-terminate-at-upstream.mdx"; -import AtUpstreamPythonSdkExample from "/examples/python-sdk/tls-terminate-at-upstream.mdx"; -import AtUpstreamRustSdkExample from "/examples/rust-sdk/tls-terminate-at-upstream.mdx"; -import AtUpstreamSshExample from "/examples/ssh/tls-terminate-at-upstream.mdx"; - -import CustomDomainAgentCliExample from "/examples/agent-cli/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainAgentConfigExample from "/examples/agent-config/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainGoSdkExample from "/examples/go-sdk/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainJavascriptSdkExample from "/examples/javascript-sdk/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainKubernetesExample from "/examples/k8s/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainPythonSdkExample from "/examples/python-sdk/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainRustSdkExample from "/examples/rust-sdk/tls-terminate-at-edge-custom-domain.mdx"; -import CustomDomainSshExample from "/examples/ssh/tls-terminate-at-edge-custom-domain.mdx"; - -import ReencryptUpstreamAgentCliExample from "/examples/agent-cli/tls-reencrypt-upstream.mdx"; -import ReencryptUpstreamAgentConfigExample from "/examples/agent-config/tls-reencrypt-upstream.mdx"; -import ReencryptUpstreamGoSdkExample from "/examples/go-sdk/tls-reencrypt-upstream.mdx"; -import ReencryptUpstreamJavascriptSdkExample from "/examples/javascript-sdk/tls-reencrypt-upstream.mdx"; -import ReencryptUpstreamKubernetesExample from "/examples/k8s/tls-reencrypt-upstream.mdx"; -import ReencryptUpstreamPythonSdkExample from "/examples/python-sdk/tls-reencrypt-upstream.mdx"; -import ReencryptUpstreamRustSdkExample from "/examples/rust-sdk/tls-reencrypt-upstream.mdx"; -import ReencryptUpstreamSshExample from "/examples/ssh/tls-reencrypt-upstream.mdx"; - -import ProxyProtoAgentCliExample from "/examples/agent-cli/tls-proxyproto.mdx"; -import ProxyProtoAgentConfigExample from "/examples/agent-config/tls-proxyproto.mdx"; -import ProxyProtoGoSdkExample from "/examples/go-sdk/tls-proxyproto.mdx"; -import ProxyProtoJavascriptSdkExample from "/examples/javascript-sdk/tls-proxyproto.mdx"; -import ProxyProtoKubernetesExample from "/examples/k8s/tls-proxyproto.mdx"; -import ProxyProtoPythonSdkExample from "/examples/python-sdk/tls-proxyproto.mdx"; -import ProxyProtoRustSdkExample from "/examples/rust-sdk/tls-proxyproto.mdx"; -import ProxyProtoSshExample from "/examples/ssh/tls-proxyproto.mdx"; - -# TLS Endpoints - -## Overview - -TLS endpoints enable you to deliver any network service that runs over a -TLS-based protocol. TLS endpoints make no assumptions about the wrapped -protocol being transported. - -TLS endpoints inspect the [Server Name Indication (SNI)](#sni) -data on incoming TLS connections to route connections to the appropriate -endpoint. - -Because the TLS protocol describes no application-level semantics, ngrok can -only offer a [limited set of traffic policy actions](/traffic-policy/actions/) -to handle TLS traffic. - -If you are delivering an HTTPS application, prefer to create an [HTTP -Endpoint](/universal-gateway/http/). - -## Quickstart - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## URLs - -URLs are validated differently depending on their -[binding](/universal-gateway/bindings). Consult the -following documentation for details on valid URLs for TLS endpoints: - -- [Public Endpoint URLs](/universal-gateway/public-endpoints/#https-tls) -- [Internal Endpoint URLs](/universal-gateway/internal-endpoints/#urls) -- [Kubernetes Endpoint URLs](/universal-gateway/kubernetes-endpoints/#urls) - -There is no standard scheme for TLS URLs so ngrok renders them as `tls://`. - -## Bindings - -TLS endpoints support `public` and `internal` bindings. `kubernetes` binding is -not supported. - -## Traffic Policy - -Attach [Traffic Policy](/traffic-policy/) to endpoints to route, authenticate -and transform the traffic through your TLS endpoints. - -### Authentication - -When you create public TLS endpoints, you often want to secure them with -authentication. You can secure your TLS endpoints with the following [Traffic -Policy](/traffic-policy/) actions. There is a limited set of actions available -to authenticate TLS traffic because the TLS protocol is low-level. - -- [IP Restriction](/traffic-policy/actions/restrict-ips/) -- [Mutual TLS](/traffic-policy/actions/terminate-tls/) - -## TLS - -### Termination - -TLS Endpoints provide you with the flexibility to define where TLS termination -occurs. You may configure your endpoint to terminate TLS at the ngrok cloud -service or you can achieve [end-to-end -encryption](/universal-gateway/tls-termination/#end-to-end-encryption) -by terminating at the agent or your upstream service. When you use end-to-end -encryption, the ngrok cloud service can not see payload that transit through -your endpoints. - -Consult the documentation on [TLS Termination -Locations](/universal-gateway/tls-termination/#termination-location) for -additional details. - -#### Cloud Service - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -#### Terminate at Agent - -See [TLS Termination at the Agent for End-to-End Encryption](/universal-gateway/tls-termination#end-to-end-encryption) for additional details. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -#### Terminate at Upstream - - - - - - - - - - - - - - - - - - - - - - - - - - - - -### Certificates - -It is very common to encounter certificate errors when working with TLS -endpoints. When terminating TLS at ngrok's cloud service, ngrok will -automatically select, provision and manage certs for you. When performing -[end-to-end -encryption](/universal-gateway/tls-termination/#end-to-end-encryption) -by terminating at the agent or upstream service, you become responsible for -provisioning, managing and distributing certificates. - -Consult the documentation on [TLS -Certificates](/universal-gateway/tls-certificates/) for details about -certificate selection, provisioning and management. - -## Agent Forwarding - -### Re-encrypt to Upstream - -If you terminate TLS at the ngrok cloud service or ngrok agent, you may want to -re-encrypt the connection from the agent to your upstream service. The ngrok -agent supports this behavior by using the non-standard `tls://` scheme syntax. - - - - -```bash -ngrok tls tls://localhost:443 --terminate-at=edge -``` - - - - - - - - - - - - - - - - - - - - - - - - - -### PROXY Protocol - -Add a [PROXY -protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) header -on connection to your upstream service. This sends connection information like -the original client IP address to your upstream service. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Compatible Clients - -### SNI - -TLS endpoints only work with modern TLS clients that populate the SNI -extension. See the documentation on [TLS -Termination](/universal-gateway/tls-termination/#sni) for additional -details on compatible clients. - -### STARTTLS - -Protocols that begin in plain text and upgrade to TLS via a mechanism like -STARTTLS in SMTP, IMAP, etc are not supported. If you need to support -connections which upgrade to TLS, use a [TCP -Endpoint](/universal-gateway/tcp/). - -## Observability - -### Traffic Inspector - -[Traffic Inspector](/obs/traffic-inspection) does not support TLS endpoints. - -### Log Export Events - -You can export logs of traffic to TLS endpoints with [ngrok's events -system](/obs/). The following events are published for log exporting: - -| Event | When | -| ------------------------------------------------------------------------ | ------------------------------------------------------------ | -| [tcp_connection_closed.v0](/obs/events/reference/#tcp-connection-closed) | Published when a TCP connection to a TCP endpoint completes. | - -## Limits & Timeouts - -[Contact us](mailto:support@ngrok.com) if you need to configure limits and -timeouts on connections to TLS endpoints. - -#### Connections - -| Limit | Name | Notes | -| --------- | ------------------- | -------------------------------------------------------------- | -| 3 seconds | ClientHello Timeout | Time between connection establishment and ClientHello received | -| 5 minutes | Client Idle Timeout | Time since data was last transmitted by the upstream service | -| 5 minutes | Server Idle Timeout | Time since data was last transmitted by the upstream service | -| No limit | Data transmitted | Data transmitted by the client or upstream service | - -#### TLS - - - -## Errors - -If a TLS handshake fails, an appropriate TLS abort code will be sent to the -client. - -In all other cases, if an error is encountered while handling TLS connections -to your endpoints (e.g. no available backends or internal server error), the -connection will be closed. The TLS protocol and its implementations are not -sufficiently flexible enough to deliver additional rich error information when -failures are encountered. - -Use the [observability](#observability) features to understand connection -handling errors. - -## API - -TLS Endpoints can be created programatically. Consult the documentation on -[Endpoint APIs](/api/resources/endpoints/). - -## Pricing - -TLS endpoints are available on Pay-as-you-go, Pro, and Enterprise plans. Consult the [Endpoints -Pricing](/universal-gateway/endpoints/#pricing) documentation for -billing details. - -See [Domains pricing](/universal-gateway/domains/#pricing) for details on -pricing for custom domains, wildcard domains and more. - -Zero-knowledge TLS is available on the Enterprise plan. diff --git a/docs/universal-gateway/tls/handshake.mdx b/docs/universal-gateway/tls/handshake.mdx new file mode 100644 index 0000000000..962ce5a718 --- /dev/null +++ b/docs/universal-gateway/tls/handshake.mdx @@ -0,0 +1,37 @@ +--- +title: How ngrok's TLS Handshake Works +description: Learn how the TLS handshake works with ngrok. +--- + +ngrok uses TLS `1.3` (the latest version) by default. If a client does not +support TLS `1.3`, ngrok will use the highest possible version that the client +supports, down to TLS `1.1`. + +You may customize the minimum and maximum supported versions of TLS with the +[`terminate-tls`](/traffic-policy/actions/terminate-tls) traffic policy action. + +### ALPN + +`https` endpoints negotiate the next protocol via ALPN with the following +default list in order of preference: + +``` +['h2', 'http/1.1'] +``` + +### SNI + +ngrok endpoints do not support legacy clients which do not set the SNI +extension. For example, the following clients (and others) will fail to work +with ngrok endpoints: + +- Microsoft Internet Explorer 6.0 +- Microsoft Internet Explorer 7 & 8 on Windows XP or earlier +- Native browser on Android 2.X +- Java <=1.6 +- [Python 2.X, 3.0, 3.1 if required modules are not installed](https://stackoverflow.com/questions/18578439/using-requests-with-tls-doesnt-give-sni-support/18579484#18579484) + +### Encrypted Client Hello + +ngrok endpoints do not yet support the draft implementation of [Encrypted +Client Hello](https://datatracker.ietf.org/doc/draft-ietf-tls-esni/). diff --git a/docs/universal-gateway/tls/index.mdx b/docs/universal-gateway/tls/index.mdx new file mode 100644 index 0000000000..26f6f3af86 --- /dev/null +++ b/docs/universal-gateway/tls/index.mdx @@ -0,0 +1,202 @@ +--- +title: How Do I Handle TLS Traffic? +--- + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; +import { ContentSwitcher } from "@site/src/components/LangSwitcher/ContentSwitcher"; +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; +import TlsLimits from "../_tls_limits.mdx"; + +## Overview + +TLS endpoints enable you to deliver any network service that runs over a +TLS-based protocol. TLS endpoints make no assumptions about the wrapped +protocol being transported. + +TLS endpoints inspect the [Server Name Indication (SNI)](#sni) +data on incoming TLS connections to route connections to the appropriate +endpoint. + +Because the TLS protocol describes no application-level semantics, ngrok can +only offer a [limited set of traffic policy actions](/traffic-policy/actions/) +to handle TLS traffic. + +If you are delivering an HTTPS application, prefer to create an [HTTP +Endpoint](/universal-gateway/http/). + +## Quickstart + + + + + +```bash +ngrok tls 80 \ + --url tls://your-name.ngrok.app \ + --traffic-policy-file traffic-policy.yml +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.TLSEndpoint( + config.WithDomain("your-name.ngrok.app"), + config.WithTLSTermination( + config.WithTLSTerminationAt(config.TLSAtEdge), + ), + ), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); +const fs = require("fs"); + +(async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + proto: "tls", + domain: "app.example.com", + crt: fs.readFileSync("/path/to/app-example-com-crt.pem", "utf8"), + key: fs.readFileSync("/path/to/app-example-com-key.pem", "utf8"), + mutual_tls_cas: [fs.readFileSync("/path/to/cas.pem", "utf8")], + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +def load_file(name): + with open(name, "r") as crt: + return bytearray(crt.read().encode()) + +listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + proto="tls", + domain="app.example.com", + crt=load_file("/path/to/app-example-com-crt.pem"), + key=load_file("/path/to/app-example-com-key.pem"), + mutual_tls_cas=load_file("/path/to/cas.pem")) + +print(f"Ingress established at: {listener.url()}"); +``` + + + + + +For the above example, you can use the following Traffic Policy file: + +```yaml title="traffic-policy.yml" +on_tcp_connect: + - actions: + - type: terminate-tls +``` + + + + + +```yaml +version: 3 +endpoints: + - name: example + url: tls://your-name.ngrok.app + upstream: + url: 80 + traffic_policy: + on_tcp_connect: + - actions: + - type: terminate-tls +``` + + + + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: example-route + namespace: ngrok-gateway +spec: + rules: + - backendRefs: + - name: game-2048 + port: 80 + kind: Service + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + remove: ["x-request-id"] + add: + - name: my-request-header-name + value: my-header-value + set: + - name: my-request-header-to-set + value: set-header-value +``` + + + + + +:::info + +TLS termination at the edge is not supported for: + +- SSH +- Rust + +::: + +## Learn more + +- **URL Validation** — URLs are validated differently depending on their [binding](/universal-gateway/bindings). To learn more about valid URLs for TLS endpoints, see [the Endpoint URLs documentation](/docs/universal-gateway/what-are-endpoint-urls/#https-tls). +- **Domains** — Public TLS endpoints must match a domain on your account. See [the domains documentation](/universal-gateway/domains/what-are-domains/) for more information. +- **Authentication** — You can secure your TLS endpoints with the [IP Restriction](/traffic-policy/actions/restrict-ips/) and [Mutual TLS](/docs/guides/other-guides/how-to-terminate-traffic-with-ngrok-configs/#mutual-tls-example) Traffic Policy actions. There is a limited set of actions available to authenticate TLS traffic because the protocol is low-level. +- **Bring your own domain** — To use your own domain with TLS endpoints, see [the guide on the subject](/universal-gateway/bring-your-own-domain). +- **Wildcard Endpoints** — You can create TLS endpoints that receive traffic from all of the subdomains matching a given wildcard domain. See [the wildcard domain docs](/universal-gateway/wildcard-domains/) for more information. +- **Traffic Policy** — Attach [Traffic Policy](/traffic-policy/) to endpoints to route, authenticate and transform the traffic through the endpoint. +- **Agent Forwarding** — The [ngrok agent](/agent/) and [Agent SDKs](/agent-sdks/) forward traffic that your endpoints receive to upstream services. See [the agent forwarding documentation](/universal-gateway/agent-forwarding/) for more information. +- **Traffic Observability** — [Traffic Inspector](/obs/traffic-inspection/) gives you a real-time view in the ngrok dashboard of the traffic flowing through your TLS endpoints. You can even [export traffic logs with the Traffic Events system](/docs/obs/events/reference/). +- **TLS Certificates** — Learn how [ngrok automatically handles TLS](/universal-gateway/tls-certificates/how-does-ngrok-handle-tls/) and [TLS termination](/universal-gateway/tls/tls-termination/) for TLS endpoints for you. + +## TLS termination + +TLS Endpoints enable you to to define where [TLS termination](/universal-gateway/tls/tls-termination/) occurs. You can configure your endpoint to terminate TLS at the ngrok cloud service. You can also achieve [end-to-end encryption](/universal-gateway/tls/tls-termination/#end-to-end-encryption) by terminating at the agent or your upstream service. + +:::tip +When you use end-to-end encryption, the ngrok cloud service can not see payloads that transit through your endpoints. +::: + +See [the TLS Termination documentation](/universal-gateway/tls/tls-termination/#termination-location) for more information. + +## Errors + +Learn how ngrok handles errors for TLS endpoints in the [Errors documentation](/errors/#tls-errors). + +## API + +TLS Endpoints can be created programatically. Consult the documentation on +[Endpoint APIs](/api/resources/endpoints/). + +## Limits & pricing + +TLS endpoints are available on Pay-as-you-go, Pro, and Enterprise plans. Consult the [pricing](/pricing-limits/) documentation for general billing details. + +For TLS limits, see the [endpoint Limits documentation](/pricing-limits/endpoint-limits/). diff --git a/docs/universal-gateway/tls/tls-clients.mdx b/docs/universal-gateway/tls/tls-clients.mdx new file mode 100644 index 0000000000..1a01ddd519 --- /dev/null +++ b/docs/universal-gateway/tls/tls-clients.mdx @@ -0,0 +1,20 @@ +--- +title: Supported TLS Clients +description: Learn about the different TLS clients available for ngrok and how to use them. +--- + +ngrok's TLS endpoints are designed to work with TLS clients that fit the criteria described on this page. + +## SNI + +TLS endpoints only work with modern TLS clients that populate the SNI +extension. See the documentation on [TLS +Termination](/universal-gateway/tls/tls-termination/#sni) for additional +details on compatible clients. + +## STARTTLS + +Protocols that begin in plain text and upgrade to TLS via a mechanism like +STARTTLS in SMTP, IMAP, etc are not supported. If you need to support +connections which upgrade to TLS, use a [TCP +Endpoint](/universal-gateway/tcp/). diff --git a/docs/universal-gateway/tls/tls-termination/index.mdx b/docs/universal-gateway/tls/tls-termination/index.mdx new file mode 100644 index 0000000000..4c41de6869 --- /dev/null +++ b/docs/universal-gateway/tls/tls-termination/index.mdx @@ -0,0 +1,39 @@ +--- +title: Terminating TLS +description: Learn how to terminate TLS with ngrok. +--- + +You can configure TLS termination for HTTPS, TCP, and TLS endpoints with ngrok. By default, ngrok automatically terminates TLS for HTTPS endpoints, but you can still customize how that termination is done using the [`terminate-tls`](/traffic-policy/actions/terminate-tls/) Traffic Policy action. + +TLS (SSL) certificate management is [automatically handled for you](/universal-gateway/automatic-certificate-management) by default for all endpoints, though you can also [bring your own TLS certificates](/universal-gateway/tls-certificates/bring-your-own-certs/). + +## How is TLS terminated by default? + +An endpoint's protocol determines the ngrok cloud service's default TLS +termination behavior. + +| Endpoint Protocol | TLS Termination | +| --------------------------------- | --------------------------------------------------------- | +| [HTTP](/universal-gateway/http/) | None | +| [HTTPS](/universal-gateway/http/) | Always at ngrok's cloud service. | +| [TLS](/universal-gateway/tls/) | Default no termination, configurable with `terminate-tls` | +| [TCP](/universal-gateway/tcp/) | Default no termination, configurable with `terminate-tls` | + +## Using `terminate-tls` + +Visit the Traffic Policy docs to [see examples using the `terminate-tls` action](/traffic-policy/actions/terminate-tls/). + +## Learn more + +- **Using Traffic Policy** — The [`terminate-tls` Traffic Policy + Action](/traffic-policy/actions/terminate-tls) enables you to terminate TLS + connections at ngrok's cloud service for TCP and TLS endpoints. +- **Behavior** — Learn about [how ngrok's TLS termination works](/universal-gateway/tls-termination/termination-mechanics/), and how its built-in optimizatiions can improve the performance of your TLS endpoints. +- **Certificates** — ngrok makes managing TLS certificates simple. See [the TLS Certificates documentation](/universal-gateway/tls-certificates/how-does-ngrok-handle-tls/) for more details on how they are [selected](/universal-gateway/tls-certificates/how-are-certificates-selected), managed, provisioned and renewed. +- **End-to-end encryption** — Enabling end-to-end encryption for TLS endpoints is straightforward. See the docs on [how TLS termination works](/universal-gateway/tls-termination/termination-mechanics/#end-to-end-encryption) to learn more. + +## Limits & pricing + +TLS endpoints are available on Pay-as-you-go, Pro, and Enterprise plans. Consult the [pricing](/pricing-limits/) documentation for general billing details. + +For TLS limits, see the [endpoint Limits documentation](/pricing-limits/endpoint-limits/). diff --git a/docs/universal-gateway/tls/tls-termination/termination-location.mdx b/docs/universal-gateway/tls/tls-termination/termination-location.mdx new file mode 100644 index 0000000000..2426183922 --- /dev/null +++ b/docs/universal-gateway/tls/tls-termination/termination-location.mdx @@ -0,0 +1,254 @@ +--- +title: Where Is TLS Terminated? +description: Learn about the different locations where TLS termination can occur in ngrok. +--- + +import CustomDomainAgentConfigExample from "/examples/agent-config/tls-terminate-at-edge-custom-domain.mdx"; +import AtAgentAgentConfigExample from "/examples/agent-config/tls-terminate-at-agent.mdx"; +import AtUpstreamAgentConfigExample from "/examples/agent-config/tls-terminate-at-upstream.mdx"; + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; + +import { LangSwitcher } from "@site/src/components/LangSwitcher"; +import { ContentSwitcher } from "@site/src/components/LangSwitcher/ContentSwitcher"; + +[TLS connections](/universal-gateway/tls/) to your ngrok endpoints can be terminated at ngrok's cloud service, at your ngrok agent, or at your upstream service. + +:::info +TLS endpoints are not supported by the ngrok Kubernetes Operator +::: + +## At ngrok's cloud service + +You can terminate TLS at the edge with ngrok's cloud service. + +This is the easiest and most common. All HTTPS endpoints terminate TLS at ngrok's cloud service. When connections are terminated by ngrok's cloud service, they are re-encrypted before they are transmitted over a Secure Tunnel to an agent. + +You can get started with the following example. + + + + + +Use a Traffic Policy file configured like the following: + +```yaml mode=traffic-policy +on_tcp_connect: + - actions: + - type: terminate-tls +``` + +Then use the following command to start your ngrok agent: + + + + +```bash +ngrok tls 80 \ + --url tls://your-name.ngrok.app \ + --traffic-policy-file traffic-policy.yml +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.TLSEndpoint( + config.WithDomain("your-name.ngrok.app"), + config.WithTLSTermination( + config.WithTLSTerminationAt(config.TLSAtEdge), + ), + ), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); +const fs = require("fs"); + +(async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + proto: "tls", + domain: "app.example.com", + crt: fs.readFileSync("/path/to/app-example-com-crt.pem", "utf8"), + key: fs.readFileSync("/path/to/app-example-com-key.pem", "utf8"), + mutual_tls_cas: [fs.readFileSync("/path/to/cas.pem", "utf8")], + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +def load_file(name): + with open(name, "r") as crt: + return bytearray(crt.read().encode()) + +listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + proto="tls", + domain="app.example.com", + crt=load_file("/path/to/app-example-com-crt.pem"), + key=load_file("/path/to/app-example-com-key.pem")) + +print(f"Ingress established at: {listener.url()}"); +``` + + + + + + + + + +:::info +TLS Termination at the edge is not supported for: + +- SSH +- Rust +- Kubernetes + ::: + +
+ +## At your ngrok agent + +You can terminate TLS at your ngrok agent. Doing so prevents TLS from being terminated at ngrok's cloud service, ensuring [end-to-end encryption](/universal-gateway/tls/tls-termination/termination-mechanics/#end-to-end-encryption) between visitors and your upstream service. + +You can get started with the following example. + + + +```bash +ngrok tls 80 \ + --terminate-at agent \ + --url tls://app.example.com \ + --crt /path/to/app-example-com-crt.pem \ + --key /path/to/app-example-com-key.pem +``` + + + + + + + + +:::info +Termination at the agent is not supported for: + +- SSH +- Rust +- Go +- Javascript +- Python +- Kubernetes + ::: + +
+ +## At your upstream service + +You can handle TLS termination at your upstream services. This is a form of [end-to-end encryption](/universal-gateway/tls/tls-termination/termination-mechanics/#end-to-end-encryption) where neither the cloud service nor an agent terminates TLS connections. Instead, your upstream application service is responsible for TLS termination. + +You can get started with the following example. + + + + +```bash +ngrok tls 443 \ + --terminate-at upstream \ + --url tls://app.example.com +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.TLSEndpoint( + config.WithDomain("app.example.com"), + ), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```ssh tabName="SSH" +ssh -R app.example.com:443:localhost:443 v2@connect.ngrok-agent.com tls +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + proto: "tls", + domain: "app.example.com", + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + proto="tls", + domain="app.example.com") + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; + +async fn listen_ngrok() -> anyhow::Result { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + + let tun = sess + .tls_endpoint() + .domain("app.example.com") + .listen() + .await?; + + println!("Listening on URL: {:?}", tun.url()); + + Ok(tun) +} +``` + + + + + + + + diff --git a/docs/universal-gateway/tls/tls-termination/termination-mechanics.mdx b/docs/universal-gateway/tls/tls-termination/termination-mechanics.mdx new file mode 100644 index 0000000000..bba959cfa2 --- /dev/null +++ b/docs/universal-gateway/tls/tls-termination/termination-mechanics.mdx @@ -0,0 +1,64 @@ +--- +title: TLS Termination Behavior +description: Learn how ngrok's TLS termination works. +--- + +ngrok's TLS termination behavior is determined by an endpoint's protocol and traffic policy. You may customize each endpoint to choose where TLS is terminated, how it is terminated and even whether it is terminated at all. When ngrok's cloud service terminates TLS, it: + +- Uses the latest and most secure version of TLS +- Uses the [TLS + Certificate](/universal-gateway/tls-certificates/how-does-ngrok-handle-tls/) attached to the + [Domain](/universal-gateway/domains/what-are-domains/) which matches the Endpoint URL's + hostname +- Accelerates your traffic by using the global load balancer to terminate at its + closest point of presence + +:::info +ngrok supports end-to-end encryption, which enables you to encrypt traffic between visitors and your upstream services so the ngrok cloud service can't access it. See the docs on [how TLS termination works](#end-to-end-encryption) to learn more. +::: + +## Acceleration + +The ngrok cloud service improves the performance of your endpoints by +accelerating TLS termination using ngrok's [global points +of presence](/universal-gateway/points-of-presence). + +TLS connection set-up requires multiple network round-trips. When round-trip +times (RTTs) are long, TLS connection establishment slows down. ngrok reduces +the latency of these round-trip times between the client and your endpoint by +terminating connections at the closest [point of +presence](/universal-gateway/points-of-presence/) via its [global load +balancer](/universal-gateway/global-load-balancer). + +## FIPS Compliance + +ngrok does not use a [FIPS-compliant](https://en.wikipedia.org/wiki/FIPS_140-2) TLS implementation by default, but one can +be enabled for your endpoints. + +[Contact us](mailto:support@ngrok.com) if you require a FIPS-compliant TLS +implementation. + +## End-to-end encryption + +You may choose to terminate TLS at your upstream service or at the ngrok agent +to achieve end-to-end encryption (E2EE), often referred to as Zero-knowledge TLS. When your endpoints operate in this +mode, the ngrok cloud service can not see the payloads that transfer through +your endpoints. + +Creating an endpoint with end-to-end encryption is simple: + +- Create a TLS or TCP endpoint +- **Do not** add a `terminate-tls` action to its traffic policy. + +That's it! Read the [Agent TLS Termination +Guide](/agent/agent-tls-termination/) for a step by step approach to set it up. + +To set up the agent to terminate TLS for you, consult the following table +because the configuration depends on which kind of agent you are using. + +| Agent | Documentation | +| ------------------- | ------------------------------------------------------------------------------------------------------- | +| Agent Config File | [`agent_tls_termination`](/agent/config/v3/#endpoint-configuration-options) | +| Go SDK | [WithTLSTerminationKeyPair](https://pkg.go.dev/golang.ngrok.com/ngrok/config#WithTLSTerminationKeyPair) | +| Other SDKs | not supported | +| Kubernetes Operator | not supported | diff --git a/docs/universal-gateway/types.mdx b/docs/universal-gateway/types.mdx deleted file mode 100644 index e1f1cc16bc..0000000000 --- a/docs/universal-gateway/types.mdx +++ /dev/null @@ -1,45 +0,0 @@ ---- -title: Endpoint Types -description: Learn about ngrok'sCloud and Agent endpoints. ---- - -Endpoints have a **type**, which can be either `agent` or `cloud`. - -## Cloud Endpoints vs Agent Endpoints - -In general, Cloud Endpoints are the most flexible option, but which endpoint type you should choose depends on your use-case. The following table outlines the differences between Cloud and Agent endpoints. - -| | **[Cloud Endpoints](/universal-gateway/cloud-endpoints/)** | **[Agent Endpoints](/universal-gateway/agent-endpoints/)** | -| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- | -| **Lifetime** | Always-on. Must be manually terminated. | Live as long as the [agent](/agent) process that started them. | -| **Connection Handling** | Can be configured with [Traffic Policy](/traffic-policy/). | Can be configured with [Traffic Policy](/traffic-policy/). | -| **Configuration** | Can be managed at any time via the [API](/api/) or [dashboard](https://dashboard.ngrok.com/endpoints). | Managed by the agent that initiates them. | -| **Dashboard accessibility** | Can be created and configured from the dashboard. | Read-only in the dashboard. | -| **Can use ephemeral domains?** | **No**. Must be provided a fully qualified URL on creation. | **Yes**. Ngrok can generate a URL for you on creation. | -| **Traffic Policy required?** | **Yes**. | **No**, but you can provide one if you'd like. | -| **Globally available** | **Yes**. | **Yes**. | -| **Can be managed with [the API](/api/)?** | **Yes**. | Yes, with the agent api. | -| **[Pricing options](https://ngrok.com/pricing?ref=docs)** | Available on paid plans. | Available on all plans. | - -Learn more in the [Endpoints](/universal-gateway/endpoints) documentation. - -### Protocols, Binding and Pooling - -Both Agent and Cloud Endpoints support: - -- All [Endpoint Protocols](/universal-gateway/protocols/) - - `http/https` - - `tcp` - - `tls` -- All [Endpoint Bindings](/universal-gateway/bindings/) - - - `public` - - `internal` - - `kubernetes` - -- [Endpoint Pooling](/universal-gateway/endpoint-pooling/). You can also pool Agent Endpoints with Cloud Endpoints. - -## Get started - -- See the [Cloud Endpoints Quickstart](/universal-gateway/cloud-endpoints/quickstart). -- See the ngrok [Getting Started guide](/getting-started/) to set up an Agent Endpoint. diff --git a/docs/universal-gateway/what-are-endpoint-urls.mdx b/docs/universal-gateway/what-are-endpoint-urls.mdx new file mode 100644 index 0000000000..d88b485caa --- /dev/null +++ b/docs/universal-gateway/what-are-endpoint-urls.mdx @@ -0,0 +1,124 @@ +--- +sidebar_label: Endpoint URLs +title: What are Endpoint URLs? +--- + +URLs are the entry point for traffic to reach the services connected to your endpoints. This could be any URL, such as `https://your-app.ngrok.io` or `tcp://your-api.internal`. + +## Public Endpoints + +When you create a [Public Endpoint], the URL you create it with is validated differently based on the protocol of the URL. + +### `http` + +- The hostname must match a [Domain](/universal-gateway/domains/what-are-domains/) in your account. +- The hostname must be a domain with a valid [public suffix](https://publicsuffix.org/). +- The port must be `80`, which is the default when creating public endpoints. + +#### Examples + +Valid: + +- `http://example.ngrok.app` +- `http://example.ngrok.app:80` +- `http://example.party` + +Invalid: + +- `http://example.ngrok.app:81` - invalid port, must be `80`, not `81` +- `http://example.doesnotexist` - invalid hostname: `.doesnotexist` is not a public suffix domain +- `http://example.internal` - invalid hostname: `.internal` is not a public suffix domain + +### `https`, `tls` + +- The hostname must match a [Domain](/universal-gateway/domains/what-are-domains/) in your account. +- The hostname must be a domain with a valid [public suffix](https://publicsuffix.org/). +- The port must be `443`. If you do not specify a port, the default `443` will be used for you. + +:::note +There is no standard scheme for TLS URLs so ngrok renders them as `tls://`. +::: + +#### Examples + +Valid: + +- `https://example.ngrok.app` +- `https://example.ngrok.app:443` +- `https://example.party` + +Invalid: + +- `https://example.ngrok.app:8443` - invalid port, must be `443` +- `https://example.nosuchtld` - invalid hostname, `.nosuchtld` is not a public suffix domain +- `https://example.internal` - invalid hostname, public endpoints cannot use `.internal` + +### `tcp` + +- You must specify a port number in TCP URLs. +- The hostname and port must match the address of a [TCP + Address](/universal-gateway/tcp-addresses/) in your account. + +#### Examples + +Valid: + +- `tcp://1.tcp.ngrok.io:12345` +- `tcp://1.tcp.eu.ngrok.io:12345` + +Invalid: + +- `tcp://1.tcp.ngrok.io` - invalid, does not specify a port number +- `tcp://example.ngrok.app:12345` - invalid, does not match a TCP Address +- `tcp://your-domain.com:12345` - invalid, does not match a TCP Address + +## Internal Endpoints + +- **Scheme** - Internal endpoints support all [Endpoint Protocols](/universal-gateway/protocols) (`http`, `https`, `tcp` and `tls`). +- **Hostname** - Hostnames **must** end with `.internal` and may contain up to 5 subdomains. You must specify a URL with a hostname, randomly-assigned hostnames are not supported. You may specify wildcard hostnames. +- **Port** - All port numbers [1-65535] are valid. For `tcp` endpoints, you **must** specify a port. +- **Namespacing** - Internal endpoints are namespaced on a per-account basis. + This means that, two different accounts may have internal endpoints with the same URL (e.g. `https://api.internal`) without conflict or interference in [endpoint pooling](/universal-gateway/endpoint-pooling). + +#### Examples + +- `https://example.internal` +- `https://example.foo.bar.internal` +- `https://example.internal:12345` +- `tls://example.internal` +- `tls://example.internal:12345` +- `tcp://example.internal:12345` + +## Kubernetes Endpoints + +Kubernetes endpoint URL hostnames must be in the following format: + +- `[http|tcp]://name.namespace[:port]` + +The following restrictions are enforced: + +- **Scheme** - Must be `http` or `tcp`. `https` and `tls` are not supported. +- **Hostname** - Hostnames must always be two parts separated by a single dot, + e.g. `foo.bar`. Wildcard hostnames are not allowed. +- **Port** - All port numbers [1-65535] are valid. Port must be specified for + `tcp` endpoints. +- **Namespacing** - Kubernetes endpoints are namespaced on a per-account basis. + Two accounts may have kubernetes endpoints with the same URL (e.g. + http://api.internal). Those endpoints will not conflict or + [pool](/universal-gateway/endpoint-pooling). + +#### Examples + +Valid: + +- `http://app.example` +- `http://app.example:12345` +- `tcp://app.example:443` +- `tcp://app.example:12345` + +Invalid: + +- `https://app.example` - invalid scheme `https` +- `tls://app.example:12345` - invalid scheme `tls` +- `http://app.foo.bar` - invalid hostname, must have only two parts +- `tcp://app.example` - tcp endpoint must specify port number diff --git a/docs/universal-gateway/wildcard-domains/index.mdx b/docs/universal-gateway/wildcard-domains/index.mdx new file mode 100644 index 0000000000..268a854abe --- /dev/null +++ b/docs/universal-gateway/wildcard-domains/index.mdx @@ -0,0 +1,38 @@ +--- +sidebar_label: Using Wildcard Domains +title: How Do I Use Wildcard Domains? +description: Learn how to use wildcard domains with ngrok. +--- + +You may create a Domain with a wildcard name, e.g. `*.example.com`. A wildcard domain enables you to: + +- Create an endpoint which receives traffic for all of its subdomains, e.g. `https://*.example.com`. See [Wildcard Endpoints](/universal-gateway/http/#wildcard-endpoints) to understand the rules for matching and precedence. +- Create an endpoint on any subdomain which matches the wildcard, e.g. `https://foo.example.com` or `https://foo.bar.baz.example.com` + +:::note +The wildcard `*` character may only be used as the first part of a +domain, you may not create domains like `app.*.example.com` or +`*-app.example.com`. +::: + +## TLS provisioning + +When you bring your own wildcard domain (e.g. `*.app.example.com`), ngrok uses +a DNS01 challenge for TLS certificate provisioning which means that you must +create two CNAME records when creating branded wildcard domains instead of just +one. + +For example, If your domain is `*.app.example.com` you will be required to create the +following two CNAME records: + +- `*.app.example.com` +- `_acme-challenge.app.example.com` + +Certificate provisioning will not begin until you have created both DNS +records. + +## Pricing + +Wildcard domains are available on our Enterprise plan self service. They are also available on Pay-as-You-Go plans if you contact support@ngrok.com. For Pay-as-You-Go when you create a wildcard domain and run endpoints domain `*.foo.com`, endpoints `https://a.foo.com` and `https://b.foo.com`, we bill you for each individual endpoint, which is why we ask that you request the feature. + +Reserving subdomains of a wildcard domain within the ngrok dashboard count towards the number of reserved domains in your account. For example, if you reserve `foo.example.com` and `*.example.com`, you have reserved two domains.. You will be charged for each subdomain you use. You may need to enable overages in order to do this on your paid plan. diff --git a/docs/universal-gateway/wildcard-domains/wildcard-endpoints.mdx b/docs/universal-gateway/wildcard-domains/wildcard-endpoints.mdx new file mode 100644 index 0000000000..054651f9ed --- /dev/null +++ b/docs/universal-gateway/wildcard-domains/wildcard-endpoints.mdx @@ -0,0 +1,140 @@ +--- +sidebar_label: Using Endpoints With Wildcard Domains +title: How Do I Use Wildcard Endpoints? +description: Learn how to create endpoints that receive traffic for all subdomains matching a wildcard domain. +--- + +import TabItem from "@theme/TabItem"; +import Tabs from "@theme/Tabs"; +import WildcardAgentConfigExample from "/examples/agent-config/http-wildcard-domain.mdx"; +import WildcardKubernetesExample from "/examples/k8s/http-wildcard-domain.mdx"; +import { LangSwitcher } from "@site/src/components/LangSwitcher"; + +You can create an endpoint which will receive traffic for all of the subdomains matching a given wildcard domain like `*.example.com`. You must create a [wildcard domain](/universal-gateway/domains/what-are-domains/#wildcard-domains) to create a public wildcard endpoint. + +For example, if you create the wildcard endpoint `https://*.example.com`, it +will receive traffic for `https://foo.example.com` and +`https://bar.example.com`. + +- Connections to URLs which match an online wildcard endpoint will be routed to + it. For example, if you have created a wildcard endpoint + `https://*.example.com`, connections to `https://foo.bar.baz.example.com` will + route to it. +- Connections are routed to the most specific online endpoint. For example, if + the endpoints `https://*.example.com` and `https://app.example.com` are both + online, a connection to `https://app.example.com` will not be routed to the + wildcard endpoint. + +## Getting started + +The following example creates a wildcard endpoint that forwards traffic to port `80`. + + + + +```bash +ngrok http 80 --url "https://*.example.com" +``` + +```sh tabName="SSH" +ssh -R '*.example.com:443:localhost:80' v2@connect.ngrok-agent.com http +``` + +```go +import ( + "context" + "net" + + "golang.ngrok.com/ngrok" + "golang.ngrok.com/ngrok/config" +) + +func ngrokListener(ctx context.Context) (net.Listener, error) { + return ngrok.Listen(ctx, + config.HTTPEndpoint( + config.WithDomain("*.example.com"), + ), + ngrok.WithAuthtokenFromEnv(), + ) +} +``` + +```jsx +const ngrok = require("@ngrok/ngrok"); + +(async function () { + const listener = await ngrok.forward({ + addr: 8080, + authtoken_from_env: true, + domain: "*.example.com", + }); + + console.log(`Ingress established at: ${listener.url()}`); +})(); +``` + +```python +import ngrok + +listener = ngrok.forward("localhost:8080", authtoken_from_env=True, + domain="*.example.com") + +print(f"Ingress established at: {listener.url()}"); +``` + +```rust +use ngrok::prelude::*; + +async fn listen_ngrok() -> anyhow::Result { + let sess = ngrok::Session::builder() + .authtoken_from_env() + .connect() + .await?; + + let tun = sess + .http_endpoint() + .domain("*.example.com") + .listen() + .await?; + + println!("Listening on URL: {:?}", tun.url()); + + Ok(tun) +} +``` + + + + + + + + + + + +## Wildcard endpoint pooling + +Wildcard endpoints do not pool with non-wildcard URLs. For example, if you have two endpoints online, `https://foo.example.com` and `https://*.example.com`, they will not pool together and traffic to `https://foo.example.com` will not be load balanced. + +## Using multiple endpoints with wildcard subdomains + +With the [Agent CLI](/agent/cli), you can create separate public endpoints for subdomains of a wildcard domain no matter where the upstream services are running. See [the Domains docs](/docs/universal-gateway/domains/#wildcard-domains) for more information. + +For example, if you reserve `*.example.com` and want to route requests to `api1.example.com` and `api2.example.com`, you can specify subdomains via the CLI. ngrok will handle routing requests to the correct endpoint, even if they're on different ports. + +The first one might be at port `80`: + +```bash +ngrok http 80 --url https://api1.example.com +``` + +While the second is at port `81`: + +```bash +ngrok http 81 --url https://api2.example.com +``` + +:::tip +This is only necessary for creating _public_ endpoints to subdomains. Internal endpoints don't require a domain. +::: diff --git a/docs/whats-new.mdx b/docs/whats-new.mdx index 83d8285838..f4b8ecf75d 100644 --- a/docs/whats-new.mdx +++ b/docs/whats-new.mdx @@ -179,7 +179,7 @@ You can expect this page to update regularly (at least monthly). We'll include t - 2023-12-20 - Removed the ability to use ngrok without an account. All users need to register for an account and use a valid authtoken to use ngrok. - 2023-12-11 - Added the ability to use [HTTP/2 between the agent and your upstream service](/universal-gateway/http/#http2-forwarding). - 2023-12-06 - Release [ngrok Agent JavaScript SDK](https://ngrok.com/blog-post/ngrok-js) and [ngrok Agent Python SDK](https://ngrok.com/blog-post/ngrok-python) allowing developers to integrate ngrok natively into their application. -- 2023-12-04 - [Cross Region TCP Endpoints](/universal-gateway/tcp-addresses/#global-load-balancer) are available meaning ngrok TCP addresses can be served from agents in any region. +- 2023-12-04 - [Cross Region TCP Endpoints](/universal-gateway/tcp-addresses/#tcp-address-load-balancing) are available meaning ngrok TCP addresses can be served from agents in any region. - 2023-12-01 - Released [ngrok Agent 3.5.0](/agent/changelog/#ngrok-agent-350---2023-12-01) - 2023-12-01 - [ngrok-go 1.7.0 Released](https://github.com/ngrok/ngrok-go/releases/tag/v1.7.0) diff --git a/examples/agent-config/http-nonlocal.mdx b/examples/agent-config/http-nonlocal.mdx index 198b53f94e..869e97515d 100644 --- a/examples/agent-config/http-nonlocal.mdx +++ b/examples/agent-config/http-nonlocal.mdx @@ -1,4 +1,4 @@ -```yaml +```yaml mode=traffic-policy version: 3 endpoints: - name: example diff --git a/examples/java-sdk/http-basic-auth.mdx b/examples/java-sdk/http-basic-auth.mdx index 40653da781..4473e0dd3c 100644 --- a/examples/java-sdk/http-basic-auth.mdx +++ b/examples/java-sdk/http-basic-auth.mdx @@ -28,4 +28,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-branded-domain.mdx b/examples/java-sdk/http-branded-domain.mdx index 3a80bd0fb4..d7162a769d 100644 --- a/examples/java-sdk/http-branded-domain.mdx +++ b/examples/java-sdk/http-branded-domain.mdx @@ -21,4 +21,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-ip-restrictions.mdx b/examples/java-sdk/http-ip-restrictions.mdx index 05f4ab17cc..45272a2339 100644 --- a/examples/java-sdk/http-ip-restrictions.mdx +++ b/examples/java-sdk/http-ip-restrictions.mdx @@ -39,4 +39,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-oauth-byo-app.mdx b/examples/java-sdk/http-oauth-byo-app.mdx index 80381e1047..52d9e6312d 100644 --- a/examples/java-sdk/http-oauth-byo-app.mdx +++ b/examples/java-sdk/http-oauth-byo-app.mdx @@ -40,4 +40,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-oauth-customize-scopes.mdx b/examples/java-sdk/http-oauth-customize-scopes.mdx index e1284ef442..fa9e638739 100644 --- a/examples/java-sdk/http-oauth-customize-scopes.mdx +++ b/examples/java-sdk/http-oauth-customize-scopes.mdx @@ -24,4 +24,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-random.mdx b/examples/java-sdk/http-random.mdx index 0df30a12c5..ad95e0bf10 100644 --- a/examples/java-sdk/http-random.mdx +++ b/examples/java-sdk/http-random.mdx @@ -20,4 +20,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-schemes.mdx b/examples/java-sdk/http-schemes.mdx index 63168f90db..b72c3719e3 100644 --- a/examples/java-sdk/http-schemes.mdx +++ b/examples/java-sdk/http-schemes.mdx @@ -20,4 +20,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-static-domain.mdx b/examples/java-sdk/http-static-domain.mdx index 3a80bd0fb4..d7162a769d 100644 --- a/examples/java-sdk/http-static-domain.mdx +++ b/examples/java-sdk/http-static-domain.mdx @@ -21,4 +21,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-webhook-verification.mdx b/examples/java-sdk/http-webhook-verification.mdx index 2c307143fa..6611ee0ec4 100644 --- a/examples/java-sdk/http-webhook-verification.mdx +++ b/examples/java-sdk/http-webhook-verification.mdx @@ -38,4 +38,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-websocket-tcp-converter.mdx b/examples/java-sdk/http-websocket-tcp-converter.mdx index 84e68a7df4..08d643bd03 100644 --- a/examples/java-sdk/http-websocket-tcp-converter.mdx +++ b/examples/java-sdk/http-websocket-tcp-converter.mdx @@ -34,4 +34,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/java-sdk/http-wildcard-domain.mdx b/examples/java-sdk/http-wildcard-domain.mdx index c5c2d8463e..edf7a55577 100644 --- a/examples/java-sdk/http-wildcard-domain.mdx +++ b/examples/java-sdk/http-wildcard-domain.mdx @@ -21,4 +21,4 @@ public class Quickstart { ``` -Java SDK Docs: +Java SDK Docs: https://github.com/ngrok/ngrok-java diff --git a/examples/k8s/custom-agent-ingress.mdx b/examples/k8s/custom-agent-ingress.mdx index 69fa9a9ac3..ca2e009f9d 100644 --- a/examples/k8s/custom-agent-ingress.mdx +++ b/examples/k8s/custom-agent-ingress.mdx @@ -1,4 +1,4 @@ -In your Helm values.yaml file, set +In your Helm `values.yaml` file, set ``` serverAddr: "tunnel.us.ingress.example.com:443" diff --git a/examples/k8s/explicit-region.mdx b/examples/k8s/explicit-region.mdx index bd3d4b0194..4d0d0aaae9 100644 --- a/examples/k8s/explicit-region.mdx +++ b/examples/k8s/explicit-region.mdx @@ -1,4 +1,4 @@ -In your Helm values.yaml file, set +In your Helm `values.yaml` file, set ``` serverAddr: "connect.eu.ngrok-agent.com:443" diff --git a/examples/k8s/http-forward-https.mdx b/examples/k8s/http-forward-https.mdx index 42d6f5f231..7d1990ada6 100644 --- a/examples/k8s/http-forward-https.mdx +++ b/examples/k8s/http-forward-https.mdx @@ -2,7 +2,7 @@ Add the `k8s.ngrok.com/app-protocols` label to the **Service** definition targeted by your ingress backend to instruct the Operator to use `https` when forwarding connections. -```yaml +```yaml tabsToSpaces=true apiVersion: v1 kind: Service metadata: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 98d7257978..d74fc60144 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2658,8 +2658,8 @@ packages: caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} - caniuse-lite@1.0.30001712: - resolution: {integrity: sha512-MBqPpGYYdQ7/hfKiet9SCI+nmN5/hp4ZzveOJubl5DTAMa5oggjAuoi0Z4onBpKPFI2ePGnQuQIzF3VxDjDJig==} + caniuse-lite@1.0.30001713: + resolution: {integrity: sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -3359,8 +3359,8 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.134: - resolution: {integrity: sha512-zSwzrLg3jNP3bwsLqWHmS5z2nIOQ5ngMnfMZOWWtXnqqQkPVyOipxK98w+1beLw1TB+EImPNcG8wVP/cLVs2Og==} + electron-to-chromium@1.5.135: + resolution: {integrity: sha512-8gXUdEmvb+WCaYUhA0Svr08uSeRjM2w3x5uHOc1QbaEVzJXB8rgm5eptieXzyKoVEtinLvW6MtTcurA65PeS1Q==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -4185,8 +4185,8 @@ packages: jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - katex@0.16.21: - resolution: {integrity: sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==} + katex@0.16.22: + resolution: {integrity: sha512-XCHRdUw4lf3SKBaJe4EvgqIuWwkPSo9XoeO8GjQW94Bp7TWv9hNhzZjZ+OH9yf1UmLygb7DIT5GSFQiyt16zYg==} hasBin: true keyv@4.5.4: @@ -9872,7 +9872,7 @@ snapshots: autoprefixer@10.4.21(postcss@8.5.3): dependencies: browserslist: 4.24.4 - caniuse-lite: 1.0.30001712 + caniuse-lite: 1.0.30001713 fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.1.1 @@ -9999,8 +9999,8 @@ snapshots: browserslist@4.24.4: dependencies: - caniuse-lite: 1.0.30001712 - electron-to-chromium: 1.5.134 + caniuse-lite: 1.0.30001713 + electron-to-chromium: 1.5.135 node-releases: 2.0.19 update-browserslist-db: 1.1.3(browserslist@4.24.4) @@ -10055,11 +10055,11 @@ snapshots: caniuse-api@3.0.0: dependencies: browserslist: 4.24.4 - caniuse-lite: 1.0.30001712 + caniuse-lite: 1.0.30001713 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - caniuse-lite@1.0.30001712: {} + caniuse-lite@1.0.30001713: {} ccount@2.0.1: {} @@ -10809,7 +10809,7 @@ snapshots: ee-first@1.1.1: {} - electron-to-chromium@1.5.134: {} + electron-to-chromium@1.5.135: {} emoji-regex@8.0.0: {} @@ -11708,7 +11708,7 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - katex@0.16.21: + katex@0.16.22: dependencies: commander: 8.3.0 @@ -12042,7 +12042,7 @@ snapshots: dagre-d3-es: 7.0.11 dayjs: 1.11.13 dompurify: 3.2.5 - katex: 0.16.21 + katex: 0.16.22 khroma: 2.1.0 lodash-es: 4.17.21 marked: 15.0.8 diff --git a/sidebars.js b/sidebars.js index a8d2e3cd93..e1a8b493e4 100644 --- a/sidebars.js +++ b/sidebars.js @@ -34,7 +34,10 @@ const sidebars = { label: "Pricing & Limits", type: "category", link: { type: "doc", id: "pricing-limits/index" }, - items: ["pricing-limits/free-plan-limits"], + items: [ + "pricing-limits/free-plan-limits", + "pricing-limits/endpoint-limits", + ], }, { label: "Universal Gateway", @@ -43,116 +46,189 @@ const sidebars = { className: "menu__list-item--category", link: { type: "doc", id: "universal-gateway/overview" }, items: [ - "universal-gateway/overview", { - label: "Concepts", + label: "Overview", type: "category", + link: { + type: "doc", + id: "universal-gateway/overview", + }, items: [ - { id: "universal-gateway/domains", type: "doc", label: "Domains" }, - { - id: "universal-gateway/tcp-addresses", - type: "doc", - label: "TCP Addresses", - }, - "universal-gateway/tls-certificates", - "universal-gateway/edges", + "universal-gateway/points-of-presence", + "universal-gateway/ddos-protection", ], }, { label: "Endpoints", type: "category", - link: { type: "doc", id: "universal-gateway/endpoints" }, + link: { + type: "doc", + id: "universal-gateway/endpoints", + }, items: [ { - id: "universal-gateway/endpoints", - type: "doc", - label: "Overview", - }, - { - label: "Types", + label: "Understanding Endpoint Bindings", type: "category", - link: { type: "doc", id: "universal-gateway/types" }, + link: { + type: "doc", + id: "universal-gateway/bindings", + }, items: [ + "universal-gateway/public-endpoints/index", { - label: "Cloud Endpoints", + label: "Internal Binding", type: "category", link: { type: "doc", - id: "universal-gateway/cloud-endpoints/index", + id: "universal-gateway/internal-endpoints/index", }, - items: ["universal-gateway/cloud-endpoints/quickstart"], - }, - { - id: "universal-gateway/agent-endpoints", - type: "doc", - label: "Agent Endpoints", + items: ["universal-gateway/internal-endpoints/quickstart"], }, + "universal-gateway/kubernetes-endpoints/index", ], }, { - label: "Protocols", + label: "Understanding Endpoint URLs", type: "category", - link: { type: "doc", id: "universal-gateway/protocols" }, + link: { + type: "doc", + id: "universal-gateway/what-are-endpoint-urls", + }, items: [ - { - id: "universal-gateway/http", - type: "doc", - label: "HTTP/S", - }, - { - id: "universal-gateway/tls", - type: "doc", - label: "TLS", - }, - { - id: "universal-gateway/tcp", - type: "doc", - label: "TCP", - }, + "universal-gateway/wildcard-domains/wildcard-endpoints", + "universal-gateway/http-s/endpoint-url-defaults", ], }, + "universal-gateway/agent-endpoints", { - label: "Bindings", + label: "Using Cloud Endpoints", type: "category", - link: { type: "doc", id: "universal-gateway/bindings" }, + link: { + type: "doc", + id: "universal-gateway/cloud-endpoints/index", + }, + items: ["universal-gateway/cloud-endpoints/quickstart"], + }, + "universal-gateway/chain-endpoints", + "universal-gateway/mock-api", + // "universal-gateway/migrate-from-tunnels", + ], + }, + { + label: "Using TCP Addresses", + type: "category", + link: { + type: "doc", + id: "universal-gateway/tcp-addresses/index", + }, + items: [ + "universal-gateway/tcp-addresses/how-are-tcp-addresses-assigned", + ], + }, + { + label: "Using Domains", + type: "category", + link: { + type: "doc", + id: "universal-gateway/domains/what-are-domains", + }, + items: [ + "universal-gateway/domains/bring-your-own-domain", + "universal-gateway/domains/what-are-managed-domains", + "universal-gateway/wildcard-domains/index", + ], + }, + "universal-gateway/ip-addresses", + { + label: "Handling Traffic", + type: "category", + items: [ + { + label: "HTTP/S", + type: "category", + link: { type: "doc", id: "universal-gateway/http-s/index" }, + items: ["universal-gateway/http-s/http-s-endpoints"], + }, + { + label: "TLS", + type: "category", + link: { + type: "doc", + id: "universal-gateway/tls/index", + }, items: [ { - id: "universal-gateway/public-endpoints", - type: "doc", - label: "Public", - }, - { - id: "universal-gateway/internal-endpoints", - type: "doc", - label: "Internal", + label: "Terminating TLS", + type: "category", + link: { + type: "doc", + id: "universal-gateway/tls/tls-termination/index", + }, + items: [ + "universal-gateway/tls/tls-termination/termination-mechanics", + "universal-gateway/tls/tls-termination/termination-location", + "universal-gateway/tls/handshake", + ], }, { - id: "universal-gateway/kubernetes-endpoints", - type: "doc", - label: "Kubernetes", + label: "Managing TLS Certificates", + type: "category", + link: { + type: "doc", + id: "universal-gateway/tls-certificates/how-does-ngrok-handle-tls", + }, + items: [ + "universal-gateway/tls-certificates/automatic-certificate-management", + "universal-gateway/tls-certificates/how-are-certificates-selected", + "universal-gateway/tls-certificates/custom-certificates", + "universal-gateway/tls-certificates/what-is-a-certificate-bundle", + "universal-gateway/tls-certificates/what-are-private-tls-keys", + ], }, + "universal-gateway/tls/tls-clients", ], }, { - id: "universal-gateway/endpoint-pooling", - type: "doc", - label: "Pooling", + label: "TCP", + type: "category", + link: { type: "doc", id: "universal-gateway/tcp/index" }, + items: ["universal-gateway/tcp/static-tcp-url"], }, + { + label: "Forwarding Traffic", + type: "category", + link: { + type: "doc", + id: "universal-gateway/agent-forwarding/index", + }, + items: [ + "universal-gateway/agent-forwarding/forward-original-connection-data", + "universal-gateway/http-s/upstream-headers", + "universal-gateway/agent-forwarding/non-local-forwarding", + "universal-gateway/agent-forwarding/serving-file-directories", + ], + }, + ], + }, + { + label: "Endpoint Pooling", + type: "category", + link: { type: "doc", id: "universal-gateway/pooling/index" }, + items: [ + "universal-gateway/pooling/pooling-quickstart", + "universal-gateway/pooling/pool-load-balancing", ], }, { - label: "Network", + label: "Using the Global Load Balancer", type: "category", link: { type: "doc", - id: "universal-gateway/global-load-balancer", + id: "universal-gateway/global-load-balancer/index", }, items: [ - "universal-gateway/global-load-balancer", - "universal-gateway/tls-termination", - "universal-gateway/ddos-protection", - "universal-gateway/ip-addresses", - "universal-gateway/points-of-presence", + "universal-gateway/global-load-balancer/gslb-endpoints", + "universal-gateway/global-load-balancer/gslb-agents", ], }, ], @@ -288,6 +364,7 @@ const sidebars = { "k8s/guides/using-loadbalancers", "k8s/guides/endpoint-types", "k8s/guides/bindings", + "universal-gateway/kubernetes-endpoints/services", "k8s/guides/pooling", "k8s/guides/custom-domain", "k8s/guides/annotations", @@ -673,6 +750,11 @@ const sidebars = { value: "", }, "faq/faq", + { + label: "Deprecated", + type: "category", + items: ["universal-gateway/edges"], + }, ], }; diff --git a/src/components/CodeBlockWithInfo/index.tsx b/src/components/CodeBlockWithInfo/index.tsx new file mode 100644 index 0000000000..ee512fd665 --- /dev/null +++ b/src/components/CodeBlockWithInfo/index.tsx @@ -0,0 +1,88 @@ +import useBaseUrl from "@docusaurus/useBaseUrl"; +import { + CodeBlock, + CodeBlockBody, + CodeBlockCode, + CodeBlockCopyButton, + CodeBlockExpanderButton, + CodeBlockHeader, + CodeBlockIcon, + CodeBlockTitle, + fmtCode, +} from "@ngrok/mantle/code-block"; +import type { ReactNode } from "react"; +import { LanguageData } from "../LangSwitcher/LanguageData"; +import type { LanguageInfo } from "../LangSwitcher/data"; + +type CodeBlockWithInfoProps = { + content: string | undefined; + // biome-ignore lint/suspicious/noExplicitAny: + language: any; + collapseLineNumber: number; + // biome-ignore lint/suspicious/noExplicitAny: + meta: any; + // biome-ignore lint/suspicious/noExplicitAny: + className?: any; + headerContent: ReactNode; + // biome-ignore lint/suspicious/noExplicitAny: + codeBlockProps?: any; + info?: LanguageInfo | undefined; +}; + +export function CodeBlockWithInfo({ + content, + language, + collapseLineNumber, + meta, + className, + headerContent, + info, + codeBlockProps, +}: CodeBlockWithInfoProps) { + const collapsible = !meta + ? false + : meta.collapsible && + content && + content.split("\n").length > collapseLineNumber; + const indentation = meta?.indentation === "tabs" ? "tabs" : "spaces"; + + return ( +
+ + + {headerContent} + + + {meta?.title && ( +
+ <> + {meta?.mode ? ( + + ) : ( + + )} + + {meta?.titleLink ? ( + + {meta.title} + + ) : ( + {meta?.title} + )} + + +
+ )} + {!meta?.disableCopy && } + + {collapsible && } +
+
+ {info && } +
+ ); +} diff --git a/src/components/LangSwitcher/ContentSwitcher.tsx b/src/components/LangSwitcher/ContentSwitcher.tsx new file mode 100644 index 0000000000..be6bcfb25e --- /dev/null +++ b/src/components/LangSwitcher/ContentSwitcher.tsx @@ -0,0 +1,30 @@ +import { useContext } from "react"; +import type { LangSwitcherContextType } from "./LangSwitcherContext"; +import LangSwitcherContext from "./LangSwitcherContext"; + +/** + * Renders its children only if the specified language matches the + * currently selected language for the LangSwithcher component. + * This is useful for conditionally rendering content based on the + * selected language. + */ +export function ContentSwitcher({ + children, + languages, +}: { + children: React.ReactNode; + languages: string[]; + className?: string; +}) { + const { selectedLanguage } = + useContext(LangSwitcherContext); + if (!languages?.length) + throw new Error("Must specify a language for the ContentSwitcher"); + + for (const lang of languages) { + if (lang === selectedLanguage) { + return
{children}
; + } + } + return null; +} diff --git a/src/components/LangSwitcher/LangSwitcherContext.tsx b/src/components/LangSwitcher/LangSwitcherContext.tsx index 03d524c722..3106518e5f 100644 --- a/src/components/LangSwitcher/LangSwitcherContext.tsx +++ b/src/components/LangSwitcher/LangSwitcherContext.tsx @@ -2,14 +2,16 @@ import type { SupportedLanguage } from "@ngrok/mantle/code-block"; import { createContext } from "react"; export type LangSwitcherContextType = { - tabLanguage: string | SupportedLanguage | null; + selectedLanguage: string | SupportedLanguage | null; defaultLanguage: string | null; - updateTab: null | ((newLang: string | SupportedLanguage) => void); + updateSelectedLanguage: + | null + | ((newLang: string | SupportedLanguage | undefined) => void); }; const LangSwitcherContext = createContext({ - tabLanguage: "", - updateTab: null, + selectedLanguage: null, + updateSelectedLanguage: null, defaultLanguage: null, }); diff --git a/src/components/LangSwitcher/LanguageData.tsx b/src/components/LangSwitcher/LanguageData.tsx new file mode 100644 index 0000000000..7b2c144066 --- /dev/null +++ b/src/components/LangSwitcher/LanguageData.tsx @@ -0,0 +1,32 @@ +import type { LanguageInfo } from "./data"; + +export function LanguageData({ data }: { data: LanguageInfo }) { + const anchoredLinks = data.links.map((link) => { + return ( + + here + + ); + }); + + const linkText = anchoredLinks.reduce( + // biome-ignore lint/suspicious/noExplicitAny: + (prev, curr, index): any => { + if (index === 0) { + return [prev, curr]; + } + if (index === data.links.length - 1) { + return [prev, ", and ", curr]; + } + return [prev, ", ", curr]; + }, + ); + + return ( +
+
+ See the ngrok {data.displayName} package docs {linkText}. +
+
+ ); +} diff --git a/src/components/LangSwitcher/data.ts b/src/components/LangSwitcher/data.ts new file mode 100644 index 0000000000..2eee098aaa --- /dev/null +++ b/src/components/LangSwitcher/data.ts @@ -0,0 +1,66 @@ +export type LanguageInfo = { + name: string; + allNames?: string[]; + displayName: string; + links: string[]; +}; + +export const languageInfo: LanguageInfo[] = [ + { + name: "go", + displayName: "Go", + links: ["https://pkg.go.dev/golang.ngrok.com/ngrok#ListenAndForward"], + }, + { + name: "rust", + displayName: "Rust", + links: [ + "https://docs.rs/ngrok/0.14.0-pre.13/ngrok/config/struct.TcpTunnelBuilder.html#method.listen_and_forward", + ], + }, + { + name: "python", + displayName: "Python", + links: [ + "https://ngrok.github.io/ngrok-python/tcp_listener_builder.html#ngrok.TcpListenerBuilder.remote_addr", + "https://ngrok.github.io/ngrok-python/index.html#full-configuration", + ], + }, + { + name: "java", + displayName: "Java", + links: ["https://github.com/ngrok/ngrok-java"], + }, + { + name: "javascript", + displayName: "JavaScript", + links: [ + "https://ngrok.github.io/ngrok-javascript/interfaces/Config.html#addr", + "https://ngrok.github.io/ngrok-javascript/classes/TcpListenerBuilder.html#listenAndForward", + ], + allNames: ["javascript", "typescript", "ts", "js", "jsx", "tsx"], + }, + { + name: "typescript", + displayName: "TypeScript", + links: [ + "https://ngrok.github.io/ngrok-javascript/interfaces/Config.html#addr", + "https://ngrok.github.io/ngrok-javascript/classes/TcpListenerBuilder.html#listenAndForward", + ], + allNames: ["typescript", "ts", "tsx"], + }, +]; + +export type CustomLanguage = { + name: string; + // The language whose syntax should be used. + // For example, a "ssh" language could use "bash" syntax. + syntaxLanguage: string; +}; + +export const customLanguages: CustomLanguage[] = [ + { + name: "ssh", + syntaxLanguage: "bash", + }, +]; diff --git a/src/components/LangSwitcher/index.tsx b/src/components/LangSwitcher/index.tsx index 7d8d9e4620..4635883344 100644 --- a/src/components/LangSwitcher/index.tsx +++ b/src/components/LangSwitcher/index.tsx @@ -1,52 +1,40 @@ import BrowserOnly from "@docusaurus/BrowserOnly"; import { Button } from "@ngrok/mantle/button"; -import { - CodeBlock, - CodeBlockBody, - CodeBlockCode, - CodeBlockCopyButton, - CodeBlockExpanderButton, - CodeBlockHeader, - CodeBlockTitle, - fmtCode, -} from "@ngrok/mantle/code-block"; -import clsx from "clsx"; import { useContext } from "react"; +import { CodeBlockWithInfo } from "../CodeBlockWithInfo"; import { CodeBlockFallback } from "../code-block"; import LangSwitcherContext, { type LangSwitcherContextType, } from "./LangSwitcherContext"; -import { getCodeBlocks } from "./utils"; +import { getCodeBlocks, languagesAreSynonyms } from "./utils"; // biome-ignore lint/suspicious/noExplicitAny: export function LangSwitcher({ children, className, ...props }: any) { - const { defaultLanguage, tabLanguage, updateTab } = + const { defaultLanguage, selectedLanguage, updateSelectedLanguage } = useContext(LangSwitcherContext); - const codeBlocks = getCodeBlocks(children) ?? []; - if (!updateTab) return "Error loading code block"; + const codeBlocks = getCodeBlocks(children); + + if (!updateSelectedLanguage) return "Error loading code block"; // if no language tab is set yet - if (tabLanguage === null) { + if (selectedLanguage === null) { // Check if the user has specified a default language const startingLanguage = // biome-ignore lint/suspicious/noExplicitAny: codeBlocks.find((child: any) => child.language === defaultLanguage) || codeBlocks[0]; - updateTab(startingLanguage?.language); + updateSelectedLanguage(startingLanguage?.language); // if no default language is set, set the first tab as the selected tab } const matchingBlock = - // biome-ignore lint/suspicious/noExplicitAny: - codeBlocks.find((child: any) => child.language === tabLanguage) || - codeBlocks[0]; - // This also needs to be updated to use the right codeblock data, not [0] - // biome-ignore lint/suspicious/noExplicitAny: - const meta: { collapsible?: boolean; [key: string]: any } = - matchingBlock?.meta || {}; - const collapsible = - meta.collapsible && matchingBlock?.content.split("\n").length > 10; + codeBlocks.find( + // biome-ignore lint/suspicious/noExplicitAny: + (child: any) => + child.language === selectedLanguage || + languagesAreSynonyms(child.language, selectedLanguage), + ) || codeBlocks[0]; return ( {() => ( - - + {/* biome-ignore lint/suspicious/noExplicitAny: */} {codeBlocks.map((child: any) => ( ))}
- - - {meta.title && ( - - {meta.title} - - )} - {!meta.disableCopy && } - - {collapsible && } - - + } + info={matchingBlock?.info} + codeBlockProps={props} + /> )} ); diff --git a/src/components/LangSwitcher/utils.ts b/src/components/LangSwitcher/utils.ts index 32506f6538..ca3bb30511 100644 --- a/src/components/LangSwitcher/utils.ts +++ b/src/components/LangSwitcher/utils.ts @@ -1,17 +1,73 @@ -import { parseLanguage, parseMetastring } from "@ngrok/mantle/code-block"; -import { Children, isValidElement } from "react"; -import type { ReactNode } from "react"; - -export const getCodeBlocks = (children: ReactNode) => { - return Children.map(children, (child, index) => { - const { className, metastring, children, language } = isValidElement(child) - ? (child.props.children?.props ?? child.props) - : {}; - const parsedLanguage = language || parseLanguage(className); - const meta = parseMetastring(metastring); - const title = - meta.title ?? (isValidElement(child) ? child.props.title : undefined); +import { + type Meta, + type SupportedLanguage, + parseLanguage, +} from "@ngrok/mantle/code-block"; +import type { ReactElement, ReactNode } from "react"; +import { type LanguageInfo, languageInfo } from "./data"; + +export function getMetaDataWithQuotes( + propertyName: string, + metastring: string, +) { + const property = `${propertyName}=`; + if (!metastring.includes(property)) return null; + // Get the substring starting with tabName= and ending with + // a closing quote and a space + const tabNameSubstring = metastring.split(property)[1] ?? ""; + // If the first character is not a quote, we shouldn't parse this property + if (tabNameSubstring[0] !== '"') return null; + const lastQuoteIndex = tabNameSubstring.indexOf(`" `); + const tabNameValueEnd = + lastQuoteIndex > 0 ? lastQuoteIndex : tabNameSubstring.length - 1; + return tabNameSubstring.substring(1, tabNameValueEnd); +} + +export function getMetaData(metastring: string | undefined) { + if (!metastring) { + return {}; + } + const meta = metastring.split(/\s+/); + const metaData: Record = {}; + // biome-ignore lint/complexity/noForEach: + meta.forEach((item) => { + const [key, value] = item.split("="); + if (key && value) { + metaData[key] = value.replace(/['"]/g, ""); // Remove " characters + } + }); + // Add the properties that use quotes to the metaData object + // biome-ignore lint/complexity/noForEach: + ["tabName", "title"].forEach((property) => { + const quotedData = getMetaDataWithQuotes(property, metastring); + if (quotedData) { + metaData[property] = quotedData; + } + }); + return metaData; +} + +export type CodeBlockData = { + language: SupportedLanguage | string | undefined; + content: ReactNode[]; + meta: Meta & { + collapsible: boolean; + titleLink?: string; + tabName?: string; + title?: string; + language?: string; + }; + info?: LanguageInfo; +}; +export const getCodeBlocks = (children: ReactElement[]): CodeBlockData[] => { + return children.map((child: ReactElement) => { + const { className, metastring, children, language } = + child?.props.children.props ?? child.props; + + const parsedLanguage = language || parseLanguage(className); + const meta = getMetaData(metastring); + const title = meta.title || child.props.title; return { language: parsedLanguage, content: children, @@ -19,23 +75,57 @@ export const getCodeBlocks = (children: ReactNode) => { ...meta, // Make it collapsible by default collapsible: true, + titleLink: meta.titleLink, + tabName: meta.tabName, + title, + disableCopy: false, }, - title, - childIndex: index, + info: getLanguageInfo(parsedLanguage), }; }); }; +export const getLanguageInfo = (language: string) => { + return languageInfo.find( + (item) => + item.name === language || item?.allNames?.some((alt) => alt === language), + ); +}; + +export function languagesAreSynonyms( + languageToCheck: string, + selectedLanguage: string | null, +) { + if (!selectedLanguage) return false; + const synonymousLanguage = languageInfo.find((lang: LanguageInfo) => + lang.allNames?.includes(selectedLanguage), + ); + return ( + synonymousLanguage?.name === languageToCheck || + synonymousLanguage?.allNames?.includes(languageToCheck) + ); +} + // The name of the query param or localstorage item to search for // to get the default tab value -export const paramName = "defaultTabLang"; +export const langParamName = "defaultTabLang"; +export const tabParamName = "defaultTabItem"; -export const getDefaultLanguage = (): string | null => { - const searchParams = new URLSearchParams(window?.location?.search); - let tempLang = searchParams.get(paramName); - if (!tempLang && localStorage) { - tempLang = localStorage.getItem(paramName); +export const getStorageLanguageAndTab = (): { + defaultLanguage: string | null; + defaultTabItem: string | null; +} => { + function getStorageItem(key: string) { + if (localStorage) { + return localStorage.getItem(key); + } + return null; } + const searchParams = new URLSearchParams(window?.location?.search); + const tempLang = + searchParams.get(langParamName) || getStorageItem(langParamName); + const tempTab = + searchParams.get(tabParamName) || getStorageItem(tabParamName); - return tempLang; + return { defaultLanguage: tempLang ?? null, defaultTabItem: tempTab ?? null }; }; diff --git a/src/components/code-block.tsx b/src/components/code-block.tsx index 9f32f134b8..944509adf9 100644 --- a/src/components/code-block.tsx +++ b/src/components/code-block.tsx @@ -1,19 +1,14 @@ -import type { Mode, SupportedLanguage } from "@ngrok/mantle/code-block"; -import { - CodeBlock, - CodeBlockBody, +import { Button } from "@ngrok/mantle/button"; +import type { CodeBlockCode, - CodeBlockCopyButton, - CodeBlockExpanderButton, - CodeBlockHeader, - CodeBlockIcon, - CodeBlockTitle, - fmtCode, - parseLanguage, - parseMetastring, + Mode, + SupportedLanguage, } from "@ngrok/mantle/code-block"; +import { CodeBlock, parseLanguage } from "@ngrok/mantle/code-block"; import type { WithStyleProps } from "@ngrok/mantle/types"; import type { ComponentProps, ReactNode } from "react"; +import { CodeBlockWithInfo } from "./CodeBlockWithInfo"; +import { getLanguageInfo, getMetaData } from "./LangSwitcher/utils"; type WithIndentation = Pick< ComponentProps, @@ -25,10 +20,6 @@ type Props = WithStyleProps & { * The code content inside the block. This contains the raw code to display as a string. */ children: string; - /** - * The array of children to show in the codeblock if the switcher functionality is active - */ - switcherChildren?: string[]; /** * Specifies the language of the code block (e.g., language-js, language-python). */ @@ -67,36 +58,34 @@ function DocsCodeBlock({ metastring, mode: _mode, title: _title, - switcherChildren, ...props }: Props) { - const language = _language ?? parseLanguage(className); - const meta = parseMetastring(metastring); - const title = _title || meta.title; - const mode = _mode || meta.mode; - const hasHeader = title || mode || _icon; - const indentation = _indentation ?? meta.indentation; - - const collapsible = meta.collapsible && children.split("\n").length > 20; + const langMatchesInClassName = className?.match(/language-(\w+)/); + const langInClassName = langMatchesInClassName + ? langMatchesInClassName[0]?.split("-")[1] + : ""; + const language = _language || parseLanguage(langInClassName); return ( - - {hasHeader && ( - - {mode ? : _icon} - {title && {title}} - - )} - - {!meta.disableCopy && } - - {collapsible && } - - + + {language.toUpperCase()} + + } + info={getLanguageInfo(language)} + codeBlockProps={props} + /> ); } diff --git a/src/theme/DocItem/Content/index.tsx b/src/theme/DocItem/Content/index.tsx index addb4b49e8..adb03e2557 100644 --- a/src/theme/DocItem/Content/index.tsx +++ b/src/theme/DocItem/Content/index.tsx @@ -3,32 +3,61 @@ import useIsBrowser from "@docusaurus/useIsBrowser"; import type { SupportedLanguage } from "@ngrok/mantle/code-block"; import LangSwitcherContext from "@site/src/components/LangSwitcher/LangSwitcherContext"; import { - getDefaultLanguage, - paramName, + getStorageLanguageAndTab, + langParamName, + tabParamName, } from "@site/src/components/LangSwitcher/utils"; import Content from "@theme-original/DocItem/Content"; import type ContentType from "@theme/DocItem/Content"; -import React, { useState, type ReactNode } from "react"; +import { type ReactNode, useState } from "react"; +import TabListContext from "../../Tabs/TabListContext"; type Props = WrapperProps; export default function ContentWrapper(props: Props): ReactNode { const isBrowser = useIsBrowser(); - const defaultLanguage = isBrowser ? getDefaultLanguage() : null; - const [tabLanguage, setTabLanguage] = useState(defaultLanguage); - const updateTab = (newLang: string | SupportedLanguage) => { + const storageData = isBrowser ? getStorageLanguageAndTab() : null; + const [selectedLanguage, setSelectedLanguage] = useState( + storageData?.defaultLanguage ?? null, + ); + const [selectedTabItem, setSelectedTabItem] = useState( + storageData?.defaultLanguage ?? null, + ); + const updateSelectedLanguage = ( + newLang: string | SupportedLanguage | undefined, + ) => { + if (!newLang) return; + if (isBrowser) { + localStorage.setItem(langParamName, newLang); + } + setSelectedLanguage(newLang); + }; + const updateSelectedTabItem = (newItem: string | undefined) => { + if (!newItem) return; if (isBrowser) { - localStorage.setItem(paramName, newLang); + localStorage.setItem(tabParamName, newItem); } - setTabLanguage(newLang); + setSelectedTabItem(newItem); }; return ( - - - + + + + ); } diff --git a/src/theme/DocSidebar/index.js b/src/theme/DocSidebar/index.tsx similarity index 55% rename from src/theme/DocSidebar/index.js rename to src/theme/DocSidebar/index.tsx index a786862b4e..c2d98ba91e 100644 --- a/src/theme/DocSidebar/index.js +++ b/src/theme/DocSidebar/index.tsx @@ -1,11 +1,12 @@ import DocSidebar from "@theme-original/DocSidebar"; import SearchBar from "@theme/SearchBar"; -export default function DocSidebarWrapper(props) { +// biome-ignore lint/suspicious/noExplicitAny: +export default function DocSidebarWrapper(props: any) { return ( - <> +
- +
); } diff --git a/src/theme/DocSidebarItem/Link/index.tsx b/src/theme/DocSidebarItem/Link/index.tsx new file mode 100644 index 0000000000..eb71b93b7d --- /dev/null +++ b/src/theme/DocSidebarItem/Link/index.tsx @@ -0,0 +1,66 @@ +import Link from "@docusaurus/Link"; +import isInternalUrl from "@docusaurus/isInternalUrl"; +import { isActiveSidebarItem } from "@docusaurus/plugin-content-docs/client"; +import { ThemeClassNames } from "@docusaurus/theme-common"; +import type { Props } from "@theme/DocSidebarItem/Link"; +import IconExternalLink from "@theme/Icon/ExternalLink"; +import clsx from "clsx"; +import { type ReactNode, useEffect, useRef } from "react"; + +import styles from "./styles.module.css"; + +export default function DocSidebarItemLink({ + item, + onItemClick, + activePath, + level, + index, + ...props +}: Props): ReactNode { + const { href, label, className, autoAddBaseUrl } = item; + const isActive = isActiveSidebarItem(item, activePath); + const isInternalLink = isInternalUrl(href); + const itemRef = useRef(null); + + useEffect(() => { + if (isActive && itemRef.current) { + itemRef.current.scrollIntoView({ + behavior: "smooth", + block: "center", + inline: "nearest", + }); + } + }, [isActive]); + return ( +
  • + onItemClick(item) : undefined, + })} + {...props} + > + {label} + {!isInternalLink && } + +
  • + ); +} diff --git a/src/theme/DocSidebarItem/Link/styles.module.css b/src/theme/DocSidebarItem/Link/styles.module.css new file mode 100644 index 0000000000..bcadcc85b6 --- /dev/null +++ b/src/theme/DocSidebarItem/Link/styles.module.css @@ -0,0 +1,3 @@ +.menuExternalLink { + align-items: center; +} diff --git a/src/theme/Tabs/TabListContext.tsx b/src/theme/Tabs/TabListContext.tsx new file mode 100644 index 0000000000..ce17867cc0 --- /dev/null +++ b/src/theme/Tabs/TabListContext.tsx @@ -0,0 +1,15 @@ +import { createContext } from "react"; + +export type TabListContextType = { + localStorageTab: string | null; + selectedTabItem: string | null; + updateSelectedTabItem: null | ((newTabItem: string | undefined) => void); +}; + +const TabListContext = createContext({ + localStorageTab: null, + selectedTabItem: null, + updateSelectedTabItem: null, +}); + +export default TabListContext; diff --git a/src/theme/Tabs/index.tsx b/src/theme/Tabs/index.tsx new file mode 100644 index 0000000000..9d327497a7 --- /dev/null +++ b/src/theme/Tabs/index.tsx @@ -0,0 +1,186 @@ +import { + type TabItemProps, + type TabValue, + sanitizeTabsChildren, + useScrollPositionBlocker, + useTabs, +} from "@docusaurus/theme-common/internal"; +import useIsBrowser from "@docusaurus/useIsBrowser"; +import { + Tabs as MantleTabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@ngrok/mantle/tabs"; +import type { Props } from "@theme/Tabs"; +import clsx from "clsx"; +import { type ReactElement, type ReactNode, useContext } from "react"; +import TabListContext from "./TabListContext"; +import styles from "./styles.module.css"; + +function getValidTabToShow( + tabValues: readonly TabValue[], + selectedValue: string | undefined, + defaultTab: string | undefined, +) { + if (selectedValue) { + const selectedTab = tabValues.find((tab) => tab.label === selectedValue); + if (selectedTab) { + return selectedTab.label; + } + } + return defaultTab; +} + +function getValidDefaultTab( + tabValues: readonly TabValue[], + localStorageTab: string | null | undefined, +) { + const defaultTab = tabValues.find( + (tab) => tab.label === localStorageTab || tab.value === localStorageTab, + ); + if (defaultTab) { + return defaultTab.label; + } + return tabValues[0]?.label; +} + +function TabList({ + className, + block, + selectedValue, + selectValue, + tabValues, + ...props +}: Props & ReturnType) { + const tabRefs: (HTMLButtonElement | null)[] = []; + const { blockElementScrollPositionUntilNextRender } = + useScrollPositionBlocker(); + const { localStorageTab, selectedTabItem, updateSelectedTabItem } = + useContext(TabListContext); + + const handleTabChange = ( + event: + | React.FocusEvent + | React.MouseEvent + | React.KeyboardEvent, + ) => { + const newTab = event.currentTarget; + const newTabIndex = tabRefs.indexOf(newTab); + const newTabValue = + tabValues[newTabIndex]?.label || tabValues[newTabIndex]?.value; + + if (newTabValue !== selectedTabItem && updateSelectedTabItem) { + blockElementScrollPositionUntilNextRender(newTab); + updateSelectedTabItem(newTabValue); + } + }; + + const handleKeydown = (event: React.KeyboardEvent) => { + let focusElement: HTMLButtonElement | null = null; + + switch (event.key) { + case "Enter": { + handleTabChange(event); + break; + } + case "ArrowRight": { + const nextTab = tabRefs.indexOf(event.currentTarget) + 1; + focusElement = tabRefs[nextTab] ?? tabRefs[0] ?? null; + break; + } + case "ArrowLeft": { + const prevTab = tabRefs.indexOf(event.currentTarget) - 1; + focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1] ?? null; + break; + } + default: + break; + } + + focusElement?.focus(); + }; + + const defaultTab = getValidDefaultTab(tabValues, localStorageTab); + const tabToShow = getValidTabToShow(tabValues, selectedValue, defaultTab); + return ( + + + {tabValues.map(({ value, label, attributes }) => ( + { + tabRefs.push(tabControl); + }} + onKeyDown={handleKeydown} + onClick={handleTabChange} + {...attributes} + > + {label || value} + + ))} + + + + ); +} + +function TabContent({ children }: Props & ReturnType) { + const childTabs = (Array.isArray(children) ? children : [children]).filter( + Boolean, + ) as ReactElement[]; + return childTabs.map((tabItem, i) => { + return ( + + {tabItem.props.children} + + ); + }); +} + +function TabsComponent(props: Props): ReactNode { + const tabs = useTabs(props); + const alphabetizedTabs = { + ...tabs, + tabValues: tabs.tabValues + .slice(0) + .sort((a, b) => + a.label && b.label ? a.label.localeCompare(b.label) : -1, + ), + }; + return ( +
    + +
    + ); +} + +export default function Tabs(props: Props): ReactNode { + const isBrowser = useIsBrowser(); + return ( + + {sanitizeTabsChildren(props.children)} + + ); +} diff --git a/src/theme/Tabs/styles.module.css b/src/theme/Tabs/styles.module.css new file mode 100644 index 0000000000..6619bf14e3 --- /dev/null +++ b/src/theme/Tabs/styles.module.css @@ -0,0 +1,7 @@ +.tabList { + margin-bottom: var(--ifm-leading); +} + +.tabItem { + margin-top: 0 !important; +} diff --git a/static/scripts/fix-redirect.js b/static/scripts/fix-redirect.js index 3eef39437a..4418cfc40e 100644 --- a/static/scripts/fix-redirect.js +++ b/static/scripts/fix-redirect.js @@ -830,7 +830,6 @@ const redirects = [ [fromExact("/docs/http/"), "/docs/universal-gateway/http/"], [fromExact("/docs/tcp/"), "/docs/universal-gateway/tcp/"], [fromExact("/docs/tls/"), "/docs/universal-gateway/tls/"], - // Kubernetes Operator Revamp [ fromExact("/docs/k8s/advanced-deployments/"), @@ -855,6 +854,102 @@ const redirects = [ [fromExact("/docs/k8s/custom-domain/"), "/docs/k8s/guides/custom-domain/"], [fromExact("/docs/k8s/user-guide/"), "/docs/k8s/"], [fromExact("/docs/k8s/with-edges/"), "/docs/k8s/guides/using-ingresses/"], + + // Question/Answer restructure redirects + + /** + * Universal Gateway > Concepts + */ + // Domains + [ + fromExact("/docs/universal-gateway/domains/"), + "/docs/universal-gateway/domains/what-are-domains/", + ], + // hashes + [ + fromExact("/docs/universal-gateway/domains/#branded-domains"), + "/docs/universal-gateway/domains/how-do-i-use-my-own-domain/", + ], + [ + fromExact("/docs/universal-gateway/domains/#global-load-balancer"), + "/docs/universal-gateway/global-load-balancer/", + ], + [ + fromExact("/docs/universal-gateway/domains/#public-endpoints"), + "/docs/universal-gateway/public-endpoints/", + ], + [ + fromExact("/docs/universal-gateway/domains/#ngrok-managed-domains"), + "/docs/universal-gateway/domains/what-are-managed-domains/", + ], + [ + fromExact("/docs/universal-gateway/domains/#hsts-preload"), + "/docs/universal-gateway/domains/what-are-managed-domains/#hsts-preload", + ], + [ + fromExact("/docs/universal-gateway/domains/#public-suffix-list"), + "/docs/universal-gateway/domains/what-are-managed-domains/#public-suffix-list", + ], + + // TCP Addresses + [ + fromExact("/docs/universal-gateway/tcp-addresses/"), + "/docs/universal-gateway/tcp-addresses/what-are-tcp-addresses/", + ], + // hashes + [ + fromExact( + "/docs/universal-gateway/tcp-addresses/#public-endpoint-creation", + ), + "/docs/universal-gateway/tcp-addresses/what-are-tcp-addresses/", + ], + [ + fromExact("/docs/universal-gateway/tcp-addresses/#address-assignment"), + "/docs/universal-gateway/tcp-addresses/how-are-tcp-addresses-assigned/", + ], + [ + fromExact("/docs/universal-gateway/tcp-addresses/#global-load-balancer/"), + "/docs/universal-gateway/tcp-addresses/what-are-tcp-addresses/#tcp-address-load-balancing", + ], + + //TLS Certificates + [ + fromExact("/docs/universal-gateway/tls-certificates/"), + "/docs/universal-gateway/tls-certificates/how-does-ngrok-handle-tls", + ], + // hashes + [ + fromExact("/docs/universal-gateway/tls-certificates/#automated"), + "/docs/universal-gateway/tls-certificates/what-is-automatic-certificate-management", + ], + [ + fromExact( + "/docs/universal-gateway/tls-certificates/#certificate-selection", + ), + "/docs/universal-gateway/tls-certificates/how-are-certificates-selected", + ], + [ + fromExact( + "/docs/universal-gateway/tls-certificates/#certificate-provisioning", + ), + "/docs/universal-gateway/tls-certificates/how-does-ngrok-handle-tls#how-certificates-work", + ], + [ + fromExact("/docs/universal-gateway/tls-certificates/#certificate-bundles"), + "/docs/universal-gateway/tls-certificates/what-is-a-certificate-bundle/", + ], + [ + fromExact("/docs/universal-gateway/tls-certificates/#private-keys"), + "/docs/universal-gateway/tls-certificates/what-are-private-tls-keys/", + ], + [ + fromExact("/docs/universal-gateway/http/"), + "/docs/universal-gateway/http-s/", + ], + [ + fromExact("/docs/guides/other-guides/how-to-set-up-a-custom-domain/"), + "/docs/universal-gateway/domains/bring-your-own-domain/", + ], ]; // get current href from window @@ -892,6 +987,6 @@ if (newPath !== currentPath && newPath !== window.location.pathname) { window.location.href = newPath; } else { console.error( - `ignoring redirect from ${window.location.href} to ${newPath}; looks loopy`, + "ignoring redirect from ${window.location.href} to ${newPath}; looks loopy", ); } diff --git a/traffic-policy/actions/restrict-ips/index.mdx b/traffic-policy/actions/restrict-ips/index.mdx index f6f284071b..415857f222 100644 --- a/traffic-policy/actions/restrict-ips/index.mdx +++ b/traffic-policy/actions/restrict-ips/index.mdx @@ -3,3 +3,7 @@ The **Restrict IPs** Traffic Policy action allows you to allow or deny traffic based on the source IP address of connections to your ngrok endpoints. You can define rules using either **Allow and Deny lists**, or **Reference IDs** to existing ngrok [IP Policies](/docs/api/resources/ip-policies/). + +:::note +This Traffic Policy action is great for restricting traffic to TLS endpoints. +::: diff --git a/traffic-policy/actions/terminate-tls/index.mdx b/traffic-policy/actions/terminate-tls/index.mdx index 99afe99e66..10244a7edf 100644 --- a/traffic-policy/actions/terminate-tls/index.mdx +++ b/traffic-policy/actions/terminate-tls/index.mdx @@ -1,3 +1,7 @@ ## Overview The **Terminate TLS** Traffic Policy action allows you to control how TLS traffic is terminated by ngrok. This action is useful for when you need to specify a custom certificate, control which TLS versions are supported, or enable mutual TLS authentication. + +:::note +This Traffic Policy action is great for restricting traffic to TLS endpoints. +:::