Multipath TCP (MPTCP) for DiscourseHub and iOS Safari PWA behind Caddy

AI-generated summary

Ethsim2 initiates a discussion on whether Multipath TCP (MPTCP) can improve connection continuity for iOS users accessing a self-hosted Discourse instance behind a Caddy reverse proxy. The author aims to resolve issues with interrupted connections or buffering when moving between Wi-Fi and cellular networks, seeking native resilience rather than just bandwidth aggregation. The server environment is confirmed to support MPTCP via Caddy v2.11.4 and Linux kernel 6.8, with appropriate sysctl settings enabled.

The post outlines several key uncertainties regarding client-side support and protocol interactions. Specifically, the author notes that while Apple’s documentation suggests apps can opt into MPTCP via URLSessionConfiguration, WKWebView does not expose this option, raising doubts about whether DiscourseHub, Safari, or installed PWAs can benefit from MPTCP. The author questions if these clients explicitly request MPTCP or if it can be used transparently.

Further technical questions address whether Docker’s bridge/NAT networking preserves MPTCP subflows or causes fallback to standard TCP. The post also seeks to compare MPTCP over HTTP/2 against HTTP/3 over QUIC, asking if QUIC’s connection migration offers comparable continuity during network switches. Finally, the author asks about Discourse-side mechanisms for recovering interrupted requests and how to verify which transport protocol an iOS client is actually using. The goal is to understand the division of responsibility between the iOS client, transport protocols, and the server infrastructure to leverage existing capabilities for better reliability.

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.4 Docker 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, driver bridge, options {}

  • Go environment: GODEBUG unset

  • 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

  1. 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?

  2. 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?

  3. 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?

  4. 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?

  5. 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!