KubeKanvas Logo
FeaturesPricingTemplates
How KubeKanvas worksBlog
FAQsContact
FeaturesPricingTemplates
How KubeKanvas worksBlog
FAQsContact

Building and Deploying a Modern Blog Platform with Next.js, Strapi, and Kubernetes – Part 2: Adding the Frontend

Deploy Next.js + Strapi blog on Kubernetes with Docker, Ingress routing, and service discovery. Complete tutorial for modern headless CMS deployment.
Shamaila Mahmood
Shamaila Mahmood
August 12, 2025
Cloud-Native Web Applications
Strapi and NextJS on Kubernetes - Part 2

This is Part 2 of a 3-part tutorial series designed to help you build a modern, scalable, and secure blog platform using Strapi, Next.js, and Kubernetes.

In this part, we’ll add a frontend to our blog using Next.js, connect it to our Strapi backend, and expose it to users through Ingress.

If you haven’t completed Part 1, make sure you have a working Strapi deployment with PostgreSQL and a configured Ingress before continuing.

Building a Modern Blog with Strapi & Kubernetes: Your First CMS in the Cloud

Why Use a Headless CMS?

A Headless CMS like Strapi separates content management from the frontend, delivering content via APIs (REST or GraphQL). This works perfectly with frameworks like Next.js, where you control how content is displayed.

Why It Fits Kubernetes

  • Microservices-ready: Strapi and Next.js run independently in your cluster
  • Scalable: Scale frontend and backend separately
  • DevOps-friendly: Easy to containerize, deploy, and manage
  • Fast Delivery: Combine API-driven content with static site generation for speed

By using a headless CMS in Kubernetes, you get a flexible, high-performance architecture built for modern web apps.


Step 1: Why Next.js?

When building a frontend for a blog, you want more than just a beautiful UI—you want speed, discoverability, and reliability.

Next.js is ideal for this because it offers:

  • SEO Optimization: With static site generation (SSG) and server-side rendering (SSR), your blog content is indexable by search engines—critical for visibility.
  • Fast Performance: Pages load quickly, especially when statically generated, improving both UX and SEO ranking.
  • Flexible Rendering Options: Mix SSG and SSR depending on content type.
  • Developer Experience: File-based routing, TypeScript support, and hot reloading make Next.js incredibly productive.
  • API Routes: Backend logic (like preview endpoints) can live alongside your frontend.

For a blog, where search engine visibility and snappy content delivery matter, Next.js is the gold standard.

Understanding the Strapi CMS Architecture

Before we dive into deployment, let's understand how our Next.js frontend will interact with Strapi:

  1. Content Fetching: Next.js will make HTTP requests to Strapi CMS via its REST API or GraphQL endpoint to fetch blog posts, author information, and media
  2. Static Generation: At build time, Next.js can pre-generate pages using Strapi content through Static Site Generation (SSG), resulting in lightning-fast page loads
  3. Dynamic Rendering: For real-time content or personalized experiences, Next.js can fetch data on each request
  4. Media Handling: Images and other media stored in Strapi will be referenced and optimized by Next.js

This architecture gives you the best of both worlds: the editorial experience of a traditional CMS with the performance and developer experience of a modern frontend framework.


Step 2: Building the Next.js Application with Static Site Generation

Creating the Frontend Application

First, let's understand what goes into a typical Next.js blog application that connects to Strapi:

Key Components:

  • Pages: Blog listing, individual blog posts, author pages
  • Components: Headers, footers, blog post cards, navigation
  • Data Fetching: Functions to communicate with Strapi API
  • Styling: CSS modules, Tailwind CSS, or styled-components
  • Image Optimization: Next.js Image component for performance

Sample Strapi Integration Code

The Next.js frontend connects to Strapi using GraphQL with proper authentication. The key integration points are:

Environment Variables Required:

  • NEXT_PUBLIC_STRAPI_URL - Your Strapi backend URL
  • NEXT_PUBLIC_STRAPI_TOKEN - API token for authentication with Strapi GraphQL endpoint

