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"
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. |
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). |
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 middleware runs sequentially for each accepted connection. If a middleware returns an error, the chain stops and the connection is closed.
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.
See the UDP middleware references for dns, ip_allow_list, and redirect.