diff --git a/agent/agent-mutual-tls-termination.mdx b/agent/agent-mutual-tls-termination.mdx index 06e227831d..572f1b2f3c 100644 --- a/agent/agent-mutual-tls-termination.mdx +++ b/agent/agent-mutual-tls-termination.mdx @@ -64,13 +64,14 @@ Using the CA certificate generated in the previous step, you can specify the `mu ```yaml policy.yml on_tcp_connect: - - actions: - - type: terminate-tls - config: - mutual_tls_certificate_authorities: - - -----BEGIN CERTIFICATE----- -... certificate ... ------END CERTIFICATE----- +- actions: + - type: terminate-tls + config: + mutual_tls_certificate_authorities: + - |- + -----BEGIN CERTIFICATE----- + ... certificate ... + -----END CERTIFICATE----- ``` ```json policy.json diff --git a/getting-started/_secure-your-app.mdx b/getting-started/_secure-your-app.mdx index dc1d9a1866..92fe4f93ef 100644 --- a/getting-started/_secure-your-app.mdx +++ b/getting-started/_secure-your-app.mdx @@ -10,20 +10,20 @@ First, create a new file called `traffic-policy.yml` in the root of your project ```yaml policy.yml on_http_request: - - name: "OAuth" - actions: - - type: "oauth" - config: - auth_id: "oauth" - provider: "google" - - name: "bad email" - expressions: - - "actions.ngrok.oauth.identity.email != 'alan@example.com'" - actions: - - type: "custom-response" - config: - body: "Hey, no auth for you ${actions.ngrok.oauth.identity.name}!" - status_code: 400 +- name: OAuth + actions: + - type: oauth + config: + auth_id: oauth + provider: google +- name: bad email + expressions: + - actions.ngrok.oauth.identity.email != 'alan@example.com' + actions: + - type: custom-response + config: + body: Hey, no auth for you ${actions.ngrok.oauth.identity.name}! + status_code: 400 ``` ```json policy.json { @@ -86,20 +86,20 @@ First, create a new file called `traffic-policy.yml` in the root of your project ```yaml policy.yml on_http_request: - - name: OAuth - actions: - - type: oauth - config: - auth_id: oauth - provider: google - - name: bad email - expressions: - - actions.ngrok.oauth.identity.email != 'alan@example.com' - actions: - - type: custom-response - config: - body: Hey, no auth for you ${actions.ngrok.oauth.identity.name}! - status_code: 400 +- name: OAuth + actions: + - type: oauth + config: + auth_id: oauth + provider: google +- name: bad email + expressions: + - actions.ngrok.oauth.identity.email != 'alan@example.com' + actions: + - type: custom-response + config: + body: Hey, no auth for you ${actions.ngrok.oauth.identity.name}! + status_code: 400 ``` ```json policy.json diff --git a/traffic-policy/examples/a-b-tests.mdx b/traffic-policy/examples/a-b-tests.mdx index 956656eaca..32b9deb7bd 100644 --- a/traffic-policy/examples/a-b-tests.mdx +++ b/traffic-policy/examples/a-b-tests.mdx @@ -19,16 +19,16 @@ This rule: ```yaml policy.yml on_http_request: - - expressions: - - rand.double() <= 0.5 - actions: - - type: forward-internal - config: - url: https://a.internal - - actions: - - type: forward-internal - config: - url: https://b.internal +- expressions: + - rand.double() <= 0.5 + actions: + - type: forward-internal + config: + url: https://a.internal +- actions: + - type: forward-internal + config: + url: https://b.internal ``` ```json policy.json @@ -77,17 +77,17 @@ You can also send the traffic to a different route using url rewrites. ```yaml policy.yml on_http_request: - - expressions: - - rand.double() <= 0.5 - actions: - - type: url-rewrite - config: - from: /path/to/test - to: /path/to/test-b - - actions: - - type: forward-internal - config: - url: https://b.internal +- expressions: + - rand.double() <= 0.5 + actions: + - type: url-rewrite + config: + from: "/path/to/test" + to: "/path/to/test-b" +- actions: + - type: forward-internal + config: + url: https://b.internal ``` ```json policy.json diff --git a/traffic-policy/examples/add-and-remove-headers.mdx b/traffic-policy/examples/add-and-remove-headers.mdx index de67150dde..743e0123df 100644 --- a/traffic-policy/examples/add-and-remove-headers.mdx +++ b/traffic-policy/examples/add-and-remove-headers.mdx @@ -16,16 +16,16 @@ This rule adds multiple headers to the request, including the client's IP addres ```yaml policy.yml on_http_request: - - actions: - - type: add-headers - config: - headers: - x-is-ngrok: 1 - x-endpoint-id: ${endpoint.id} - x-client-ip: ${conn.client_ip} - x-client-conn-start: ${conn.ts.start} - x-client-loc: ${conn.geo.city}, ${conn.geo.country} - x-client-path: ${req.url.path} +- actions: + - type: add-headers + config: + headers: + x-is-ngrok: '1' + x-endpoint-id: "${endpoint.id}" + x-client-ip: "${conn.client_ip}" + x-client-conn-start: "${conn.ts.start}" + x-client-loc: "${conn.geo.city}, ${conn.geo.country}" + x-client-path: "${req.url.path}" ``` ```json policy.json @@ -66,11 +66,11 @@ This rule removes the `X-Powered-By` header. ```yaml policy.yml on_http_request: - - actions: - - type: remove-headers - config: - headers: - - X-Powered-By +- actions: + - type: remove-headers + config: + headers: + - X-Powered-By ``` ```json policy.json @@ -109,14 +109,15 @@ This rule: ```yaml policy.yml on_http_request: - - expressions: - - "'2' in req.headers['X-Api-Version']" - name: "Deprecate API v2" - actions: - - type: "custom-response" - config: - status_code: 400 - body: '{"error":{"message":"Version 2 of the API is no longer supported. Use Version 3 instead."}}' +- expressions: + - "'2' in req.headers['X-Api-Version']" + name: Deprecate API v2 + actions: + - type: custom-response + config: + status_code: 400 + body: '{"error":{"message":"Version 2 of the API is no longer supported. Use + Version 3 instead."}}' ``` ```json policy.json diff --git a/traffic-policy/examples/add-authentication.mdx b/traffic-policy/examples/add-authentication.mdx index c701a15f93..5293938707 100644 --- a/traffic-policy/examples/add-authentication.mdx +++ b/traffic-policy/examples/add-authentication.mdx @@ -12,37 +12,37 @@ This rule adds key-based rate limiting to your endpoints based on your consumers ```yaml policy.yml on_http_request: - - name: Add JWT authentication and rate limiting - actions: - - type: rate-limit - config: - name: Only allow 30 requests per minute - algorithm: sliding_window - capacity: 30 - rate: 60s - bucket_key: - - req.headers['x-api-key'] - - type: jwt-validation - config: - issuer: - allow_list: - - value: https:// - audience: - allow_list: - - value: - http: - tokens: - - type: jwt - method: header - name: Authorization - prefix: Bearer - jws: - allowed_algorithms: - - RS256 - keys: - sources: - additional_jkus: - - https:///.well-known/jwks.json +- name: Add JWT authentication and rate limiting + actions: + - type: rate-limit + config: + name: Only allow 30 requests per minute + algorithm: sliding_window + capacity: 30 + rate: 60s + bucket_key: + - req.headers['x-api-key'] + - type: jwt-validation + config: + issuer: + allow_list: + - value: https:// + audience: + allow_list: + - value: "" + http: + tokens: + - type: jwt + method: header + name: Authorization + prefix: 'Bearer ' + jws: + allowed_algorithms: + - RS256 + keys: + sources: + additional_jkus: + - https:///.well-known/jwks.json ``` ```json policy.json @@ -128,28 +128,28 @@ This rule grants conditional access to a page using the following ngrok [OAuth a ```yaml policy.yml on_http_request: - - name: OAuth - actions: - - type: oauth - config: - auth_id: oauth - provider: google - - name: good email - expressions: - - actions.ngrok.oauth.identity.email.endsWith('@ngrok.com') - actions: - - type: custom-response - config: - body: Welcome ${actions.ngrok.oauth.identity.name}! - status_code: 200 - - name: bad email - expressions: - - !actions.ngrok.oauth.identity.email.endsWith('@ngrok.com') - actions: - - type: custom-response - config: - body: Hey, no auth for you ${actions.ngrok.oauth.identity.name}! - status_code: 400 +- name: OAuth + actions: + - type: oauth + config: + auth_id: oauth + provider: google +- name: good email + expressions: + - actions.ngrok.oauth.identity.email.endsWith('@ngrok.com') + actions: + - type: custom-response + config: + body: Welcome ${actions.ngrok.oauth.identity.name}! + status_code: 200 +- name: bad email + expressions: + - "!actions.ngrok.oauth.identity.email.endsWith('@ngrok.com')" + actions: + - type: custom-response + config: + body: Hey, no auth for you ${actions.ngrok.oauth.identity.name}! + status_code: 400 ``` ```json policy.json @@ -213,23 +213,23 @@ This rule uses the `actions.ngrok.oidc.identity_token` [OIDC action result varia ```yaml policy.yml on_http_request: - - name: OIDC - actions: - - type: openid-connect - config: - issuer_url: https://accounts.google.com - client_id: - client_secret: - scopes: - - openid - - profile - - email - - name: Headers - actions: - - type: add-headers - config: - headers: - id-token: ${actions.ngrok.oidc.identity_token} +- name: OIDC + actions: + - type: openid-connect + config: + issuer_url: https://accounts.google.com + client_id: "" + client_secret: "" + scopes: + - openid + - profile + - email +- name: Headers + actions: + - type: add-headers + config: + headers: + id-token: "${actions.ngrok.oidc.identity_token}" ``` ```json policy.json diff --git a/traffic-policy/examples/compress-json-responses.mdx b/traffic-policy/examples/compress-json-responses.mdx index f621a53361..5fb59747d6 100644 --- a/traffic-policy/examples/compress-json-responses.mdx +++ b/traffic-policy/examples/compress-json-responses.mdx @@ -17,15 +17,15 @@ If your upstream service already handles compression, ngrok skips this step. ```yaml policy.yml on_http_response: - - name: Add compression - actions: - - type: compress-response - config: - algorithms: - - gzip - - br - - deflate - - compress +- name: Add compression + actions: + - type: compress-response + config: + algorithms: + - gzip + - br + - deflate + - compress ``` ```json policy.json diff --git a/traffic-policy/examples/enforce-tls.mdx b/traffic-policy/examples/enforce-tls.mdx index 2bfca5e4e5..1cba1bcbb8 100644 --- a/traffic-policy/examples/enforce-tls.mdx +++ b/traffic-policy/examples/enforce-tls.mdx @@ -3,8 +3,6 @@ title: Enforce TLS Example sidebarTitle: Enforce TLS --- - - With Traffic Policy, you can prevent obsolete and potentially vulnerable browsers, SDKs, or CLI tools like `curl` from attempting to access your API. This rule: @@ -16,14 +14,14 @@ This rule: ```yaml policy.yml on_http_request: - - name: Reject requests using old TLS versions - expressions: - - conn.tls.version < '1.3' - actions: - - type: custom-response - config: - status_code: 401 - body: Unauthorized: TLS version too old +- name: Reject requests using old TLS versions + expressions: + - conn.tls.version < '1.3' + actions: + - type: custom-response + config: + status_code: 401 + body: 'Unauthorized: TLS version too old' ``` ```json policy.json diff --git a/traffic-policy/examples/event-logging.mdx b/traffic-policy/examples/event-logging.mdx index 5eaa04a3fb..f52d85d949 100644 --- a/traffic-policy/examples/event-logging.mdx +++ b/traffic-policy/examples/event-logging.mdx @@ -3,8 +3,6 @@ title: Event Logging Example sidebarTitle: Event Logging --- - - With Traffic Policy, you can connect your API to ngrok's [log exporting system](/obs/) for smarter troubleshooting, testing, and integration of logging services like Datadog for your API gateway and upstream services. This rule: @@ -16,24 +14,25 @@ This rule: ```yaml policy.yml on_http_request: - - actions: - - type: custom-response - config: - status_code: 503 - body:

