Skip to content

Reverse proxy and TLS

How TLS and domains work depends on how you installed Copula.

Provisioned installation (wizard): Caddy included

The setup wizard deploys Caddy (caddy:2.11.4-alpine, service copula-caddy) as part of the stack:

  • Caddy is the only service that publishes ports 80 and 443.
  • It obtains and renews a Let's Encrypt certificate for the instance domain automatically (HTTP-01 challenge — port 80 must be reachable and DNS must already resolve).
  • It reverse-proxies HTTPS traffic to copula-back.

No extra configuration is needed. If you use a custom domain, its A record must point at the server before provisioning — otherwise certificate issuance fails.

Hairpin NAT

If the server cannot reach its own public domain from inside (hairpin NAT not supported by the router), the final health probe of the deploy can fail even though the installation itself is healthy. See Troubleshooting.

Manual installation: bring your own proxy

The manual compose stack has no TLS and no proxy — the backend listens on host port 8901. Put a reverse proxy in front of it. The backend serves WebSocket chat, so the proxy must forward WebSocket upgrades.

Example nginx server block proxying https://copula.example.com to the backend:

nginx
server {
    listen 443 ssl;
    server_name copula.example.com;

    ssl_certificate     /etc/letsencrypt/live/copula.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/copula.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8901;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support (the backend serves WebSocket chat)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Obtain certificates with certbot or install your own. Once the proxy is up, add https://<domain> as a Space in the Copula app.