Hosting

Bring a domain and a small Linux server.

snug’s supported production shape is one Docker Compose stack: the app, its media server, and Caddy for HTTPS.

What you need

  • A Linux host with Docker Engine and the Compose plugin.
  • A public IPv4 address.
  • A domain with an A record pointing to that address.
  • Inbound TCP 80 and 443.
  • Inbound UDP and TCP 40000-40400 for voice and video.

A 2 vCPU, 4 GiB host is a comfortable starting point for an active group. Network transfer and UDP quality matter more than extra RAM; 4 TiB of monthly outbound transfer leaves useful room for screen sharing.

Prepare Docker once

snug publishes a media port range. On Linux, disable Docker’s userland proxy so it does not create a helper process for every port and protocol.

{
  "userland-proxy": false
}

Merge that key into /etc/docker/daemon.json, preserve any existing settings, then validate and restart Docker:

sudo dockerd --validate --config-file=/etc/docker/daemon.json
sudo systemctl restart docker

Set the two addresses

The server package contains compose.yaml and .env.example. From its app directory:

cp .env.example .env

Edit the domain people will visit and the public address browsers should use for media:

SNUG_DOMAIN=chat.example.com
SNUG_ANNOUNCED_IPS=203.0.113.10

On a home network, announce the reachable LAN address first and the public address second. That lets people inside the house avoid broken NAT hairpin routes.

Open the web and media paths

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 40000:40400/udp
sudo ufw allow 40000:40400/tcp

If the host sits behind a router, forward the same ports to it. Opening only 443 creates a convincing failure: chat works, but voice and video do not.

Start the room

docker compose up -d
docker compose ps
docker compose logs -f snug caddy

Caddy obtains HTTPS automatically once DNS resolves. The first person to visit creates the founder identity and becomes the first admin.

Join voice with a friend outside the host’s network. In that person’s connection info, a UDP path is the healthy default. TCP usually means the UDP range is blocked or announced with the wrong address.

Once the room is running, protect the data and make upgrades boring.

Continue to operations →