Get started - Deliver and secure APIs in production
You've developed a world-class API, and now you want to make it available for clients to access. This guide takes you from bringing your API online in one line to configuring an API gateway that simplifies routing, security, contract management, protocol translation, and more, providing a single point of entry for clients and services accessing your APIs.
Prerequisites
You'll need an ngrok account to follow the steps in this guide. You can sign up for free if you don't already have one.
You'll also need a deployed API to manage with ngrok. If you're just getting started or performing a proof-of-concept, you can deploy our sample REST API for testing purposes. In that case, you'll also need git installed.
Install the ngrok agent
Download the appropriate version of the ngrok agent, and install it on the same subnet as the API you wish to manage.
Create an ngrok API key
Create an ngrok API key using the ngrok dashboard. Make sure you save the API key before you leave the screen because it won't be displayed again.
Add the API key to the ngrok agent
Run the following command to add the API key to your ngrok agent, substituting your API key for {API_KEY}
:
ngrok config add-api-key {API_KEY}
Setup sample API
To test the policy actions in this guide, you can use the sample API to simulate an environment with multiple APIs deployed and managed independently.
Clone the repo:
git clone git@github.com:ngrok-samples/ngrok-rest-api.git
Install dependencies:
npm install
Start the application on the default port (8001
):
npm run start
Locate src/index.js
, and modify the PORT
value to 8002
:
const PORT = 8001; // Change to 8002
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Start a second instance:
npm run start
Create an internal endpoint
Create an internal endpoint for one of the instances of the API by running the following command:
ngrok http 8001 --url=https://api.internal
Reserve a domain
Run the following command to reserve a domain:
ngrok api reserved-domains create --url {NGROK_SUBDOMAIN}.ngrok.app
If the subdomain you chose is already in use, you'll get a 400
error with a message to that effect. In that case, run the
command again with a different subdomain. Alternatively, you can reserve the domain through the dashboard,
which will show you which subdomains are available as you type.
This example uses an
ngrok-managed domain, but you can use
your own branded domain when you're ready for production.
In that case, substitute your branded subdomain for {NGROK_SUBDOMAIN}.ngrok.app
in the command above, and
follow the steps
to configure DNS.
Bring your API online
You've created an internal endpoint to one of the instances of your API, but you need a cloud endpoint to receive traffic and apply policies before forwarding requests to your backend service via the internal endpoints. You'll start by bringing one of the instances online.
Create a traffic policy file
Unlike other endpoint types, cloud endpoints must contain at least one traffic policy action which specifies a forward-internal
action
and the URL to an internal endpoint where traffic should be forwarded.
Create a file called policies.yaml
and paste the following contents:
---
on_http_request:
- actions:
- type: forward-internal
config:
url: https://api.internal
binding: internal
Create a cloud endpoint
Run the following command from the same directory where you created policies.yaml
to create a cloud endpoint, substituting the
subdomain (i.e. mydomain.ngrok.app
) you reserved in the previous step for {YOUR_DOMAIN}
:
ngrok api endpoints create \
--bindings public \
--description "sample description" \
--metadata sample-metadata \
--url https://{YOUR_DOMAIN} \
--traffic-policy "$(cat policies.yaml)"
You'll receive a 201
response similar to the following:
{
"bindings": [
"public"
],
"created_at": "2024-10-25T14:35:28Z",
"description": "sample description",
"domain": {
"id": "rd_2nvupgtpY4RuEPITujbfHpkhxmO",
"uri": "https://api.ngrok.com/reserved_domains/rd_2nvupgtpY4RuEPITujbfHpkhxmO"
},
"hostport": "mydomain.ngrok.app:443",
"id": "ep_2nvwbSCefcZv0At2ewhzMHPBT3V",
"metadata": "sample-metadata",
"proto": "https",
"public_url": "https://mydomain.ngrok.app",
"traffic_policy": "{\"on_http_request\":[{\"actions\":[{\"type\":\"forward-internal\",\"config\":{\"url\":\"https://mandy.ngrok.internal\",\"binding\":\"internal\"}}]}]}",
"type": "cloud",
"updated_at": "2024-10-25T14:35:28Z",
"uri": "https://api.ngrok.com/endpoints/ep_2nvwbSCefcZv0At2ewhzMHPBT3V",
"url": "https://mydomain.ngrok.app"
}
Save the value of id
because you'll need it in a later step.
Access your API
You can now access the sample API via the subdomain you reserved above. For example,
you can run the following command to access the cards
endpoint:
curl -X GET https://{YOUR_SUBDOMAIN}.ngrok.app/cards
You'll receive a 200
response similar to to the following:
{
"cards": [
{
"id": "ccof:uIbfJXhXETSP197M3GB",
"billing_address": {
"address_line_1": "500 Electric Ave",
"address_line_2": "Suite 600",
"locality": "New York",
"administrative_district_level_1": "NY",
"postal_code": "10003",
"country": "US"
},
"bin": "411111",
"card_brand": "VISA",
"card_type": "CREDIT",
"cardholder_name": "Amelia Earhart",
"customer_id": "VDKXEEKPJN48QDG3BGGFAK05P8",
"enabled": true,
"exp_month": 11,
"exp_year": 2018,
"last_4": "1111",
"prepaid_type": "NOT_PREPAID",
"reference_id": "user-id-1",
"version": 1
}
]
}
Stop the agent to remove the internal endpoint you just created.
Manage APIs with traffic policy actions
Your API is now online, but it is completely exposed to the outside world. Next, add some traffic policy actions to authenticate
requests and shape the traffic that reaches your backend service. You'll do this by running a command to update the configuration
of your existing cloud endpoint, so you'll need the id
from the previous step.
If you didn't save the id when you created
the cloud endpoint, run the following command, locate your endpoint, and grab its id
:
ngrok api endpoints list
Route by headers
You can configure traffic policy actions to direct traffic based on HTTP header values.
Start internal endpoints
To implement this example, run each of the following commands in a separate terminal to start internal endpoints to the two instances of the sample API:
ngrok http 8001 --url=https://v1.api.internal
ngrok http 8002 --url=https://v2.api.internal
Update traffic policies
This example looks for a header named X-Api-Version
and routes traffic to different instances of the /cards
endpoint of the sample API.
Feel free to modify it for your own API if you're not using the sample app. Update your policies.yaml
file with the contents below,
overwriting all previous contents:
# Route by header
---
on_http_request:
- expressions:
- "'1' in req.headers['x-api-version']"
actions:
- type: forward-internal
config:
url: https://v1.api.internal
binding: internal
- expressions:
- "'2' in req.headers['x-api-version']"
actions:
- type: forward-internal
config:
url: https://v2.api.internal
binding: internal
- actions:
- type: forward-internal
config:
url: https://v2.api.internal
binding: internal
You must always include the forward-internal
action as the final step in your policy action since once it executes,
no subsequent policy actions will be executed. Additionally, you always need a terminating policy action.
In this case, the traffic forwards to https://v2.api.internal
if the header is set to a value other than 1
or 2
or
if the header isn't present in the request.
Run the following command, substituting your {ENDPOINT_ID}
, to update the cloud endpoint with the new policy actions:
ngrok api endpoints update {ENDPOINT_ID} --traffic-policy "$(cat policies.yaml)"
Test traffic policies
You can test this by passing a header value when you send a request to this API. Try it with version 1.
curl -X GET https://{YOUR_SUBDOMAIN}.ngrok.app/cards --header "X-Api-Version: 1"
You'll receive a 200
response similar to to the following:
{
"cards": [
{
"id": "ccof:uIbfJXhXETSP197M3GB",
"billing_address": {
"address_line_1": "500 Electric Ave",
"address_line_2": "Suite 600",
"locality": "New York",
"administrative_district_level_1": "NY",
"postal_code": "10003",
"country": "US"
},
"bin": "411111",
"card_brand": "VISA",
"card_type": "CREDIT",
"cardholder_name": "Amelia Earhart",
"customer_id": "VDKXEEKPJN48QDG3BGGFAK05P8",
"enabled": true,
"exp_month": 11,
"exp_year": 2018,
"last_4": "1111",
"prepaid_type": "NOT_PREPAID",
"reference_id": "user-id-1",
"version": 1
}
]
}
Go to the terminal where you started the internal endpoint https://v1.api.internal
on port 8001
, and you'll see the request hit
the correct endpoint.
ngrok (Ctrl+C to quit)
Found a bug? Let us know: https://github.com/ngrok/ngrok
Session Status online
Account ngrok Marketing Team (Plan: All)
Version 3.18.1
Region United States (us)
Latency 97ms
Web Interface http://127.0.0.1:4040
Forwarding https://v1.api.internal -> http://localhost:8001
Connections ttl opn rt1 rt5 p50 p90
0 1 0.00 0.00 0.00 0.00
HTTP Requests
-------------
15:00:14.035 CDT GET /cards 200 OK
Change the header value to 2
and run the command again. You should see this request hit the https://v2.api.internal
endpoint on port 8002
.
Stop both agent instances to remove the internal endpoints you just created.
Route by path
Path-based routing enables you to direct traffic to different backend services based on the value of the path.
Start internal endpoints
To implement this example, run the following commands in separate terminals to start internal endpoints to the two instances of the sample API:
ngrok http 8001 --url=https://companyA.api.internal
ngrok http 8002 --url=https://companyB.api.internal
Update traffic policies
This example routes traffic to two different backends depending on the path. Copy the following contents into your policy.yaml
file, overwriting all previous contents:
# Route by path
---
on_http_request:
# Handle /cards/*
- expressions:
- req.url.path.startsWith('/cards/')
actions:
- type: forward-internal
config:
url: http://companyA.api.internal
# Handle /payments/*
- expressions:
- req.url.path.startsWith('/payments/')
actions:
- type: forward-internal
config:
url: http://companyB.api.internal
You must always include the forward-internal
action as the final step in your policy action since once it executes,
no subsequent policy actions will be executed. Additionally, you always need a terminating policy action.
In this case, the traffic forwards to https://companyB.api.internal if the path begins with a value other than /cards
or /payments
Now, run the following command to apply the new policies to your cloud endpoint.
ngrok api endpoints update {ENDPOINT_ID} --traffic-policy "$(cat policies.yaml)"
Test traffic policies
Run the following command to hit the /cards
endpoint:
curl -X GET https://{YOUR_SUBDOMAIN}.ngrok.app/cards
Examine the terminal where you started the https://companyA.api.internal
endpoint on port 8001
, and you can
see that the request hit the correct endpoint. Repeat the steps for the /payments
endpoint and confirm the request
was sent to the https://companyB.api.internal
endpoint on port 8002
.
Stop both agent instances to remove the internal endpoints you just created.
Configure URL rewrites
The URL Rewrite traffic policy action allows you to modify the incoming request URL using regular expressions before it reaches the upstream service, without changing the URL seen by the client. This action allows you to route user requests without exposing internal system details.
Start an internal endpoint
Run the following command to start an internal endpoint:
ngrok http 8001 --url=https://api.internal
Update traffic policies
These traffic policies allow you to redirect requests sent to the /credit-cards
endpoint to the /cards
endpoint
without the client seeing the backend URL. Copy the following contents into your policy.yaml file, overwriting all previous contents:
# URL Rewrite
---
on_http_request:
- expressions:
- "req.url.path == '/credit-cards'"
actions:
- type: url-rewrite
config:
from: credit-cards
to: cards
- actions:
- type: forward-internal
config:
url: https://api.internal
binding: internal
You must always include the forward-internal
action as the final step in your policy action since once it executes,
no subsequent policy actions will be executed. Additionally, you always need a terminating policy action.
In this case, the traffic forwards to https://api.internal
if a path other than /credit-cards
is encountered.
Test traffic policies
Run the following command to hit the /credit-cards
endpoint, which doesn't exist, and confirm that you are redirected
to the /cards
endpoint instead:
curl -X GET https://{YOUR_SUBDOMAIN}.ngrok.app/credit-cards
Stop the agent to remove the internal endpoint you just created.
Enable rate limiting
Add rate limiting to your API gateway to ensure your service does not become overwhelmed by too many requests and that each of your clients has fair access to your API.
Start an internal endpoint
Run the following command to start an internal endpoint:
ngrok http 8001 --url=https://api.internal
Update traffic policies
This traffic policy action allows 30 requests over a 60 second window based on the API key of the client as determined by the value of the HTTP header. You can also limit by endpoint, authentication status, or pricing tier.
Copy the following contents into your policy.yaml file, overwriting all previous contents:
# Rate Limiting
---
on_http_request:
- expressions: []
name: Add 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']
- actions:
- type: forward-internal
config:
url: https://api.internal
binding: internal
You must always include the forward-internal
action as the final step in your policy action since once it executes,
no subsequent policy actions will be executed.
Run the following command, substituting your {ENDPOINT_ID}
, to update the cloud endpoint with the new policy actions:
ngrok api endpoints update {ENDPOINT_ID} --traffic-policy "$(cat policies.yaml)"
Test traffic policies
You can test the rate limiting action by running the following command, substituting the appropriate value for {YOUR_DOMAIN}
:
for i in `seq 1 50`; do curl -X GET -w '%{http_code}' https://{YOUR_DOMAIN}/ ; done
You'll see a response similar to the first example until you
hit the rate limit, and then you'll see 429
errors returned.
Stop the agent to remove the internal endpoint you just created.
Add JWT validation
The JWT Validation policy action allows you to integrate your ngrok endpoints with your existing auth provider. This example provides step-by-step instructions for integrating with Auth0, but you can configure JWT validation for any OAuth provider. Check out our integrations guides for specific examples.
Define your API in Auth0
- Login to your Auth0 Tenant Dashboard:
- Select Applications > APIs
- Click + Create API
- Name your API whatever you'd like
- Add your ngrok domain as the identifier
- Leave the default values for JSON Web Token (JWT) Profile * and JSON Web Token Signing Algorithm *
- Click Create
Access your JWT
Upon creating your new API, Auth0 will create an associated application under Applications > APIs in the left navigation bar.
Navigate to your application, and click on the Test
tab. Here, you will
find a signed, fully functional JWT, as well as examples of how to programmatically
generate one.
Start an internal endpoint
Run the following command to start an internal endpoint:
ngrok http 8001 --url=https://api.internal
Update traffic policies
This traffic policy integrates ngrok with your auth provider so ngrok can validate JWTs passed in requests to your API.
You must always include the forward-internal
action as the final step in your policy action since once it executes,
no subsequent policy actions will be executed.
Copy the following contents into your policy.yaml
file, overwriting all previous contents:
---
on_http_request:
- actions:
- type: "jwt-validation"
config:
issuer:
allow_list:
- value: "https://{YOUR_AUTH0_TENANT_ID}.us.auth0.com/"
audience:
allow_list:
- value: "https://{YOUR_NGROK_DOMAIN}"
http:
tokens:
- type: "jwt"
method: "header"
name: "Authorization"
prefix: "Bearer "
jws:
allowed_algorithms:
- "RS256"
keys:
sources:
additional_jkus:
- "https://{YOUR_AUTH0_TENANT_ID}.us.auth0.com/.well-known/jwks.json"
- name: "Forward internal"
actions:
- type: "forward-internal"
config:
url: "https://api.internal"
binding: internal
Test traffic policies
You can test the JWT validation policy by running the following command, substituting your domain for {YOUR_NGROK_DOMAIN}
and
the JWT obtained from the Auth0 dashboard for {YOUR_JWT}
:
curl -X GET https://{YOUR_NGROK_DOMAIN}/cards \
--header "Authorization: Bearer {YOUR_JWT}"
You'll receive a 200
response with the same contents as before.
Run the same command, switching out one character of your JWT, and you'll get a 403 Forbidden
error.
Run the command with no Authorization
header, substituting your domain for {YOUR_NGROK_DOMAIN}
:
curl -X GET https://{YOUR_NGROK_DOMAIN}/cards
You'll receive a 201 Unauthorized
error.