Kamal Proxy Image Contract
Relevant source files
The following files were used as context for generating this wiki page:
Kamal uses kamal-proxy to facilitate zero-downtime deployments by seamlessly switching traffic between application containers. The "Proxy Image Contract" defines the strict requirements for the Docker image, versioning strategy, and metadata labels that the Kamal CLI expects when managing the proxy lifecycle. This contract ensures compatibility between the Ruby gem and the Go-based proxy binary.
Sources: README.md:5-7, CLAUDE.md:104-108
Image Identification and Metadata
Kamal relies on specific Docker labels to identify and manage proxy containers. The image must carry the label org.opencontainers.image.title=kamal-proxy. This label is critical for cleanup operations, as Kamal uses it to prune old images and containers during the kamal proxy remove command.
Sources: CLAUDE.md:108, test/cli/proxy_test.rb:149-151
Configuration Digesting
To detect configuration drift and determine if a reboot is necessary, Kamal attaches a configuration digest to the proxy container using the label org.kamal.proxy-config-digest.
Sources: test/cli/proxy_test.rb:16-17, test/cli/proxy_test.rb:116-120
Versioning and Compatibility
Kamal enforces a strict versioning contract to ensure the CLI can successfully communicate with the proxy.
Version Detection Logic
Kamal reads the running proxy version directly from the Docker image tag using a specific inspect command:
docker inspect kamal-proxy --format '{{.Config.Image}}'
Sources: CLAUDE.md:104-105
Minimum Version Requirements
The CLI maintains a MINIMUM_VERSION constant. If the running proxy version is older than this minimum, Kamal will refuse to boot or deploy until the proxy is rebooted and updated. Version comparisons are performed using Gem::Version.
Sources: CLAUDE.md:104-105, test/cli/proxy_test.rb:128-132, test/proxy_flag_coverage_test.rb:48-55
Fork Versioning Strategy
For the dash fork of Kamal, a four-segment tagging system is used (e.g., v0.9.2.1). This ensures the fork versions sort above the upstream base but below the next upstream release, preventing collisions with official tags.
Sources: CLAUDE.md:106-107
Command and Flag Contract
The proxy image must support specific subcommands and flags that Kamal invokes during the deployment lifecycle.
Core Subcommands
| Subcommand | Description |
|---|---|
run | Starts the proxy server and begins routing traffic. |
deploy | Registers a new application version and begins the transition. |
list | Lists currently registered services. Must support --json for verification. |
drain | Gracefully stops the proxy after finishing active requests. |
hold | Used in the port-holder architecture to maintain ports during transitions. |
domains | Manages runtime SSL domain discovery (refresh, list, stats). |
cache | Administers the response cache (purge, stats). |
Sources: test/cli/proxy_test.rb:19, test/cli/proxy_test.rb:108-112, test/cli/proxy_test.rb:252-258, test/proxy_flag_coverage_test.rb:23-26
The Flag Coverage Requirement
Kamal maintains a manifest of flags accepted by the proxy. Any new flag added to the proxy must either be exposed via deploy.yml or explicitly waived in the gem's test suite to ensure the CLI surface area matches the proxy's capabilities.
Sources: test/proxy_flag_coverage_test.rb:10-18
Lifecycle and Architecture Flows
The proxy image contract enables two primary architectural patterns for updates: Standard Reboot and Port-Handoff.
Zero-Downtime Port Handoff
When using the port-holder architecture, Kamal manages two generations of the proxy simultaneously to ensure no requests are dropped.
The sequence of a zero-downtime handoff between proxy generations using a shared network namespace.
Sources: test/cli/proxy_test.rb:133-150
Configuration Validation Flow
Kamal performs extensive validation of the proxy configuration before attempting to interact with the image on remote hosts.
Logic flow for validating proxy settings within the Kamal Configuration module.
Sources: lib/kamal/configuration/validator/proxy.rb:5-40, lib/kamal/configuration.rb:304-315
Runtime Environment and Secrets
The proxy expects specific environment variables and volume mounts to function correctly according to the contract.
- Secrets File: Sensitive credentials (like ACME DNS tokens or Redis cache URLs) are delivered via a
0600permissioned file at.kamal/proxy/secrets.env. This prevents secrets from appearing indocker inspector process listings. - Config Volume: The named volume
kamal-proxy-configis mounted to/home/kamal-proxy/.config/kamal-proxyto persist state across reboots. - Docker Socket: For "scale-to-zero" (sleep) features, the Docker runtime socket must be mounted into the proxy container via the
proxy/run/docker_socketconfiguration.
Sources: test/cli/proxy_test.rb:39-45, test/cli/proxy_test.rb:142-145, lib/kamal/configuration.rb:339-345
Conclusion
The Kamal Proxy Image Contract establishes the operational boundaries required for kamal-proxy to serve as the ingress layer for containerized applications. By adhering to specific labeling, versioning, and command-line interfaces, the proxy image allows Kamal to perform complex deployment maneuvers—such as zero-downtime handoffs and automatic configuration drift correction—with high reliability.