Key Features:

  • GraphQL client with Bearer token authentication
  • TypeScript interfaces matching Strapi's schema structure
  • Error handling for network requests
  • Static site generation for optimal performance

💡 Complete Source Code Available: You can find the complete, working Next.js frontend code in our GitHub repository: GitHub Repository

The repository includes:

  • Full Next.js application with modern UI design
  • Tailwind CSS styling and responsive components
  • GraphQL integration with Strapi
  • Docker configuration for containerization
  • All necessary configuration files

Important to note is the use of environment variable NEXT_PUBLIC_STRAPI_URL. This contains the URL of the Strapi deployment and the NEXT_PUBLIC_STRAPI_TOKEN for authentication.

Building the Docker Image

Your Next.js application needs to be containerized for Kubernetes deployment. The Docker setup uses a multi-stage build process for optimal production deployment:

Why Use Next.js Standalone Server?

We're using Next.js standalone output mode, which creates a self-contained deployment that includes all necessary dependencies. This approach provides several advantages:

  1. Simplicity: Single Node.js process handles all requests, no need for nginx configuration
  2. Flexibility: Full Next.js features including API routes and middleware
  3. Developer Experience: Easier debugging and development alignment
  4. Modern Approach: Recommended by Vercel for containerized deployments
  5. Resource Efficiency: Optimized standalone output with minimal dependencies

Standalone Server Configuration

The next.config.js is configured with output: 'standalone', which creates a minimal production server. Environment variables are embedded at build time for security and performance.

The repository contains a docker file, use the docker file to create and run or publish the image.

Build and push your image:

# Build the image with environment variables
docker build \
  --build-arg NEXT_PUBLIC_STRAPI_URL=http://strapi-service:1337 \
  --build-arg NEXT_PUBLIC_STRAPI_TOKEN=your-api-token \
  -t yourdockerhub/nextjs-blog:latest .

# Test the image locally (optional)
docker run -p 3000:3000 yourdockerhub/nextjs-blog:latest

# Push to registry
docker push yourdockerhub/nextjs-blog:latest

Step 3: Kubernetes Deployment of the Next.js Frontend

Now let's perform the Kubernetes deployment of the containerized Next.js application. Here's an enhanced deployment with production-ready configurations:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: blog-frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: blog-frontend
  template:
    metadata:
      labels:
        app: blog-frontend
    spec:
      containers:
        - name: nextjs
          image: yourdockerhub/nextjs-blog:latest
          ports:
            - containerPort: 3000

Understanding the Standalone Server Deployment:

We're using Next.js standalone server mode, where the environment variables (NEXT_PUBLIC_STRAPI_URL and NEXT_PUBLIC_STRAPI_TOKEN) are embedded into the standalone output during the Docker build process. This means:

  1. Build-time Configuration: The Strapi URL and token are set when building the Docker image using --build-arg
  2. No Runtime Environment Variables: The running container doesn't need these variables since they're already compiled into the standalone server
  3. Port 3000: Next.js standalone server runs on port 3000

This deployment connects the frontend to the Strapi backend using strapi-service (strapi-service:1337). Remember we created this service in the Part 1. In your deployment of Strapi you also need to install GraphQL plugin to be able to query Strapi through GraphQL.

Building a Modern Blog with Strapi & Kubernetes: Your First CMS in the Cloud

Strapi NextJS Ingress Architecture Diagram

Copy-Pasting sounds boring and outdated? Try our ready template

Start with the template that I have written specially to deploy Strapi/Next application in Kubernetes. Do not waste your time copy-pasting them.
Use Template Now

Just like with Strapi, the Next.js frontend must also be exposed via a Kubernetes Service. This allows other resources—such as an Ingress—to reach the application reliably.

