Part 1: The Client (for users)
Windows
Installs the app, adds a desktop shortcut, and handles file associations. To update, just run the new installer.
Run from anywhere — USB drives, restricted environments. Create a folder named data next to the .exe and GoodComms keeps all settings, logs, and cache there instead of AppData.
Linux
The Linux client is a portable binary — no installation required:
chmod +x gc-client
./gc-client
Screen sharing requires PipeWire and xdg-desktop-portal — already present on most modern desktop distros.
Joining a Server
- Launch the app and click the + (Plus) icon in the sidebar.
- Enter the address your server owner gave you — a domain or an IP address.
- Register a new account or log in. Accounts are local to each server — there is no global GoodComms account.
- Enable Save Password for a one-click quick-join button on your next launch.
Part 2: Setting Up a Server (for owners)
The server authenticates sessions, stores messages in SQLite, and relays media packets — it never processes or decodes your data. CPU and RAM needs are minimal; bandwidth and storage are the real scaling factors. This walkthrough covers the recommended production setup: Docker + a domain + Caddy. For self-signed/LAN, manual TLS, or bare-binary setups, see Deploy a Server.
Step 1: Compose file
Caddy on the host (most common for a simple VPS): expose TCP 4076 on loopback only, point Caddy at
localhost:4076. Prefer a fully commented config? Use the
.env template with env_file: .env.
# docker-compose.yml
services:
goodcomms-server:
image: goodcomms/gc-server:latest
container_name: gc-server
restart: unless-stopped
ports:
- "127.0.0.1:4076:4076" # TCP - loopback only, your host proxy connects here
- "4077:4077/udp" # Voice (Opus) - must be open in your firewall
- "4078:4078/udp" # Video (H.264) - must be open in your firewall
environment:
- IP_ADDR=0.0.0.0
- PORT=4076
- NO_TLS=true # The proxy handles TLS - do not remove this
- TRUST_PROXY=true # Rate limiting keys on X-Forwarded-For - required behind a proxy
- DATABASE_PATH=/app/data/goodcomms.db
- STORAGE_DIR=/app/uploads
- DRIVE_DIR=/app/drive
- RETENTION_DAYS=0 # 0 = media kept forever
- LOG_DIR=/app/logs
# First run only - remove after logging in:
# - ADMIN_USER=your_username
# - ADMIN_PASS=your_secure_password
volumes:
- ./data:/app/data # Database and certs
- ./uploads:/app/uploads # Chat file uploads
- ./drive:/app/drive # Server Drive files
- ./logs:/app/logs # Server logs
# Caddyfile
chat.yourdomain.com {
reverse_proxy localhost:4076
}
Caddy running in Docker instead? Drop the loopback port mapping, put both containers on a shared network, and
proxy to gc-server:4076 — the full variant is on the
deploy page.
Nginx and Traefik work the same way: TLS terminates at the proxy, GoodComms receives plain HTTP on 4076.
Step 2: Open firewall ports
Your proxy handles TCP 443. Voice and video are direct UDP — they cannot be proxied and must be open at every layer (server firewall, cloud security group, router): UDP 4077 (voice) and UDP 4078 (video).
Voice/video silently failing is almost always these two ports being blocked.
Step 3: Bootstrap your owner account
Uncomment ADMIN_USER / ADMIN_PASS in the compose file, then:
docker compose up -d
Connect with the client and log in — that claims the Owner role. Then immediately
docker compose down, remove the two credential lines, and
docker compose up -d again. Your account lives in the database now; credentials
don't belong in config files.
Part 3: Building Your Community
Channels
In Admin → Channels, click New Channel. A channel can be Text, Voice, or both. Private channels are hidden from everyone except roles you grant.
Note: a channel's privacy (public vs. private) can't be changed after creation — everything else (name, description, type, position) can.
Roles
Roles use a hierarchy — higher numbers have authority over lower ones:
| Role | Hierarchy | Description |
|---|---|---|
| Owner | 101 | Full control, bypasses all permission checks |
| Administrator | 100 | Broad administrative access |
| Default | 10 | Base role assigned to all new members |
Example moderator: create a role named Moderator at hierarchy 50, grant manage_messages + manage_users, assign it under Admin → Users. They can moderate anyone ranked below them but can't touch channels or roles.
Server Drive
The Drive tab is private file storage for your community — folders, uploads, sharing — stored on your own hardware with no third-party cloud.
Troubleshooting
Can't connect to the server
Verify the domain resolves to your server's IP, the proxy is running and forwarding to 4076, and check logs: docker compose logs -f goodcomms-server
Voice or video not working
Almost always a firewall issue — verify UDP 4077 and 4078 are open at every layer. These ports cannot be proxied; they must be directly reachable.
Self-signed certificate warning
Expected when connecting via IP address instead of a domain — click Connect anyway. Normal for LAN setups; see Mode B.
Linux screen sharing issues
Ensure PipeWire and xdg-desktop-portal are installed and running. System-audio loopback isn't supported on Linux. If the picker doesn't appear on a second stream, restart the app.
GIF search not working
GIF search is optional and configured by the server owner via GIPHY_API_KEY / KLIPY_API_KEY.
Updating the Server
docker compose pull # Pull the new image
docker compose up -d # Restart with it - zero config changes needed
Your database, uploads, and drive files live in the mounted volumes and are untouched by updates. Pin image: to a version tag if you'd rather not track latest.
All deployment modes, ports, and environment variables: Deploy a Server. Found a bug? Open an issue on GitHub.