/kamal-proxy

Lightweight proxy server for Kamal

Primary LanguageGoMIT LicenseMIT

Kamal Proxy - A minimal HTTP proxy for zero-downtime deployments

What it does

Kamal Proxy is a tiny HTTP proxy, designed to make it easy to coordinate zero-downtime deployments. By running your web applications behind Kamal Proxy, you can deploy changes to them without interrupting any of the traffic that's in progress. No particular cooperation from an application is required for this to work.

Kamal Proxy is designed to work as part of Kamal, which provides a complete deployment experience including container packaging and provisioning. However, Kamal Proxy could also be used standalone or as part of other deployment tooling.

A quick overview

To run an instance of the proxy, use the kamal-proxy run command. There's no configuration file, but there are some options you can specify if the defaults aren't right for your application.

For example, to run the proxy on a port other than 80 (the default) you could:

kamal-proxy run --http-port 8080

Run kamal-proxy help run to see the full list of options.

To route traffic through the proxy to a web application, you deploy instances of the application to the proxy. Deploying an instance makes it available to the proxy, and replaces the instance it was using before (if any).

Use the format hostname:port when specifying the instance to deploy.

For example:

kamal-proxy deploy service1 --target web-1:3000

This will instruct the proxy to register web-1:3000 to receive traffic under the service name service1. It will immediately begin running HTTP health checks to ensure it's reachable and working and, as soon as those health checks succeed, will start routing traffic to it.

If the instance fails to become healthy within a reasonable time, the deploy command will stop the deployment and return a non-zero exit code, allowing deployment scripts to handle the failure appropriately.

Each deployment takes over all the traffic from the previously deployed instance. As soon as Kamal Proxy determines that the new instance is healthy, it will route all new traffic to that instance.

The deploy command also waits for traffic to drain from the old instance before returning. This means it's safe to remove the old instance as soon as deploy returns successfully, without interrupting any in-flight requests.

Because traffic is only routed to a new instance once it's healthy, and traffic is drained completely from old instances before they are removed, deployments take place with zero downtime.

Host-based routing

Host-based routing allows you to run multiple applications on the same server, using a single instance of Kamal Proxy to route traffic to all of them.

When deploying an instance, you can specify a host that it should serve traffic for:

kamal-proxy deploy service1 --target web-1:3000 --host app1.example.com

When deployed in this way, the instance will only receive traffic for the specified host. By deploying multiple instances, each with their own host, you can run multiple applications on the same server without port conflicts.

Only one service at a time can route a specific host:

kamal-proxy deploy service1 --target web-1:3000 --host app1.example.com
kamal-proxy deploy service2 --target web-2:3000 --host app1.example.com # returns "Error: host is used by another service"
kamal-proxy remove service1
kamal-proxy deploy service2 --target web-2:3000 --host app1.example.com # succeeds

Automatic TLS

Kamal Proxy can automatically obtain and renew TLS certificates for your applications. To enable this, add the --tls flag when deploying an instance:

kamal-proxy deploy service1 --target web-1:3000 --host app1.example.com --tls

Custom TLS certificate

When you obtained your TLS certificate manually, manage your own certificate authority, or need to install Cloudflare origin certificate, you can manually specify path to your certificate file and the corresponding private key:

kamal-proxy deploy service1 --target web-1:3000 --host app1.example.com --tls --tls-certificate-path cert.pem --tls-private-key-path key.pem

Specifying run options with environment variables

In some environments, like when running a Docker container, it can be convenient to specify run options using environment variables. This avoids having to update the CMD in the Dockerfile to change the options. To support this, kamal-proxy run will read each of its options from environment variables if they are set. For example, setting the HTTP port can be done with either:

kamal-proxy run --http-port 8080

or:

HTTP_PORT=8080 kamal-proxy run

If any of the environment variables conflict with something else in your environment, you can prefix them with KAMAL_PROXY_ to disambiguate them. For example:

KAMAL_PROXY_HTTP_PORT=8080 kamal-proxy run

Building

To build Kamal Proxy locally, if you have a working Go environment you can:

make

Alternatively, build as a Docker container:

make docker

Trying it out

See the example folder for a Docker Compose setup that you can use to try out the proxy commands.