Skip to content

Latest commit

Β 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Chatty - Self-Hosted Real-Time Chat Server

A scalable, containerized real-time chat server built with Node.js, Socket.io, Redis, and MongoDB. Designed to serve multiple applications with full multi-tenancy support.

🌟 Features

  • Multi-Tenancy: Isolate conversations by project ID
  • General Chat Rooms: Public chat channels per project
  • Direct Messaging: 1:1 private conversations
  • Offline Messaging: Messages are persisted and delivered when users come online
  • Horizontal Scaling: Redis adapter enables multiple server instances
  • Load Balancing: Nginx with sticky sessions for WebSocket connections
  • Message Persistence: MongoDB stores complete chat history
  • Full Containerization: Docker Compose orchestrates all services

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Clients   β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Nginx (Port 80) β”‚  ← Load Balancer
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”
    β–Ό         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Server β”‚ β”‚ Server β”‚  ← Chat Server Instances
β”‚   1    β”‚ β”‚   2    β”‚
β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
    β”‚          β”‚
    β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜
         β”‚
    β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”
    β–Ό          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Redis  β”‚ β”‚ MongoDBβ”‚  ← Data Layer
β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Components

  • chatty-nginx: Nginx reverse proxy/load balancer
  • chatty-server: Node.js + Socket.io (2 replicas)
  • chatty-redis: Pub/Sub for cross-server messaging
  • chatty-mongo: Persistent message storage

πŸ“‹ Prerequisites

  • Docker & Docker Compose
  • Node.js 18+ (for local development/testing)

πŸš€ Quick Start

1. Start the Server

cd c:/desarrollo/gravity
docker-compose up -d --build

This starts all services:

  • Nginx on port 80
  • 2 chat server instances
  • Redis and MongoDB (internal only)

2. Verify Deployment

docker ps

You should see 5 containers running with chatty_ prefix.

3. Test with CLI Client

docker run --rm --network chatty_chat-net \
  -e SOCKET_URL=http://chatty-nginx:80 \
  -v ${PWD}:/app -w /app node:18-alpine \
  sh -c "npm install socket.io-client ts-node typescript --quiet && npx ts-node test-client.ts"

4. Run React Native Web Client

cd r_chat
npm install
npm run web

Open your browser and connect with:

  • Project ID: my-app
  • User ID: user-1

πŸ“‘ API Documentation

Connection

Connect to the server with query parameters:

import { io } from 'socket.io-client';

const socket = io('http://localhost:80', {
  query: {
    projectId: 'my-app',
    userId: 'user-123'
  }
});

Events

Client β†’ Server

Event Payload Description
join_general - Join the project's general chat room
join_dm { targetUserId: string } Join a 1:1 DM room with another user
send_message { room: string, message: string } Send a message to a room

Server β†’ Client

Event Payload Description
connect - Successfully connected to server
history { room: string, messages: Message[] } Chat history when joining a room
receive_message { projectId, room, userId, message, timestamp } New message received
disconnect - Disconnected from server

Room Naming Convention

  • General Chat: ${projectId}:general
  • Direct Message: ${projectId}:dm:${user1}:${user2} (sorted alphabetically)

Example Usage

// Join general chat
socket.emit('join_general');

// Send message to general
socket.emit('send_message', {
  room: 'my-app:general',
  message: 'Hello everyone!'
});

// Join DM with user-456
socket.emit('join_dm', { targetUserId: 'user-456' });

// Send DM
socket.emit('send_message', {
  room: 'my-app:dm:user-123:user-456',
  message: 'Hey there!'
});

// Listen for messages
socket.on('receive_message', (data) => {
  console.log(`${data.userId}: ${data.message}`);
});

πŸ”’ Security Features

  • Project Isolation: Users can only access rooms within their project
  • Room Validation: Server validates room names match the user's project
  • Internal Services: Redis and MongoDB are not exposed to the host
  • Connection Authentication: projectId and userId required to connect

πŸ› οΈ Development

Project Structure

gravity/
β”œβ”€β”€ src/
β”‚   └── server.ts          # Main server logic
β”œβ”€β”€ r_chat/                # React Native client
β”‚   β”œβ”€β”€ app/
β”‚   β”‚   β”œβ”€β”€ index.tsx      # Connection screen
β”‚   β”‚   β”œβ”€β”€ chat.tsx       # Chat screen
β”‚   β”‚   └── _layout.tsx    # Navigation
β”œβ”€β”€ docker-compose.yml     # Container orchestration
β”œβ”€β”€ Dockerfile             # Server container
β”œβ”€β”€ nginx.conf             # Load balancer config
β”œβ”€β”€ test-client.ts         # Test script
└── .env                   # Environment variables

Local Development

  1. Install dependencies:
npm install
  1. Create tsconfig.json (already exists)

  2. Run tests:

npx ts-node test-client.ts

Environment Variables

Create .env file:

COMPOSE_PROJECT_NAME=chatty

πŸ“Š Monitoring & Logs

View Server Logs

docker logs chatty_chatty-server_1
docker logs chatty_chatty-server_2

View All Containers

docker ps

Check MongoDB Data

docker exec -it chatty_chatty-mongo_1 mongosh
use chat-db
db.messages.find()

πŸ”„ Scaling

To add more server instances, update docker-compose.yml:

chat-server:
  deploy:
    replicas: 5  # Increase from 2

Then restart:

docker-compose up -d --scale chatty-server=5

πŸ§ͺ Testing

The project includes comprehensive tests for:

  • βœ… Multi-project isolation
  • βœ… General chat functionality
  • βœ… Direct messaging
  • βœ… Offline message delivery
  • βœ… Cross-server communication (via Redis)

Run tests:

npm run test  # Run test-client.ts in container

🚒 Deployment

Production Recommendations

  1. Use environment variables for configuration:

    environment:
      - MONGO_URI=${MONGO_URI}
      - REDIS_HOST=${REDIS_HOST}
  2. Enable SSL in Nginx:

    listen 443 ssl;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
  3. Use managed databases (MongoDB Atlas, Redis Cloud)

  4. Add authentication middleware for enhanced security

  5. Implement rate limiting in Nginx

πŸ“ Message Schema

MongoDB stores messages with the following structure:

{
  projectId: string;    // Tenant identifier
  room: string;         // Room name
  userId: string;       // Sender ID
  message: string;      // Message content
  timestamp: Date;      // When sent
}

Indexes exist on projectId and room for fast queries.

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test thoroughly
  5. Submit a pull request

πŸ“„ License

ISC

πŸ†˜ Troubleshooting

Port 80 already in use

docker-compose down
docker ps  # Check for conflicting containers

Containers won't start

docker-compose logs chatty-server
docker-compose logs chatty-mongo

Can't connect from client

  • Ensure Docker containers are running
  • Check SOCKET_URL points to correct host
  • Verify firewall settings

Messages not syncing across servers

  • Check Redis connection in logs
  • Verify Redis adapter is initialized

πŸ“ž Support

For issues or questions, please open an issue on the repository.


Built with ❀️ using Node.js, Socket.io, Redis, MongoDB, and Docker.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages