diff --git a/src/quic.rs b/src/quic.rs index 72dd328..625a88e 100644 --- a/src/quic.rs +++ b/src/quic.rs @@ -9,11 +9,16 @@ use rcgen::{CertifiedKey, generate_simple_self_signed}; use ring::digest; use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; -/// Shared transport config: long idle timeout + keep-alive. +/// Shared transport config: very long idle timeout + frequent keep-alive. +/// +/// Keep-alive is set well under the idle timeout so QUIC sends PING frames +/// before any NAT/firewall along the path prunes the UDP mapping. The idle +/// timeout itself is set to ~1h so even in the unlikely event a keep-alive +/// gets dropped, a single retry still recovers. fn transport_config() -> TransportConfig { let mut transport = TransportConfig::default(); - transport.max_idle_timeout(Some(Duration::from_secs(300).try_into().unwrap())); - transport.keep_alive_interval(Some(Duration::from_secs(5))); + transport.max_idle_timeout(Some(Duration::from_secs(3600).try_into().unwrap())); + transport.keep_alive_interval(Some(Duration::from_secs(10))); transport.max_concurrent_bidi_streams(VarInt::from_u32(4096)); transport } diff --git a/src/server/quic_listener.rs b/src/server/quic_listener.rs index 3b62c99..165beff 100644 --- a/src/server/quic_listener.rs +++ b/src/server/quic_listener.rs @@ -52,8 +52,8 @@ async fn handle_connection( let state = state.clone(); let conn = connection.clone(); tokio::spawn(async move { - conn.closed().await; - info!(%remote, "connection closed, cleaning up"); + let reason = conn.closed().await; + info!(%remote, "QUIC connection closed: {reason}"); state.remove_connection(connection_id); }); } diff --git a/src/server/traefik.rs b/src/server/traefik.rs index c56d699..85dc5fe 100644 --- a/src/server/traefik.rs +++ b/src/server/traefik.rs @@ -36,6 +36,13 @@ pub struct TraefikRouter { #[serde(rename_all = "camelCase")] pub struct TraefikTls { cert_resolver: String, + domains: Vec, +} + +#[derive(Serialize)] +pub struct TraefikTlsDomain { + main: String, + sans: Vec, } #[derive(Serialize)] @@ -91,6 +98,10 @@ async fn handler(State(state): State>) -> Json { entry_points: vec![state.traefik_entrypoint.clone()], tls: state.traefik_cert_resolver.as_ref().map(|r| TraefikTls { cert_resolver: r.clone(), + domains: vec![TraefikTlsDomain { + main: state.base_domain.clone(), + sans: vec![format!("*.{}", state.base_domain)], + }], }), }, );