In the service definition below, the selector field must match the matchLabels used in the frontend deployment, ensuring traffic is routed to the correct pods. Similarly, the targetPort must match the containerPort defined inside the deployment. These values ensure that network communication from Kubernetes Services correctly maps onto your running containers.

apiVersion: v1
kind: Service
metadata:
  name: frontend-service
  labels:
    app: blog-frontend
spec:
  type: ClusterIP
  selector:
    app: blog-frontend
  ports:
    - name: http
      protocol: TCP
      port: 3000
      targetPort: 3000

Understanding Kubernetes Services

A Service in Kubernetes provides several critical functions:

  1. Service Discovery: Other pods can find your application using the service name (blog-frontend)
  2. Load Balancing: If you scale to multiple pods, the service automatically distributes traffic
  3. Stable Networking: Even if pods are recreated, the service provides a consistent endpoint
  4. Port Abstraction: External clients don't need to know which port the container is actually listening on

In the service definition above:

  • selector: Must match the matchLabels used in the deployment
  • port: The port that other services will use to connect
  • targetPort: The actual port your application listens on inside the container

Apply the service:

kubectl apply -f blog-frontend-service.yaml

Test the service internally:

# Get a shell in any pod in the cluster
kubectl run -it --rm debug --image=busybox --restart=Never -- sh

# From inside the pod, test the service
wget -qO- http://frontend-service:3000

Now as in previous article (Part 1) we used port forwarding to view the application running in browser, you can do the same to access your frontend in your browser.

Building a Modern Blog with Strapi & Kubernetes: Your First CMS in the Cloud

kubectl port-forward service/frontend-service 8080:3000

In real setups this is not what you would like to do. We create software so that others can use it and not to run on local. To make the application available without port-forwarding, we need to make it accessible from outside the cluster. One way of doing so is with NodePort service. Another way is with Ingress.

What is Ingress

Ingress is Kubernetes' way of managing external access to services in your cluster, typically HTTP and HTTPS traffic. Think of it as a smart reverse proxy that sits at the edge of your cluster and routes incoming requests to the right services based on rules you define. Unlike NodePort services that expose individual services on random high ports, Ingress gives you clean URLs and can handle multiple services through a single entry point. It also provides advanced features like SSL termination, path-based routing, and load balancing - making it the preferred way to expose web applications to the internet.

Install NGINX Ingress Controller for Docker Desktop

Before we start configuring Ingress we need to install Ingress Controller in our cluster. Following is the command to install Ingress Controller in Docker Desktop.

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/cloud/deploy.yaml

Wait for it to be ready

kubectl wait --namespace ingress-nginx --for=condition=ready pod --selector=app.kubernetes.io/component=controller --timeout=300s

For a better understanding about Namespaces, read our blog, Namespaces Are Not a Security Boundary — Stop Pretending They Are

Step 5: Configure Ingress for Public Access

So far, we've been using port-forwarding to access both Strapi and our Next.js frontend. While this works for development, we need to configure Ingress to make both applications accessible from the internet. We'll set up routing rules so that Strapi (for the admin interface) and the Next.js frontend (for the public blog) are both available through clean URLs.

Understanding Ingress Path Routing

Kubernetes Ingress allows you to route HTTP/HTTPS traffic based on the request path:

  • Path-based routing: Different URLs go to different services
  • Host-based routing: Different domains go to different services
  • Priority: More specific paths take precedence over general ones

In our case:

  • /admin → Routes to Strapi for content management
  • / → Routes to Next.js frontend for the public blog

Updated Ingress Configuration

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - http:
        paths:
          # Strapi admin interface
          - path: /admin
            pathType: Prefix
            backend:
              service:
                name: strapi-service
                port:
                  number: 1337
          # Next.js frontend (catch-all)
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-service
                port:
                  number: 3000

Understanding Path Priority

The order of paths in the Ingress matters:

  1. Most specific first: /admin is more specific than /
  2. Catch-all last: / will match any path that doesn't match the above

