Skip to content

Instantly share code, notes, and snippets.

@jedda
Created May 29, 2025 00:29
Show Gist options
  • Save jedda/62643893faffd9143f9587a12ca1db38 to your computer and use it in GitHub Desktop.
Save jedda/62643893faffd9143f9587a12ca1db38 to your computer and use it in GitHub Desktop.
Envoy Configuration for Apple Network Relay (CONNECT & CONNECT-UDP) - HTTP/2 & HTTP/3
# This Envoy config is intended for user with Apple Network Relay clients:
# https://support.apple.com/en-au/guide/deployment/dep91a6e427d/web
# and can be used to support both HTTP/3 and HTTP/2 with both Extended CONNECT and MASQUE (CONNECT-UDP).
#
# It features:
# - HTTP/2 listener (with client certificate validation)
# - HTTP/3 listener
# - Dynamic forward proxy cluster
#
# In its current form, it can be used for testing and experimenting with relay and MASQUE technologies, but it is
# not optimised for performance or hardened for security - please be careful as this config will allow very open arbitrary
# proxying of TCP and UDP! Also be careful with buffers - this config is designed for small scale testing.
#
# At the time of publishing, the latest version of Envoy (and the version used for testing and validation) was 1.34.1
#
# A detailed write-up about Network Relay on Apple platforms is here:
# https://jedda.me/beneath-the-masque-network-relay-on-apple-platforms
static_resources:
listeners:
# HTTP/2 Listener Configuration (TCP/443)
- name: listener_h2
address:
socket_address:
address: 0.0.0.0
port_value: 443
per_connection_buffer_limit_bytes: 8388608 # 8 MiB
listener_filters:
- name: "envoy.filters.listener.tls_inspector"
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.listener.tls_inspector.v3.TlsInspector
filter_chains:
- transport_socket:
name: envoy.transport_sockets.tcp_stats
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tcp_stats.v3.Config
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
require_client_certificate: true
common_tls_context:
alpn_protocols: ["h2"]
tls_params:
tls_minimum_protocol_version: TLSv1_3 # TLS 1.3 is required
tls_certificates:
- certificate_chain:
filename: "/etc/envoy/ssl/cert.pem"
private_key:
filename: "/etc/envoy/ssl/key.pem"
validation_context:
trusted_ca:
filename: "/etc/envoy/ssl/devices_ca.pem"
filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: h2_manager
codec_type: AUTO
common_http_protocol_options:
idle_timeout: 3600s # 1 hour
headers_with_underscores_action: REJECT_REQUEST
http2_protocol_options:
allow_connect: true
initial_stream_window_size: 2097152 # 2 MiB
initial_connection_window_size: 8388608 # 8 MiB
max_concurrent_streams: 1000
use_remote_address: true
normalize_path: true
merge_slashes: true
path_with_escaped_slashes_action: UNESCAPE_AND_REDIRECT
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/var/log/envoy/access_h2.log"
log_format:
text_format_source:
inline_string: "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" response_code=%RESPONSE_CODE% duration=%DURATION% bytes_received=%BYTES_RECEIVED% bytes_sent=%BYTES_SENT% authority=%REQ(:AUTHORITY)% client_cert_uri_san=%DOWNSTREAM_PEER_URI_SAN% client_cert_dns_san=%DOWNSTREAM_PEER_DNS_SAN% client_cert_subject=%DOWNSTREAM_PEER_SUBJECT% client_cert_issuer=%DOWNSTREAM_PEER_ISSUER%\n"
stream_idle_timeout: 900s
request_timeout: 0s
route_config:
name: connect_route
virtual_hosts:
- name: allow_all
domains: ["*"]
routes:
- match:
connect_matcher: {}
route:
cluster: dynamic_forward_proxy_cluster
timeout: 0s
upgrade_configs:
- upgrade_type: CONNECT
connect_config: {}
- upgrade_type: CONNECT-UDP
connect_config: {}
http_filters:
- name: envoy.filters.http.dynamic_forward_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_forward_proxy.v3.FilterConfig
dns_cache_config:
name: dynamic_dns_cache
dns_lookup_family: V4_ONLY
dns_refresh_rate: 60s
dns_min_refresh_rate: 60s
dns_failure_refresh_rate:
base_interval: 5s
max_interval: 300s
typed_dns_resolver_config:
name: envoy.network.dns_resolver.cares
typed_config:
"@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig
resolvers:
- socket_address:
address: 172.16.80.11
port_value: 53
host_ttl: 300s
max_hosts: 4096
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
# HTTP/3 Listener Configuration (UDP/443)
- name: listener_h3
address:
socket_address:
address: 0.0.0.0
port_value: 443
protocol: UDP
per_connection_buffer_limit_bytes: 8388608 # 8 MiB
udp_listener_config:
quic_options:
quic_protocol_options:
max_concurrent_streams: 1000
initial_stream_window_size: 2097152 # 2 MiB
initial_connection_window_size: 8388608 # 8 MiB
filter_chains:
- transport_socket:
name: envoy.transport_sockets.quic
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicDownstreamTransport
downstream_tls_context:
common_tls_context:
alpn_protocols: ["h3"]
tls_certificates:
- certificate_chain:
filename: "/etc/envoy/ssl/cert.pem"
private_key:
filename: "/etc/envoy/ssl/key.pem"
filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: h3_manager
codec_type: HTTP3
use_remote_address: true
normalize_path: true
merge_slashes: true
path_with_escaped_slashes_action: UNESCAPE_AND_REDIRECT
common_http_protocol_options:
idle_timeout: 3600s
headers_with_underscores_action: REJECT_REQUEST
http3_protocol_options:
allow_extended_connect: true
stream_idle_timeout: 900s
request_timeout: 0s
access_log:
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/var/log/envoy/access_h3.log"
log_format:
text_format_source:
inline_string: "[%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" response_code=%RESPONSE_CODE% duration=%DURATION% bytes_received=%BYTES_RECEIVED% bytes_sent=%BYTES_SENT% authority=%REQ(:AUTHORITY)%\n"
route_config:
name: quic_route
virtual_hosts:
- name: allow_all_quic
domains: ["*"]
routes:
- match:
connect_matcher: {}
route:
cluster: dynamic_forward_proxy_cluster
upgrade_configs:
- upgrade_type: CONNECT
connect_config: {}
- upgrade_type: CONNECT-UDP
connect_config: {}
http_filters:
- name: envoy.filters.http.dynamic_forward_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_forward_proxy.v3.FilterConfig
dns_cache_config:
name: dynamic_dns_cache
dns_lookup_family: V4_ONLY
dns_refresh_rate: 60s
dns_min_refresh_rate: 60s
dns_failure_refresh_rate:
base_interval: 5s
max_interval: 300s
typed_dns_resolver_config:
name: envoy.network.dns_resolver.cares
typed_config:
"@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig
resolvers:
- socket_address:
address: 172.16.80.11
port_value: 53
host_ttl: 300s
max_hosts: 4096
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: dynamic_forward_proxy_cluster
per_connection_buffer_limit_bytes: 131072 # 128 KiB
lb_policy: CLUSTER_PROVIDED
cluster_type:
name: envoy.clusters.dynamic_forward_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.clusters.dynamic_forward_proxy.v3.ClusterConfig
dns_cache_config:
name: dynamic_dns_cache
dns_lookup_family: V4_ONLY
host_ttl: 300s
max_hosts: 4096
dns_refresh_rate: 60s
dns_min_refresh_rate: 60s
dns_failure_refresh_rate:
base_interval: 5s
max_interval: 300s
typed_dns_resolver_config:
name: envoy.network.dns_resolver.cares
typed_config:
"@type": type.googleapis.com/envoy.extensions.network.dns_resolver.cares.v3.CaresDnsResolverConfig
resolvers:
- socket_address:
address: 172.16.80.11
port_value: 53
overload_manager:
refresh_interval: 0.25s
resource_monitors:
- name: "envoy.resource_monitors.global_downstream_max_connections"
typed_config:
"@type": type.googleapis.com/envoy.extensions.resource_monitors.downstream_connections.v3.DownstreamConnectionsConfig
max_active_downstream_connections: 20000
- name: "envoy.resource_monitors.fixed_heap"
typed_config:
"@type": type.googleapis.com/envoy.extensions.resource_monitors.fixed_heap.v3.FixedHeapConfig
max_heap_size_bytes: 8589934592 # 8 GiB
actions:
- name: "envoy.overload_actions.disable_http_keepalive"
triggers:
- name: "envoy.resource_monitors.fixed_heap"
threshold:
value: 0.92
- name: "envoy.overload_actions.stop_accepting_requests"
triggers:
- name: "envoy.resource_monitors.fixed_heap"
threshold:
value: 0.95
loadshed_points:
- name: "envoy.load_shed_points.tcp_listener_accept"
triggers:
- name: "envoy.resource_monitors.fixed_heap"
threshold:
value: 0.95
admin:
access_log_path: /var/log/envoy/admin.log
address:
socket_address:
address: 127.0.0.1
port_value: 9901
profile_path: /tmp/envoy.prof
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment