Creating and Installing Custom Lua Plugins in Kong
Get up and running with custom Kong plugins in minutes.

What is Kong?
If you’ve ever done any Microservice development you may have heard of the term “API Gateway” before. An API Gateway is an architectural design pattern related to microservices that solves the problem of how clients are supposed to communicate with a large number of discrete microservices that make up a larger application or platform. API Gateways solve this problem by providing a single access point for all clients to an application.
Generally, an API Gateway’s only job is to accept requests and proxy them to the appropriate backend service, but in reality, they often have several more duties including rate-limiting, authentication, authorization, caching, filtering, logging, and more.

There is no shortage of potential offerings when looking at the landscape of API Gateway services and technologies. Most of the major cloud players have their own gateways, Amazon API Gateway for AWS, API Management in Azure, and most notably Apigee for GCP. However, there exist many options beyond those offered by the cloud providers, including more established enterprise options like the Anypoint Platform from Mulesoft, and a whole host of newer options such as Kong, Tyk, and Express Gateway, all of which offer open-source versions. Of these latter three, Kong is arguably the most widely used and feature-rich — so it’s a good place to start.

At its core, Kong is an application written in Lua and built on top of Nginx using OpenResty. Kong also offers a variety of additional functionality as part of its OSS version and even more with its enterprise package. In my opinion, Kong was the most interesting of the API Gateways to look at for 3 reasons.
- It offers a free, open-source version that is highly capable and works right out of the box.
- It’s highly extensible, with the ability to add custom plugins in addition to a number of very usable built-in plugins.
- It’s a super performant. When configured and provisioned well, Kong is blazing fast.
Kong Plugins
Kong is a Lua application designed to load and execute Lua modules (which we more commonly refer to as “plugins”) and provides an entire development environment for them, including an SDK, database abstractions, migrations, and more.
Kong allows for the extensibility of its request handling capabilities by the way of adding custom Lua plugins. These plugins can add just about any functionality you can think of, including proxying, request/response modification, rate-limiting, and more. Plugins can be applied to individual routes, whole APIs, or globally on the Kong instance. Currently, Kong plugins can only be written in Lua, but support for plugins written in Go is expected to be added in version 2.0 which is coming soon.
Writing a Custom Plugin
Kong provides a Plugin Development Kit (PDK) which exposes various methods for interacting with a request and performing other actions or accessing data stores from within the plugin scope. If you’re like me and are unfamiliar with Lua, I thought this walkthrough was useful for getting started.
A typical plugin should be structured as follows in order to be installed successfully in Kong:
<plugin-name>
├── kong
│ └── plugins
│ └── <plugin-name>
│ ├── handler.lua
│ └── schema.lua
└── <plugin-name>-<version>.rockspec
Let’s look briefly at each of these files.
handler.lua
The handler.lua file must return a table implementing the functions you wish to be executed. In other words, this file will handle the core of your plugin’s logic. While you can create additional Lua files the contain additional logic, the handler.lua is the only module that will actually be invoked directly by Kong at runtime. You can read more about the options available to the handler.lua module here.
schema.lua
The schema.lua module is to return a Lua table with properties that will define how your plugins can later be configured by users. You can read more about the options available to the schema.lua module here.
<plugin_name>-<version>.rockspec
LuaRocks is the package manager for the Lua programming language and rockspec files are used to define a package, which is also called a rock. In order to package a new plugin, you will need to provide a rockspec file.
Running Kong
For the ease of running and testing Kong locally, I recommend to use docker-compose and create your own configuration based on Kong’s own docker implementations. In addition to this, I’d also recommend running Konga which is a third-party GUI that can be used to interact with the Kong Admin API in the browser.
In order to do this, we’ll need a Dockerfile for running Kong itself as well as a docker-compose file that will provide Postgres (for running Kong) as well as Konga and MongoDB (a Konga dependency). I won’t go into too much depth around these documents but you can view all of the files for this project here.
Dockerfile
docker-compose.yml
Other Scripts and Configs
There are also a few other scripts and configs we’ll need to tie everything together. For brevity, I won’t list their contents here — but you can view them in the shared repo.
These files include a kong.conf file, which will be used to configure the Kong instance. We will also need a docker-entrypoint.sh file which you can see referenced in the Dockerfile — this file is used to define the startup behavior of Kong, including running a small script to install our custom plugins.
Finally, we need to add a small user seed file in order to bootstrap Konga. I’ve named mine kus.js, and you can see it referenced in the docker-compose.yml file.
Our Custom Plugin
We’re going to build a sensitive data filter which will try to detect any secret tokens headers in our response headers and remove them. We’ll name our plugin hide-token.
Note: this is just an illustrative example, I’ve based my code on the more capable, built-in plugin Response-Transformer which could also likely handle this use case.
handler.lua
schema.lua
header_filter.lua
I’ve also added a separate file to contain the actual header removal logic. This was to separate responsibilities as well as to show how to include an additional file beyond the two strictly required ones.
hide-token-1.0.0.rockspec
You can learn more about the rockspec format here.
Installing the Plugin
At this point installing the plugin should be fairly simple if you’ve followed along. We just need to make the following modifications:
- Add a small script to be called from your docker-entrypoint.sh file. This script just needs to build the plugin by calling
luarocks make
in the same directory as your rockspec file.
2. Add your plugin name to the plugins attribute in the kong.conf file.
That’s it.
Testing
Let’s begin by starting up our environment by running docker-compose build && docker-compose up -d
in the root of our project. (This may take a while to pull all the layers). If that step was successful you should be able to navigate to http://localhost:1337
and see the Konga login screen.
You can log into Konga using the credentials from your user seed file. Once logged in you should be able to click on the Plugins
item in the sidebar menu and then click + Add Global Plugin
and see your custom plugin listed under the Other
category. You can go ahead and add your plugin and configure as you desire.

