DevOps
Moving Off PaaS: Deploying Production Laravel Stacks with Kamal 2
Michael Laweh Dev.to (EN Zone)
3 views
Platform-as-a-Service (PaaS) providers make launching a web application simple. You push code, and they handle the infrastructure. However, as your application grows, the cost scales aggressively. What starts as a $20/month hobby server can scale to hundreds or thousands of dollars for simple database upgrades, extra RAM, or custom background workers.
In the past, moving off a PaaS meant adopting complex container orchestrators like Kubernetes or spending hours writing custom server setup scripts.
Kamal 2 (created by 37signals) offers a middle ground. It is an infrastructure-agnostic deployment tool that allows you to deploy containerized applications to any virtual private server (like Hetzner, DigitalOcean, or bare metal) with zero downtime, using a clean SSH-based workflow.
Here is a practical engineering guide to deploying a production Laravel application using Kamal 2.
1. Prerequisites and Docker Setup
To deploy with Kamal, your application must be containerized. We need a production-ready Dockerfile that packages PHP-FPM, Nginx, and the necessary PHP extensions.
Create a Dockerfile in the root of your Laravel project:
FROM php:8.4-fpm-alpine
# Install system dependencies and PHP extensions
RUN apk add --no-cache \
nginx \
supervisor \
postgresql-dev \
libxml2-dev \
oniguruma-dev \
libpng-dev \
zip \
unzip \
git \
curl \
bash
RUN docker-php-ext-install pdo_pgsql mbstring xml gd bcmath opcache
# Copy Nginx and Supervisor configs
COPY docker/nginx.conf /etc/nginx/nginx.conf
COPY docker/supervisord.conf /etc/supervisord.conf
# Copy application files\WORKDIR /var/www/html
COPY . .
# Install composer dependencies
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
RUN composer install --no-dev --optimize-autoloader --no-interaction
# Set directory permissions
RUN chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache
# Expose port 80 and boot supervisor
EXPOSE 80
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
2. Installation and Initializing Kamal
Ensure you have Docker running locally. Then, install Kamal on your local development machine:
gem install kamal
Once installed, run the initialization command in your Laravel project root:
kamal init
This command generates three key files:
config/deploy.yml: The primary deployment configuration file.
.env: Locally contains secret keys and registry passwords (ignored by git).
.kamal/secrets: Scripts for managing secrets securely.
3. Configuring config/deploy.yml
The deploy.yml file defines your servers, your container image registry, and your service configurations. Here is a production configuration setting up a Laravel app and a Redis server on a single VPS:
service: my-laravel-app
image: klytron/my-laravel-app
servers:
web:
hosts:
- 192.0.2.1 # Your VPS IP address
labels:
traefik.http.routers.my-laravel-app.rule: "Host(`app.example.com`)"
registry:
username: klytron
password:
- KAMAL_REGISTRY_PASSWORD
env:
clear:
DB_CONNECTION: pgsql
DB_HOST: 192.0.2.1
DB_PORT: 5432
DB_DATABASE: my_database
REDIS_HOST: my-laravel-app-redis
secret:
- APP_KEY
- DB_PASSWORD
accessories:
redis:
image: redis:7.2-alpine
roles:
- web
port: "6379:6379"
4. Managing Environment Secrets
To prevent sensitive API keys or database passwords from leaking, Kamal retrieves secrets from your local .env file on deployment and injects them into the running container securely.
Define your local variables in your local .env:
KAMAL_REGISTRY_PASSWORD=dckr_pat_your_docker_hub_token
APP_KEY=base64:your_production_laravel_key
DB_PASSWORD=your_production_database_password
When you deploy, Kamal reads these values and writes them to an encrypted environment file inside the target server.
5. Executing the First Deployment
With your servers, registry, and environment variables configured, run the setup routine:
```bash\ kamal setup
This command will:
1. SSH into your target server.
2. Install Docker (if not present).
3. Install Traefik as a reverse proxy.
4. Boot configured accessories like Redis.
5. Build, push, and pull your Docker images.
6. Start containers and manage traffic routing.
For subsequent updates, run `kamal deploy` for seamless zero-downtime rolling updates.
👉 **[Read the complete deep-dive with the full code repository and bonus security checklist on klytron.com](https://klytron.com/blog/moving-off-paas-kamal-2-laravel)**
Read original: https://dev.to/klytron/moving-off-paas-deploying-production-laravel-stacks-with-kamal-2-2h0j
← Previous
Digitale Souveränität: Europas Weg zur Infra-Unabhängigkeit
Next →
Mastering Advanced Server-Side Caching Patterns in Next.js 14
Related
Syncing your Obsidian
DevOps
1
DEV Community
Mastering Advanced Server-Side Caching Patterns in Next.js 14
DevOps
4
Dev.to (EN Zone)
Digitale Souveränität: Europas Weg zur Infra-Unabhängigkeit
DevOps
4
Dev.to (EN Zone)
Running a nested Proxmox homelab and Docker development on the same Windows machine
DevOps
6
DEV Community
Comments0
No comments yet — be the first