Server
The server section defines network listeners, HTTP routers, TCP routers, middleware, and TLS certificates.
server:
load_value: ""
entrypoints:
web:
address: ":8080"
network: tcp
http:
tls:
store: {}
middlewares: {}
routers: {}
tcp:
middlewares: {}
routers: {}Entrypoints
Entrypoints are named listeners. Routers attach to one or more entrypoints.
server:
entrypoints:
web:
address: ":8080"
network: tcp
docker:
address: ":2375"
network: tcp| Field | Default | Description |
|---|---|---|
address | Address passed to net.Listen, such as :8080 or /var/run/app.sock. | |
network | tcp | Network passed to net.Listen. Use udp, udp4, or udp6 for a UDP entrypoint, which is bound with net.ListenPacket and consumed by server.udp routers. |
HTTP Routers
HTTP routers match a host, path, and entrypoint, then run an ordered middleware chain.
server:
http:
routers:
app:
host: example.com
path:
- /api/*
entrypoints:
- web
middlewares:
- strip_api
- app_service
tls: {}
pre_middlewares:
request_id: true
server_info: true| Field | Description |
|---|---|
host | Optional host rule. The port is stripped before matching. Empty host acts as a fallback for the entrypoint. |
path | One or more chi route patterns. |
entrypoints | Listener names. Defaults to all listeners. |
middlewares | Ordered middleware names from server.http.middlewares. |
tls | Enable TLS on this router when present. |
pre_middlewares.request_id | Enable built-in request ID middleware. Default is true. |
pre_middlewares.server_info | Enable built-in Server response header. Default is true. |
Each router always includes panic recovery, Turna request context setup, optional pre-middlewares, configured middlewares, and a final 204 No Content fallback.
HTTP Middlewares
Declare middleware instances under server.http.middlewares, then reference their names from routers.
server:
http:
middlewares:
strip_api:
strip_prefix:
prefix: /api
app_service:
service:
loadbalancer:
servers:
- url: http://localhost:3000
routers:
app:
path: /api/*
middlewares:
- strip_api
- app_serviceA single named middleware object uses the first configured middleware type in the registry. Do not put multiple middleware types under one middleware name; create separate named middleware entries and chain them in the router.
See the HTTP middleware index for all supported keys.
TLS
Add tls: {} to a router to serve that router over TLS. Do not mix TLS and non-TLS routers on the same entrypoint.
server:
entrypoints:
websecure:
address: ":8443"
http:
tls:
min_version: "1.3"
client_ca_files:
- ./client-ca.pem
store:
default:
- cert_file: ./cert.pem
key_file: ./key.pem
app.example.com:
- cert_file: ./app.pem
key_file: ./app-key.pem
"*.internal.example.com":
- cert_file: ./internal.pem
key_file: ./internal-key.pem
routers:
secure:
entrypoints:
- websecure
path: /*
tls: {}
middlewares:
- app| Field | Default | Description |
|---|---|---|
min_version | 1.3 | Minimum accepted TLS version: 1.2 or 1.3. |
client_ca_files | PEM CA bundles used to request and verify optional client certificates. Presented certificates that do not chain to these roots fail the TLS handshake. | |
store.<host> | Certificate(s) served for the SNI host name <host>. | |
store.default | Fallback certificate used when no SNI host matches or the client sends no SNI. | |
self_signed | Customizes the generated certificate (see below). | |
acme | Automatic certificate provisioning from an ACME CA such as Let's Encrypt (see below). |
When client_ca_files is non-empty, the listener uses Go's VerifyClientCertIfGiven mode. A certificate is not mandatory for every route on the shared listener, but any presented certificate is verified and exposed to handlers through r.TLS.VerifiedChains. The client CA pool is global to the HTTP TLS configuration and is cloned onto every TLS entrypoint, so all of them request client certificates and reject an untrusted certificate if one is presented. This is the native trust path used by the auth middleware's mTLS client-credentials flow.
SNI (multiple certificates)
store keys are SNI host names. On each TLS handshake the certificate is selected by the client's SNI server name:
- exact host match (e.g.
app.example.com), - wildcard match by replacing the first label (e.g.
api.internal.example.commatches*.internal.example.com), - an ACME-provisioned certificate when
acmeis enabled and the host is allowed, - the
defaulthost key, - a generated self-signed certificate when nothing else matches.
ACME (Let's Encrypt)
Enable acme to automatically obtain and renew certificates from an ACME CA (Let's Encrypt by default) using the TLS-ALPN-01 challenge. The challenge is answered over the existing TLS entrypoint, so no extra HTTP port is required, but the TLS entrypoint (usually :443) must be reachable from the public internet for validation to succeed.
server:
entrypoints:
websecure:
address: ":443"
http:
tls:
acme:
enabled: true
email: admin@example.com
domains:
- app.example.com
cache_dir: ./acme-cache
# Use the staging CA while testing to avoid rate limits.
directory_url: "https://acme-staging-v02.api.letsencrypt.org/directory"
routers:
secure:
entrypoints:
- websecure
path: /*
tls: {}
middlewares:
- app| Field | Default | Description |
|---|---|---|
enabled | false | Turns on ACME certificate provisioning. |
email | Contact address registered with the ACME account. | |
domains | Allow-list of host names certificates may be issued for. A request for a host outside this list is rejected. | |
cache_dir | acme-cache | Directory used to persist the account key and issued certificates. |
directory_url | Let's Encrypt production | ACME directory endpoint. Leave empty for the Let's Encrypt production CA, or set the staging URL while testing. |
Certificates are issued on first request and renewed automatically. Use the Let's Encrypt staging directory (https://acme-staging-v02.api.letsencrypt.org/directory) during testing; the production CA enforces strict rate limits. Wildcard certificates are not supported by the TLS-ALPN-01 challenge — list each host explicitly under domains. Entries configured in store still take precedence for their exact/wildcard host names.
Self-signed certificate
If no certificate is configured for a matched host, Turna generates a self-signed certificate. By default it is valid for localhost, 127.0.0.1, and ::1. Extend it with self_signed:
server:
http:
tls:
self_signed:
organization:
- turna
dns_names:
- dev.local
ips:
- 192.168.1.10TCP Routers
TCP routers attach TCP middleware chains to TCP entrypoints.
server:
entrypoints:
docker:
address: ":2375"
tcp:
middlewares:
local_only:
ip_allow_list:
source_range:
- 127.0.0.1/32
docker_socket:
redirect:
address: /var/run/docker.sock
network: unix
routers:
docker:
entrypoints:
- docker
middlewares:
- local_only
- docker_socketTCP middlewares form a chain for each accepted connection, in router order. Filters such as ip_allow_list, rate_limit or conn_limit check the connection and call the next middleware; wrappers such as tls_terminate, proxy_protocol, idle_timeout or bandwidth_limit pass a wrapped connection to the next middleware; terminal middlewares such as redirect, load_balancer, socks5, http_connect or sni_router consume the connection. If a middleware returns an error, the chain stops and the connection is closed. Expected rejections (deny list, limits) are logged at debug level.
server:
tcp:
middlewares:
metrics:
telemetry: {}
limit:
conn_limit:
max_per_ip: 20
tls:
tls_terminate:
certificates:
- cert_file: /certs/tls.crt
key_file: /certs/tls.key
backend:
load_balancer:
servers:
- address: 10.0.0.1:5432
- address: 10.0.0.2:5432
routers:
db:
entrypoints:
- db
middlewares:
- metrics
- limit
- tls
- backendTCP middlewares: bandwidth_limit, conn_limit, http_connect, idle_timeout, ip_allow_list, ip_deny_list, load_balancer, log, proxy_protocol, rate_limit, redirect, sni_router, socks5, telemetry, tls_terminate.
UDP Routers
UDP routers attach UDP middleware chains to UDP entrypoints (network: udp). UDP is connectionless, so the chain runs per received datagram instead of per connection.
server:
entrypoints:
dns:
address: ":5353"
network: udp
udp:
middlewares:
local_only:
ip_allow_list:
source_range:
- 127.0.0.1/32
resolver:
dns:
origin: example.com
records:
- "@ IN A 10.0.0.1"
- "www IN A 10.0.0.2"
- "*.dev IN A 10.0.0.9"
upstream:
- 1.1.1.1:53
routers:
dns:
entrypoints:
- dns
middlewares:
- local_only
- resolverUDP middleware runs sequentially for each datagram. A pre-filter such as ip_allow_list returns an error to drop the packet; a terminal middleware such as dns or redirect writes the response back to the peer. Datagrams are handled concurrently with a bounded worker pool.
UDP middlewares: dns, ip_allow_list, ip_deny_list, load_balancer, log, mirror, rate_limit, redirect, telemetry.