marchat

module
v0.4.0-beta.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 27, 2025 License: MIT

README

marchat

marchat - terminal chat application

Go CI MIT License GitHub Repo Go Version GitHub all releases Docker Pulls Self-Host Weekly mtkblogs.com

A lightweight terminal chat with separate server and client binaries, real-time messaging over WebSockets, optional end-to-end encryption, and a flexible plugin ecosystem. Built for developers who prefer the command line and want reliable, self-hosted group chat with minimal operational overhead.

Server Demo Client Demo

Table of Contents

Overview

marchat started as a fun weekend project for father-son coding sessions and has since evolved into a lightweight, self-hosted terminal chat application designed specifically for developers who love the command line. It currently runs with a local SQLite database and real-time messaging over WebSockets, with planned support for PostgreSQL and MySQL to enable greater scalability and flexibility.

Key Benefits:

  • Self-hosted: No external services required
  • Cross-platform: Runs on Linux, macOS, and Windows
  • Secure: Optional E2E encryption with X25519/ChaCha20-Poly1305, including global encryption for public channels
  • Extensible: Plugin ecosystem for custom functionality
  • Lightweight: Minimal resource usage, perfect for servers

Features

Feature Description
Terminal UI Beautiful TUI built with Bubble Tea
Real-time Chat Fast WebSocket-based messaging with a lightweight SQLite backend
Plugin System Install and manage plugins via remote registry with :store and :plugin commands
E2E Encryption Optional X25519 key exchange with ChaCha20-Poly1305, global encryption for public channels, individual encryption for direct messages
File Sharing Send files up to 1MB with :sendfile
Admin Controls User management, bans, and database operations with improved ban/unban experience
Themes Choose from patriot, retro, or modern themes
Docker Support Containerized deployment with security features
Cross-Platform File Sharing Theme Switching

marchat running on Android via Termux, demonstrating file transfer through reverse proxy and real-time theme switching

Changelog

v0.4.0-beta.3 (Latest)
  • Fixed SQL Query Performance: Improved message retrieval efficiency by changing ORDER BY created_at ASC to ORDER BY created_at DESC in GetRecentMessages and GetMessagesAfter functions
  • Enhanced Message Ordering: SQL queries now fetch newest messages first for better performance, while maintaining chronological display order through Go sorting
  • Database Optimization: More efficient message history loading, especially for users with large message histories
v0.4.0-beta.2
  • Plugin system with remote registry support
  • Ban history gaps feature for improved moderation
  • Global E2E encryption for public channels
  • Enhanced admin controls and user management

Database Schema

The database includes these key tables:

  • messages: Core message storage with message_id for tracking
  • user_message_state: Per-user message history state
  • ban_history: Ban/unban event tracking for history gaps feature

Installation & Setup

Binary Installation

Download pre-built binaries for v0.4.0-beta.3:

# Linux (amd64)
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.4.0-beta.3/marchat-v0.4.0-beta.3-linux-amd64.zip
unzip marchat-v0.4.0-beta.3-linux-amd64.zip
chmod +x marchat-server marchat-client

# macOS (amd64)
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.4.0-beta.3/marchat-v0.4.0-beta.3-darwin-amd64.zip
unzip marchat-v0.4.0-beta.3-darwin-amd64.zip
chmod +x marchat-server marchat-client

# Windows
# Download from GitHub releases page, extract the ZIP,
# and run marchat-server.exe and marchat-client.exe from PowerShell or CMD.

# Android/Termux (arm64)
pkg install wget unzip
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.4.0-beta.3/marchat-v0.4.0-beta.3-android-arm64.zip
unzip marchat-v0.4.0-beta.3-android-arm64.zip
chmod +x marchat-server marchat-client

Docker Installation

Pull from Docker Hub:

# Latest release
docker pull codecodesxyz/marchat:v0.4.0-beta.3

# Run with environment variables
docker run -d \
  -p 8080:8080 \
  -e MARCHAT_ADMIN_KEY=$(openssl rand -hex 32) \
  -e MARCHAT_USERS=admin1,admin2 \
  codecodesxyz/marchat:v0.4.0-beta.3
Source Installation

Prerequisites:

  • Go 1.23+ (download)
  • For Linux clipboard support: sudo apt install xclip (Ubuntu/Debian) or sudo yum install xclip (RHEL/CentOS)

Build from source:

