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
/.
- Type:
exec- Type:
string - Required: yes
- Purpose: Executor for requests hitting that path.
- Constraint: must reference an existing executor plugin.
- Type:
json_api- Type:
boolean - Required: no
- Default:
false - Purpose: Enables or disables the JSON DNS API for this path.
- Type:
- 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:
:portmeans dual-stack[::]:port; use0.0.0.0:portfor 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
certandkeyare both present.
- HTTPS is enabled only when
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
certandkeyare both present.
- HTTPS is enabled only when
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:
certandkeymust 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=86400so clients can discover HTTP/3 on the same port.
Behavior
- Each
pathcan route to a differentexec, which is useful for multi-entry policies. - Registers both GET and POST DoH access methods commonly used for RFC 8484.
- With
json_apienabled, GET requests can use JSON API parameters:name(required),type(optional, defaults to1, numeric or text RR type),cd,do,edns_client_subnet, andrandom_padding(accepted and ignored). - If a GET request includes both
dns=andname/type, RFC 8484dns=takes precedence. ct=application/dns-messagereturns DNS wire format; otherwise the JSON API returnsapplication/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-Svcheader.
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: truerequires bothcertandkey.- If a reverse proxy is involved, define a trusted boundary for
src_ip_headerto 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.
:portmeans dual-stack[::]:port; use0.0.0.0:portfor 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
certandkeyare 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.