Kong Gateway is a cloud-native, platform-agnostic API, LLM, and MCP gateway built on top of OpenResty (NGINX + LuaJIT). It sits in front of your APIs and microservices and gives you a single place to handle routing, load balancing, authentication, rate limiting, transformations, observability, and AI traffic — all configurable at runtime without restarting or redeploying your services.
This guide covers everything you need to run and operate Kong as a user: installing it, proxying your first API, configuring the building blocks (Services, Routes, Consumers, Upstreams), and using its plugins. Architecture, the full kong.conf reference, deployment topologies, and security hardening live in the companion Admin Guide.
Note
This guide documents the open-source Kong Gateway, version 3.10.0. Everything here is derived directly from the source code at the documented commit. Features that require a Kong Enterprise subscription or Kong Konnect (the SaaS control plane) are called out where relevant but are not the focus of this guide.
Table of Contents
- What Kong Does
- Quick Start (5 minutes)
- Installation
- Core Concepts
- Everyday Usage
- Working with Plugins
- The Plugin Catalog
- Declarative (DB-less) Configuration
- The
kongCLI Reference - Common Workflows
- Advanced Usage
- How Kong Works (Concepts in Depth)
- Troubleshooting
- FAQ
- Reference Tables
1. What Kong Does
When a client calls one of your APIs through Kong, Kong becomes the middle layer between the client and your backend service:
┌─────────────────────────────────────┐
Client ──request──► │ Kong Gateway │ ──► Your Service
│ │ (upstream)
│ 1. Match the Route │
│ 2. Run plugins (auth, rate-limit…) │
│ 3. Load-balance to an upstream │
Client ◄─response── │ 4. Run response plugins │ ◄── Your Service
└─────────────────────────────────────┘
With Kong you can, without touching your service code:
- Proxy and route HTTP, HTTPS, gRPC, gRPCs, TCP, TLS, and UDP traffic.
- Load balance across multiple backend instances with health checks.
- Authenticate consumers using API keys, JWT, OAuth 2.0, Basic Auth, HMAC, LDAP, or sessions.
- Control traffic with rate limiting, request size limits, request termination, and IP restriction.
- Transform requests and responses (headers, bodies, query strings).
- Observe traffic with Prometheus, Datadog, StatsD, OpenTelemetry, Zipkin, and a variety of logging plugins.
- Govern AI/LLM traffic through a universal LLM API across OpenAI, Anthropic, Azure, Bedrock, Gemini, Mistral, Cohere, Hugging Face, and more.
- Extend the gateway with custom plugins in Lua, Go, JavaScript, Python, or WebAssembly.
Kong is the data plane that enforces policy; you describe that policy as data (entities like Services, Routes, and Plugins), and Kong applies it to live traffic in real time.
Tip
Kong runs natively on Kubernetes via the official Kubernetes Ingress Controller. If you run on Kubernetes, you typically configure Kong through Kubernetes resources rather than calling the Admin API directly.
2. Quick Start (5 minutes)
The fastest way to try Kong is the official docker-kong Compose stack, which brings up Kong plus a PostgreSQL database. You will add authentication to a sample API in a few commands.
Step 1 — Start the Gateway
Docker Compose (with database)
git clone https://github.com/Kong/docker-kong
cd docker-kong/compose/
KONG_DATABASE=postgres docker-compose --profile database up
Docker (DB-less)
docker run -d --name kong \
-e "KONG_DATABASE=off" \
-e "KONG_PROXY_ACCESS_LOG=/dev/stdout" \
-e "KONG_ADMIN_ACCESS_LOG=/dev/stdout" \
-e "KONG_ADMIN_LISTEN=0.0.0.0:8001" \
-p 8000:8000 -p 8001:8001 \
kong/kong:3.10
Once Kong is up, these ports are available on localhost:
| Port | Purpose |
|---|---|
:8000 |
Proxy — send your API traffic here |
:8443 |
Proxy over HTTPS |
:8001 |
Admin API — configure Kong (HTTP) |
:8444 |
Admin API over HTTPS |
:8002 |
Kong Manager web UI (Enterprise/Konnect features vary) |
Verify Kong is responding:
curl -i http://localhost:8001/
HTTP/1.1 200 OK
Content-Type: application/json
...
{ "version": "3.10.0", "tagline": "Welcome to kong", ... }
Step 2 — Add a Service
A Service points at your upstream API. Here we use the public httpbin test service:
curl -i -X POST http://localhost:8001/services \
--data name=example-service \
--data url='https://httpbin.org'
HTTP/1.1 201 Created
...
{ "id": "…", "name": "example-service", "host": "httpbin.org", "port": 443, "protocol": "https", ... }
Step 3 — Add a Route
A Route decides which incoming requests reach that Service:
curl -i -X POST http://localhost:8001/services/example-service/routes \
--data 'paths[]=/example' \
--data name=example-route
Step 4 — Send traffic through the proxy
curl -i http://localhost:8000/example/anything
HTTP/1.1 200 OK
...
(httpbin echoes your request — you just proxied through Kong!)
Step 5 — Protect it with an API key
Enable the key-auth plugin on the Route, create a Consumer, and give them a key:
# Enable key authentication on the route
curl -i -X POST http://localhost:8001/routes/example-route/plugins \
--data name=key-auth
# Create a consumer
curl -i -X POST http://localhost:8001/consumers \
--data username=alice
# Issue an API key to that consumer
curl -i -X POST http://localhost:8001/consumers/alice/key-auth \
--data key=secret-api-key-123
Now the route is locked down:
curl -i http://localhost:8000/example/anything # 401 Unauthorized
curl -i http://localhost:8000/example/anything \
-H 'apikey: secret-api-key-123' # 200 OK
HTTP/1.1 401 Unauthorized
{ "message": "No API key found in request" }
You just added authentication to an API without changing the API. That is the core Kong workflow: create entities, attach plugins, send traffic.
Tip
Prefer a single config file over many
curlcalls? Run Kong in DB-less mode and describe everything in one YAML file. See Declarative (DB-less) Configuration.
3. Installation
Kong supports Linux and macOS. Choose the distribution that fits how you run software.
3.1 Installation methods
Docker
docker pull kong/kong:3.10
Run it pointing at PostgreSQL (traditional mode) or with KONG_DATABASE=off for DB-less. Official images and tags are on Docker Hub.
Kubernetes
Use the official Helm chart and/or the Kubernetes Ingress Controller:
helm repo add kong https://charts.konghq.com
helm repo update
helm install kong/kong --generate-name
Package (deb/rpm)
Download the .deb or .rpm for your distribution from the official install page and install with your package manager, e.g.:
sudo apt install ./kong-3.10.0.amd64.deb # Debian/Ubuntu
sudo yum install kong-3.10.0.el8.amd64.rpm # RHEL/CentOS
From source (LuaRocks)
Kong is published as a LuaRocks rock and depends on a specific OpenResty build. Building from source is for contributors and advanced users; see DEVELOPER.md in the repository. Most users should use a packaged distribution.
3.2 Requirements
| Requirement | Detail |
|---|---|
| Operating system | Linux or macOS |
| Runtime | OpenResty (bundled in the official packages); requires NGINX 1.27.1.2 |
| Database (traditional mode) | PostgreSQL 9.5 or newer |
| Database (DB-less mode) | None — configuration is held in memory (LMDB) |
| Memory | A few hundred MB minimum; scales with cache sizes and config size |
Important
You only need PostgreSQL if you run in traditional or hybrid control-plane mode. In DB-less mode Kong needs no database at all — it loads a declarative config file into an in-memory LMDB store.
3.3 First start (traditional mode)
If you run Kong against PostgreSQL, bootstrap the database schema once, then start:
# 1. Bootstrap the database (run once, creates Kong's schema)
kong migrations bootstrap -c /etc/kong/kong.conf
# 2. Start Kong
kong start -c /etc/kong/kong.conf
Kong started
Confirm it is healthy:
kong health
nginx.......running
Kong is healthy at /usr/local/kong
3.4 The configuration file
Kong reads a single configuration file (default /etc/kong/kong.conf) when you run kong start or kong prepare. A fully commented template ships as kong.conf.default; copy it to get started:
cp /etc/kong/kong.conf.default /etc/kong/kong.conf
Every setting can also be supplied as an environment variable by uppercasing it and prefixing KONG_. For example:
export KONG_LOG_LEVEL=notice # same as `log_level = notice`
export KONG_DATABASE=off # same as `database = off`
export KONG_PROXY_LISTEN="0.0.0.0:8000"
Note
The full list of every configuration property, its default, and its meaning is in the Admin Guide → Configuration Reference. As a user you usually only set a handful (database connection, listen addresses, log level).
Validate a config file at any time without starting Kong:
kong check /etc/kong/kong.conf
configuration at /etc/kong/kong.conf is valid
4. Core Concepts
Everything you configure in Kong is an entity — a piece of data stored in the database (traditional mode) or loaded from a YAML file (DB-less mode). You create, read, update, and delete entities through the Admin API (a RESTful API on port 8001), through the decK CLI, or through a declarative config file.
These are the entities you will use most often.
4.1 The request-handling entities
Consumer ─────┐
│ (credentials, plugin scoping)
▼
Client ─► Route ─► Service ─► Upstream ─► Target(s) ─► your backend
│ │ (load balancing across targets)
└─ Plugins run along this path ─┘
| Entity | What it represents |
|---|---|
| Service | An abstraction of one of your upstream APIs/microservices (where to send traffic). |
| Route | Rules for matching client requests (paths, hosts, methods, headers, SNIs…) and mapping them to a Service. |
| Consumer | A client/application that uses your APIs. Credentials and per-consumer policy attach here. |
| Plugin | A unit of functionality (auth, rate limiting, logging…) that runs on requests, scoped globally or to a Service/Route/Consumer. |
| Upstream | A virtual hostname representing a pool of backend targets, with load balancing and health checks. |
| Target | A single backend host:port (with a weight) that belongs to an Upstream. |
| Certificate / SNI | TLS certificates and the SNI hostnames they serve. |
| Consumer Group | A way to group consumers for shared policy (used by some plugins). |
| Vault | A reference to a secrets backend so sensitive values aren't stored in plain config. |
| Key / Key Set | Cryptographic keys (e.g. for JWT verification) managed as entities. |
4.2 Services
A Service tells Kong where to send traffic. You can define it field-by-field or with the convenient url shorthand.
# Using the url shorthand (sets protocol, host, port, path at once)
curl -X POST http://localhost:8001/services \
--data name=billing \
--data url='https://billing.internal:8443/api'
# Equivalent, field by field
curl -X POST http://localhost:8001/services \
--data name=billing \
--data protocol=https \
--data host=billing.internal \
--data port=8443 \
--data path=/api
Key Service fields (with defaults):
| Field | Default | Description |
|---|---|---|
name |
— | Human-friendly unique name. |
protocol |
http |
One of http, https, grpc, grpcs, tcp, tls, udp. |
host |
— | Upstream host or the name of an Upstream entity. |
port |
80 |
Upstream port. |
path |
— | Path prefix prepended to the upstream request. |
retries |
5 |
Retries on proxy failure (0–32767). |
connect_timeout |
60000 |
Connection timeout (ms). |
write_timeout |
60000 |
Write timeout (ms). |
read_timeout |
60000 |
Read timeout (ms). |
tls_verify |
— | Verify the upstream's TLS certificate. |
client_certificate |
— | Client cert for mTLS to the upstream. |
enabled |
true |
Whether the Service is active. |
Note
Set
hostto the name of an Upstream entity to get load balancing and health checks instead of pointing at a single host. See Load balancing.
4.3 Routes
A Route decides which requests reach a Service. A Route can match on any combination of paths, hosts, methods, headers, SNIs, and (for stream traffic) sources/destinations.
curl -X POST http://localhost:8001/services/billing/routes \
--data name=billing-route \
--data 'paths[]=/billing' \
--data 'methods[]=GET' \
--data 'methods[]=POST' \
--data 'hosts[]=api.example.com'
Key Route fields (with defaults):
| Field | Default | Description |
|---|---|---|
protocols |
["http","https"] |
Protocols this Route accepts. |
paths |
— | Path patterns to match (plain prefixes or regexes). |
hosts |
— | Host header values to match. |
methods |
— | HTTP methods to match. |
headers |
— | Header values to match (cannot include host). |
snis |
— | SNIs to match (TLS/HTTPS/gRPCs/tls_passthrough only). |
strip_path |
true |
Strip the matched path prefix before proxying upstream. |
preserve_host |
false |
Forward the client's Host header upstream. |
https_redirect_status_code |
426 |
Status returned when only the protocol fails to match. |
request_buffering |
true |
Buffer the request body. |
response_buffering |
true |
Buffer the response body. |
regex_priority |
0 |
Tie-breaker when multiple regex routes match. |
path_handling |
v0 |
How service path + route path + request path combine. |
Tip
strip_pathis one of the most common sources of confusion. Withstrip_path=true(the default) and a route path of/billing, a request to/billing/invoicesis sent upstream as/invoices. Set it tofalseto forward the full path.
4.4 Consumers and credentials
A Consumer is anyone (a user, app, or service) calling your APIs. Authentication plugins attach credentials to consumers.
# Create a consumer
curl -X POST http://localhost:8001/consumers --data username=mobile-app
# Give them a key-auth credential
curl -X POST http://localhost:8001/consumers/mobile-app/key-auth --data key=abc123
# Give them basic-auth credentials
curl -X POST http://localhost:8001/consumers/mobile-app/basic-auth \
--data username=mobile-app --data password=s3cr3t
Once authenticated, Kong adds identity headers to the upstream request (e.g. X-Consumer-ID, X-Consumer-Username), so your backend knows who is calling.
4.5 Tags
Most entities accept a tags array. Tags let you filter and organize entities, which is invaluable in large deployments:
curl -X POST http://localhost:8001/services \
--data name=payments --data url=http://payments:8080 \
--data 'tags[]=team-fintech' --data 'tags[]=pci'
# List everything tagged team-fintech
curl http://localhost:8001/services?tags=team-fintech
5. Everyday Usage
This section walks through the tasks you will perform most often.
5.1 Proxying an API
The minimum to proxy an API is a Service plus a Route:
curl -X POST http://localhost:8001/services \
--data name=orders --data url=http://orders.internal:8080
curl -X POST http://localhost:8001/services/orders/routes \
--data name=orders --data 'paths[]=/orders'
Traffic to http://localhost:8000/orders/... now reaches http://orders.internal:8080/....
5.2 Routing rules
Routes are matched in priority order based on how specific they are. You can combine matchers:
# Host + path
curl -X POST http://localhost:8001/services/orders/routes \
--data 'hosts[]=shop.example.com' --data 'paths[]=/v2/orders'
# Regex path (prefix with ~ to force regex evaluation)
curl -X POST http://localhost:8001/services/orders/routes \
--data 'paths[]=~/orders/\d+'
# Header match
curl -X POST http://localhost:8001/services/orders/routes \
--data 'headers.x-api-version=2'
Note
Kong 3.x defaults to the
traditional_compatiblerouter, which uses a fast expression engine under the hood while keeping the classicpaths/hosts/methodsinterface. You can opt into writing raw router expressions by settingrouter_flavor = expressionsinkong.conf(see the Admin Guide).
5.3 Adding authentication
Attach an auth plugin to a Route (or Service, or globally), then create Consumers with credentials. Available auth plugins: key-auth, basic-auth, jwt, oauth2, hmac-auth, ldap-auth, session.
# JWT authentication on a service
curl -X POST http://localhost:8001/services/orders/plugins --data name=jwt
# Create a consumer and a JWT credential
curl -X POST http://localhost:8001/consumers --data username=partner
curl -X POST http://localhost:8001/consumers/partner/jwt \
--data algorithm=HS256 --data secret=my-signing-secret
A common pattern is multiple auth methods with an anonymous fallback: set the anonymous config field on each auth plugin to a fallback consumer, then use the acl plugin to authorize.
5.4 Load balancing with Upstreams and Targets
To balance across several backend instances, create an Upstream and add Targets, then point a Service's host at the Upstream name:
# 1. Create the upstream (a virtual hostname)
curl -X POST http://localhost:8001/upstreams --data name=orders-pool
# 2. Add backend targets with weights
curl -X POST http://localhost:8001/upstreams/orders-pool/targets \
--data target=10.0.0.11:8080 --data weight=100
curl -X POST http://localhost:8001/upstreams/orders-pool/targets \
--data target=10.0.0.12:8080 --data weight=100
# 3. Point a service at the upstream by name
curl -X POST http://localhost:8001/services \
--data name=orders --data host=orders-pool --data port=8080
Upstreams support several load-balancing algorithms (round-robin, consistent hashing, least-connections, latency) and active/passive health checks that automatically remove unhealthy targets from rotation. Health-check configuration lives on the Upstream entity; see the Admin Guide for the full field reference.
5.5 Rate limiting
# Allow 100 requests per minute, counted per consumer
curl -X POST http://localhost:8001/services/orders/plugins \
--data name=rate-limiting \
--data config.minute=100 \
--data config.policy=local
The rate-limiting plugin counts against one of: consumer, credential, ip, service, header, or path (the limit_by field). For multi-node deployments use config.policy=redis (shared) or config.policy=cluster; local counts per node only.
5.6 Transforming requests and responses
# Add a header to every upstream request
curl -X POST http://localhost:8001/services/orders/plugins \
--data name=request-transformer \
--data 'config.add.headers=x-source:kong'
# Remove a header from responses
curl -X POST http://localhost:8001/services/orders/plugins \
--data name=response-transformer \
--data 'config.remove.headers=server'
5.7 Inspecting what you've configured
curl http://localhost:8001/services # list all services
curl http://localhost:8001/routes # list all routes
curl http://localhost:8001/consumers # list all consumers
curl http://localhost:8001/plugins # list all enabled plugins
curl http://localhost:8001/orders/anything # NOT this — that's the proxy port (8000)
Caution
The Admin API (
:8001) and the proxy (:8000) are different ports. The Admin API can create, modify, and delete everything in your gateway — never expose it to the public internet. See the Admin Guide → Security for how to lock it down.
6. Working with Plugins
Plugins are how Kong does almost everything beyond plain proxying. A plugin can be attached at four scopes, from broadest to narrowest:
| Scope | How to attach | Applies to |
|---|---|---|
| Global | POST /plugins |
Every request through the node. |
| Service | POST /services/{id}/plugins |
All routes of that Service. |
| Route | POST /routes/{id}/plugins |
One Route. |
| Consumer | POST /consumers/{id}/plugins |
One Consumer (where supported). |
When multiple instances of the same plugin could apply, the most specific scope wins (Route+Consumer > Route > Service > Global).
6.1 Enabling and configuring a plugin
Every plugin has a name and a config object whose fields are defined by that plugin's schema. Configure fields with the config.<field> convention:
curl -X POST http://localhost:8001/routes/orders/plugins \
--data name=rate-limiting \
--data config.minute=60 \
--data config.limit_by=ip \
--data config.policy=local
6.2 Listing, updating, and deleting plugins
# Find the plugin instance id
curl http://localhost:8001/routes/orders/plugins
# Update its config
curl -X PATCH http://localhost:8001/plugins/{plugin-id} \
--data config.minute=120
# Disable temporarily without deleting
curl -X PATCH http://localhost:8001/plugins/{plugin-id} --data enabled=false
# Delete it entirely
curl -X DELETE http://localhost:8001/plugins/{plugin-id}
6.3 Which plugins are loaded
By default Kong loads the bundled set (the 44 plugins shipped with the gateway). You control which plugins a node will load with the plugins setting in kong.conf:
# Load only the bundled plugins plus a custom one
export KONG_PLUGINS="bundled,my-custom-plugin"
# Load nothing but two specific plugins (faster startup, less memory)
export KONG_PLUGINS="key-auth,rate-limiting"
# Disable all plugins
export KONG_PLUGINS=off
Important
Loading a plugin only makes it available — it does not enable it on any traffic. You still attach instances via the Admin API. Also: Kong will refuse to start if a plugin that has configured instances in the database is removed from the
pluginslist. Remove all instances before dropping a plugin.
7. The Plugin Catalog
Kong 3.10.0 bundles 44 plugins. They are grouped below by purpose. To use any of them, attach an instance with POST .../plugins --data name=<plugin> and set its config.* fields.
7.1 Authentication
| Plugin | Purpose |
|---|---|
key-auth |
API key authentication (key in header, query, or body). |
basic-auth |
HTTP Basic authentication (username/password). |
jwt |
Verify JSON Web Tokens signed by consumer credentials. |
oauth2 |
OAuth 2.0 flows (authorization code, client credentials, password, implicit). |
hmac-auth |
HMAC signature authentication over request components. |
ldap-auth |
Authenticate against an LDAP directory. |
session |
Maintain authenticated sessions with a session cookie. |
7.2 Security & access control
| Plugin | Purpose |
|---|---|
acl |
Allow/deny consumers by group membership. |
cors |
Cross-Origin Resource Sharing headers and preflight handling. |
ip-restriction |
Allow/deny by client IP or CIDR range. |
bot-detection |
Block requests from known bots by User-Agent. |
request-size-limiting |
Reject requests whose body exceeds a size limit. |
request-termination |
Short-circuit requests with a fixed response (maintenance mode, blocking). |
standard-webhooks |
Verify inbound webhooks per the Standard Webhooks spec. |
7.3 Traffic control
| Plugin | Purpose |
|---|---|
rate-limiting |
Limit request rate per second/minute/hour/day/month/year. |
response-ratelimiting |
Rate limit based on custom counters returned by the upstream. |
proxy-cache |
Cache upstream responses in memory to reduce backend load. |
redirect |
Issue HTTP redirects for matched requests. |
7.4 Transformations
| Plugin | Purpose |
|---|---|
request-transformer |
Add/remove/replace/rename request headers, query args, and body fields. |
response-transformer |
Modify response headers and body. |
correlation-id |
Inject a unique correlation/request ID header. |
grpc-gateway |
Transcode JSON/REST requests to gRPC upstreams. |
grpc-web |
Allow gRPC-Web browser clients to reach gRPC services. |
7.5 Logging
| Plugin | Purpose |
|---|---|
file-log |
Append request/response logs to a file. |
http-log |
POST logs to an HTTP(S) endpoint. |
tcp-log |
Stream logs over TCP. |
udp-log |
Stream logs over UDP. |
syslog |
Send logs to syslog. |
loggly |
Send logs to Loggly. |
7.6 Analytics & observability
| Plugin | Purpose |
|---|---|
prometheus |
Expose metrics in Prometheus format (with an optional Grafana dashboard). |
datadog |
Send metrics to a Datadog agent (StatsD). |
statsd |
Send metrics to a StatsD server. |
opentelemetry |
Export traces (and more) via OTLP to an OpenTelemetry collector. |
zipkin |
Distributed tracing with Zipkin/B3 propagation. |
7.7 Serverless & cloud functions
| Plugin | Purpose |
|---|---|
aws-lambda |
Invoke an AWS Lambda function as the upstream. |
azure-functions |
Invoke an Azure Function as the upstream. |
pre-function |
Run custom Lua before other plugins (sandboxed). |
post-function |
Run custom Lua after other plugins (sandboxed). |
7.8 AI Gateway
Kong's AI Gateway plugins turn Kong into a universal, governed front door for LLM and MCP traffic.
| Plugin | Purpose |
|---|---|
ai-proxy |
Universal LLM API — route to OpenAI, Anthropic, Azure, Bedrock, Gemini, Mistral, Cohere, Hugging Face, Ollama, and more behind one interface. |
ai-prompt-decorator |
Inject system/assistant prompts (prepend/append messages). |
ai-prompt-template |
Enforce reusable, parameterized prompt templates. |
ai-prompt-guard |
Allow/deny prompts by pattern (prompt firewall). |
ai-request-transformer |
Use an LLM to transform the incoming request. |
ai-response-transformer |
Use an LLM to transform the upstream response. |
7.9 TLS automation
| Plugin | Purpose |
|---|---|
acme |
Automatic Let's Encrypt (ACME) certificate issuance and renewal. |
Tip
Every plugin's exact configuration fields, defaults, and validation rules are defined by its
schema.lua. The Admin Guide lists each plugin's config reference; you can also introspect any plugin's schema live atGET /schemas/plugins/{plugin-name}.
8. Declarative (DB-less) Configuration
In DB-less mode Kong needs no database. You describe your entire configuration in a single YAML (or JSON) file and load it into Kong's in-memory store. This is ideal for GitOps, immutable deployments, and Kubernetes.
8.1 Enable DB-less mode
Set the database to off and point at a declarative config file:
export KONG_DATABASE=off
export KONG_DECLARATIVE_CONFIG=/etc/kong/kong.yml
kong start
8.2 Generate a starter file
kong config init kong.yml
This writes an example kong.yml you can edit. A minimal declarative config looks like:
_format_version: "3.0"
services:
- name: orders
url: http://orders.internal:8080
routes:
- name: orders-route
paths:
- /orders
plugins:
- name: rate-limiting
config:
minute: 100
policy: local
consumers:
- username: mobile-app
keyauth_credentials:
- key: abc123
plugins:
- name: key-auth
route: orders-route
8.3 Validate and load
# Check syntax without loading
kong config parse kong.yml
# Load it into a running DB-less node via the Admin API
curl -X POST http://localhost:8001/config \
-F config=@kong.yml
Note
In DB-less mode the Admin API is read-only for entities — you cannot
POST /servicesto create entities one at a time. The only write endpoint isPOST /config, which replaces the whole configuration atomically.
8.4 Converting between modes
If you started in traditional (database) mode and want a declarative snapshot:
kong config db_export kong.yml # database -> file
kong config db_import kong.yml # file -> database (traditional mode only)
Tip
The decK CLI is the recommended tool for managing declarative configuration in either mode: it diffs your file against the running config and applies only the changes, supports validation, and integrates with CI.
9. The kong CLI Reference
The kong command manages the gateway node (starting, stopping, migrations, config). It is the tool you run on the host where Kong is installed. Add --v for verbose output or --vv for debug output to any command.
9.1 Command summary
| Command | Purpose |
|---|---|
kong start |
Start Kong (and NGINX) in the configured prefix. |
kong stop |
Stop a running node (SIGTERM). |
kong quit |
Gracefully stop — finish in-flight requests first (SIGQUIT). |
kong reload |
Reload config without dropping connections (SIGHUP). |
kong restart |
stop then start. |
kong health |
Check whether the node's services are running. |
kong check <conf> |
Validate a configuration file. |
kong prepare |
Prepare the prefix so you can start NGINX directly. |
kong migrations |
Manage database schema migrations. |
kong config |
Work with declarative config files. |
kong vault |
Vault/secret utilities. |
kong hybrid |
Hybrid-mode utilities (generate certificates). |
kong drain |
Make /status/ready return 503 (for graceful removal from a load balancer). |
kong version |
Print the Kong version (-a for all dependencies). |
kong roar |
Print the Kong mascot. 🦍 |
9.2 kong start
Usage: kong start [OPTIONS]
Options:
-c,--conf Configuration file.
-p,--prefix Override prefix directory.
--nginx-conf Custom Nginx configuration template.
--run-migrations Run migrations before starting.
--db-timeout Timeout (seconds) for all database operations.
--lock-timeout Timeout (seconds) waiting on the leader node's migrations.
--nginx-conf-flags Flags controlling how Nginx templates are rendered.
kong start -c /etc/kong/kong.conf --run-migrations
9.3 kong migrations
Usage: kong migrations COMMAND [OPTIONS]
Commands:
bootstrap Bootstrap the database and run all migrations.
up Run any new migrations.
finish Finish pending migrations after 'up'.
list List executed migrations.
reset Reset the database (ERASES ALL DATA).
status Dump migration status as JSON.
Options:
-y,--yes Assume "yes" to prompts (non-interactive).
-q,--quiet Suppress all output.
-f,--force Run migrations even if reported as already executed.
--db-timeout Timeout (seconds) for database operations.
--lock-timeout (default 60) Timeout waiting on the leader node.
-c,--conf Configuration file.
-p,--prefix Override prefix directory.
The zero-downtime upgrade flow is migrations up (apply new, backward-compatible migrations while the old version runs) → deploy new nodes → migrations finish (apply the rest):
kong migrations up -c /etc/kong/kong.conf
kong migrations finish -c /etc/kong/kong.conf
Caution
kong migrations reseterases all data in Kong's database and drops its schemas. It prompts for confirmation; with--yesit runs without prompting. Never run it against a production database you want to keep.
9.4 kong config
Usage: kong config COMMAND [OPTIONS]
Commands:
init [<file>] Generate an example config file (default ./kong.yml).
db_import <file> Import a declarative config file into the database.
db_export [<file>] Export the database into a declarative config file.
parse <file> Parse/validate a declarative file without loading it.
Options:
-c,--conf Configuration file.
-p,--prefix Override prefix directory.
9.5 kong quit (graceful shutdown)
Usage: kong quit [OPTIONS]
Options:
-p,--prefix Prefix Kong is running at.
-t,--timeout (default 10) Timeout before forced shutdown.
-w,--wait (default 0) Wait time before initiating the shutdown.
kong quit sends SIGQUIT so all in-flight requests finish before the node stops. If the timeout is reached, the node is forcefully stopped (SIGTERM). Combine kong drain (stop accepting new readiness traffic) with kong quit for zero-downtime rollouts.
9.6 kong vault get
Resolve a secret reference from a configured vault. The open-source distribution ships the environment-variable vault (env):
TEST=hello kong vault get env/test
hello
9.7 kong hybrid gen_cert
Generate the mTLS certificate/key pair used for control-plane ↔ data-plane communication in hybrid mode:
kong hybrid gen_cert # writes ./cluster.crt and ./cluster.key
kong hybrid gen_cert -d 365 # valid for 365 days (default 1095 / 3 years)
9.8 kong version
kong version -a
Kong: 3.10.0
ngx_lua: ...
nginx: ...
Lua: LuaJIT ...
10. Common Workflows
10.1 Add authentication + rate limiting to an existing API
# Assume service `orders` and route `orders-route` already exist
curl -X POST http://localhost:8001/routes/orders-route/plugins --data name=key-auth
curl -X POST http://localhost:8001/routes/orders-route/plugins \
--data name=rate-limiting --data config.minute=100 --data config.policy=local
curl -X POST http://localhost:8001/consumers --data username=client-a
curl -X POST http://localhost:8001/consumers/client-a/key-auth --data key=KEY-A
10.2 Canary / weighted rollout with Upstreams
Shift traffic gradually by adjusting target weights:
curl -X POST http://localhost:8001/upstreams/orders-pool/targets \
--data target=10.0.0.20:8080 --data weight=10 # new version: 10%
# old version stays at weight=90 → ~10% canary
10.3 Maintenance mode
curl -X POST http://localhost:8001/routes/orders-route/plugins \
--data name=request-termination \
--data config.status_code=503 \
--data 'config.message=Service under maintenance'
10.4 Automatic HTTPS with Let's Encrypt
curl -X POST http://localhost:8001/plugins \
--data name=acme \
--data 'config.account_email=[email removed]' \
--data 'config.domains[]=api.example.com' \
--data config.tos_accepted=true
10.5 Zero-downtime config change
# Edit /etc/kong/kong.conf, then:
kong reload -c /etc/kong/kong.conf
reload sends SIGHUP: NGINX spawns new workers with the new config and retires old workers after their requests complete — no dropped connections.
10.6 Route an LLM through the AI Gateway
curl -X POST http://localhost:8001/services \
--data name=ai --data url='http://localhost:32000'
curl -X POST http://localhost:8001/services/ai/routes \
--data name=openai --data 'paths[]=/chat'
curl -X POST http://localhost:8001/routes/openai/plugins \
--data name=ai-proxy \
--data 'config.route_type=llm/v1/chat' \
--data 'config.model.provider=openai' \
--data 'config.model.name=gpt-4o' \
--data 'config.auth.header_name=Authorization' \
--data 'config.auth.header_value=Bearer $OPENAI_KEY'
Clients now POST OpenAI-style chat requests to http://localhost:8000/chat and Kong handles provider routing, auth, and (with the other AI plugins) prompt governance.
11. Advanced Usage
11.1 Custom Lua with serverless functions
The pre-function and post-function plugins let you run arbitrary Lua at specific request phases. Code runs in a sandbox by default (untrusted_lua = sandbox in kong.conf):
curl -X POST http://localhost:8001/routes/orders-route/plugins \
--data name=pre-function \
--data 'config.access[1]=kong.log.notice("hello from Lua")'
Warning
The sandbox restricts access to the OS and global environment, but LuaJIT is not a hardened secure runtime. Treat the Admin API as privileged and never expose it publicly even with sandboxing on. Set
untrusted_lua = offto disable custom Lua entirely.
11.2 Secrets management with Vaults
Instead of putting secrets directly in plugin config, reference them from a vault using {vault://...} syntax. The open-source distribution includes the environment-variable vault:
# Store the secret in an env var, reference it in config
export MY_REDIS_PASSWORD=supersecret
curl -X POST http://localhost:8001/services/orders/plugins \
--data name=rate-limiting \
--data config.policy=redis \
--data 'config.redis.password={vault://env/my-redis-password}'
11.3 The Status API
A read-only API (default 127.0.0.1:8007) for monitoring tools. It never exposes sensitive data and is safe to wire into load-balancer health checks:
curl http://localhost:8007/status # node metrics + db reachability
curl http://localhost:8007/status/ready # 200 when ready to serve, 503 otherwise
curl http://localhost:8007/status/dns # new DNS client stats (if enabled)
kong drain flips /status/ready to 503 so a load balancer stops sending new traffic before you kong quit.
11.4 Custom plugins
You can write your own plugins in:
- Lua — native; a plugin is a directory under
kong/plugins/<name>/withhandler.luaandschema.lua. Make it loadable withKONG_PLUGINS=bundled,<name>andKONG_LUA_PACKAGE_PATH. - Go, JavaScript, Python — via external "pluginservers" (process-based plugins using the corresponding PDK:
go-pdk,kong-pdkfor JS/Python). - WebAssembly — enable
wasm = onand drop.wasmfilter modules intowasm_filters_path.
Plugin authoring (the PDK, phases, and the "add a plugin in N steps" recipe) is covered in the Admin Guide.
12. How Kong Works (Concepts in Depth)
You don't need this section to use Kong, but it helps explain why things behave the way they do.
12.1 The request lifecycle
Kong processes each proxied request through NGINX/OpenResty phases. Plugins hook into these phases:
rewrite ─► access ─► (balancer) ─► header_filter ─► body_filter ─► log
│ │ │ │ │ │
│ │ │ │ │ └─ logging plugins
│ │ │ │ └─ response body transforms
│ │ │ └─ response header transforms
│ │ └─ pick an upstream target, retry on failure
│ └─ auth, rate limiting, request transforms run here (most plugins)
└─ earliest hook; runs before routing
12.2 Deployment topologies
Kong supports three ways to run, set by role and database in kong.conf:
| Topology | database |
role |
Description |
|---|---|---|---|
| Traditional | postgres |
traditional |
Each node talks to a shared PostgreSQL; config via Admin API. |
| DB-less | off |
traditional |
No database; config from a declarative file loaded into memory. |
| Hybrid | postgres (CP) / off (DP) |
control_plane / data_plane |
A control plane holds config in a database and pushes it over mTLS to stateless data planes that proxy traffic. |
Hybrid mode is the recommended production topology at scale: data planes keep serving traffic even if the control plane or database is temporarily down. The deep dive lives in the Admin Guide.
12.3 Caching and propagation
Kong caches entities in shared memory to avoid hitting the database on every request. When you change config through the Admin API, other nodes pick it up on their next poll (db_update_frequency, default 5s). This is why a change made on one node may take a few seconds to take effect cluster-wide. DB-less and hybrid data planes instead receive a full config push.
12.4 The router
Kong matches requests to Routes using a router engine. Kong 3.x defaults to traditional_compatible, which compiles your paths/hosts/methods into a fast expression engine while preserving the classic interface. The expressions flavor lets you write router expressions directly; traditional is the legacy pre-3.0 engine (deprecated).
13. Troubleshooting
Troubleshooting entries use the format Error → Cause → Solution → Prevention.
Error: No API key found in request
- Cause: The
key-authplugin is enabled on the route but the request did not include a valid key in the configured location. - Solution: Send the key in the header named by
config.key_names(defaultapikey):-H 'apikey: <key>'. Verify a matching credential exists for a consumer. - Prevention: Document the expected header name for your API consumers; the default is
apikey.
Error: no Route matched with those values
- Cause: No Route's matchers (path/host/method/protocol) matched the incoming request.
- Solution: Check the request path,
Hostheader, and method against your Routes (GET /routes). Rememberstrip_pathand that paths starting with~are regexes. - Prevention: Add a catch-all route for diagnostics, or use the
Kong-Debug: 1request header withallow_debug_header = onto see which Service/Route matched.
Error: an invalid response was received from the upstream server / 502 Bad Gateway
- Cause: Kong reached the upstream but the connection failed or the upstream returned an invalid response.
- Solution: Verify the Service
host/port/protocoland that the backend is reachable from the Kong node. Checkconnect_timeout/read_timeout. - Prevention: Use Upstreams with health checks so unhealthy targets are removed automatically.
Error: Kong is already running in <prefix>
- Cause:
kong startfound a live NGINX PID in the prefix. - Solution:
kong stop(orkong restart) first; if the process is truly gone, remove stale sockets/PID from the prefix. - Prevention: Use
kong restartrather thanstartwhen redeploying on the same host.
Error: Kong is not running at <prefix>
- Cause:
kong health/kong stopcould not find a running node at the prefix. - Solution: Confirm the prefix with
-p, and that the node was started with the same prefix/config. - Prevention: Always pass a consistent
-c/-p(orKONG_PREFIX) across commands.
Error: Database needs bootstrapping or is older than Kong 1.0
- Cause: The PostgreSQL database has not been initialized with Kong's schema.
- Solution: Run
kong migrations bootstrap -c <conf>. - Prevention: Bootstrap as part of your provisioning before the first
kong start.
Error: cannot run 'kong config db_import' ... database=off
- Cause:
db_import/db_exportonly work in traditional (database) mode. - Solution: In DB-less mode, reload your declarative configuration with
POST /configinstead. - Prevention: Know which mode the node runs in (
databasesetting).
Error: JWT plugin returns HTTP 500
- Cause: A misconfigured JWT credential (algorithm/secret mismatch) or unexpected token claim can surface as a 500 (reported in issue #14827 for some token shapes).
- Solution: Verify the consumer's JWT credential
algorithmandsecret/rsa_public_keymatch how the token is signed; enable--vvlogging to see the parser error. - Prevention: Test tokens with a known-good credential before rolling out; pin the
algorithm.
Error: high latency / CPU after adding many regex routes
- Cause: The PCRE regex cache is too small for the number of regex paths (relevant when
router_flavor = traditional). - Solution: Increase
nginx_http_lua_regex_cache_max_entries(recommended: at leastregex_paths * 2), or switch totraditional_compatible/expressionswhich don't use PCRE. - Prevention: Prefer the default
traditional_compatiblerouter; avoidtraditionalunless required.
Tip
For deeper timing analysis, enable request debugging (
request_debug = on) and send theX-Kong-Request-Debug: *header. Kong returns per-component timing inX-Kong-Request-Debug-Output. Protect this withX-Kong-Request-Debug-Token.
14. FAQ
Q: Do I need a database to run Kong?
No. DB-less mode (database = off) keeps configuration in memory from a declarative file. You only need PostgreSQL for traditional mode or a hybrid control plane.
Q: What's the difference between the proxy port (8000) and the Admin API port (8001)?
Port 8000/8443 is where your API clients send traffic. Port 8001/8444 is the management API where you configure Kong. Never expose the Admin API publicly.
Q: How do I expose Kong over HTTPS?
HTTPS is enabled by default on 8443. Kong auto-generates a self-signed certificate on first start; supply real certificates with ssl_cert/ssl_cert_key (or per-SNI via Certificate entities), or automate with the acme plugin.
Q: Can a plugin run on every request automatically?
Yes — attach it globally with POST /plugins. Scope it to a Service, Route, or Consumer to narrow it.
Q: How many plugins does Kong ship with? 44 in the open-source 3.10.0 distribution. You can also write your own in Lua, Go, JavaScript, Python, or WebAssembly.
Q: What protocols can Kong proxy?
http, https, grpc, grpcs, tcp, tls, tls_passthrough, and udp. Stream (TCP/TLS/UDP) routing uses stream_listen.
Q: How do I apply config changes without downtime?
kong reload (SIGHUP) reloads kong.conf without dropping connections. Entity changes via the Admin API or POST /config take effect without any restart.
Q: How do I do a zero-downtime version upgrade?
Use the expand/contract migration flow: kong migrations up (backward-compatible changes), roll new nodes, then kong migrations finish. Drain old nodes with kong drain + kong quit.
Q: Where do per-consumer identity headers come from?
After an auth plugin authenticates a request, Kong injects headers like X-Consumer-ID, X-Consumer-Username, and X-Consumer-Custom-ID to the upstream so your backend knows the caller.
Q: How do I rate-limit across multiple Kong nodes?
Use config.policy=redis (shared counters in Redis) or config.policy=cluster. The default local counts per node only.
Q: Is there a UI?
Kong Manager (port 8002) provides a web UI. Advanced Manager features depend on Kong Enterprise/Konnect; the open-source build focuses on the Admin API and decK.
Q: How do I limit which plugins load to speed up startup?
Set plugins (or KONG_PLUGINS) to just the plugins you use, e.g. key-auth,rate-limiting. This reduces memory and startup time.
Q: My change took a few seconds to take effect — is that normal?
Yes, in traditional mode other nodes poll for changes every db_update_frequency seconds (default 5). DB-less/hybrid data planes get pushed updates.
Q: How do I see Kong's version and dependencies?
kong version -a.
Q: Can Kong call serverless functions directly?
Yes — the aws-lambda and azure-functions plugins invoke cloud functions as the upstream, so a Route can be backed by a function instead of a server.
Q: What is the AI Gateway?
A set of plugins (ai-proxy and friends) that give you one unified API across many LLM providers plus prompt governance, security, and observability for AI/MCP traffic.
15. Reference Tables
15.1 Default ports
| Port | Service | Config setting |
|---|---|---|
8000 |
Proxy (HTTP) | proxy_listen |
8443 |
Proxy (HTTPS) | proxy_listen |
8001 |
Admin API (HTTP) | admin_listen |
8444 |
Admin API (HTTPS) | admin_listen |
8002 |
Kong Manager (HTTP) | admin_gui_listen |
8445 |
Kong Manager (HTTPS) | admin_gui_listen |
8007 |
Status API | status_listen |
8005 |
Cluster (hybrid CP) | cluster_listen |
15.2 Supported protocols
http, https, grpc, grpcs, tcp, tls, tls_passthrough, udp
15.3 Core entities
workspaces, consumers, certificates, services, routes, snis, upstreams, targets, plugins, tags, ca_certificates, clustering_data_planes, parameters, vaults, key_sets, keys, filter_chains
15.4 Kong-injected headers
| Header | Meaning |
|---|---|
X-Kong-Request-Id |
Unique ID for the request. |
X-Kong-Proxy-Latency |
Time Kong spent processing before proxying (ms). |
X-Kong-Upstream-Latency |
Time the upstream took to send response headers (ms). |
X-Kong-Response-Latency |
Time Kong took to produce a response (ms). |
X-Consumer-ID / X-Consumer-Username |
Identity of the authenticated consumer. |
X-RateLimit-Remaining |
Remaining requests in the current rate-limit window. |
Via / Server |
kong/3.10.0 server tokens. |
15.5 Rate-limit windows
second, minute, hour, day, month, year
15.6 Useful Admin API endpoints
| Method & Path | Purpose |
|---|---|
GET / |
Node information and version. |
GET /status |
Health and database reachability. |
POST /services |
Create a Service. |
POST /services/{id}/routes |
Create a Route under a Service. |
POST /consumers |
Create a Consumer. |
POST /{services,routes,consumers}/{id}/plugins |
Enable a plugin at a scope. |
POST /plugins |
Enable a plugin globally. |
POST /config |
Replace whole config (DB-less). |
GET /schemas/plugins/{name} |
Inspect a plugin's config schema. |
GET /upstreams/{id}/health |
Health status of an upstream's targets. |