A lightweight, performant, self-hosted chat application built with Rust. Chatter implements real-time messaging, voice chat, and screen sharing.
Development is moving fast — features are offered as-is with no guarantee of stability.

Chatter is deployed via Docker Compose. The stack includes three services: the Chatter application, MongoDB, and coturn (the TURN server required for WebRTC voice and screen sharing).
3478/tcp, 3478/udp, 49152-49252/udp (TURN relay range)git clone https://github.com/Sphyrna-029/Chatter.git
cd Chatter
The TURN server enables WebRTC (voice and screen share) to work across different networks and through NATs. Coturn is included in the Docker Compose stack and reads from turnserver.conf in the project root.
Open turnserver.conf and set a strong username and password:
user=chatter:your-strong-password
Then configure the external-ip line based on your hosting scenario — see the TURN server configuration section below.
Copy the example below into a .env file in the project root:
JWT_SECRET=change-this-to-a-long-random-string
TURN_USERNAME=chatter
TURN_PASSWORD=your-strong-password
TURN_USERNAME and TURN_PASSWORD must match the credentials in turnserver.conf.
Open docker-compose.yml and adjust the settings for your environment. At minimum:
chatter service (default is 127.0.0.1:8067)TURN_PUBLIC_URL if your domain name differs from the internal TURN addressdocker compose up -d
Chatter will be available on the port you configured. Register an account from the login screen — the first user to register is automatically promoted to server admin.
WebRTC requires a TURN server for peers who cannot connect directly (e.g. users behind strict firewalls or symmetric NATs). Coturn handles this. The critical setting is external-ip in turnserver.conf, which tells coturn what address to advertise to clients.
If your server is directly on the internet with a public IP (no NAT between the server and the internet), set external-ip to that IP:
external-ip=203.0.113.1
docker-compose.yml — no changes needed for TURN. Leave TURN_URL as-is:
TURN_URL: "turn:host.docker.internal:3478"
TURN_USERNAME: ${TURN_USERNAME:-chatter}
TURN_PASSWORD: ${TURN_PASSWORD:-changeme}
Since coturn uses network_mode: host, it binds directly to the server's network interfaces and the relay ports are immediately reachable.
If your server sits behind a router or has both a private LAN IP and a public IP, coturn needs to know both so it can bind on the LAN interface but advertise the public address to clients.
Set external-ip in turnserver.conf using the format PUBLIC_IP/LAN_IP:
# Replace with your actual public IP and LAN IP
external-ip=203.0.113.1/192.168.1.100
To find your LAN IP:
ip addr show | grep 'inet '
To find your public IP:
curl -s https://ifconfig.me
In docker-compose.yml, also set TURN_PUBLIC_URL so the Chatter backend sends clients the correct public TURN address:
TURN_URL: "turn:host.docker.internal:3478"
TURN_PUBLIC_URL: "turn:yourdomain.com:3478"
TURN_USERNAME: ${TURN_USERNAME:-chatter}
TURN_PASSWORD: ${TURN_PASSWORD:-changeme}
TURN_URL is used internally by the Chatter container to reach coturn. TURN_PUBLIC_URL is what gets sent to browser clients — it must be reachable from the internet.
In both scenarios, ensure the following are open and forwarded to your server:
| Port | Protocol | Purpose |
|---|---|---|
| 3478 | TCP + UDP | TURN signaling |
| 49152–49252 | UDP | TURN relay media |
On your router (NAT scenario), forward these port ranges to the server's LAN IP. On the server's firewall (ufw, iptables, cloud security group), allow inbound traffic on these ports.
After deployment, you can test your TURN server using a WebRTC ICE tester such as Trickle ICE. Enter your TURN URL and credentials and click "Gather candidates" — you should see relay candidates appear. If you only see host or srflx candidates but no relay candidates, the TURN server is not reachable.
Uncomment the relevant environment variables in docker-compose.yml:
| Variable | Purpose |
|---|---|
KLIPY_API_KEY | GIF search |
STEAM_API_KEY + SERVER_URL | Steam integration |
HTTPS is required for WebRTC (voice and screen sharing). A Traefik example is included as comments in docker-compose.yml. Nginx or Caddy work equally well — proxy traffic to the Chatter container's port (8000 internally).
Example Traefik labels (uncomment and fill in):
labels:
traefik.enable: "true"
traefik.http.routers.chatter.entrypoints: "your-https-entrypoint"
traefik.http.routers.chatter.rule: "Host(`yourdomain.com`)"
traefik.http.routers.chatter.tls.certResolver: "your-tls-resolver"
traefik.http.routers.chatter.tls: "true"
The first registered user is automatically promoted to server admin. Admins have a "Server Dashboard" button in the sidebar with:
mongo_data). Deleting the volume deletes all data.See LICENSE for details.
TypeScript
59.3%
Rust
39.7%
A lightweight, performant, self-hosted chat application built with Rust. Chatter implements real-time messaging, voice chat, and screen sharing.
Development is moving fast — features are offered as-is with no guarantee of stability.

