# Deploying a Real-Time Chat App on AWS Lightsail Containers | Next.js & WebSocket Backend

GitHub Repo: [https://github.com/prafulpatel16/realtime-](https://github.com/prafulpatel16/realtime-) chatapp-test.git

Video Link: [https://youtu.be/kVH8n5w6Gkw](https://youtu.be/kVH8n5w6Gkw)

[https://youtu.be/LlCu7K45cBI](https://youtu.be/LlCu7K45cBI)

### Real-Time Use Case Solution: Real-Time Chat Application for Customer Support

#### **Solution Overview:**

To solve this problem, the company deploys a **real-time chat application** that integrates directly into their e-commerce website. The application consists of:

* **Next.js Frontend** for the chat interface, allowing customers to engage with support agents or AI-driven chatbots.
    
* **WebSocket Backend** to handle bi-directional, real-time communication between customers and the support team.
    
* **Dockerized Containers** deployed on **AWS Lightsail** to ensure scalability and performance.
    

### **Architecture and Workflow**

#### **Components:**

1. **Frontend (Next.js)**: A user-friendly chat widget embedded in the e-commerce site where customers can enter their inquiries. It allows real-time messaging with the support backend.
    
2. **Backend (WebSocket Server)**: Handles real-time communication between the frontend chat widget and either support agents or AI bots. All communication is managed through WebSocket connections, ensuring real-time message delivery without delays.
    
3. **Docker Containers on AWS Lightsail**: The frontend and backend are deployed as separate Docker containers on AWS Lightsail, ensuring high availability, security, and cost-effectiveness.
    

#### **Real-Time Workflow:**

1. **Customer Initiates Chat**: A customer browsing the e-commerce site initiates a chat session from the embedded chat widget.
    
2. **Connection Established**: The Next.js frontend establishes a WebSocket connection to the backend running on AWS Lightsail.
    
3. **Real-Time Messaging**: The customer’s queries are sent to the backend in real-time and are either directed to a human support agent or handled by an AI-driven chatbot.
    
4. **Instant Responses**: The customer receives an instant response, reducing wait time from hours (via email) to seconds. Support agents can handle multiple conversations simultaneously, further improving efficiency.
    
5. **Scalability**: During peak times, AWS Lightsail scales the container services to handle additional chat sessions without downtime.
    

---

### **Key Features and Benefits**

1. **Instant Response Time**: Real-time communication ensures that customer queries are answered immediately, leading to higher customer satisfaction.
    
2. **Scalable Solution**: The system can scale to support thousands of concurrent users, especially during peak hours or events, using the elasticity of AWS Lightsail.
    
3. **Seamless User Experience**: Customers can communicate with agents without leaving the website, providing a seamless experience that keeps them engaged and more likely to complete purchases.
    
4. **Cost Efficiency**: By deploying in lightweight Docker containers on AWS Lightsail, the company minimizes infrastructure costs while maintaining high performance.
    
5. **Operational Efficiency**: The chat system enables support agents to handle multiple customers in real time, reducing the need for hiring more agents.
    

---

### **Technical Stack**

* **Frontend**: Next.js for chat UI
    
* **Backend**: WebSocket server in Node.js
    
* **Containerization**: Docker
    
* **Cloud Platform**: AWS Lightsail for cost-effective container deployment
    
* **Scalability**: Autoscaling support during high-traffic periods
    
* **Security**: SSL/TLS configuration for secure WebSocket communication
    

The real-time chat allows customers to receive instant answers to their queries, reducing wait times significantly and increasing customer satisfaction. The system is designed to scale dynamically during peak times, ensuring smooth operations during high-traffic periods such as sales.

````plaintext

 Step 1: Initialize the Project
Create a new directory for the chat application and initialize both Next.js and the WebSocket server.


mkdir realtime-chat-app
cd realtime-chat-app

### 1.1. Next.js Frontend Setup
First, let's create the Next.js frontend.

npx create-next-app@latest frontend

You can go through the prompts or use flags to set up the defaults:

npx create-next-app@latest frontend --ts --eslint --src-dir --tailwin

This command sets up a TypeScript Next.js project with ESLint, `src` directory structure, and TailwindCSS for styling (optional, but highly recommended).

### 1.2. WebSocket Backend Setup
Next, let's set up the backend in a `backend` folder, which will host the WebSocket server.


mkdir backend
cd backend
npm init -y
npm install ws express cors dotenv


The `ws` package is for WebSocket implementation, `express` is for running an HTTP server, and `dotenv` is for environment variables.

### Step 2: Directory Structure

Here is the full directory structure for the app:

realtime-chat-app/
│
├── backend/
│   ├── server.js         # WebSocket backend server
│   ├── package.json      # Node.js dependencies
│   └── .env              # Environment variables for WebSocket server
│
├── frontend/
│   ├── public/           # Static files
│   ├── src/              # Application logic
│   │   ├── components/   # React components for chat UI
│   │   ├── pages/        # Next.js pages
│   │   ├── utils/        # WebSocket connection utility
│   ├── package.json      # Next.js dependencies
│   ├── tailwind.config.js # TailwindCSS configuration (optional)
│   └── .env.local        # Frontend environment variables
└── README.md             # Project documentation
```

### Step 3: Backend WebSocket Server Setup

Inside the `backend` folder, create a file `server.js`:

```javascript
// backend/server.js
const express = require('express');
const { Server } = require('ws');
const cors = require('cors');
require('dotenv').config();

const app = express();
app.use(cors());

const PORT = process.env.PORT || 8080;

// HTTP server for serving WebSocket on the same port
const server = app.listen(PORT, () => {
  console.log(`WebSocket server running on port ${PORT}`);
});

// WebSocket server
const wss = new Server({ server });

wss.on('connection', (ws) => {
  console.log('Client connected');

  ws.on('message', (message) => {
    console.log(`Received: ${message}`);
    
    // Broadcasting the message to all connected clients
    wss.clients.forEach((client) => {
      if (client.readyState === ws.OPEN) {
        client.send(message);
      }
    });
  });

  ws.on('close', () => {
    console.log('Client disconnected');
  });
});
```

Create a `.env` file for the backend:

```plaintext
# backend/.env
PORT=8080
```

### Step 4: Next.js Frontend Setup

Go to the `frontend` directory and update `src/pages/index.tsx` to use WebSocket.

Here’s how the basic chat interface will look:

```tsx
// frontend/src/pages/index.tsx
import { useState, useEffect } from 'react';

const ChatPage = () => {
  const [messages, setMessages] = useState<string[]>([]);
  const [input, setInput] = useState('');
  const [ws, setWs] = useState<WebSocket | null>(null);

  useEffect(() => {
    const socket = new WebSocket(process.env.NEXT_PUBLIC_WS_URL as string);
    setWs(socket);

    socket.onmessage = (event) => {
      const newMessage = event.data;
      setMessages((prevMessages) => [...prevMessages, newMessage]);
    };

    socket.onclose = () => {
      console.log('WebSocket connection closed');
    };

    return () => {
      socket.close();
    };
  }, []);

  const sendMessage = () => {
    if (ws && input.trim()) {
      ws.send(input);
      setInput('');
    }
  };

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-2xl font-bold">Chat Room</h1>
      <div className="border rounded p-2 h-64 overflow-y-scroll">
        {messages.map((message, index) => (
          <div key={index} className="py-1">{message}</div>
        ))}
      </div>
      <input
        type="text"
        value={input}
        onChange={(e) => setInput(e.target.value)}
        className="border p-2 rounded w-full my-2"
        placeholder="Type a message..."
      />
      <button
        onClick={sendMessage}
        className="bg-blue-500 text-white p-2 rounded"
      >
        Send
      </button>
    </div>
  );
};

export default ChatPage;
```

This `ChatPage` component listens to WebSocket messages and renders them in a chat box. Users can type a message and send it, which will be broadcast to all connected clients via the WebSocket server.

### Step 5: Environment Variables

In the `frontend` folder, create a `.env.local` file:

```plaintext
NEXT_PUBLIC_WS_URL=ws://localhost:8080
```

### Step 6: Tailwind CSS Setup (Optional)

If you chose to use Tailwind, add it to the frontend project:

```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
```

Update `tailwind.config.js`:

```javascript
// frontend/tailwind.config.js
module.exports = {
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

Then, add the following to your `src/styles/globals.css`:

```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

### Step 7: Run the Application

#### 7.1. Start WebSocket Backend

```bash
cd backend
npm start
```

#### 7.2. Start Next.js Frontend

```bash
cd frontend
npm run dev
```

The frontend will be available at `http://localhost:3000` and the WebSocket server at `ws://localhost:8080`.

### Step 8: Testing Routes and Final App
When you visit `http://localhost:3000`, you should see a chat interface. Messages sent will appear for all connected clients, thanks to the WebSocket setup.

### Final Routes
1. **Frontend Route**: 
   - `/` (Chat interface)
2. **WebSocket Backend Route**: 
   - `ws://localhost:8080` (WebSocket connection endpoint)

With these steps, you have a fully working chat application with a real-time WebSocket backend and Next.js frontend.

Step 7: Run the Application
7.1. Start WebSocket Backend

cd backend
npm start

7.2. Start Next.js Frontend
cd frontend
npm run dev
````

frontend

.env

```plaintext
NEXT_PUBLIC_WS_URL=ws://localhost:8080
```

backend

.env

```plaintext
# backend/.env
PORT=8080
```

\# docker-compose.yml version: '3' services: websocket-backend: build: ./backend ports: - "8080:8080" environment: - PORT=8080 restart: always nextjs-frontend: build: ./frontend ports: - "3000:3000" environment: - NEXT\_PUBLIC\_WS\_URL=ws://websocket-backend:8080 depends\_on: - websocket-backend restart: always

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727037809295/d1e6d83c-5277-4a73-942f-775b02f8665c.png align="center")

docker-compose up --build

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727037344654/8a9ca2a2-1d72-4d59-8d90-f28ab750909a.png align="center")

open frontend web app url

http://localhost:3000

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727037461358/cc22ac9e-db21-4771-8c8c-abe143551277.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727037500216/05cbf253-52dd-4e05-809b-1eb6bd7d7b6c.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727037534097/de369e3b-0370-406f-9c0f-315b3c484502.png align="center")

