Skip to content

Next.JS

Full Stack edited this page Apr 18, 2025 · 2 revisions

Configuring the nginx to run multi-app shell application

read

Perfect β€” using a reverse proxy is an excellent choice for a modular, iframe-free, loosely coupled Next.js monorepo, especially for banking portals where:

  • Teams own independent applications (accounts, loans, estimator)
  • Apps can scale and deploy independently
  • Unified UX can still be achieved via shared design system

πŸ” Reverse Proxy Architecture

πŸ—οΈ Setup Overview:

User ⇄ [ Nginx / Traefik / API Gateway ]
              ⇓              ⇓
    /portal β†’ apps/portal   /estimator β†’ apps/estimator
                            /analysis  β†’ apps/analysis

Each app lives in its own folder/repo and gets its own subdomain or route path.


βš™οΈ Option A: NGINX Reverse Proxy Example

🧾 nginx.conf

server {
  listen 80;
  server_name yourbank.com;

  location / {
    proxy_pass http://localhost:3000; # portal app
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }

  location /estimator/ {
    rewrite ^/estimator(/.*)$ $1 break;
    proxy_pass http://localhost:3001; # estimator app
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }

  location /analysis/ {
    rewrite ^/analysis(/.*)$ $1 break;
    proxy_pass http://localhost:3002; # analysis app
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}
  • Runs:
    • portal on port 3000
    • estimator on port 3001
    • analysis on port 3002
  • All apps use basePath config (see next step)

πŸ“¦ App-Level Config: next.config.js

For apps other than the shell (estimator, analysis):

// apps/estimator/next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  basePath: '/estimator',
  output: 'standalone',
};

module.exports = nextConfig;

🌐 Example Folder Structure

apps/
β”œβ”€β”€ portal/      β†’ basePath: "/"
β”œβ”€β”€ estimator/   β†’ basePath: "/estimator"
β”œβ”€β”€ analysis/    β†’ basePath: "/analysis"

βœ… Benefits

Benefit Why it matters in banking
Independent deployments You can roll out changes to /loans without affecting /accounts
Subdomain or path-based routing Matches common banking UX patterns
No iframe required Full native navigation
Supports shared auth Auth cookies/JWT via domain or SSO provider
Better fault isolation One app going down doesn’t break others

🧠 Pro Tips

  • Use shared auth package in all apps (e.g. next-auth or JWT utils)
  • Add design system as packages/ui/ to maintain UX consistency
  • Use basePath-aware links (<Link href="/estimator/foo">) and dynamic imports

Monorepo example

Certainly! Here's a complete setup for building and deploying individual Next.js applications from a monorepo using Docker. This configuration allows each app to be developed, built, and deployed independently, facilitating a modular and scalable architecture.ξˆ†


πŸ—‚οΈ Monorepo Structure

ξˆƒYour project directory should be organized as followsξˆ„ξˆ† ξˆƒ

monorepo/
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ portal/      # Main shell application
β”‚   β”œβ”€β”€ estimator/   # Estimator application
β”‚   └── analysis/    # Analysis application
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ ui/          # Shared UI components
β”‚   └── auth/        # Shared authentication logic
β”œβ”€β”€ nginx/
β”‚   └── default.conf # NGINX reverse proxy configuration
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ turbo.json
└── package.json
```ξˆ„ξˆ†

---

## 🐳 Dockerfile for Each App
ξˆƒEach application (`portal`, `estimator`, `analysis`) should have its own `Dockerfile` located in its respective directory. Here's a sample `Dockerfile` using multi-stage builds for optimized production image:ξˆ„ξˆ†
ξˆƒ
```dockerfile
# Stage 1: Build
FROM node:18-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci
RUN npm run build