Now that we have a global plugin configured, we should add a Service and Route to test against —I ended up using mockoon for this after not having much luck with any of the free hosted services I found. It was a joy to use for ad-hoc testing; super simple and flexible.
My mock endpoint should return the JSON {“status”:”A-OK”}
as well as headers SECRET-TOKEN: MUH SECRETZ
and NOT-SO-SECRET: abc123
along with a 200 OK response.
For my test, I added a new Service to proxy to http://host.docker.internal:3000/
which will route from the docker container to my MacBook and hit the open port for mockoon. I then added a new Route to this service to match all incoming requests without removing the path using the regex /.*
.
Before configuring my plugin the response looked like this when curled.
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Content-Length: 17
< Connection: keep-alive
< X-Powered-By: Express
< SECRET-TOKEN: MUH SECRETZ
< NOT-SO-SECRET: abc123
< ETag: W/"11-xthkVpV/BvEyfleURt8wQpCqVD8"
< Date: Sun, 12 Jan 2020 16:52:20 GMT
< X-Kong-Upstream-Latency: 1528
< X-Kong-Proxy-Latency: 11
< Via: kong/1.4.3
<
* Connection #0 to host 0.0.0.0 left intact
{"status":"A-OK"}
After enabling my plugin to filter out the SECRET-TOKEN
header the response looks like this. Notice a certain header is missing.
< HTTP/1.1 200 OK
< Content-Type: application/json; charset=utf-8
< Content-Length: 17
< Connection: keep-alive
< X-Powered-By: Express
< NOT-SO-SECRET: abc123
< ETag: W/"11-xthkVpV/BvEyfleURt8wQpCqVD8"
< Date: Sun, 12 Jan 2020 16:54:07 GMT
< X-Kong-Upstream-Latency: 2322
< X-Kong-Proxy-Latency: 14
< Via: kong/1.4.3
<
* Connection #0 to host 0.0.0.0 left intact
{"status":"A-OK"}
Conclusion
This was just a simple example of getting Kong running locally in Docker and adding a simple custom plugin — which is just scratching the surface of what Kong is capable of. Let me know below if there are any other Kong related subjects you’d like to hear about, or if any of its competitors like Tyk or express-gateway are of interest.