This ensures that:

  • yourdomain.com/admin → Goes to Strapi admin
  • yourdomain.com/, yourdomain.com/blog/my-post → Goes to Next.js

Apply the updated Ingress:

kubectl apply -f blog-ingress.yaml

Step 6: Testing the Complete Setup

Verify Ingress Controller

First, make sure your Ingress controller is running and has an external IP:

kubectl get ingress blog-ingress
kubectl get services -n ingress-nginx

Test Different Endpoints

Once your Ingress has an external IP, test different paths:

# Get the Ingress IP
export INGRESS_IP=$(kubectl get ingress blog-ingress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

# Test the frontend
curl http://$INGRESS_IP/

# Test Strapi admin (should redirect to login)
curl http://$INGRESS_IP/admin


Meanwhile, /admin will still take you to the Strapi CMS interface for content management.

The following diagram cleanly describes what we have done so far.

Strapi NextJS Ingress Architecture Diagram

Conclusion

Congratulations! You've successfully completed a Kubernetes deployment of a full-stack blog platform with a Next.js frontend and Strapi CMS backend. In this part, we accomplished several key milestones:

  • Deployed a Next.js frontend that connects to your Strapi backend via GraphQL/REST APIs
  • Configured Kubernetes Services for reliable internal communication between components
  • Set up Ingress routing to expose both the public blog and admin interface through clean URLs
  • Implemented path-based routing so /admin goes to Strapi, and / displays your beautiful blog
  • Learned production deployment patterns including multi-stage Docker builds and service discovery

Your blog is now functional and accessible to you without port-forwarding! However, there's still one critical limitation: your content disappears every time the Strapi pod restarts because we're still using Strapi's default in-memory database inside the container.

Coming up in Part 3: We'll make your blog truly production-ready by configuring a persistent PostgreSQL database to ensure your content survives pod restarts, and we'll set up AWS S3 for reliable media storage so your images and files are safely stored outside the cluster. No more losing your hard work when Kubernetes reschedules pods!

KubernetesNext.jsStrapiDockerHeadless CMSContainer OrchestrationIngress Controller

Related Articles

Deep Dive: The Magic Behind KubeKanvas – Feature by Feature
Deep Dive: The Magic Behind KubeKanvas – Feature by Feature
Visualize, validate, and deploy Kubernetes configs with ease—discover the power of KubeKanvas beyond...
Essa Hashmi
Essa Hashmi
September 19, 2025
KubeKanvas Features
Seamless Kubernetes Workload Migrations with KubeKanvas
Seamless Kubernetes Workload Migrations with KubeKanvas
Seamlessly migrate Kubernetes apps across clusters with KubeKanvas—simplify, visualize, and accelera...
Shamaila Mahmood
Shamaila Mahmood
September 16, 2025
Cloud-Native Web Applications
Why KubeKanvas is the Go-To Tool for Kubernetes Beginners and Seasoned Experts Alike
Why KubeKanvas is the Go-To Tool for Kubernetes Beginners and Seasoned Experts Alike
Empowering CIOs and CTOs, this blog explores why KubeKanvas is the essential tool for simplifying Ku...
Rafay Siddiquie
September 10, 2025
C-Suite Articles
Introducing Custom Resource Support in KubeKanvas: Extend Your Kubernetes Definitions
Introducing Custom Resource Support in KubeKanvas: Extend Your Kubernetes Definitions
Discover how KubeKanvas now supports Custom Resource Definitions (CRDs) and Custom Resources (CRs), ...
Shamaila Mahmood
Shamaila Mahmood
September 3, 2025
KubeKanvas Features
KubeKanvas Logo
Visual Kubernetes cluster design tool that helps you create, manage, and deploy your applications with ease.

Product

  • Features
  • Pricing
  • Templates

Resources

  • Blog
  • Tutorials

Company

  • About Us
  • Contact
  • Terms of Service
  • Privacy Policy
  • Impressum
XGitHubLinkedIn
© 2025 KubeKanvas. All rights reserved.