# Stage 2: Production
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/package.json ./package.json
RUN npm install --production
EXPOSE 3000
CMD ["npm", "start"]
``
ξˆ„ξˆ†
ξˆƒEnsure that each application's `package.json` includes the necessary script:ξˆ„ξˆ†
ξˆƒ
```json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  }
}
``
ξˆ„ξˆ†

---

## βš™οΈ NGINX Reverse Proxy Configuration
ξˆƒThe `nginx/default.conf` file routes incoming requests to the appropriate application based on the URL pat:ξˆ„ξˆ†
ξˆƒ
```nginx
server {
  listen 80;
  server_name localhost;

  location / {
    proxy_pass http://portal:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }

  location /estimator/ {
    rewrite ^/estimator(/.*)$ $1 break;
    proxy_pass http://estimator:3001;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }

  location /analysis/ {
    rewrite ^/analysis(/.*)$ $1 break;
    proxy_pass http://analysis:3002;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}
``
ξˆ„ξˆ†

---

## 🐳 Docker Compose Configuratio

ξˆƒThe `docker-compose.yml` file orchestrates the building and running of all servics:ξˆ„

ξˆƒ
```yaml
version: '3.8'

services:
  nginx:
    image: nginx:latest
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
    ports:
      - "80:80"
    depends_on:
      - portal
      - estimator
      - analysis

  portal:
    build: ./apps/portal
    ports:
      - "3000:3000"

  estimator:
    build: ./apps/estimator
    ports:
      - "3001:3000"

  analysis:
    build: ./apps/analysis
    ports:
      - "3002:3000"
``
ξˆ„ξˆ†

---

## πŸš€ Deployment Steps

1. **Build and Start Services*: ξˆƒFrom the root of your monorepo, un:ξˆ„ξˆ†

   ```bash
   docker-compose up --build
   ``
ξˆ„ξˆ†

2. **Access Applications**:

  - ξˆƒMain Portal: [http://localhost/](http://localhot/)ξˆ„
  - ξˆƒEstimator App: [http://localhost/estimator](http://localhost/estimaor)ξˆ„
  - ξˆƒAnalysis App: [http://localhost/analysis](http://localhost/analyis)ξˆ„ξˆ†

---

## πŸ“¦ Shared Packaes

ξˆƒThe `packages/` directory contains shared modules like `ui` and `auth`. To use these in your applicatons:ξˆ„ξˆ†

1. **Install Dependencie**: ξˆƒEnsure that each app's `package.json` includes the shared packages as dependenies.ξˆ„ξˆ†

2. **Configure Module Resolutio**: ξˆƒUse tools like [Yarn Workspaces](https://classic.yarnpkg.com/en/docs/workspaces/) or [npm Workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces) to manage shared packages within the monoepo.ξˆ„ξˆ†

3. **Import Module**: ξˆƒIn your application code, import shared modules as neded:ξˆ„ξˆ†

   ```javascript
   import { Button } from '@myorg/ui';
   import { useAuth } from '@myorg/auth';

CI & CD Pipeline Configuration

read

For building a CI/CD pipeline using AWS to deploy your Next.js multi-app monorepo with Docker, you can leverage AWS CodePipeline and AWS CodeBuild for building, testing, and deploying your applications to services like Amazon ECS, Elastic Beanstalk, or Amazon S3 for static hosting.

Here’s a step-by-step guide for creating a CI/CD pipeline for your Next.js monorepo:


πŸ”§ Prerequisites

  1. AWS Account: Set up AWS services like CodePipeline, CodeBuild, and IAM.
  2. AWS CLI & AWS CodePipeline Setup: Install and configure the AWS CLI.
  3. Docker: Your application should be Dockerized (as shown in the previous setup).
  4. Amazon S3 (for static sites) or Amazon ECS (for containerized apps): You can deploy your apps to either of these services.
  5. GitHub or AWS CodeCommit: For code repository integration.

πŸš€ Step-by-Step CI/CD Pipeline Setup

1. Set Up CodeBuild Projects (for building Docker images)

  • Create a CodeBuild Project for each app (portal, estimator, analysis).

CodeBuild Buildspec Example (buildspec.yml)

For each app, define a buildspec.yml file in the root directory (for Docker build and deploy). For instance, here’s a buildspec.yml for the Portal app:

version: 0.2

phases:
  install:
    commands:
      - echo Installing dependencies...
      - npm install
  build:
    commands:
      - echo Building the app...
      - npm run build
  post_build:
    commands:
      - echo Build completed on `date`
      - docker build -t portal-image .
      - $(aws ecr get-login --no-include-email --region us-east-1)
      - docker tag portal-image:latest <aws_account_id>.dkr.ecr.us-east-1.amazonaws.com/portal-repo:latest
      - docker push <aws_account_id>.dkr.ecr.us-east-1.amazonaws.com/portal-repo:latest
artifacts:
  files:
    - apps/portal/Dockerfile
    - apps/portal/package.json
    - apps/portal/next.config.js

For each other app (estimator, analysis), create similar buildspec.yml files that build Docker images and push them to Amazon Elastic Container Registry (ECR).

2. Create ECR Repositories

  • Elastic Container Registry (ECR) will store your Docker images.
  1. Go to the ECR console.
  2. Create repositories for each app (portal-repo, estimator-repo, analysis-repo).
  3. Use the provided authentication command from AWS CLI to authenticate Docker to ECR.

3. Set Up CodePipeline

Step 1: Create CodePipeline

  1. Go to the AWS CodePipeline console.
  2. Create a new pipeline for each app (or a single pipeline for all apps).
    • Source: GitHub or AWS CodeCommit (where your monorepo is hosted).
    • Build: Link to the CodeBuild Project you set up earlier for each app.

Step 2: Set Up Deploy Stage

For ECS (Elastic Container Service) or Elastic Beanstalk, you can define the deploy stage.

ECS (Elastic Container Service) Setup:

  1. Create an ECS Cluster.
  2. Define a Task Definition for your containerized apps.
  3. Set up an ECS Service to run your Docker containers.
  4. In CodePipeline, set the Deploy stage to deploy to ECS. This will pull the Docker image from ECR and run it on ECS.

Here’s a simple example of an ECS task definition:

{
  "family": "my-app-task",
  "containerDefinitions": [
    {
      "name": "portal-container",
      "image": "<aws_account_id>.dkr.ecr.us-east-1.amazonaws.com/portal-repo:latest",
      "memory": 512,
      "cpu": 256,
      "essential": true,
      "portMappings": [
        {
          "containerPort": 3000,
          "hostPort": 3000
        }
      ]
    }
  ]
}

Elastic Beanstalk Setup:

  1. Create an Elastic Beanstalk Application for each app (portal, estimator, analysis).
  2. Choose Docker as the platform.
  3. In CodePipeline, set the Deploy stage to deploy to Elastic Beanstalk.

πŸ“œ Example Full Pipeline Flow

  1. Source Stage:

    • GitHub / CodeCommit (Repository where your monorepo is hosted).
  2. Build Stage (with AWS CodeBuild):

    • Builds each app’s Docker image and pushes it to ECR.
  3. Deploy Stage (with ECS / Elastic Beanstalk):

    • Deploys the app to ECS or Elastic Beanstalk.

πŸ› οΈ Additional Considerations

A. Environment Variables for Docker Builds

You may need environment variables for sensitive data like API keys. Use AWS Secrets Manager or AWS Systems Manager Parameter Store to manage secrets securely.

B. Testing Stage (Optional)

You can include unit or integration tests in the pipeline before the deployment stage.

C. Auto Scaling & Load Balancer

For production-grade setups, consider adding an Application Load Balancer (ALB) for routing traffic to ECS containers and enabling auto-scaling.


πŸš€ Deploy Your Pipeline

Once everything is set up, push your code to the repository, and AWS CodePipeline will automatically trigger the pipeline for each app.


🌐 Want More Advanced Options?

  • CI/CD for multiple environments (e.g., dev, staging, prod).
  • Blue-Green deployment strategy for ECS.
  • Monitoring: Use CloudWatch logs and metrics for monitoring the health of your deployments.

Clone this wiki locally