Chatter is deployed via Docker Compose. The stack includes three services: the Chatter application, MongoDB, and coturn (the TURN server required for WebRTC voice and screen sharing).
3478/tcp, 3478/udp, 49152-49252/udp (TURN relay range)git clone https://github.com/Sphyrna-029/Chatter.git
cd Chatter
The TURN server enables WebRTC (voice and screen share) to work across different networks and through NATs. Coturn is included in the Docker Compose stack and reads from turnserver.conf in the project root.
Open turnserver.conf and set a strong username and password:
user=chatter:your-strong-password
Then configure the external-ip line based on your hosting scenario — see the TURN server configuration section below.
Copy the example below into a .env file in the project root:
JWT_SECRET=change-this-to-a-long-random-string
TURN_USERNAME=chatter
TURN_PASSWORD=your-strong-password
TURN_USERNAME and TURN_PASSWORD must match the credentials in turnserver.conf.
Open docker-compose.yml and adjust the settings for your environment. At minimum:
chatter service (default is 127.0.0.1:8067)TURN_PUBLIC_URL if your domain name differs from the internal TURN addressdocker compose up -d
Chatter will be available on the port you configured. Register an account from the login screen — the first user to register is automatically promoted to server admin.
WebRTC requires a TURN server for peers who cannot connect directly (e.g. users behind strict firewalls or symmetric NATs). Coturn handles this. The critical setting is external-ip in turnserver.conf, which tells coturn what address to advertise to clients.
If your server is directly on the internet with a public IP (no NAT between the server and the internet), set external-ip to that IP:
external-ip=203.0.113.1
docker-compose.yml — no changes needed for TURN. Leave TURN_URL as-is:
TURN_URL: "turn:host.docker.internal:3478"
TURN_USERNAME: ${TURN_USERNAME:-chatter}
TURN_PASSWORD: ${TURN_PASSWORD:-changeme}
Since coturn uses network_mode: host, it binds directly to the server's network interfaces and the relay ports are immediately reachable.
If your server sits behind a router or has both a private LAN IP and a public IP, coturn needs to know both so it can bind on the LAN interface but advertise the public address to clients.
Set external-ip in turnserver.conf using the format PUBLIC_IP/LAN_IP:
# Replace with your actual public IP and LAN IP
external-ip=203.0.113.1/192.168.1.100
To find your LAN IP:
ip addr show | grep 'inet '
To find your public IP:
curl -s https://ifconfig.me
In docker-compose.yml, also set TURN_PUBLIC_URL so the Chatter backend sends clients the correct public TURN address:
TURN_URL: "turn:host.docker.internal:3478"
TURN_PUBLIC_URL: "turn:yourdomain.com:3478"
TURN_USERNAME: ${TURN_USERNAME:-chatter}
TURN_PASSWORD: ${TURN_PASSWORD:-changeme}
TURN_URL is used internally by the Chatter container to reach coturn. TURN_PUBLIC_URL is what gets sent to browser clients — it must be reachable from the internet.
In both scenarios, ensure the following are open and forwarded to your server:
| Port | Protocol | Purpose |
|---|---|---|
| 3478 | TCP + UDP | TURN signaling |
| 49152–49252 | UDP | TURN relay media |
On your router (NAT scenario), forward these port ranges to the server's LAN IP. On the server's firewall (ufw, iptables, cloud security group), allow inbound traffic on these ports.
After deployment, you can test your TURN server using a WebRTC ICE tester such as Trickle ICE. Enter your TURN URL and credentials and click "Gather candidates" — you should see relay candidates appear. If you only see host or srflx candidates but no relay candidates, the TURN server is not reachable.
Uncomment the relevant environment variables in docker-compose.yml:
| Variable | Purpose |
|---|---|
KLIPY_API_KEY | GIF search |
STEAM_API_KEY + SERVER_URL | Steam integration |
HTTPS is required for WebRTC (voice and screen sharing). A Traefik example is included as comments in docker-compose.yml. Nginx or Caddy work equally well — proxy traffic to the Chatter container's port (8000 internally).
Example Traefik labels (uncomment and fill in):
labels:
traefik.enable: "true"
traefik.http.routers.chatter.entrypoints: "your-https-entrypoint"
traefik.http.routers.chatter.rule: "Host(`yourdomain.com`)"
traefik.http.routers.chatter.tls.certResolver: "your-tls-resolver"
traefik.http.routers.chatter.tls: "true"
The first registered user is automatically promoted to server admin. Admins have a "Server Dashboard" button in the sidebar with:
mongo_data). Deleting the volume deletes all data.See LICENSE for details.
TypeScript
59.3%
Rust
39.7%