No description
Find a file
2026-03-26 21:16:47 +01:00
src feat: added relay perf metrics 2026-03-26 20:10:26 +00:00
.gitignore initial commit 2026-03-07 18:29:34 +01:00
Cargo.lock docs, chore: updated readme and bumped version 2026-03-26 21:12:30 +01:00
Cargo.toml docs, chore: updated readme and bumped version 2026-03-26 21:12:30 +01:00
README.md docs: fixed argument 2026-03-26 21:16:47 +01:00

relay-server

relay-server aims to be a simple, yet flexible server side implementation of the MASQUE Protocol.

The project is written in Rust using tokio-quiche.

MASQUE

MASQUE is an extention the HTTP protocol. This server supports the normal HTTP CONNECT method anongside the MASQUE HTTP CONNECT-UDP. Technically there also is CONNECT-IP but as it is still a draft and support is almost non existant it is not (yet?) implemented on this server.

Usage

Bind address is mandatory and can be IPv4, IPv6, or both:

./relay-server -a "[::]:443" --ipv6-only --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>
./relay-server -a "0.0.0.0:443" --ipv4-only --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>
./relay-server -a "[::]:443" -a "0.0.0.0:443" --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>

If neither --ipv4-only nor --ipv6-only is set, dual-stack outbound is used.

Fixed outbound address mode (v4, v6, or both):

./relay-server -a "[::]:443" --outbound-ipv6 2001:db8::10 --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>
./relay-server -a "0.0.0.0:443" --outbound-ipv4 198.51.100.10 --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>
./relay-server -a "[::]:443" -a "0.0.0.0:443" --outbound-ipv4 198.51.100.10 --outbound-ipv6 2001:db8::10 --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>

Random outbound source from prefix mode (v4, v6, or both):

./relay-server -a "[::]:443" --outbound-prefix-ipv6 2001:db8::/48 --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>
./relay-server -a "0.0.0.0:443" --outbound-prefix-ipv4 198.51.100.0/24 --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>
./relay-server -a "[::]:443" -a "0.0.0.0:443" --outbound-prefix-ipv4 198.51.100.0/24 --outbound-prefix-ipv6 2001:db8::/48 --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>

Outbound interface mode:

./relay-server -a "[::]:443" -a "0.0.0.0:443" --outbound-interface eth0 --tls-cert-path <the TLS cert> --tls-private-key-path <the TLS key>

Connection Timeouts

  • Downstream client idle timeout defaults to 600s and can be configured with --client-idle-timeout-secs <seconds>.
  • If no HTTP/3 events arrive within this timeout, the relay closes that client connection and drains associated relay tasks.
  • Upstream grace timeout defaults to 30s and can be configured with --upstream-timeout-secs <seconds>.
  • After downstream has closed, the relay waits this long for upstream to finish before closing the tunnel.
  • Per-connection relay drain timeout defaults to 10s and can be configured with --relay-shutdown-drain-timeout-secs <seconds>.
  • If relays do not drain in time, remaining relay tasks are aborted.

Graceful Shutdown

  • On SIGTERM/SIGINT (for example via systemctl restart), the relay stops accepting new connections.
  • Active client connections are asked to shut down and associated relay tasks are drained.
  • Maximum drain time defaults to 20s and can be configured with --graceful-shutdown-timeout-secs <seconds>.
  • After the drain timeout, remaining connection tasks are aborted.

Additionally you can also add the --client-auth-root-cert-path argument. This enables mTLS. If no client certificate is provided or if it is not directly signed by one of the CAs in that file the connection is terminated.

In outbound-prefix mode, the relay only binds sockets to random addresses from the configured prefixes. It does not modify system addresses, routes, or sysctls.

For Linux prefix mode, configure the host yourself before starting the relay. Example for IPv6:

sysctl -w net.ipv6.ip_nonlocal_bind=1
ip -6 route replace local 2001:db8::/48 dev lo
ip -6 addr replace 2001:db8::1/48 dev lo

Example for IPv4:

sysctl -w net.ipv4.ip_nonlocal_bind=1
ip -4 route replace local 198.51.100.0/24 dev lo
ip -4 addr replace 198.51.100.1/24 dev lo

For return traffic to reach the server, your upstream router/provider must route the prefix to this host.

Metrics

The server exposes a Prometheus metrics endpoint you can enable with --metrics-address <address:port>. The metrics include QUIC statistics, used bandwidth, the number of active connections and relay timings.

iOS Clients

MASQUE can be a VPN replacement on iOS/Apple devices. If you just want to use it you need to provision MDM profiles. This can be done with a MDM solution or just with .mobileconfig files. If you dont already know how you create them a quite good tool i have found is https://configurator.expo.app/. There you can just create a new profile, add the relay payload and there add this server (only in the HTTP/3 field, as it does not support HTTP/2 currently).

For mTLS you can use the Certificate UUID parameter. If you have some kind of certificate payload in you configuration profile (e.g. ACME, scep or a hardcoded one) you can link it there. While you are at it you also may configure included or excluded domains to filter traffic going to this relay or add multiple relays to hop through multiple proxies.