{# Build the effective extra_hosts list once #} {% set _extra_hosts = [] %} {% if talk_nextcloud_extra_host_ip | length > 0 %} {% set _ = _extra_hosts.append((talk_nextcloud_url | urlsplit('hostname')) ~ ':' ~ talk_nextcloud_extra_host_ip) %} {% endif %} {% for h in talk_extra_hosts %} {% set _ = _extra_hosts.append(h) %} {% endfor %} networks: {{ talk_traefik_network }}: external: true {{ talk_internal_network }}: driver: bridge services: nats: image: {{ talk_nats_image }} container_name: nats restart: unless-stopped {% if _extra_hosts | length > 0 %} extra_hosts: {% for h in _extra_hosts %} - "{{ h }}" {% endfor %} {% endif %} command: > -js -m 8222 -p 4222 healthcheck: test: ["CMD", "nc", "-z", "localhost", "4222"] interval: 10s timeout: 3s retries: 10 networks: - {{ talk_internal_network }} janus: image: {{ talk_janus_image }} container_name: janus restart: unless-stopped {% if _extra_hosts | length > 0 %} extra_hosts: {% for h in _extra_hosts %} - "{{ h }}" {% endfor %} {% endif %} environment: PUBLIC_IP: "{{ talk_janus_public_ip }}" RTP_RANGE: "{{ talk_janus_rtp_port_min }}-{{ talk_janus_rtp_port_max }}" volumes: - ./janus/janus.jcfg:/usr/local/etc/janus/janus.jcfg:ro - ./janus/janus.transport.websockets.jcfg:/usr/local/etc/janus/janus.transport.websockets.jcfg:ro - ./janus/janus.logger.jcfg:/usr/local/etc/janus/janus.logger.jcfg:ro networks: - {{ talk_internal_network }} ports: - "{{ talk_janus_rtp_port_min }}-{{ talk_janus_rtp_port_max }}:{{ talk_janus_rtp_port_min }}-{{ talk_janus_rtp_port_max }}/udp" - "{{ talk_janus_rtp_port_min }}-{{ talk_janus_rtp_port_max }}:{{ talk_janus_rtp_port_min }}-{{ talk_janus_rtp_port_max }}/tcp" ulimits: nofile: soft: 65536 hard: 65536 signaling: image: {{ talk_signaling_image }} container_name: signaling restart: unless-stopped depends_on: nats: condition: service_healthy {% if _extra_hosts | length > 0 %} extra_hosts: {% for h in _extra_hosts %} - "{{ h }}" {% endfor %} {% endif %} volumes: - ./signaling/server.conf:/config/server.conf:ro - {{ talk_docker_volume_dir }}/signaling/data:/var/lib/signaling networks: - {{ talk_traefik_network }} - {{ talk_internal_network }} labels: - traefik.enable=true - traefik.docker.network={{ talk_traefik_network }} # Public WebSocket route (/spreed) - traefik.http.routers.signal-public.rule=Host(`{{ talk_domain }}`) && PathPrefix(`/spreed`) - traefik.http.routers.signal-public.entrypoints={{ 'websecure' if talk_use_ssl else 'web' }} {% if talk_use_ssl %} - traefik.http.routers.signal-public.tls=true - traefik.http.routers.signal-public.tls.certresolver={{ talk_cert_resolver }} {% endif %} - traefik.http.routers.signal-public.service=signal-svc - traefik.http.routers.signal-public.middlewares=signal-ws # Public backend API route (/api/) - traefik.http.routers.signal-backend.rule=Host(`{{ talk_domain }}`) && PathPrefix(`/api/`) - traefik.http.routers.signal-backend.entrypoints={{ 'websecure' if talk_use_ssl else 'web' }} {% if talk_use_ssl %} - traefik.http.routers.signal-backend.tls=true - traefik.http.routers.signal-backend.tls.certresolver={{ talk_cert_resolver }} {% endif %} - traefik.http.routers.signal-backend.service=signal-svc {% if talk_internal_domain | length > 0 %} # Internal split-horizon route (full host on int domain, WebSocket-aware) - traefik.http.routers.signal-int.rule=Host(`{{ talk_internal_domain }}`) - traefik.http.routers.signal-int.entrypoints={{ 'websecure' if talk_use_ssl else 'web' }} {% if talk_use_ssl %} - traefik.http.routers.signal-int.tls=true - traefik.http.routers.signal-int.tls.certresolver={{ talk_cert_resolver }} {% endif %} - traefik.http.routers.signal-int.service=signal-svc - traefik.http.routers.signal-int.middlewares=signal-ws {% endif %} # Common service - traefik.http.services.signal-svc.loadbalancer.server.port=8181 # WebSocket upgrade headers - traefik.http.middlewares.signal-ws.headers.customrequestheaders.Upgrade=websocket - traefik.http.middlewares.signal-ws.headers.customrequestheaders.Connection=Upgrade