Deploy a Next.js App on alawadi.cloud in 5 Minutes
A step-by-step guide to containerising a Next.js (or any Node.js) app and deploying it to alawadi.cloud using GitHub Actions + OIDC, with no static secrets needed.
You have a Next.js app (or any Node app). You want it live on a real URL, with TLS, auto-deploy from GitHub, and managed Postgres in the same project. This guide does exactly that in around five minutes of actual work.
What you'll need
- A Next.js app in a GitHub repository
- Docker Desktop (to build and test locally)
- An alawadi.cloud account (open the portal, or email support if you need beta access)
Step 1: Write a production Dockerfile
Create a Dockerfile at the repo root. Next.js produces a standalone build that we can embed in a minimal Node image:
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]Make sure next.config.ts has output: "standalone" set.
Step 2: Create a project and container on alawadi.cloud
- Sign in with Google at
portal.alawadi.cloud - Click New project, give it a name
- Inside the project, click Add container
- Choose a name (e.g.
web) and leave the image field blank for now
Step 3: Set up push-to-deploy via GitHub OIDC
In the container's Deploy tab, click Configure GitHub OIDC trust. Enter your repository name (owner/repo) and the branch you deploy from (e.g. main).
This creates a trust relationship: GitHub Actions can now authenticate as this container without storing any secrets.
Step 4: Add the GitHub Actions workflow
Create .github/workflows/deploy.yml:
name: Deploy to alawadi.cloud
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push image
run: |
docker build -t registry.alawadi.cloud/${{ secrets.REGISTRY_SLUG }}/web:${{ github.sha }} .
echo "${{ secrets.REGISTRY_PASSWORD }}" | \
docker login registry.alawadi.cloud -u ${{ secrets.REGISTRY_USER }} --password-stdin
docker push registry.alawadi.cloud/${{ secrets.REGISTRY_SLUG }}/web:${{ github.sha }}
- name: Get deploy token
id: token
run: |
TOKEN=$(curl -sf -X POST \
https://api.alawadi.cloud/v1/containers/${{ secrets.CONTAINER_ID }}/deploy-token \
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
-H "Content-Type: application/json" | jq -r .token)
echo "token=$TOKEN" >> $GITHUB_OUTPUT
- name: Deploy
run: |
curl -sf -X POST \
https://api.alawadi.cloud/v1/containers/${{ secrets.CONTAINER_ID }}/deploy \
-H "Authorization: Bearer ${{ steps.token.outputs.token }}" \
-H "Content-Type: application/json" \
-d '{"image":"registry.alawadi.cloud/${{ secrets.REGISTRY_SLUG }}/web:${{ github.sha }}"}'Add REGISTRY_SLUG, REGISTRY_USER, REGISTRY_PASSWORD, and CONTAINER_ID as repository secrets in GitHub Settings → Secrets.
Step 5: Add Postgres
In the same project, click Add database → Postgres. The connection string is injected automatically as the DATABASE_URL environment variable into your container. Read it in your app:
// lib/db.ts
import { Pool } from "pg";
export const pool = new Pool({ connectionString: process.env.DATABASE_URL });What you get
- Auto-deploy on every push to
main, with no CI secrets leaking - Live logs available from the portal dashboard
- Managed Postgres in the same isolated namespace
- TLS on your
.alawadi.cloudsubdomain, managed automatically - Restart, stop, start from the dashboard or API
Push to main, watch the workflow run, and your app is live.
Questions? Open a support ticket in the portal, or email [email protected].
The company behind alawadi.cloud
The company building an Arabic-first cloud platform, from the physical servers up to the developer experience.