TLS Connection Issues (bytes remaining on stream)

Symptoms IRC clients show “connection to server lost (bytes remaining on stream)” errors repeatedly.

Cause Attempting to proxy IRC protocol through Caddy using HTTP-based directives.

What Did Not Work

1. **Caddy reverse_proxy**
   - reverse_proxy is designed for HTTP, not raw TCP
   - IRC is a long-lived, bidirectional, line-oriented protocol
   - This causes stream corruption and connection drops
2. **Caddy tcp_proxy**
   - tcp_proxy is not a valid Caddy directive in standard builds
   - Would require custom Caddy build with layer4 module (mholt/caddy-l4)
   - Even with proper module, Caddy has known issues with TCP stream corruption

What Finally Worked

Ergo native TLS termination with certificate sync from Caddy.

Implementation

1. **docker-compose.yml changes**
   - Expose port 6697 from Ergo directly, not through Caddy
   - Remove port 6697 from Caddy
   - Add certificate volume mount to Ergo: ./irc/certs:/ircd/certs:ro
2. **ircd.yaml configuration**
   - Configure Ergo to listen on 127.0.0.1:6667 for The Lounge (plaintext, internal)
   - Configure Ergo to listen on :6697 with TLS certificates
   - TLS certificates specified in listeners section:
     ```yaml
     ":6697":
         tls-certificates:
             - cert: /ircd/certs/fullchain.pem
               key: /ircd/certs/privkey.pem
     ```
3. **Certificate sync script**
   - Create sync-irc-certs.sh to copy certificates from Caddy to Ergo
   - Caddy stores certificates at /data/caddy/certificates/acme-v02.api.letsencrypt.org-directory/irc-direct.folk.zone/
   - Script copies .crt to fullchain.pem and .key to privkey.pem
   - Script sends SIGHUP to Ergo to reload certificates without dropping connections
   - Add to cron for automatic renewals
4. **Caddyfile**
   - Remove IRC proxy block entirely
   - Keep irc-direct.folk.zone info page for certificate renewal
   - Caddy continues to handle HTTP for The Lounge and other services

Benefits

  1. No TCP relay layer, eliminating stream corruption risk
  2. Ergo handles TLS natively as designed
  3. Certificates managed by Caddy, synced to Ergo
  4. Certificate renewals handled automatically with cron
  5. The Lounge connects internally via Docker network
  6. External IRC clients connect directly to Ergo on port 6697

Prevention Use native TLS termination for IRC daemons instead of proxying through HTTP reverse proxies. IRC is a TCP protocol, not HTTP.

Last updated: 2026-06-21