Deploy docker containers on AWS Lightsail containers

### Prerequisites:

1. **AWS CLI Installed**: Ensure you have the AWS CLI installed. You can verify this by running:
    
    ```plaintext
    aws --version
    If it’s not installed, follow the AWS CLI installation guide.
    ```
    
2. [**AWS CLI Configured**: Make sure t](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)he AWS CLI is configured with valid credentials. If not, configure it withaws configure
    
    [You’ll need to](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) provide your AWS **Access Key ID**, **Secret** [**Access Key**, **Region**, and **O**](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)**utput format** (e.g., `json`).
    

### Steps to Create an ECR Repository:

1. **Create the ECR Repository**: You can create a[n ECR repository using the](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) following AWS CLI command:
    
    ```plaintext
    ecr create-repository --repository-name <repository-name> --region <region>
    Replace <repository-name> with the name of your repository and <region> with the AWS region where you want to create it. For example:
    ```
    
    ```plaintext
    ecr create-repository --repository-name my-realtime-chatapp --region us-east-1
    ```
    
2. **Example Output**: Upon successful creation, you should get a response like this:
    
    ```plaintext
    jsonCopy code{
        "repository": {
            "repositoryArn": "arn:aws:ecr:us-east-1:123456789012:repository/my-realtime-chatapp",
            "registryId": "123456789012",
            "repositoryName": "my-realtime-chatapp",
            "repositoryUri": "123456789012.dkr.ecr.us-east-1.amazonaws.com/my-realtime-chatapp",
            "createdAt": 1644870241.0,
            "imageTagMutability": "MUTABLE",
            "imageScanningConfiguration": {
                "scanOnPush": false
            },
            "encryptionConfiguration": {
                "encryptionType": "AES256"
            }
        }
    }
    ```
    
    ### Steps to Push Docker Images to ECR:
    
    #### 1\. **Authenticate Docker to Your ECR Registry**
    
    Before pushing images to ECR, you need to authenticate Docker to your Amazon ECR registry.
    
    Run this command to authenticate (replace `<your-region>` with your AWS region, e.g., `us-east-1`):
    
    ```plaintext
    aws ecr get-login-password --region <your-region> | docker login --username AWS --password-stdin <your-account-id>.dkr.ecr.<your-region>.amazonaws.com
    ```
    
    For example, if your AWS region is `us-east-1` and your account ID is `123456789012`, the command would be:
    
    ```plaintext
    aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com
    ```
    
