Continuing the discussion from Caddy in front of app’s Nginx via Docker Compose:
Following my earlier discussion about running Caddy in front of Discourse’s nginx container to provide HTTP/3 and QUIC 0-RTT, I’ve been looking into a separate but related question: whether Multipath TCP (MPTCP) could improve connection continuity for iOS users moving between Wi-Fi and cellular networks.
My earlier work was primarily concerned with initial page-loading performance. This question is different: I regularly access my private Discourse study archive while moving between activities, and interrupted connections or buffering can delay access to important information.
Why I’m asking
In some locations, Wi-Fi is reliable while cellular reception is poor; elsewhere, the situation is reversed.
Ordinary iOS network switching has not always provided the continuity I need. I already use separate network bonding/failover technology for connection resilience, but I’m interested in understanding whether some of that continuity could be achieved natively between an iOS client and my Discourse server.
In particular, I’m interested in connection handover and avoiding stalled requests, rather than necessarily aggregating the bandwidth of two connections.
What I’ve found so far
The Linux MPTCP compatibility documentation lists Caddy v2.10.0 onwards as supporting MPTCP by default, subject to operating-system support.
Apple’s MPTCP documentation describes how applications can opt into MPTCP through URLSessionConfiguration.
However, I also found an Apple Developer Forums explanation indicating that WKWebView doesn’t expose an equivalent MPTCP configuration option.
This leaves me uncertain about whether DiscourseHub, Safari or an installed iOS PWA could benefit from MPTCP, particularly when HTTP/3 over QUIC is also available.
Confirmed server environment
I’ve checked the production VPS using read-only commands, without modifying its configuration.
-
Reverse proxy: Caddy v2.11.4, official
caddy:2.11.4Docker image -
Host: Ubuntu, Linux kernel
6.8.0-146-generic -
Host MPTCP:
net.mptcp.enabled = 1 -
Container MPTCP:
/proc/sys/net/mptcp/enabled = 1 -
Docker network:
caddy_default, driverbridge, options{} -
Go environment:
GODEBUGunset -
Published ports: TCP 80, TCP 443 and UDP 443, on IPv4 and IPv6
Discourse’s nginx remains behind Caddy, with Caddy providing the public HTTPS and HTTP/3 endpoint.
These checks suggest that the server has the basic prerequisites for MPTCP support, although I haven’t verified actual MPTCP negotiation through Docker’s published-port forwarding.
Questions
-
DiscourseHub: Does its iOS networking use components capable of requesting MPTCP, or is its main web content handled through networking APIs that don’t expose this capability?
-
Safari and installed PWAs: Is there any difference between accessing Discourse through DiscourseHub, Safari and an installed iOS PWA? Does the client have to explicitly request MPTCP, or could any of these access methods benefit transparently?
-
Docker networking: Can the bridge/NAT configuration preserve the initial MPTCP negotiation and additional subflows, or could this cause connections to fall back to ordinary TCP?
-
HTTP/3 versus MPTCP: Since HTTP/3 uses QUIC over UDP rather than TCP, would QUIC connection migration provide any comparable continuity when switching networks? Is there a practical distinction between HTTP/2 over MPTCP and HTTP/3 over QUIC in this situation?
-
Discourse-side recovery: Are there existing mechanisms in Discourse or its iOS clients for recovering interrupted requests when the underlying network changes? Is there a recommended way to establish which transport an iOS client is actually using?
I’m not proposing that Discourse itself should manage multiple network interfaces. I’m trying to understand where responsibility lies between the iOS client, the transport protocol, Docker/Caddy and Discourse, and whether there are existing capabilities I could make use of.
I’d be grateful for any pointers or corrections to my understanding.
Thanks!