Deploy a Server

Four deployment modes, from a production reverse-proxy setup to a bare binary under systemd. Every template on this page is copy-ready.

.env config Mode A: Reverse Proxy Mode B: Self-Signed Mode C: Manual TLS Mode D: Bare Binary Ports Environment Variables

Configuration via .env file

All modes support a .env file instead of listing environment variables inline. A fully commented template is provided above as server.env.example. With Docker Compose, use env_file: in place of environment::

services:
  goodcomms-server:
    env_file: .env       # reads key=value pairs from .env in the same directory
    ports:
      - "4077:4077/udp"
      - "4078:4078/udp"

For systemd, use EnvironmentFile= in the service unit (see Mode D). For the bare binary on Linux: set -a; source .env; set +a; ./gc-server

Mode A: Reverse Proxy

Recommended

Best for: production deployments with a domain, using Caddy, Nginx, or Traefik.

services:
  goodcomms-server:
    image: goodcomms/gc-server:latest   # pin a version tag for reproducible deploys
    container_name: gc-server
    restart: unless-stopped
    networks:
      - proxy-network
    ports:
      - "4077:4077/udp"  # Voice
      - "4078:4078/udp"  # Video
      # Note: TCP 4076 is NOT exposed; the proxy reaches it via proxy-network
    environment:
      - IP_ADDR=0.0.0.0
      - PORT=4076          # Internal TCP port for proxy to forward to
      - VOICE_PORT=4077
      - VIDEO_PORT=4078
      - NO_TLS=true        # Proxy handles TLS - critical
      - 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
      # Optional: GIF integration
      # - GIPHY_API_KEY=your_key_here
      # - KLIPY_API_KEY=your_key_here
      # Optional: Admin bootstrap (first run only)
      # - ADMIN_USER=admin
      # - ADMIN_PASS=changeme
    volumes:
      - ./data:/app/data
      - ./uploads:/app/uploads
      - ./drive:/app/drive

networks:
  proxy-network:
    external: true

Caddyfile example:

chat.yourdomain.com {
    reverse_proxy gc-server:4076
}

Proxy on the host instead of in Docker? See the walkthrough on the Get Started page — it covers both wirings step by step.

Mode B: Standalone Self-Signed

Best for: LAN parties, home servers, or quick testing. No domain or proxy required.

services:
  goodcomms-server:
    image: goodcomms/gc-server:latest   # pin a version tag for reproducible deploys
    container_name: gc-server
    restart: unless-stopped
    ports:
      - "443:443"          # HTTPS
      - "80:80"            # HTTP redirect
      - "4077:4077/udp"    # Voice
      - "4078:4078/udp"    # Video
    environment:
      - IP_ADDR=0.0.0.0
      - PORT=443
      - HTTP_PORT=80
      - VOICE_PORT=4077
      - VIDEO_PORT=4078
      # NO_TLS is false by default - self-signed certs auto-generated
      - DATABASE_PATH=/app/data/goodcomms.db
      - STORAGE_DIR=/app/uploads
      - DRIVE_DIR=/app/drive
    volumes:
      - ./data:/app/data   # Also stores auto-generated certs
      - ./uploads:/app/uploads
      - ./drive:/app/drive

Client behavior: connecting via IP (e.g. https://192.168.1.50) automatically accepts self-signed certs; connecting via a domain requires a valid TLS certificate.

Mode C: Standalone Manual TLS

Best for: production with your own certificates (Let's Encrypt, Certbot, etc.) and no proxy.

services:
  goodcomms-server:
    image: goodcomms/gc-server:latest   # pin a version tag for reproducible deploys
    container_name: gc-server
    restart: unless-stopped
    ports:
      - "443:443"          # HTTPS
      - "80:80"            # HTTP redirect
      - "4077:4077/udp"    # Voice
      - "4078:4078/udp"    # Video
    environment:
      - IP_ADDR=0.0.0.0
      - PORT=443
      - HTTP_PORT=80
      - VOICE_PORT=4077
      - VIDEO_PORT=4078
      - TLS_CERT_PATH=/app/certs/fullchain.pem
      - TLS_KEY_PATH=/app/certs/privkey.pem
      - DATABASE_PATH=/app/data/goodcomms.db
      - STORAGE_DIR=/app/uploads
      - DRIVE_DIR=/app/drive
    volumes:
      - ./data:/app/data
      - ./uploads:/app/uploads
      - ./drive:/app/drive
      - ./certs:/app/certs:ro  # Mount your cert files read-only

Mode D: Bare Binary (systemd)

Best for: servers without Docker. The binary accepts the same environment variables and CLI flags as every mode above. Download gc-server from the downloads page, then:

chmod +x gc-server
sudo mv gc-server /opt/goodcomms/gc-server
sudo mkdir -p /opt/goodcomms/{data,uploads,drive}
sudo useradd --system --no-create-home --shell /bin/false goodcomms
sudo chown -R goodcomms:goodcomms /opt/goodcomms

Copy server.env.example to /opt/goodcomms/.env, edit it, then create /etc/systemd/system/goodcomms.service:

[Unit]
Description=GoodComms Server
After=network.target

[Service]
Type=simple
User=goodcomms
WorkingDirectory=/opt/goodcomms
EnvironmentFile=/opt/goodcomms/.env
ExecStart=/opt/goodcomms/gc-server
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable goodcomms
sudo systemctl start goodcomms
sudo journalctl -u goodcomms -f   # follow logs

To bootstrap the owner account: set ADMIN_USER / ADMIN_PASS in .env, start, log in once with the client, then remove them and restart. Windows can run the same way (PowerShell env vars + gc-server.exe) or as a service via NSSM — the Docker path is the best-tested for production.

Key Ports

Port Protocol Purpose
443 / 4076TCPWebSocket / HTTP signaling (proxied or direct)
80TCPHTTP to HTTPS redirect (standalone modes)
4077UDPVoice (Opus) — must be directly reachable, cannot be proxied
4078UDPVideo (H.264) — must be directly reachable, cannot be proxied

Voice and video silently fail if UDP 4077/4078 are blocked — this is the most common setup issue. Check the server firewall, cloud security groups, and router forwarding.

Environment Variables

Variable Default Description
PORT443Main TCP port
NO_TLSfalseSet to true when behind a proxy
TRUST_PROXYfalseRate limiting keys on the first X-Forwarded-For hop. Required behind a reverse proxy (Mode A); leave off otherwise
VOICE_PORT4077UDP voice port
VIDEO_PORT4078UDP video port
DATABASE_PATHdata/goodcomms.dbSQLite database
STORAGE_DIRuploadsChat file uploads
DRIVE_DIRdriveServer drive files
RETENTION_DAYS0Auto-delete old media (0 = disabled)
ADMIN_USER / ADMIN_PASS-Bootstrap the owner account (first run only — remove afterwards)
GIPHY_API_KEY / KLIPY_API_KEY-Optional GIF search integration

New to GoodComms? Start with the Get Started guide. Questions or issues? Open an issue on GitHub.