Incus dynamic upstreams for Caddy v2+ 🧨
Go to file
2024-12-29 16:32:09 +00:00
.gitignore feat: init 2024-12-12 15:31:54 +01:00
go.mod chore(dep): upgrade otel dependency 2024-12-28 17:08:00 -07:00
go.sum chore(dep): upgrade otel dependency 2024-12-28 17:08:00 -07:00
incus.go refactor: less info/error 2024-12-18 15:47:59 +01:00
LICENSE feat: init 2024-12-12 15:31:54 +01:00
README.md chore(dep): upgrade otel dependency 2024-12-28 17:08:00 -07:00

caddy-incus-upstreams

Status: HIGHLY experimental, patches welcome 🚩

Incus dynamic upstreams for Caddy v2+ 🧨

In other words, Caddy can automatically pick up your Incus instances when they have 3 config keys attached to them which specify 1. that they want to be routed 2. which domain should be routed to them 3. which port they'll answer on. Combined with the lightweight configuration and the Auto-TLS (magic) powers of Caddy, provisioning Incus instances to serve on the web is much more convenient.

Usage

Set the following config on your Incus instance.

incus launch images:alpine/3.20 <instance-name>
incus config set <instance-name> user.caddyserver.http.enable=true
incus config set <instance-name> user.caddyserver.http.matchers.host=<domain>
incus config set <instance-name> user.caddyserver.http.upstream.port=<port>

Build a fresh Caddy with this plugin.

xcaddy build --with=git.coopcloud.tech/decentral1se/caddy-incus-upstreams 

Wire up a Caddyfile based on this example.

<domain> {
  reverse_proxy {
    dynamic incus
  }
}

And then make sure everything gets picked up with a reload/restart.

caddy reload
incus restart <instance-name>

Notes

The plugin responds to the following Incus events:

  • api.EventLifecycleInstanceCreated
  • api.EventLifecycleInstanceRestarted
  • api.EventLifecycleInstanceResumed
  • api.EventLifecycleInstanceStarted

There is a rather crude implementation for handling these events. We simply wire up a few seconds of sleep to allow for the network part of the instance to come up. Otherwise, there is no network address to retrieve.

We currently only match against the upstream ipv4 addresses of instances.

The system user that runs Caddy must be root or be in the incus-admin group so that it can make queries across projects for different instances.

FAQ

Does this support wildcard certificates?

Yes! You'll need to enable a DNS plugin and wire up something like this in your Caddyfile.

{
  acme_dns <your-provider-here> <your-token-here>
}

*.<domain> {
  reverse_proxy {
    dynamic incus
  }
}

Hackin'

Install xcaddy and Incus.

Create this Caddyfile in the root of the project repository.

{
  debug
  http_port 6565
}

http://foo.localhost {
  reverse_proxy {
    dynamic incus
  }
}

Then create a new instance and assign the relevant config.

incus launch images:alpine/3.20 foo
incus config set foo user.caddyserver.http.enable=true
incus config set foo user.caddyserver.http.matchers.host=foo.localhost
incus config set foo user.caddyserver.http.upstream.port=80

Serve something from your instance.

incus shell foo
apk add python3
python3 -m http.server 80

Run Caddy with the plugin baked in.

xcaddy run

And finally, route a request to the instance via Caddy.

curl -X GET http://foo.localhost:6565

🧨

ACK

License