Service Unavailable

Our servers are currently down for maintenance. Please check back later.

- headers: - content-type: text/html +- actions: + - type: custom-response + config: + status_code: 503 + body: "

Service Unavailable

Our servers are currently + down for maintenance. Please check back later.

" + headers: + content-type: text/html on_http_response: - - name: Log unsuccessful requests - expressions: - - res.status_code < '200' && res.status_code >= '300' - actions: - - type: log - config: - metadata: - message: Unsuccessful request - edge_id: - success: false +- name: Log unsuccessful requests + expressions: + - res.status_code < '200' && res.status_code >= '300' + actions: + - type: log + config: + metadata: + message: Unsuccessful request + edge_id: "" + success: false ``` ```json policy.json diff --git a/traffic-policy/examples/oauth-protection.mdx b/traffic-policy/examples/oauth-protection.mdx index bb68ccb3e5..39ccaf8dd9 100644 --- a/traffic-policy/examples/oauth-protection.mdx +++ b/traffic-policy/examples/oauth-protection.mdx @@ -37,10 +37,10 @@ Create this traffic policy file in the same directory where you run your ngrok a ```yaml policy.yml on_http_request: - - actions: - - type: oauth - config: - provider: google +- actions: + - type: oauth + config: + provider: google ``` ```json policy.json @@ -131,19 +131,19 @@ This section includes two examples of how to apply these additional auth lifecyc ```yaml policy.yml on_http_request: - - expressions: - - req.url.path == '/ngrok/logout' - actions: - - type: redirect - config: - location: /ngrok/login?auth_id=my-login - - actions: - - type: oauth - config: - provider: google - auth_id: my-login - idle_session_timeout: 15m - max_session_duration: 1h +- expressions: + - req.url.path == '/ngrok/logout' + actions: + - type: redirect + config: + location: "/ngrok/login?auth_id=my-login" +- actions: + - type: oauth + config: + provider: google + auth_id: my-login + idle_session_timeout: 15m + max_session_duration: 1h ``` ```json policy.json diff --git a/traffic-policy/examples/rate-limit-requests.mdx b/traffic-policy/examples/rate-limit-requests.mdx index 0c43e80586..c0bbec3a6f 100644 --- a/traffic-policy/examples/rate-limit-requests.mdx +++ b/traffic-policy/examples/rate-limit-requests.mdx @@ -17,17 +17,17 @@ This rule applies rate limiting of 30 requests per minute to the endpoint `/api/ ```yaml policy.yml on_http_request: - - expressions: - - req.url.contains('/api/specific_endpoint') - actions: - - type: rate-limit - config: - name: Only allow 30 requests per minute - algorithm: sliding_window - capacity: 30 - rate: 60s - bucket_key: - - conn.client_ip +- expressions: + - req.url.contains('/api/specific_endpoint') + actions: + - type: rate-limit + config: + name: Only allow 30 requests per minute + algorithm: sliding_window + capacity: 30 + rate: 60s + bucket_key: + - conn.client_ip ``` ```json policy.json @@ -66,30 +66,30 @@ This rule creates a lower rate limit for unauthenticated (likely free) users, wh ```yaml policy.yml on_http_request: - - expressions: - - !('Authorization' in req.headers) - name: Unauthorized rate limiting tier - actions: - - type: rate-limit - config: - name: Allow 10 requests per minute - algorithm: sliding_window - capacity: 10 - rate: 60s - bucket_key: - - conn.client_ip - - expressions: - - ('Authorization' in req.headers) - name: Authorized rate limiting tier - actions: - - type: rate-limit - config: - name: Allow 100 requests per minute - algorithm: sliding_window - capacity: 100 - rate: 60s - bucket_key: - - conn.client_ip +- expressions: + - "!('Authorization' in req.headers)" + name: Unauthorized rate limiting tier + actions: + - type: rate-limit + config: + name: Allow 10 requests per minute + algorithm: sliding_window + capacity: 10 + rate: 60s + bucket_key: + - conn.client_ip +- expressions: + - "('Authorization' in req.headers)" + name: Authorized rate limiting tier + actions: + - type: rate-limit + config: + name: Allow 100 requests per minute + algorithm: sliding_window + capacity: 100 + rate: 60s + bucket_key: + - conn.client_ip ``` ```json policy.json @@ -151,54 +151,54 @@ This rule checks for a `Tier` header in the request and applies rate limiting ba ```yaml policy.yml on_http_request: - - expressions: - - !('Tier' in req.headers) - name: Free rate limiting tier - actions: - - type: rate-limit - config: - name: Allow 10 requests per minute - algorithm: sliding_window - capacity: 10 - rate: 60s - bucket_key: - - conn.client_ip - - expressions: - - getReqHeader('tier').exists(v, v.matches('(?i)bronze')) - name: Bronze rate limiting tier - actions: - - type: rate-limit - config: - name: Allow 100 requests per minute - algorithm: sliding_window - capacity: 100 - rate: 60s - bucket_key: - - conn.client_ip - - expressions: - - getReqHeader('tier').exists(v, v.matches('(?i)silver')) - name: Bronze rate limiting tier - actions: - - type: rate-limit - config: - name: Allow 1000 requests per minute - algorithm: sliding_window - capacity: 1000 - rate: 60s - bucket_key: - - conn.client_ip - - expressions: - - getReqHeader('tier').exists(v, v.matches('(?i)gold')) - name: Gold rate limiting tier - actions: - - type: rate-limit - config: - name: Allow 10000 requests per minute - algorithm: sliding_window - capacity: 10000 - rate: 60s - bucket_key: - - conn.client_ip +- expressions: + - "!('Tier' in req.headers)" + name: Free rate limiting tier + actions: + - type: rate-limit + config: + name: Allow 10 requests per minute + algorithm: sliding_window + capacity: 10 + rate: 60s + bucket_key: + - conn.client_ip +- expressions: + - getReqHeader('tier').exists(v, v.matches('(?i)bronze')) + name: Bronze rate limiting tier + actions: + - type: rate-limit + config: + name: Allow 100 requests per minute + algorithm: sliding_window + capacity: 100 + rate: 60s + bucket_key: + - conn.client_ip +- expressions: + - getReqHeader('tier').exists(v, v.matches('(?i)silver')) + name: Bronze rate limiting tier + actions: + - type: rate-limit + config: + name: Allow 1000 requests per minute + algorithm: sliding_window + capacity: 1000 + rate: 60s + bucket_key: + - conn.client_ip +- expressions: + - getReqHeader('tier').exists(v, v.matches('(?i)gold')) + name: Gold rate limiting tier + actions: + - type: rate-limit + config: + name: Allow 10000 requests per minute + algorithm: sliding_window + capacity: 10000 + rate: 60s + bucket_key: + - conn.client_ip ``` ```json policy.json diff --git a/traffic-policy/examples/route-requests.mdx b/traffic-policy/examples/route-requests.mdx index da814bb07e..dffd641e9a 100644 --- a/traffic-policy/examples/route-requests.mdx +++ b/traffic-policy/examples/route-requests.mdx @@ -3,8 +3,6 @@ title: Route Request Examples sidebarTitle: Route Requests --- - - With Traffic Policy, you can use [CEL interpolation](/traffic-policy/concepts/cel-interpolation) to dynamically forward requests to different internal endpoints based on URL request attributes, including but not limited to: - URL @@ -26,11 +24,11 @@ This rule forwards requests from `https://*.example.com` to `https:// ```yaml policy.yml on_http_request: - - name: Route requests based on URL - actions: - - type: forward-internal - config: - url: https://${req.host.split(".example.com")[0]}.internal +- name: Route requests based on URL + actions: + - type: forward-internal + config: + url: https://${req.host.split(".example.com")[0]}.internal ``` ```json policy.json @@ -62,9 +60,9 @@ This rule forwards requests containing a `X-Customer-Value: {CUSTOMER}` header t ```yaml policy.yml on_http_request: actions: - - type: forward-internal - config: - url: https://${getReqHeader('X-Customer-Value')[0]}.internal + - type: forward-internal + config: + url: https://${getReqHeader('X-Customer-Value')[0]}.internal ``` ```json policy.json diff --git a/traffic-policy/examples/url-rewrites.mdx b/traffic-policy/examples/url-rewrites.mdx index 2bca788e3f..f7bf0a722e 100644 --- a/traffic-policy/examples/url-rewrites.mdx +++ b/traffic-policy/examples/url-rewrites.mdx @@ -3,8 +3,6 @@ title: URL Rewrites Examples sidebarTitle: URL Rewrites --- - - With Traffic Policy, you can map permalinks to "pretty" alternatives that are easier for both humans and [SEO bots](https://developers.google.com/search/docs/crawling-indexing/googlebot) to understand. This is especially useful for blogs that use a CMS, since the generated permalinks might be affecting your SEO performance. This rule rewrites a user-friendly URL like @@ -14,13 +12,13 @@ This rule rewrites a user-friendly URL like ```yaml policy.yml on_http_request: - - expressions: - - req.url.path.startsWith('/blog') - actions: - - type: url-rewrite - config: - from: /blog/([0-9]+)/([a-zA-Z]+)/ - to: /blog/index.php?p=$1&title=$2 +- expressions: + - req.url.path.startsWith('/blog') + actions: + - type: url-rewrite + config: + from: "/blog/([0-9]+)/([a-zA-Z]+)/" + to: "/blog/index.php?p=$1&title=$2" ``` ```json policy.json diff --git a/traffic-policy/examples/user-agent-filtering.mdx b/traffic-policy/examples/user-agent-filtering.mdx index 5b05a49577..3986ec733f 100644 --- a/traffic-policy/examples/user-agent-filtering.mdx +++ b/traffic-policy/examples/user-agent-filtering.mdx @@ -13,13 +13,13 @@ This rule delivers tailored content to Microsoft Edge users by matching on the ` ```yaml policy.yml on_http_request: - - expressions: - - req.user_agent.name == 'Edge' - actions: - - type: custom-response - config: - status_code: 200 - body: Hello Edge User! +- expressions: + - req.user_agent.name == 'Edge' + actions: + - type: custom-response + config: + status_code: 200 + body: Hello Edge User! ``` ```json policy.json @@ -51,12 +51,12 @@ You can also quickly block bots from your site by denying them by user-agent usi ```yaml policy.yml on_http_request: - - expressions: - - req.user_agent.is_bot - actions: - - type: deny - config: - status_code: 403 +- expressions: + - req.user_agent.is_bot + actions: + - type: deny + config: + status_code: 403 ``` ```json policy.json diff --git a/universal-gateway/cloud-endpoints/forwarding-and-load-balancing.mdx b/universal-gateway/cloud-endpoints/forwarding-and-load-balancing.mdx index 7553116890..2fc88f81bc 100644 --- a/universal-gateway/cloud-endpoints/forwarding-and-load-balancing.mdx +++ b/universal-gateway/cloud-endpoints/forwarding-and-load-balancing.mdx @@ -114,10 +114,10 @@ and most common use cases: forwarding traffic to other endpoints ```yaml policy.yml on_http_request: - - actions: - - type: forward-internal - config: - url: https://your-domain-name.internal +- actions: + - type: forward-internal + config: + url: https://your-domain-name.internal ``` ```json policy.json diff --git a/universal-gateway/cloud-endpoints/routing-and-policy-decentralization.mdx b/universal-gateway/cloud-endpoints/routing-and-policy-decentralization.mdx index 94b4b452d0..0ddf7a947d 100644 --- a/universal-gateway/cloud-endpoints/routing-and-policy-decentralization.mdx +++ b/universal-gateway/cloud-endpoints/routing-and-policy-decentralization.mdx @@ -4,9 +4,6 @@ sidebarTitle: Path-based Forwarding description: How to use ngrok cloud endpoints to route by path, and have different traffic policies for each endpoint. --- - - - This guide provides an example on how to forward traffic to internal endpoints based on path using ngrok Cloud Endpoints. The cloud endpoint will have a traffic policy to route traffic to one of two internal endpoints depending on the path, but each internal endpoint will also have its own traffic policy to independently handle incoming traffic. ## Core Concepts @@ -48,19 +45,20 @@ We will use a traffic policy to simulate accessing an API endpoint. ```yaml policy.yml on_http_request: - - expressions: - - !(hasReqHeader('Api-Key')) - actions: - - type: deny - config: - status_code: 404 - - actions: - - type: custom-response - config: - status_code: 200 - body:

Hello world

The quick brown fox jumps over the lazy dog.

- headers: - content-type: text/html +- expressions: + - "!(hasReqHeader('Api-Key'))" + actions: + - type: deny + config: + status_code: 404 +- actions: + - type: custom-response + config: + status_code: 200 + body: "

Hello world

The quick brown fox jumps over the + lazy dog.

" + headers: + content-type: text/html ``` ```json policy.json @@ -186,18 +184,18 @@ full control over how traffic is handled. ```yaml policy.yml on_http_request: - - expressions: - - req.url.path.startsWith('/api/') - actions: - - type: forward-internal - config: - url: https://api.internal - binding: internal - - actions: - - type: forward-internal - config: - url: https://homepage.internal - binding: internal +- expressions: + - req.url.path.startsWith('/api/') + actions: + - type: forward-internal + config: + url: https://api.internal + binding: internal +- actions: + - type: forward-internal + config: + url: https://homepage.internal + binding: internal ``` ```json policy.json