Skip to main content

HTTP and QUIC Encrypted Ingress

Encrypted DNS ingress over HTTP and QUIC, including DoH, HTTP/2, optional HTTP/3, and DoQ.

http_server​

Included instandardfull

HTTP/3 support: full only

Purpose​

Provides DNS over HTTPS and can serve HTTP/1.1, HTTP/2, and optional HTTP/3.

Example Configuration​

- tag: doh_in
type: http_server
args:
# HTTPS / DoH bind address
listen: ":443"
# Certificate required for HTTPS and HTTP/3
cert: "/etc/oxidns/server.crt"
# Private key required for HTTPS and HTTP/3
key: "/etc/oxidns/server.key"
# Also enable DoH over HTTP/3 when TLS is present
enable_http3: true
# Restore the real client IP from a reverse-proxy header
src_ip_header: "X-Forwarded-For"
# Idle timeout for HTTP/1.1, HTTP/2, and HTTP/3 connections
idle_timeout: 30
entries:
# Standard RFC 8484 endpoint
- path: "/dns-query"
exec: "seq_main"
# Enable the JSON DNS API for this entry
json_api: true
# Alternate path for a different policy chain
- path: "/dns-alt"
exec: "seq_alt"

Configuration Details​

entries​

  • Type: array; Required: yes; Default: none
  • Purpose: Maps HTTP request paths to executors.
  • Examples:
    • path: "/dns-query", exec: "seq_main"
    • path: "/dns-alt", exec: "seq_alt"
  • Each item contains:
    • path
      • Type: string
      • Required: yes
      • Purpose: DoH request path.
      • Constraint: must start with /.
    • exec
      • Type: string
      • Required: yes
      • Purpose: Executor for requests hitting that path.
      • Constraint: must reference an existing executor plugin.
    • json_api
      • Type: boolean
      • Required: no
      • Default: false
      • Purpose: Enables or disables the JSON DNS API for this path.
  • Runtime impact:
    • Different paths can enter different policy chains.

listen​

  • Type: string; Required: yes; Default: none
  • Purpose: Defines the HTTP or HTTPS bind address.
  • Examples:
    • listen: ":80"
    • listen: ":443"
  • Supported forms:
    • ip:port
    • [ipv6]:port
    • :port
  • Runtime impact:
    • :port means dual-stack [::]:port; use 0.0.0.0:port for IPv4-only.

src_ip_header​

  • Type: string; Required: no; Default: none
  • Purpose: Header name used to read the original client address.
  • Example: src_ip_header: "X-Forwarded-For"
  • Runtime impact:
    • Allows a reverse proxy to pass through the real source address.

cert​

  • Type: string; Required: no; Default: none
  • Purpose: HTTPS certificate file path.
  • Example: cert: "/etc/oxidns/server.crt"
  • Runtime impact:
    • HTTPS is enabled only when cert and key are both present.

key​

  • Type: string; Required: no; Default: none
  • Purpose: HTTPS private key file path.
  • Example: key: "/etc/oxidns/server.key"
  • Runtime impact:
    • HTTPS is enabled only when cert and key are both present.

idle_timeout​

  • Type: integer; Required: no; Default: 30
  • Unit: seconds
  • Purpose: Controls idle HTTP connection lifetime.
  • Example: idle_timeout: 30
  • Runtime impact:
    • Affects HTTP/1.1 / HTTP/2 long-lived connection behavior.

enable_http3​

  • Type: boolean; Required: no; Default: false
  • Purpose: Enables HTTP/3 in addition to HTTP/2.
  • Example: enable_http3: true
  • Requirements:
    • cert and key must both be configured.
  • Runtime impact:
    • Starts an additional QUIC-based DoH listener task.
    • HTTP/1.1 / HTTP/2 responses include Alt-Svc: h3=":<listen-port>"; ma=86400 so clients can discover HTTP/3 on the same port.

Behavior​

  • Each path can route to a different exec, which is useful for multi-entry policies.
  • Registers both GET and POST DoH access methods commonly used for RFC 8484.
  • With json_api enabled, GET requests can use JSON API parameters: name (required), type (optional, defaults to 1, numeric or text RR type), cd, do, edns_client_subnet, and random_padding (accepted and ignored).
  • If a GET request includes both dns= and name/type, RFC 8484 dns= takes precedence.
  • ct=application/dns-message returns DNS wire format; otherwise the JSON API returns application/dns-json.
  • HTTP/1.1 and HTTP/2 are negotiated automatically on the same listener with no extra configuration.
  • When HTTP/3 is enabled, an extra QUIC listener is started.
  • When HTTP/3 is enabled, HTTP/1.1 / HTTP/2 responses advertise the same listen port through the Alt-Svc header.

Good Fits​

  • Standard DoH exposure.
  • Multiple DNS policy entry points on one listener.
  • Deployments behind a reverse proxy that preserve the original client IP with src_ip_header.
Notes
  • enable_http3: true requires both cert and key.
  • If a reverse proxy is involved, define a trusted boundary for src_ip_header to avoid spoofed source IPs.

quic_server​

Included instandardfull

Purpose​

Provides DNS over QUIC.

Example Configuration​

- tag: doq_in
type: quic_server
args:
# Policy chain used by DoQ requests
entry: "seq_main"
# Common DoQ port
listen: ":853"
# TLS certificate is mandatory for DoQ
cert: "/etc/oxidns/server.crt"
# TLS private key is mandatory for DoQ
key: "/etc/oxidns/server.key"
# QUIC transport idle timeout in seconds
idle_timeout: 30

Configuration Details​

entry​

  • Type: string; Required: yes; Default: none
  • Purpose: Selects the executor used by DoQ requests.
  • Example: entry: "seq_main"
  • Requirements:
    • Must reference an existing executor plugin.

listen​

  • Type: string; Required: yes; Default: none
  • Purpose: Defines the QUIC bind address.
  • Example: listen: ":853"
  • Runtime impact:
    • Occupies a UDP port.
    • :port means dual-stack [::]:port; use 0.0.0.0:port for IPv4-only.

cert​

  • Type: string; Required: yes; Default: none
  • Purpose: Path to the TLS certificate required by DoQ.
  • Example: cert: "/etc/oxidns/server.crt"
  • Runtime impact:
    • The listener cannot start if the certificate is invalid.

key​

  • Type: string; Required: yes; Default: none
  • Purpose: Path to the TLS private key required by DoQ.
  • Example: key: "/etc/oxidns/server.key"
  • Runtime impact:
    • The listener cannot start if the private key is invalid.

idle_timeout​

  • Type: integer; Required: no; Default: none
  • Unit: seconds
  • Purpose: Controls QUIC transport idle timeout.
  • Example: idle_timeout: 30
  • Runtime impact:
    • Affects when idle QUIC connections are reclaimed.

Behavior​

  • DoQ always requires TLS, so cert and key are mandatory.
  • ALPN is fixed to doq.
  • Each bidirectional stream represents one independent DNS exchange.
  • Shutdown or reload closes QUIC connections to interrupt unfinished reads and writes, then waits for accepted executor work to finish. Drain time depends on the executor chain's own timeouts.

Good Fits​

  • Encrypted DNS ingress with low latency.
  • Modern clients that benefit from QUIC transport behavior.
Notes
  • The listener still consumes a UDP port underneath.
  • Do not bind the same address and port as udp_server.