Kong – full mini project folder

Here’s a full mini project folder for Kong that you can copy as-is.

It uses Kong Gateway in DB-less mode, so all config lives in one declarative kong.yml file. That mode is a good fit for CI/CD and Git-managed config, but the Admin API is effectively read-only for config changes in this setup. (Kong Docs)

Folder structure

kong-mini-project/
├── app/
│ ├── package.json
│ └── server.js
├── kong/
│ └── kong.yml
├── .dockerignore
├── Dockerfile
└── compose.yml

1) app/package.json

{
"name": "kong-mini-project",
"version": "1.0.0",
"description": "Node app behind Kong Gateway",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"license": "MIT"
}

2) app/server.js

const http = require("http");
const PORT = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
if (req.url === "/healthz") {
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: true }));
}
const body = {
ok: true,
message: "Hello from app behind Kong",
method: req.method,
url: req.url,
host: req.headers.host,
time: new Date().toISOString()
};
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(body, null, 2));
});
server.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});

3) Dockerfile

FROM node:20-alpine
WORKDIR /app
COPY app/package.json ./
RUN npm install --omit=dev
COPY app/server.js ./
ENV PORT=3000
EXPOSE 3000
CMD ["npm", "start"]

4) .dockerignore

node_modules
npm-debug.log
.git
.github

5) kong/kong.yml

This is the heart of the project. It defines:

  • one upstream Service
  • one public Route
  • a key-auth plugin
  • a rate-limiting plugin
  • one Consumer with an API key

Kong’s declarative config format supports entities like Services, Routes, Consumers, and Plugins in DB-less mode. The Key Auth plugin can require API keys, and the Rate Limiting plugin can throttle requests by time window such as per minute. When authentication is present, rate limiting uses the authenticated Consumer identity. (Kong Docs)

_format_version: "3.0"
services:
- name: app-service
url: http://app:3000
routes:
- name: app-route
paths:
- /api
protocols:
- http
- https
plugins:
- name: key-auth
service: app-service
config:
key_names:
- apikey
- name: rate-limiting
service: app-service
config:
minute: 5
policy: local
consumers:
- username: demo-client
keyauth_credentials:
- key: super-secret-demo-key

A note on policy: local: that works well for a single local node, but Kong notes that plugins needing shared database state do not fully function in DB-less mode, so this is best for learning or single-node setups rather than clustered distributed quotas. (Kong Docs)

6) compose.yml

Kong’s Docker docs support running Kong with Docker Compose, and the read-only Docker Compose guide for DB-less mode uses KONG_DATABASE=off plus KONG_DECLARATIVE_CONFIG pointing to the config file. (Kong Docs)

services:
kong:
image: kong:3.10
environment:
KONG_DATABASE: "off"
KONG_DECLARATIVE_CONFIG: /kong/declarative/kong.yml
KONG_PROXY_ACCESS_LOG: /dev/stdout
KONG_ADMIN_ACCESS_LOG: /dev/stdout
KONG_PROXY_ERROR_LOG: /dev/stderr
KONG_ADMIN_ERROR_LOG: /dev/stderr
KONG_ADMIN_LISTEN: 0.0.0.0:8001
ports:
- "8000:8000" # public proxy
- "8001:8001" # admin api (read-only for config in DB-less mode)
volumes:
- ./kong/kong.yml:/kong/declarative/kong.yml:ro
app:
build:
context: .
dockerfile: Dockerfile

7) Run it

docker compose up -d --build

Then test it.

Without an API key, access should fail because the route is protected by the Key Auth plugin. (Kong Docs)

curl -i http://localhost:8000/api

With the API key in a header, it should succeed. Kong’s Key Auth plugin supports reading keys from headers, query parameters, or request body, depending on config. (Kong Docs)

curl -i \
-H "apikey: super-secret-demo-key" \
http://localhost:8000/api

You can also use a query string:

curl -i "http://localhost:8000/api?apikey=super-secret-demo-key"

8) Test rate limiting

The plugin is set to 5 requests per minute, so the sixth quick request should return 429. Kong’s rate-limiting plugin supports time windows including seconds, minutes, hours, days, months, and years. (Kong Docs)

for i in {1..6}; do
curl -s -o /dev/null -w "%{http_code}\n" \
-H "apikey: super-secret-demo-key" \
http://localhost:8000/api
done

9) Useful checks

See running containers:

docker compose ps

Follow Kong logs:

docker compose logs -f kong

Follow app logs:

docker compose logs -f app

Read the service list from the Admin API:

curl http://localhost:8001/services

In DB-less mode, that Admin API is useful for inspection, but Kong’s docs say you cannot use it for normal write-based configuration management because the declarative file is the source of truth. (Kong Docs)

10) What makes this different from Traefik

With Traefik, the main workflow was “discover containers and route traffic to them.” With Kong, the model is “define Services and Routes, then attach policy plugins like auth and rate limiting.” Kong’s docs emphasize entities such as Services, Routes, Consumers, Upstreams, and Plugins as the core gateway model. (Kong Docs)

So in practice:

  • Traefik is great for app routing and reverse proxying.
  • Kong is better when you want API-specific control like identity, quotas, and policy.

11) Resume line

Built a containerized API behind Kong Gateway in DB-less mode using declarative configuration, API key authentication, and per-consumer rate limiting.

12) Best next upgrade

The strongest next step is to add JWT auth or request transformation, because those show off Kong as an API gateway rather than just a reverse proxy. Kong’s plugin ecosystem is one of its main strengths. (Kong Docs)