Help creating a new example boilerplate plugin and how to compile it?

So I’m working on building a very basic boilerplate Caddy plugin. But I’m having issues just compiling caddy with a plugin and I was hoping I could get some guidance. After this I will be working on porting an ingress toolkit and a onion routed DHT server as plugins. Caddy has the exact structure I realized I needed and instead of reinventing the wheel it seems building plugins on Caddy makes more sense.

The guide seems to assume some knowledge and doesn’t fully explain the process of building caddy with plugins.

It is my understanding to compile caddy with a plugin you need to modify:

caddy/caddy/caddymain/run.go

And add in the import line

_ "github.com/lostinblue/boilerplate-caddy-plugin"

Then this will cause the init() function in the plugin to run:

https://raw.githubusercontent.com/lostinblue/boilerplate-caddy-plugin/master/boilerplate.go

I’m trying to implement the simplest possible boilerplate plugin:

package boilerplate

import (
	"net/http"
	"regexp"
	"time"

	"github.com/mholt/caddy"
	"github.com/mholt/caddy/caddyhttp/httpserver"
)

type matchDef struct {
	Re       *regexp.Regexp
	Duration time.Duration
}

func init() {
	caddy.RegisterPlugin("boilerplate", caddy.Plugin{
		ServerType: "http",
		Action:     setup,
	})
}

func setup(c *caddy.Controller) error {
	cfg := httpserver.GetConfig(c)
	mid := func(next httpserver.Handler) httpserver.Handler {
		return boilerplateHandler{Next: next}
	}
	cfg.AddMiddleware(mid)

	return nil
}

type boilerplateHandler struct {
	Next  httpserver.Handler
	Rules []*matchDef
}

func (h boilerplateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
	for _, rule := range h.Rules {
		if rule.Re.MatchString(r.URL.Path) {
			w.Header().Set("Boilerplate", "TEST")
			break
		}
	}
	return h.Next.ServeHTTP(w, r)
}
1 Like

To be clear, my setup works when I remove my custom directive.

That’s right, so far (at a glance, since I’m not sure what to look for). Are you getting an error?

After modifying run.go, you simply run ./build.bash in the caddy subfolder in the caddy repo and it will spit out a binary in the current folder called caddy. Run that and make sure your directive “boilerplate” appears in your Caddyfile.

Odd, thought I included the errors but I clearly did not.

working.website {
  gzip
  root /var/www/website
  boilerplate
}

So If I call my directive inside like shown above I get the following error:

Caddyfile:4 - Parse error: Unknown directive 'boilerplate'

And when I call it outside like so:

working.website {
  gzip
  root /var/www/website
  boilerplate
}
boilerplate

Then I get this error, because I guess its assuming its a domain:

[boilerplate] failed to get certificate: acme: Error 400 - urn:acme:error:malformed - Error creating new authz :: DNS name does not have enough labels

For now I’m trying on a fresh install to see if that makes any difference. I see places I can simplify the boilerplate code further too which I will go ahead and do.

So it does seem I’m doing it right so there must be something being overlooked on my end.

Well, putting it outside will make Caddy think it’s a site address; see The Caddyfile — Caddy Documentation for the syntax.

So inside is correct. Make sure you’ve followed all the instructions here: https://github.com/mholt/caddy/wiki/Writing-a-Plugin:-Directives

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.