Why Use Kamal for Deployment?
Wondering why Kamal is the right choice? Kamal makes your deployments stress-free and efficient. Here’s how:
- Kamal uses clean, YAML-based config files that are easy to set up and manage.
- Seamlessly integrates with Docker for consistent builds, no matter where you deploy.
- Enjoy rolling deployments that keep your app running smoothly—no more midnight emergencies.
- Kamal constantly monitors your app’s health so you can rest easy.
What You Need Before Starting
Let’s make sure you’re all set before we start:
- AWS account + CLI configured
- Docker installed (know your way around basic commands)
- Kamal 2.4 or later
- Familiarity with GitHub Actions
- A Next.js app ready to rock
Initializing Kamal in Your Project
Before diving into configuration, you need to initialize Kamal in your project. This sets up the necessary directory structure and files. Run the following command inside your project repository:
kamal init
This command will create a .kamal
directory with the initial configuration files you'll customize later.
Project Structure Breakdown
Here’s a quick peek at how your project should look:
project-root/
├── .kamal/ # Kamal config
│ ├── deploy.yml # Deployment settings
│ └── secrets # Secrets storage
├── .github/workflows/ # GitHub Actions workflows
│ └── release-deploy.yml # Auto-deployment script
├── Dockerfile # Docker build instructions
├── package.json # Dependencies
├── yarn.lock # Lock file
├── .env # Local env variables
├── public/ # Static assets
└── .next/ # Compiled Next.js build
Example deploy.yml
(Kamal Configuration)
defaults:
service: web-app
image: example/web-app
servers:
web:
- 192.168.1.1
ssh:
user: ubuntu
keys: ["~/.ssh/example-key.pem"]
proxy:
ssl: false
app_port: 3000
host: stagingapp.example.io
healthcheck:
path: /
interval: 3
timeout: 30
registry:
server: 123456789012.dkr.ecr.us-west-1.amazonaws.com
username: AWS
password: <%= %x(aws ecr get-login-password) %>
builder:
arch: amd64
context: .
env:
clear:
NEXT_PUBLIC_APP_BACKEND_URL: https://staging.api.example.io
NEXT_PUBLIC_APP_PUBLIC_IP_API: https://pro.ip-api.com/json/?key=dummykey
Building the Dockerfile
Here’s a lean Dockerfile for production-ready Next.js apps:
FROM node:lts-bookworm-slim AS base
FROM base AS deps
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --frozen-lockfile
ARG NEXT_PUBLIC_APP_BACKEND_URL
ARG NEXT_PUBLIC_APP_PUBLIC_IP_API
ENV NEXT_PUBLIC_APP_BACKEND_URL=$NEXT_PUBLIC_APP_BACKEND_URL
ENV NEXT_PUBLIC_APP_PUBLIC_IP_API=$NEXT_PUBLIC_APP_PUBLIC_IP_API
COPY . .
RUN yarn run build
FROM base AS release
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/package.json ./package.json
COPY --from=deps /app/.next ./.next
COPY --from=deps /app/public ./public
EXPOSE 3000
CMD ["yarn", "start"]
Automating with GitHub Actions
Time to make deployments automatic! Here’s a GitHub Actions workflow you can use:
name: Release Deploy
on:
release:
types: [published]
permissions:
contents: read
packages: write
id-token: write
env:
ECR_REPOSITORY: example/web-app
jobs:
package:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create .env file
run: |
echo "${{ secrets.PROD_ENV_FILE }}" > .env
- name: Configure AWS
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: us-west-1
- name: Login to ECR
uses: aws-actions/amazon-ecr-login@v2
- name: Build & Push Docker Image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
push: true
tags: |
${{ steps.login-ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}
Wrapping Up
And that’s it! Kamal 2.4 makes self-hosting Next.js apps on AWS ECR a breeze. With GitHub Actions handling the automation, deployments are seamless.
Top comments (0)