# caddy-incus-upstreams > Status: **HIGHLY experimental**, patches welcome 🚩 [`Incus`](https://linuxcontainers.org/incus/) dynamic upstreams for [`Caddy`](https://caddyserver.com/docs/) 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. ```bash incus launch images:alpine/3.20 incus config set user.caddyserver.http.enable=true incus config set user.caddyserver.http.matchers.host= incus config set user.caddyserver.http.upstream.port= ``` Build a fresh `Caddy` with this plugin. ```bash xcaddy build --with=git.coopcloud.tech/decentral1se/caddy-incus-upstreams ``` Wire up a `Caddyfile` based on this example. ```Caddyfile { reverse_proxy { dynamic incus } } ``` And then make sure everything gets picked up with a `reload`/`restart`. ``` caddy reload incus restart ``` ## 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](https://caddy.community/t/how-to-use-dns-provider-modules-in-caddy-2/8148j) and wire up something like this in your `Caddyfile`. ```Caddyfile { acme_dns } *. { reverse_proxy { dynamic incus } } ``` ## Hackin' Install [`xcaddy`](https://github.com/caddyserver/xcaddy) and [`Incus`](https://linuxcontainers.org/incus/). Create this `Caddyfile` in the root of the project repository. ```Caddyfile { debug http_port 6565 } http://foo.localhost { reverse_proxy { dynamic incus } } ``` Then create a new instance and assign the relevant config. ```bash 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 * [`caddy-docker-upstreams`](https://github.com/invzhi/caddy-docker-upstreams) ## License