How to build, install, and run a go plugin

Is there any up to date documentation or examples for creating, installing, and running a go plugin.
Some (most?) of the existing examples seem to be out of date and the current docs are not very clear.

The first example I followed makes use of GitHub - Kong/go-pluginserver: Kong Go Plugin Server. However, I see that it is deprecated

the external go-pluginserver is deprecated, and no longer maintained. For Kong 2.8.0, while existing usage of the old style will still be supported, users are encouraged to upgrade to the new embedded server style. And it will be no longer supported since Kong 3.0.0. Check out the Docs for upgrade steps.

What is “old style” vs “embedded server style”? Do I need to run a server using “”?

What should the dockerfile look like?

How to I install and run the plugin?
I have tried the plugins but this example set: GitHub - Kong/go-plugins: A collection of Kong plugins written in Go but I’m getting this error when trying to run the plugin: “Not a plugin info table”.

	A "hello world" plugin in Go,
	which reads a request header and sets a response header.

package main

import (


func main() {
	server.StartServer(New, Version, Priority)

var Version = "0.2"
var Priority = 1

type Config struct {
	Message string

func New() interface{} {
	return &Config{}

func (conf Config) Access(kong *pdk.PDK) {
	host, err := kong.Request.GetHeader("host")
	if err != nil {
		log.Printf("Error reading 'host' header: %s", err.Error())

	message := conf.Message
	if message == "" {
		message = "hello"
	kong.Response.SetHeader("x-hello-from-go", fmt.Sprintf("Go says %s to %s", message, host))


pluginserver_my-plugin_query_cmd=/kong/go-plugins/my-plugin -dump

Any help would be greatly appreciated

Hope this video helps

I had the same problem as you. My understanding from what I read in the docs is that in “the old style”, an external go pluginserver needed to be build and it would be used for every plugin created. The embedded server implementation means that now every plugin has its own server and it is build automatically when running the plugin executable.
Your plugin code looks alright.
To add the plugin to Kong you need to build a custom image. I built the image in two stages: the builder stage, where I used a golang base image to build the plugin executable, and then I built the Kong image and I copied the executable. For example, my Dockerfile looked like this:

FROM golang:1.18.1-alpine3.15 as builder

RUN mkdir /myplugin

COPY /customs/plugin.go /myplugin/
RUN cd /myplugin/ && \
  go mod init kong-go-plugin && \
  go get && \
  go get -d -v && \
  go build && \
  go build plugin.go

FROM kong:2.8.1-alpine

USER root
COPY --from=builder /myplugin/plugin /usr/local/bin/

USER kong
EXPOSE 8000 8443 8001 8444
HEALTHCHECK --interval=10s --timeout=10s --retries=10 CMD kong health
CMD ["kong", "docker-start"]

So, now the plugin executable will exist in the /usr/local/bin/ location inside the Kong container.
You could manually run ./plugin inside your container and you would see plugin.socket created in /usr/local/kong . Basically, this is where the embedded server exists.

The env vars in my case looked like this:

  plugins: bundled, plugin
  pluginserver_names: plugin
  pluginserver_plugin_socket: /usr/local/kong/plugin.socket
  pluginserver_plugin_start_cmd: /usr/local/bin/plugin
  pluginserver_plugin_query_cmd: /usr/local/bin/plugin -dump

In my case this worked. I hope it helps!

Followed the steps, but still see the problem of loading plugin
kong_1 | 2022/04/21 09:19:24 [notice] 1109#0: *17 [kong] process.lua:256 Starting go-hello, context: ngx.timer
kong_1 | 2022/04/21 09:19:24 [info] 1109#0: *17 [go-hello:1130] 2022/04/21 09:19:24 removing “/usr/local/kong/go-hello.socket”: remove /usr/local/kong/go-hello.socket: read-only file system, context: ngx.timer
kong_1 | 2022/04/21 09:19:24 [notice] 1109#0: signal 17 (SIGCHLD) received from 1130
kong_1 | 2022/04/21 09:19:24 [notice] 1109#0: *17 [kong] process.lua:272 external pluginserver ‘go-hello’ terminated: exit 0, context: ngx.timer

In building my Docker image with a Go plugin, I started from kong/go-plugin-tool:latest-alpine-latest:

FROM kong/go-plugin-tool:latest-alpine-latest AS builder
RUN mkdir -p /tmp/go-plugins/bin/
COPY src/ /tmp/go-plugins/src/
RUN cd /tmp/go-plugins/src && \
   go get && \
   go mod init kong-bespoke-plugins-go && \
   go build -o ../bin/request-transformer-addtoken ./request-transformer-addtoken/request-transformer-addtoken.go 

FROM kong/kong-gateway:
USER root
COPY --from=builder /tmp/go-plugins/bin/* /usr/local/bin/

And then add it to the Kong configuration:

     -e "KONG_PLUGINSERVER_NAMES=request-transformer-addtoken" \
     -e "KONG_PLUGINSERVER_REQUEST_TRANSFORMER_ADDTOKEN_QUERY_CMD=/usr/local/bin/request-transformer-addtoken -dump" \
     -e "KONG_PLUGINS=bundled,request-transformer-addtoken" \

I also struggled a bit with the PDK documentation, having to figure it out by trial-and-error. Hopefully as the PDK matures, so will the documentation/examples.