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.
- Overview
- Features
- Breaking Changes
- Installation & Setup
- Quick Start
- Configuration
- TLS Support
- Usage
- Security
- Troubleshooting
- Roadmap
- Getting Help
- Contributing
- Appreciation
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
- Extensible: Plugin ecosystem for custom functionality
- Lightweight: Minimal resource usage, perfect for servers
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 :store and :plugin commands |
E2E Encryption | Optional X25519 key exchange with ChaCha20-Poly1305 |
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 |
Enhanced User Experience | Improved message history persistence after moderation actions |
Cross-Platform File Sharing | Theme Switching |
---|---|
![]() |
![]() |
marchat running on Android via Termux, demonstrating file transfer through reverse proxy and real-time theme switching
Important
Database Schema Migration Required
v0.3.0-beta.1 includes breaking changes that require database migration.
v0.3.0-beta.1 introduces per-user message state tracking to fix the "frozen message history" bug where banned/unbanned users could only see messages from before their ban. This enhancement requires database schema changes that will affect existing installations.
Before building from source:
-
Backup your database:
cp ./config/marchat.db ./config/marchat.db.backup
-
Build and run - migration happens automatically during server startup
-
Verify migration - check server logs for migration messages
- New table:
user_message_state
for tracking per-user message history - Schema update:
messages
table getsmessage_id
column - Automatic migration: Existing messages get
message_id = id
- Performance: New indexes added for efficient queries
- Duration: Typically under 30 seconds for most installations
If migration fails or you need to downgrade:
# Stop the server
# Restore from backup
cp ./config/marchat.db.backup ./config/marchat.db
# Restart with previous version
- Improved user experience: Banned/unbanned users see complete message history
- Better moderation: Clean slate for users after ban/unban cycles
- Enhanced performance: Optimized queries with new indexes
- Future-proof: Foundation for advanced message tracking features
Download pre-built binaries for v0.3.0-beta.1:
# Linux (amd64)
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.3.0-beta.1/marchat-v0.3.0-beta.1-linux-amd64.zip
unzip marchat-v0.3.0-beta.1-linux-amd64.zip
chmod +x marchat-server marchat-client
# macOS (amd64)
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.3.0-beta.1/marchat-v0.3.0-beta.1-darwin-amd64.zip
unzip marchat-v0.3.0-beta.1-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.3.0-beta.1/marchat-v0.3.0-beta.1-linux-arm64.zip
unzip marchat-v0.3.0-beta.1-linux-arm64.zip
chmod +x marchat-server marchat-client
# Android/Termux (armv7)
pkg install wget unzip
wget https://github.com/Cod-e-Codes/marchat/releases/download/v0.3.0-beta.1/marchat-v0.3.0-beta.1-linux-armv7.zip
unzip marchat-v0.3.0-beta.1-linux-armv7.zip
chmod +x marchat-server marchat-client
Pull from Docker Hub:
# Latest release
docker pull codecodesxyz/marchat:v0.3.0-beta.1
# 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.3.0-beta.1
Using Docker Compose:
# docker-compose.yml
version: '3.8'
services:
marchat:
image: codecodesxyz/marchat:v0.3.0-beta.1
ports:
- "8080:8080"
environment:
- MARCHAT_ADMIN_KEY=${MARCHAT_ADMIN_KEY}
- MARCHAT_USERS=${MARCHAT_USERS}
volumes:
- ./config:/marchat/config
Note
SQLite Database Permissions: SQLite requires write permissions on both the database file and its directory. Incorrect permissions may cause runtime errors on Docker/Unraid setups.
Automatic Fix: The Docker image now automatically creates the complete directory structure (/marchat/server/
) with all necessary subdirectories (config, db, data, plugins) and sets proper ownership at startup. This resolves permission issues that previously required manual intervention.
Manual Fix (if needed): Create the required directories and ensure proper ownership:
mkdir -p ./config/db
chown -R 1000:1000 ./config/db
chmod 775 ./config/db
The container user (UID 1000) must match the ownership of these folders/files.
Prerequisites:
- Go 1.23+ (download)
- For Linux clipboard support:
sudo apt install xclip
(Ubuntu/Debian) orsudo 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
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
# Set environment variables
export MARCHAT_ADMIN_KEY="your-generated-key"
export MARCHAT_USERS="admin1,admin2"
# Start server
./marchat-server
# 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
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 |
Create config.json
for client configuration:
{
"username": "your-username",
"server_url": "ws://localhost:8080/ws",
"theme": "patriot",
"twenty_four_hour": true
}
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.
- 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
TLS is optional but recommended for secure deployments. To enable TLS:
- Obtain SSL/TLS certificates (self-signed for testing, CA-signed for production)
- Set environment variables:
export MARCHAT_TLS_CERT_FILE="/path/to/cert.pem" export MARCHAT_TLS_KEY_FILE="/path/to/key.pem"
- Start the server - it will automatically detect TLS 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
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.
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 |
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 |
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
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
Warning
Change default admin key immediately
The default admin key changeme
is insecure. Generate a secure key:
openssl rand -hex 32
-
Generate Secure Keys:
# Admin key openssl rand -hex 32 # JWT secret (optional) openssl rand -base64 32
-
Secure File Permissions:
# Secure database file chmod 600 ./config/marchat.db # Secure config directory chmod 700 ./config
-
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
- Use
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
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 and consider manual schema migration |
Local Network:
# Ensure server binds to all interfaces
export MARCHAT_PORT=8080
./marchat-server
See the project roadmap for planned features, performance enhancements, and future development goals.
- GitHub Issues: Report bugs
- GitHub Discussions: Ask questions
- Documentation: Plugin Ecosystem
- Security: Security Policy
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 ./...
Special thanks to these wonderful communities and bloggers for featuring and supporting marchat:
- Self-Host Weekly by Ethan Sholly
- mtkblogs.com by Reggie
License: MIT License
Commercial Support: Contact [email protected]