[{"data":1,"prerenderedAt":194},["ShallowReactive",2],{"seo-verification":3,"blog-deploy-your-applications-with-kamal-on-a-vps-ma-en":6,"promo-bar-likely":193},{"google":4,"bing":5},"EycwPY2XMyTkVzas3n1ygeNJFGAH513qrMjfDljzsMQ","",{"key":7,"data":8},"blog-deploy-your-applications-with-kamal-on-a-vps-ma-en",{"id":9,"slug":10,"slugs":11,"title":15,"excerpt":16,"readTime":17,"views":18,"isPinned":19,"noindex":19,"publishedAt":20,"updatedAt":21,"category":22,"categories":27,"featuredImage":29,"bgImage":30,"posterImage":31,"relatedSolution":29,"intro":32,"sections":33,"ctaTitle":136,"ctaBody":137,"ctaButton":138,"ctaUrl":139,"relatedPosts":140},40,"deploy-your-applications-with-kamal-on-a-vps",{"fr":12,"en":10,"ar":13,"es":14},"deployer-avec-kamal","انشر-تطبيقاتك-باستخدام-kamal-على-خادم-vps","desplegar-con-kamal","Deploy web applications with Kamal on a VPS","Complete Kamal v2 guide: installation, deploy.yml configuration, kamal-proxy, secrets, multi-server deployments, GitHub Actions CI\u002FCD and troubleshooting.",12,1,false,"2026-05-11T00:00:00+00:00","2026-11-08T01:13:14+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},3,"Deployment","deploiement","bg-success\u002F10 text-success",[28],{"id":23,"name":24,"slug":25,"color":26,"icon":25},null,"\u002Fblog\u002Fcovers\u002Fbg.svg","\u002Fblog\u002Fcovers\u002Fdeployer-avec-kamal-poster.svg","Kamal (formerly MRSK), built by 37signals, deploys containerized applications to one or more VPS servers from your local machine — no heavyweight orchestrator required. Since version 2, released in September 2024 (bundled by default in Rails 8, released November 2024), it replaces Traefik with its own purpose-built proxy (kamal-proxy) and centralizes secret management in `.kamal\u002Fsecrets`. The `kamal deploy` command coordinates Docker build, registry push and zero-downtime cutover in a single pass — on a single VPS or across a cluster of fifty servers.",[34,38,50,53,56,84,87,90,93,96,99,102,133],{"type":35,"title":36,"body":37},"h2","Why choose Kamal over Kubernetes to deploy web applications on a VPS?","Kubernetes solves large-scale coordination problems — service discovery, horizontal autoscaling, multi-team namespaces — that simply do not exist on a single VPS or a small cluster. Just to install it with kubeadm, the official documentation asks for 2 GB of RAM per machine and 2 CPUs for the control plane, before any application. Kamal targets a different space: it takes your Dockerfile, builds the image locally or on the server, pushes it to a registry, runs it on your servers over SSH and switches traffic without downtime using kamal-proxy. All configuration lives in a single `config\u002Fdeploy.yml` file versioned alongside your code. No control plane to maintain, no API certificates to renew, no YAML spread across ten resource types. You keep the operational simplicity of a VPS — direct SSH access, readable `docker ps`, logs in a file — while gaining a professional deployment workflow with instant rollback, health checks and automatic HTTPS.",{"type":39,"title":40,"items":41},"ul","What Kamal v2 gives you",[42,43,44,45,46,47,48,49],"**Zero-downtime deployments** — kamal-proxy waits for health checks to pass on the new container before switching traffic, and drains in-flight requests on the old one","**Single command** — `kamal deploy` chains build, registry push, SSH deployment and verification without manual steps","**Automatic Let's Encrypt HTTPS** — kamal-proxy handles TLS certificate renewal; no separate Certbot setup required","**Instant rollback** — `kamal rollback [VERSION]` repoints the proxy to an image already on the server within seconds","**Structured secret management** — `.kamal\u002Fsecrets` supports reading from 1Password, Bitwarden or environment variables without storing plain-text values in the repository","**Native multi-server and multi-role support** — web servers, Sidekiq workers, Postgres and Redis accessories described in one file, deployed in parallel","**Multiple apps on a single VPS** — since Kamal 2, several applications share one kamal-proxy without configuration conflicts","**Any stack** — Rails, Django, Node.js, Go, PHP: Kamal only requires a Dockerfile and a container registry",{"type":35,"title":51,"body":52},"Prerequisites before deploying with Kamal","On the VPS side, Kamal needs a Linux server reachable over SSH with a key (no password); its documentation mandates no particular distribution or size, but plan for at least 2 vCPU and 2 GB RAM for a standard web application with its database. Kamal can install Docker itself during the first `kamal setup` (get.docker.com script), but that requires root access over SSH — Kamal connects as root by default. Ports 80 and 443 open inbound and a DNS A record pointing to the VPS IP are required before enabling SSL. On your local machine, two options exist: install the Ruby gem (`gem install kamal`, with a Ruby environment) or use the official Docker image. The current version is 2.12.0 (June 2026). You also need a container registry — Docker Hub, GitHub Container Registry or a private registry — and its credentials.",{"type":35,"title":54,"body":55},"Kamal v1 vs Kamal v2: what changed","Kamal 2, released in September 2024 (bundled by default in Rails 8, released November 2024), replaces Traefik with kamal-proxy, an in-house reverse proxy developed by 37signals. The change is structural: Traefik is declarative (you submit a configuration and it converges), while Kamal is imperative. Version 1 had to poll Traefik's API repeatedly to determine whether a deployment had succeeded — a source of race conditions. With kamal-proxy, commands are direct and synchronous. In terms of configuration, the `traefik:` block disappears from `deploy.yml` and is replaced by `proxy:` with keys `host`, `ssl` and `app_port`. Secrets move from `.env` to `.kamal\u002Fsecrets`, a shell-evaluated file that can call external CLI tools (`op read`, `bw get`). The configuration is converted by hand; `kamal upgrade` then migrates the servers: it removes Traefik, starts kamal-proxy, then restarts the application and accessories on the new network. Kamal 2 also introduces multiple applications on a single proxy and maintenance mode (`kamal app maintenance`, then `kamal app live` to go back online).",{"type":57,"title":58,"steps":59},"steps","Installing and running your first deployment with Kamal v2",[60,63,66,69,72,75,78,81],{"title":61,"body":62},"Install Kamal on your local machine","Run `gem install kamal` (Ruby environment required) or, if you prefer to avoid Ruby, use the Docker alias: `alias kamal='docker run -it --rm -v \"${PWD}:\u002Fworkdir\" -v \"${SSH_AUTH_SOCK}:\u002Fssh-agent\" -e SSH_AUTH_SOCK=\u002Fssh-agent -v \u002Fvar\u002Frun\u002Fdocker.sock:\u002Fvar\u002Frun\u002Fdocker.sock ghcr.io\u002Fbasecamp\u002Fkamal:latest'`. Verify with `kamal version` — current version is 2.12.0.",{"title":64,"body":65},"Initialize configuration in your project","In the project root directory, run `kamal init`. Kamal generates `config\u002Fdeploy.yml` and `.kamal\u002Fsecrets`. Fill in `deploy.yml`: service name (`service: myapp`), image (`image: youruser\u002Fmyapp`), server list (`servers: web: - 203.0.113.10`), and registry (`registry: server: ghcr.io` or omitted for Docker Hub).",{"title":67,"body":68},"Configure secrets and environment variables","Add `.kamal\u002Fsecrets` to your `.gitignore`. In this file, declare secrets as shell variables: `KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD` (read from local environment) or `DB_PASSWORD=$(op read op:\u002F\u002Fvault\u002Fmyapp\u002Fdb-password)` (from 1Password). In `config\u002Fdeploy.yml`, reference them under `env.secret:` for secret values and `env.clear:` for non-sensitive variables like `RAILS_ENV=production`.",{"title":70,"body":71},"Configure the proxy and SSL","In `config\u002Fdeploy.yml`, add the proxy section: `proxy: host: app.your-domain.com ssl: true app_port: 3000`. Kamal-proxy will automatically obtain a Let's Encrypt certificate via ACME (ports 80 and 443 open). Make sure the DNS A record already points to the VPS IP before this step — the ACME challenge fails otherwise.",{"title":73,"body":74},"Provision the server (one-time step)","Run `kamal setup`. Kamal connects via SSH, installs Docker if absent, authenticates the registry, starts kamal-proxy and deploys the first version of the application. This command is the only bootstrapping step: it configures the server from scratch. On an already-equipped server, `kamal setup` detects existing Docker and skips reinstallation.",{"title":76,"body":77},"Deploy subsequent updates","For each update, run `kamal deploy`. Kamal builds the image (or retrieves it from cache if unchanged), pushes it to the registry, starts a new container alongside the old one, waits for the health check to pass (default `GET \u002Fup`), switches kamal-proxy to the new container, drains existing connections and stops the old one. The operation is visible in real time in your terminal.",{"title":79,"body":80},"Check status and view logs","After deployment: `kamal app details` shows the running version on each server, `kamal app logs -f` streams logs in real time, `kamal app exec -i 'bin\u002Frails console'` opens a console inside the production container. To check proxy status: `kamal proxy details`.",{"title":82,"body":83},"Manage accessories (database, cache)","Declare Postgres under the `accessories:` key in `deploy.yml`: image, port (bound to localhost, `port: \"127.0.0.1:5432:5432\"`, never published on all interfaces), volumes, variables. `kamal accessory boot db` starts the service on the right server. Accessories do not go through kamal-proxy — they are connected directly by the application via environment variables. This keeps the entire stack described in a single versioned file.",{"type":35,"title":85,"body":86},"Multi-server configuration and parallel deployments","Kamal deploys to all servers in a role in parallel by default. For a web cluster, list their IPs under `servers: web:`. For rolling deployments, add `boot: limit: 2 wait: 10` — Kamal will deploy to 2 servers at a time with 10 seconds between batches. Roles let you differentiate servers: under `servers:` declare `web:` (HTTP servers) and `workers:` with a specific command like `bundle exec sidekiq`. Each role can have its own servers, secrets and variables. kamal-proxy runs on every server of the primary role (`web` by default); other roles, such as `workers`, do not run it. With several web servers, put a load balancer in front of them: kamal-proxy's automatic HTTPS assumes a single-server deployment. For multiple applications on a single VPS, each has its own `service:` and `host:` in its `deploy.yml`; kamal-proxy distinguishes them by hostname and routes requests without additional configuration.",{"type":35,"title":88,"body":89},"Environment variables and secrets — best practices","The separation between clear variables and secrets is explicit in Kamal 2. In `deploy.yml`, non-sensitive variables go under `env: clear:` (they appear in logs and container inspection), and secrets under `env: secret:` — their value is read from `.kamal\u002Fsecrets` at deploy time and written to an environment file on the server instead of being passed in plain text in the `docker run` command. A secret in `.kamal\u002Fsecrets` is only injected if it is listed under `env: secret:` — at the root for all roles, or in the role or accessory that uses it. The `kamal secrets print` command displays resolved values to verify that reading from a password manager works correctly before deploying. For multiple environments (staging, production), `.kamal\u002Fsecrets.staging` and `.kamal\u002Fsecrets.production` coexist; `.kamal\u002Fsecrets-common` holds shared values.",{"type":91,"body":92},"tip","If a deployment introduces a regression, do not wait for the next build cycle: run `kamal rollback [VERSION]` to repoint kamal-proxy to a previous image already on the VPS within seconds. List available versions with `kamal app images`. Rollback rebuilds nothing — it repoints the proxy in seconds. Additionally, `kamal app exec 'command'` runs migrations in a container of the current version (`--reuse` for the active container, `-i` for a console) without manually opening an SSH session.",{"type":35,"title":94,"body":95},"Automatic HTTPS with kamal-proxy and Let's Encrypt","Kamal-proxy manages the complete TLS lifecycle: it listens on ports 80 and 443, responds to Let's Encrypt ACME challenges, obtains the certificate, stores it on the server and renews it automatically before expiration. The only prerequisite is that the hostname declared in `proxy: host:` resolves to the VPS IP and that ports 80 and 443 are open — the certificate is requested on the first HTTPS connection, and the ACME challenge fails until DNS has propagated. On a server hosting several applications, each application has its own `host:`; kamal-proxy routes by hostname and manages a separate certificate per domain. This automatic HTTPS assumes a single-server deployment: beyond that, terminate TLS on a load balancer. For domains that do not require TLS (internal environments, staging without a public domain), simply omit `ssl: true` from the `proxy:` section — the proxy then responds in HTTP on port 80.",{"type":35,"title":97,"body":98},"Troubleshooting — common errors when deploying with Kamal","**SSH connection timeout**: verify the server IP is reachable (`ssh -i your_key root@203.0.113.10`) and that the firewall allows port 22. The SSH agent must be running (`eval $(ssh-agent) && ssh-add`). **Target failed to become healthy**: the default health check hits `GET \u002Fup` — if your application does not respond on that path, declare `proxy: healthcheck: path: \u002Fhealth` in `deploy.yml`. Also verify `app_port:` matches the port your container actually listens on. **Registry authentication error**: run `kamal registry login` then retry; in CI, verify the `KAMAL_REGISTRY_PASSWORD` variable is exported before `kamal deploy`. **Port conflict on the server**: if an external process occupies port 80 or 443, kamal-proxy cannot start. Identify it with `ss -tlnp | grep -E '80|443'` and stop it. **Kamal setup fails on Docker installation**: automatic installation requires root access over SSH. If automatic installation is blocked by system policy, install Docker manually and rerun `kamal setup` — it detects existing Docker and moves to the next step.",{"type":35,"title":100,"body":101},"Integrating Kamal into a GitHub Actions CI\u002FCD pipeline","A typical GitHub Actions workflow for Kamal 2 has two jobs: a test job (run on every push) and a conditional deployment job (triggered on push to `main` or release publication). In the deployment job, install Ruby and the Kamal gem, then run `kamal deploy` with secrets injected from GitHub Secrets. Key elements of `.github\u002Fworkflows\u002Fdeploy.yml`: the deploy job depends on the test job (`needs: test`), configures environment variables (`KAMAL_REGISTRY_PASSWORD: ${{ secrets.KAMAL_REGISTRY_PASSWORD }}`), installs Kamal with a pinned version (`gem install kamal -v 2.12.0`), then runs `kamal deploy`. The SSH agent is configured via `webfactory\u002Fssh-agent@v0.10.0` with the private key stored in GitHub Secrets. Each deployment is traceable in the Actions tab, with full logs and the option to trigger manually via `workflow_dispatch`.",{"type":103,"title":104,"rows":105,"headers":130},"comparison","Kamal v1 vs Kamal v2 — key differences at a glance",[106,110,114,118,122,126],[107,108,109],"Proxy","Traefik (declarative, API polling)","kamal-proxy (imperative, direct commands)",[111,112,113],"Secrets",".env at project root",".kamal\u002Fsecrets (shell-evaluated, password manager support)",[115,116,117],"SSL","Managed by Traefik via ACME","Managed by kamal-proxy (Let's Encrypt built-in)",[119,120,121],"Multiple apps","Not natively supported","Native: multiple apps per server, single proxy",[123,124,125],"Upgrade","—","`kamal upgrade` migrates the servers (config converted by hand)",[127,128,129],"Proxy config in deploy.yml","`traefik:` block","`proxy:` block with `host`, `ssl`, `app_port`",[5,131,132],"Kamal v1","Kamal v2",{"type":35,"title":134,"body":135},"Kamal on a ServOrbit VPS — from command to live domain","A ServOrbit Cloud VPS running Ubuntu 24.04 meets all Kamal prerequisites out of the box: SSH key access, 1 Gbit\u002Fs network and a dedicated IP. The typical workflow: create a DNS A record pointing `app.your-domain.com` to the VPS IP, then run `kamal setup` from your local machine — Kamal installs Docker, starts kamal-proxy, obtains the Let's Encrypt certificate and deploys your application in one pass. From that point, every `kamal deploy` from your terminal or CI pipeline applies the update with zero downtime. To host multiple projects on the same VPS, each with its own domain and certificate, add an application in a second `deploy.yml` pointing to the same server — kamal-proxy routes by hostname without reconfiguration. Billing remains that of the VPS, with no additional deployment overhead.","Drive your Kamal deployments on a ServOrbit Cloud VPS","Provision a Cloud VPS with the Deployment template and key-based SSH access: Kamal installs Docker on it and deploys your application with zero downtime from the very first command.","See the Cloud VPS","\u002Fvps-cloud",[141,161,177],{"id":142,"slug":143,"slugs":144,"title":148,"excerpt":149,"readTime":150,"views":151,"isPinned":19,"noindex":19,"publishedAt":152,"updatedAt":153,"category":154,"categories":155,"featuredImage":29,"bgImage":30,"posterImage":157,"relatedSolution":158},33,"deploy-your-applications-with-caprover-on-a-vps",{"fr":145,"en":143,"ar":146,"es":147},"deployer-avec-caprover","انشر-تطبيقاتك-باستخدام-caprover-على-خادم-vps","desplegar-aplicaciones-con-caprover-en-un-vps","Deploy your applications with CapRover on a VPS","Complete CapRover guide: installation, captain-definition, GitHub Actions CI\u002FCD, multi-node cluster, backups and troubleshooting 502, build failed and Docker API errors.",10,2,"2026-05-18T00:00:00+00:00","2026-11-04T16:30:25+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},[156],{"id":23,"name":24,"slug":25,"color":26,"icon":25},"\u002Fblog\u002Fcovers\u002Fdeployer-avec-caprover-poster.svg",{"categorySlug":159,"appSlug":160},"application-deployment-devops","caprover",{"id":162,"slug":163,"slugs":164,"title":168,"excerpt":169,"readTime":170,"views":18,"isPinned":19,"noindex":19,"publishedAt":171,"updatedAt":172,"category":173,"categories":174,"featuredImage":29,"bgImage":30,"posterImage":176,"relatedSolution":29},34,"deploy-your-applications-with-dokku-on-a-vps",{"fr":165,"en":163,"ar":166,"es":167},"deployer-avec-dokku","انشر-تطبيقاتك-باستخدام-dokku-على-خادم-vps","desplegar-aplicaciones-con-dokku-en-un-vps","Deploy your applications with Dokku on a VPS","Complete Dokku v0.35 guide: installation, buildpacks, env vars, rollback, postgres\u002Fredis\u002Fletsencrypt plugins and troubleshooting common errors.",11,"2026-05-17T00:00:00+00:00","2026-10-18T21:57:59+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},[175],{"id":23,"name":24,"slug":25,"color":26,"icon":25},"\u002Fblog\u002Fcovers\u002Fdeployer-avec-dokku-poster.svg",{"id":178,"slug":179,"slugs":180,"title":184,"excerpt":185,"readTime":150,"views":18,"isPinned":19,"noindex":19,"publishedAt":186,"updatedAt":153,"category":187,"categories":188,"featuredImage":29,"bgImage":30,"posterImage":190,"relatedSolution":191},35,"deploy-your-applications-with-portainer-on-a-vps",{"fr":181,"en":179,"ar":182,"es":183},"deployer-avec-portainer","انشر-تطبيقاتك-باستخدام-portainer-على-خادم-vps","desplegar-aplicaciones-con-portainer-en-un-vps","Deploy your applications with Portainer on a VPS","Manage Docker visually with Portainer on your VPS: containers, stacks, volumes and networks managed from a clear web interface.","2026-05-16T00:00:00+00:00",{"id":23,"name":24,"slug":25,"color":26,"icon":25},[189],{"id":23,"name":24,"slug":25,"color":26,"icon":25},"\u002Fblog\u002Fcovers\u002Fdeployer-avec-portainer-poster.svg",{"categorySlug":159,"appSlug":192},"portainer",true,1794270388254]