3. Amazon ECR repositories use a specific URL format for tagging images, which includes your AWS account ID, region, and repository name.
    
    You will need to tag both images (`realtime-chatapp-test-nextjs-frontend` and `realtime-chatapp-test-websocket-backend`) so they point to the correct ECR repository.
    
    ##### Tag the Frontend Image:
    
    ```plaintext
    docker tag realtime-chatapp-test-nextjs-frontend:latest <your-account-id>.dkr.ecr.<your-region>.amazonaws.com/my-realtime-chatapp:frontend-latest
    ```
    
    Example:
    
    ```plaintext
    docker tag realtime-chatapp-test-nextjs-frontend:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-realtime-chatapp:frontend-latest
    ```
    
    ##### Tag the Backend Imagedocker tag realtime-chatapp-test-websocket-backend:latest &lt;your-account-id&gt;.dkr.ecr.&lt;your-region&gt;.amazonaws.com/my-realtime-chatapp:backend-latest
    
    Example:
    
    ```plaintext
    bdocker tag realtime-chatapp-test-websocket-backend:latest 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-realtime-chatapp:backend-latest
    ```
    
    #### 3\. **Push the Docker Images to ECR**
    
    Now that the images are tagged, you can push them to the ECR repository.
    
    ##### Push the Frontend Image:
    
    ```plaintext
    docker push <your-account-id>.dkr.ecr.<your-region>.amazonaws.com/my-realtime-chatapp:frontend-latest
    ```
    
    Example:
    
    ```plaintext
    docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-realtime-chatapp:frontend-latest
    ```
    
    ##### Push the Backend Image:
    
    ```plaintext
    docker push <your-account-id>.dkr.ecr.<your-region>.amazonaws.com/my-realtime-chatapp:backend-latest
    ```
    
    Example:
    
    ```plaintext
    bashCopy codedocker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/my-realtime-chatapp:backend-latest
    ```
    
    ### Verify Your Images in ECR:
    
    Once the push is successful, you can verify that your images have been uploaded by going to the [Amazon ECR Console](https://console.aws.amazon.com/ecr) and checking the `my-realtime-chatapp` repository.
    

When configuring a WebSocket connection on AWS Lightsail or any other environment, WebSockets generally use either:

* `ws://` for unencrypted WebSocket connections
    
* `wss://` for encrypted WebSocket connections (WebSockets over TLS/SSL, similar to HTTPS).
    

### Which Protocol to Use:

1. `ws://` (Unencrypted WebSocket):
    
    * This is used for **local development** or when you don’t have SSL/TLS certificates configured on your server.
        
    * Example: `ws://`[`localhost:8080`](http://localhost:8080)
        
2. `wss://` (Secure WebSocket):
    
    * This is the **recommended** protocol for production environments, including AWS Lightsail.
        
    * WebSocket connections secured with SSL/TLS (just like HTTPS).
        
    * Example: `wss://`[`your-domain.com/websocket`](http://your-domain.com/websocket)
        

Deploy on AWS Lighsail

Create IAM Role:

EC2-Lightsail-ECR-Route53-Role

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727150623140/1ffa5ce8-7f04-4eac-9c04-8548ac969566.png align="center")

Create a Policy:

[LightSailAccess](https://us-east-1.console.aws.amazon.com/iam/home?region=us-east-2#/roles/details/EC2-Lightsail-ECR-Route53-Role/editPolicy/LightSailAccess?step=addPermissions)

```plaintext
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:DeleteServiceLinkedRole",
                "iam:GetServiceLinkedRoleDeletionStatus"
            ],
            "Resource": "arn:aws:iam::*:role/aws-service-role/lightsail.amazonaws.com/AWSServiceRoleForLightsail*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CopySnapshot",
                "ec2:DescribeSnapshots",
                "ec2:CopyImage",
                "ec2:DescribeImages"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetAccountPublicAccessBlock"
            ],
            "Resource": "*"
        }
    ]
}
```

### **Setup AWS Lightsai**[**l**](https://lightsail.aws.amazon.com)

1. [**Log In to**](https://lightsail.aws.amazon.com) **AWS Light**[**sail:**](https://lightsail.aws.amazon.com)
    
    * [Go t](https://lightsail.aws.amazon.com)o [AWS Lightsail.](https://lightsail.aws.amazon.com)
        
    * [Sign in](https://lightsail.aws.amazon.com) with your A[WS credential](https://lightsail.aws.amazon.com)s.
        
2. **Create a Lightsail** [**Container Ser**](https://lightsail.aws.amazon.com)**vice:**
    
    * Navigate to the **Con**[**tainers** secti](https://lightsail.aws.amazon.com)on.
        
    * Click on **Create a c**[**ontainer serv**](https://lightsail.aws.amazon.com)**ice**.
        
    * Choose the size of [the container](https://lightsail.aws.amazon.com) based on your application's resource needs (start with a smaller plan if unsure).
        
    * Select the AWS regi[on closest to](https://lightsail.aws.amazon.com) your users.
        

### **Deploy Frontend and Backend Containers**

1. **Deploy Backend Container:**
    
    * After creating the container service, select it and click **Add container**.
        
    * Under **Container Name**, enter a name like `backend`.
        
    * Set the **Container image** to your backend image (e.g., `<your-username>/realtime-chat-backend:latest`).
        
    * Set **Open ports** to `8080` (the port your WebSocket server listens on).
        
    * Click **Save**.
        
2. **Deploy Frontend Container:**
    
    * Repeat the above steps for your frontend:
        
        * Add a container named `frontend`.
            
        * Set the **Container image** to your frontend image (e.g., `<your-username>/realtime-chat-frontend:latest`).
            
        * Set **Open ports** to `3000` (the port your Next.js app listens on).
            
    * Click **Save** and **Deploy**.
        

Deploy both the containers within one Lightsail Container service

Access the Webapp and verify on the browser

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1727555365785/801a37e9-3f2d-408b-8228-f256b0082b19.png align="center")

---

### Conclusion

By deploying a real-time chat application using Next.js, WebSockets, and AWS Lightsail containers, the e-commerce company solved their customer support issues, scaled their infrastructure efficiently, and significantly boosted both customer satisfaction and revenue. This real-time business solution is a powerful use case for modern e-commerce platforms looking to optimize user engagement and operational efficiency.