git clone https://github.com/Cod-e-Codes/marchat.git
cd marchat
go mod tidy
go build -o marchat-server ./cmd/server
go build -o marchat-client ./client
chmod +x marchat-server marchat-client

Quick Start

For security, generate a strong random key to use as your admin key. This step is recommended but you can set any non-empty string as the admin key.

openssl rand -hex 32
2. Start Server
# Set environment variables
export MARCHAT_ADMIN_KEY="your-generated-key"
export MARCHAT_USERS="admin1,admin2"

# Start server
./marchat-server
3. Connect Client
# Connect as admin
./marchat-client --username admin1 --admin --admin-key your-generated-key --server ws://localhost:8080/ws

# Connect as regular user
./marchat-client --username user1 --server ws://localhost:8080/ws

Configuration

Environment Variables
Variable Required Default Description
MARCHAT_ADMIN_KEY Yes - Admin authentication key
MARCHAT_USERS Yes - Comma-separated admin usernames
MARCHAT_PORT No 8080 Server port
MARCHAT_DB_PATH No ./config/marchat.db Database file path
MARCHAT_LOG_LEVEL No info Log level (debug, info, warn, error)
MARCHAT_CONFIG_DIR No Auto-detected Custom config directory
MARCHAT_TLS_CERT_FILE No - Path to TLS certificate file
MARCHAT_TLS_KEY_FILE No - Path to TLS private key file
MARCHAT_BAN_HISTORY_GAPS No true Enable ban history gaps (prevents banned users from seeing messages during ban periods)
MARCHAT_PLUGIN_REGISTRY_URL No GitHub registry URL for plugin registry (default: https://raw.githubusercontent.com/Cod-e-Codes/marchat-plugins/main/registry.json)
MARCHAT_GLOBAL_E2E_KEY No - Base64-encoded 32-byte global encryption key for public channels
Configuration File

Create config.json for client configuration:

{
  "username": "your-username",
  "server_url": "ws://localhost:8080/ws",
  "theme": "patriot",
  "twenty_four_hour": true
}

TLS Support

TLS (Transport Layer Security) enables secure WebSocket connections using wss:// instead of ws://. This is essential for production deployments and when exposing the server over the internet.

When to Use TLS
  • Public deployments: When the server is accessible from the internet
  • Production environments: For enhanced security and privacy
  • Corporate networks: When required by security policies
  • HTTPS reverse proxies: When behind nginx, traefik, or similar
Enabling TLS

TLS is optional but recommended for secure deployments. To enable TLS:

  1. Obtain SSL/TLS certificates (self-signed for testing, CA-signed for production)
  2. Set environment variables:
    export MARCHAT_TLS_CERT_FILE="/path/to/cert.pem"
    export MARCHAT_TLS_KEY_FILE="/path/to/key.pem"
    
  3. Start the server - it will automatically detect TLS configuration
Example Configuration

With TLS (recommended for production):

# Generate self-signed certificate for testing
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes

# Set environment variables
export MARCHAT_ADMIN_KEY="your-secure-key"
export MARCHAT_USERS="admin1,admin2"
export MARCHAT_TLS_CERT_FILE="./cert.pem"
export MARCHAT_TLS_KEY_FILE="./key.pem"

# Start server (will show wss:// in banner)
./marchat-server

Without TLS (development/testing):

# No TLS certificates set
export MARCHAT_ADMIN_KEY="your-secure-key"
export MARCHAT_USERS="admin1,admin2"

# Start server (will show ws:// in banner)
./marchat-server
Client Connection

The client connection URL automatically reflects the server's TLS status:

  • TLS enabled: Connect to wss://host:port/ws
  • TLS disabled: Connect to ws://host:port/ws

The server banner displays the correct WebSocket URL scheme based on TLS configuration.

TLS Verification Bypass

For development and testing with self-signed certificates, you can bypass TLS verification:

# Connect with TLS verification bypass
./marchat-client --skip-tls-verify --server wss://localhost:8080/ws

# Regular connection (with verification)
./marchat-client --server wss://localhost:8080/ws

[!WARNING] Security Warning: Use --skip-tls-verify only for development and testing. Production deployments should use valid TLS certificates.

Plugin System

The plugin system allows you to extend marchat's functionality with custom commands and features. Plugins are automatically downloaded from the configured registry.

Plugin Registry

By default, marchat uses the GitHub plugin registry. You can configure a custom registry:

# Use default GitHub registry
export MARCHAT_PLUGIN_REGISTRY_URL="https://raw.githubusercontent.com/Cod-e-Codes/marchat-plugins/main/registry.json"

# Use custom registry
export MARCHAT_PLUGIN_REGISTRY_URL="https://my-registry.com/plugins.json"
Plugin Commands
Command Description Example
:store Browse available plugins :store
:plugin install <name> Install a plugin :plugin install echo
:plugin uninstall <name> Remove a plugin :plugin uninstall echo
:plugin list List installed plugins :plugin list
Available Plugins
  • Echo: Simple echo plugin for testing

Ban History Gaps

The ban history gaps feature prevents banned users from seeing messages that were sent during their ban periods. This creates a more effective moderation experience by ensuring users cannot access conversation history from when they were excluded from the chat.

How It Works

When enabled, the system:

  1. Tracks ban events in a dedicated ban_history table
  2. Records ban/unban timestamps with admin attribution
  3. Filters message history for users with ban records
  4. Maintains performance by only filtering for users who have been banned
Enabling Ban History Gaps

Set the environment variable to enable this feature:

# Enable ban history gaps (enabled by default)
export MARCHAT_BAN_HISTORY_GAPS=true

# Start server with feature enabled
./marchat-server
Behavior Examples

With Ban History Gaps Enabled:

  • User gets banned → cannot see new messages
  • User gets unbanned → reconnects and sees only messages sent after their unban
  • Messages sent during ban period are permanently hidden from that user

With Ban History Gaps Disabled:

  • User gets banned → cannot see new messages
  • User gets unbanned → reconnects and sees all messages (including those sent during ban)

Usage

Basic Commands
Command Description Example
:theme <name> Switch theme :theme patriot
:time Toggle 12/24-hour format :time
:clear Clear chat buffer :clear
:sendfile <path> Send file (<1MB) :sendfile document.txt
:savefile <name> Save received file :savefile received.txt
Plugin Commands
Command Description Admin Only
:store Open plugin store No
:plugin list List installed plugins No
:plugin install <name> Install plugin No
:plugin uninstall <name> Uninstall plugin Yes
Admin Commands
Command Description Example
:cleardb Wipe server database :cleardb
:kick <username> Disconnect user :kick user1
:ban <username> Ban user for 24h with improved user experience after unban :ban user1
:unban <username> Remove user ban with clean message history restoration :unban user1

Connect as admin:

./marchat-client --username admin1 --admin --admin-key your-key --server ws://localhost:8080/ws
E2E Encryption Commands
Command Description Example
:showkey Display public key :showkey
:addkey <user> <key> Add user's public key :addkey alice <base64-key>

Enable E2E encryption:

./marchat-client --e2e --keystore-passphrase your-passphrase --username alice --server ws://localhost:8080/ws
Global E2E Encryption

marchat supports global E2E encryption for public channels, allowing secure group chat without requiring individual key exchange between users. This feature uses a shared global encryption key that all clients can use to encrypt and decrypt messages in public channels.

How Global E2E Works
  • Shared Key: All clients use the same global encryption key for public channels
  • No Key Exchange: No need to exchange individual public keys for group chat
  • Environment Variable: Set MARCHAT_GLOBAL_E2E_KEY to share the same key across clients
  • Automatic Generation: If no global key is provided, a new one is generated and displayed
Setting Up Global E2E Encryption

Option 1: Use Environment Variable (Recommended for shared deployments)

# Generate a 32-byte key and encode as base64
openssl rand -base64 32

# Set the environment variable with the generated key
export MARCHAT_GLOBAL_E2E_KEY="your-generated-base64-key"

# Run client with E2E enabled
./marchat-client --e2e --keystore-passphrase your-passphrase --username alice --server ws://localhost:8080/ws

Option 2: Let marchat Generate a Key

# Run client without environment variable - marchat will generate a new key
./marchat-client --e2e --keystore-passphrase your-passphrase --username alice --server ws://localhost:8080/ws

# The client will display the generated key:
# 🔐 Generated new global E2E key (ID: RsLi9ON0ZYvEPOmyMs1IhWL5vPTGEfamExCPuaESV7M=)
# 💡 Set MARCHAT_GLOBAL_E2E_KEY=fF+HkmGArkPNsdb+M+qj/JgBmCTV8R0J7zEW80Izjtw= to share this key across clients
Sharing the Global Key

To enable multiple clients to communicate securely, share the global key:

  1. Copy the generated key from the client output
  2. Set the environment variable on all client machines:
    export MARCHAT_GLOBAL_E2E_KEY="fF+HkmGArkPNsdb+M+qj/JgBmCTV8R0J7zEW80Izjtw="
    
  3. Run all clients with the same global key
Global vs Individual E2E
Feature Global E2E Individual E2E
Setup Complexity Simple - one shared key Complex - exchange keys per user
Group Chat ✅ Works immediately ❌ Requires key exchange
Direct Messages ❌ Not supported ✅ Full support
Key Management One global key Individual key pairs
Use Case Public channels Private conversations
Expected Output

When global E2E is working correctly, you'll see:

🔐 Using global E2E key from environment variable
🌐 Global chat encryption: ENABLED (Key ID: RsLi9ON0ZYvEPOmyMs1IhWL5vPTGEfamExCPuaESV7M=)
✅ Encryption validation passed
🔐 E2E encryption enabled with keystore: config/keystore.dat

Security

Critical Security Warnings

[!WARNING] Change default admin key immediately The default admin key changeme is insecure. Generate a secure key:

openssl rand -hex 32
Security Best Practices
  1. Generate Secure Keys:

    # Admin key
    openssl rand -hex 32
    
    # JWT secret (optional)
    openssl rand -base64 32
    
  2. Secure File Permissions:

    # Secure database file
    chmod 600 ./config/marchat.db
    
    # Secure config directory
    chmod 700 ./config
    
  3. Production Deployment:

    • Use wss:// for secure WebSocket connections
    • Implement reverse proxy (nginx/traefik)
    • Restrict server access to trusted networks
    • Use Docker secrets for sensitive environment variables
E2E Encryption

When enabled, E2E encryption provides:

  • Forward Secrecy: Unique session keys per conversation
  • Server Privacy: Server cannot read encrypted messages
  • Key Management: Local encrypted keystore with passphrase protection
  • Global Encryption: Shared global key for public channel encryption
  • Individual Encryption: Per-user key pairs for direct messages

Troubleshooting

Common Issues
Issue Solution
Connection failed Verify server URL uses ws:// or wss://
TLS certificate errors Ensure certificate and key files are readable and valid
Admin commands not working Ensure --admin flag and correct --admin-key
Clipboard not working (Linux) Install xclip: sudo apt install xclip
Permission denied (Docker) Rebuild with correct UID/GID: docker-compose build --build-arg USER_ID=$(id -u)
Port already in use Change port: export MARCHAT_PORT=8081
Database migration fails Ensure proper database file permissions and backup before building from source
Message history missing after update Expected behavior - user message states reset for improved ban/unban experience
Server fails to start after source build Check database permissions - migrations are automatic
Ban history gaps not working Ensure MARCHAT_BAN_HISTORY_GAPS=true is set (default) and database has ban_history table
TLS certificate errors Use --skip-tls-verify flag for development with self-signed certificates
Plugin installation fails Check MARCHAT_PLUGIN_REGISTRY_URL is accessible and registry format is valid
E2E encryption not working Ensure --e2e flag is used and keystore passphrase is provided. Check debug logs for detailed error messages
Global E2E key not working Verify MARCHAT_GLOBAL_E2E_KEY is set correctly and is a valid base64-encoded 32-byte key. Use openssl rand -base64 32 to generate a valid key
"no session key found for global" error Fixed in latest version - global E2E key support automatically handles this error
Blank encrypted messages Fixed in v0.3.0-beta.5 - ensure you're using the latest version and have added recipient public keys with :addkey
E2E startup failures Fixed in v0.3.0-beta.6 - "conversation: test" session key issue resolved
Network Connectivity

Local Network:

# Ensure server binds to all interfaces
export MARCHAT_PORT=8080
./marchat-server

Roadmap

See the project roadmap for planned features, performance enhancements, and future development goals.

Getting Help

Contributing

We welcome contributions! See the contribution guidelines for:

  • Development setup
  • Code style guidelines
  • Pull request process

Quick Start for Contributors:

git clone https://github.com/Cod-e-Codes/marchat.git
cd marchat
go mod tidy
go test ./...

Appreciation

Special thanks to these wonderful communities and bloggers for featuring and supporting marchat:

For a full list of contributors, see CONTRIBUTORS.md.


License: MIT License

Commercial Support: Contact cod.e.codes.dev@gmail.com

Directories

Path Synopsis
cmd
license command
server command
plugin
sdk module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL