Skip to main content

Configure your server

The httpserver package provides flexible configuration options through YAML config files. All settings live under httpserver.<name> where <name> is the server name you pass to NewServer.

Default server

The simplest configuration is a single server named "default":

httpserver:
default:
port: 8080
httpserver.RunDefaultServer(func(ctx context.Context, config cfg.Config, logger log.Logger, router *httpserver.Router) error {
router.GET("/ping", handler)
return nil
})

Multiple named servers

You can run multiple HTTP servers in one application, each with its own configuration:

httpserver:
public:
port: 8080
admin:
port: 8090
mode: release
httpserver.RunServers(map[string]httpserver.RouterFactory{
"public": publicDefiner,
"admin": adminDefiner,
})

Or register them individually as module factories:

application.WithModuleFactory("http-public", httpserver.NewServer("public", publicDefiner))
application.WithModuleFactory("http-admin", httpserver.NewServer("admin", adminDefiner))

Full configuration reference

Settings

FieldTypeDefaultDescription
compressionCompressionSettings-Gzip compression settings.
concurrencyConcurrencySettings-Concurrent request and connection pressure limits. See Concurrency and connection pressure.
corsCorsSettings-CORS middleware settings.
errorsErrorsSettings-Error response privacy settings.
loggingLoggingSettings-Request logging settings.
max_body_bytesint10485760Maximum incoming request body size in bytes. 0 disables the limit.
modestring"release"Gin mode: debug, release, or test.
portstring"8080"Port the server listens on. Use "0" for a random port (useful in tests).
routerRouterSettings-Gin router settings.
timeoutTimeoutSettings-IO timeout settings.

Compression settings

httpserver:
default:
compression:
level: default
decompression: true
exclude:
path:
- /api/events
extension:
- .png
pathRegex:
- \.json$
FieldTypeDefaultDescription
decompressionbooltrueWhether to decompress gzip-encoded request bodies.
excludeCompressionExcludeSettings-Paths/extensions/regexes to exclude from compression.
levelstring"default"Compression level: "none", "default", "fast", "best", or "0""9".

Compression exclude settings

FieldTypeDescription
extensionstring arrayFile extensions to exclude (e.g., .png).
pathstring arrayExact paths to exclude (e.g., /api/events).
pathRegexstring arrayRegex patterns to exclude (e.g., \.json$).
caution

Always exclude SSE endpoints from compression. Gzip buffering will break real-time streaming. See Stream with SSE for details.

CORS settings

httpserver:
default:
cors:
allowed_origin_pattern: "https://example\\.com"
allowed_headers:
- Content-Type
- Authorization
allowed_methods:
- GET
- POST
- PUT
- DELETE
FieldTypeDescription
allowed_headersstring arrayAllowed request headers for CORS requests.
allowed_methodsstring arrayAllowed HTTP methods for CORS requests.
allowed_origin_patternstringRegular expression matched against the full Origin value.

Register the package middleware with router.UseFactory(httpserver.CorsFactory). The factory reads httpserver.<name>.cors for the server currently being built.

The origin pattern is anchored internally. For example, https://example\\.com allows https://example.com, but not https://example.com.evil.com.

Error settings

httpserver:
default:
errors:
privacy: private
FieldTypeDefaultDescription
privacystring"private"Error detail policy for 5xx responses. Use "private" to hide internal details, or "public" to return the original error message.

With the default private setting, internal 5xx errors return {"err":"internal server error"}. Status errors below 500 still expose their message, so client errors returned through NewErrorWithStatus or GetErrorHandler()(status, err) remain useful to API clients.

Set privacy to public only when exposing internal 5xx error messages is intentional:

httpserver:
default:
errors:
privacy: public

Logging settings

The server logs request metadata by default. Use logging when you need to add selected headers or request bodies to the request log:

httpserver:
default:
logging:
request_body: true
request_body_base64: false
request_headers:
- Content-Type
- X-Correlation-Id
FieldTypeDefaultDescription
request_bodyboolfalseRead and log the full request body as request_body.
request_body_base64boolfalseBase64-encode request_body. Only applies when request_body is enabled. Useful for binary or non-UTF-8 payloads.
request_headersstring array[]Header names to include under request_headers. Only the configured headers are logged.

Request logs already include standard metadata such as method, path, raw path, query string, status, duration, client IP, host, referer, user agent, response bytes, and compression/request-size fields when available. Incoming X-Request-Id and X-Session-Id headers are also added to the log context automatically when present.

caution

Only enable request body or sensitive header logging deliberately. Request bodies, cookies, authorization headers, API keys, tokens, and query parameters may contain secrets or personal data. Body logging also reads the full request body into memory and can significantly increase log volume. Validation bind errors are logged at warning level and may log invalid field values even when request body logging is disabled; these values are truncated before logging.

Request body size limit

By default, each server limits incoming request bodies to 10 MiB. The limit is applied after request decompression, so compressed uploads are checked by their decompressed size.

httpserver:
default:
max_body_bytes: 10485760

Set max_body_bytes to 0 to disable the limit, or raise it for endpoints that intentionally accept larger bodies.

Router settings

httpserver:
default:
router:
use_raw_path: false
FieldTypeDefaultDescription
use_raw_pathboolfalseUse Gin's raw escaped URL path for route matching when available.

By default, Gin matches routes against the decoded request path. Enable use_raw_path only when your routes need to distinguish escaped path segments, for example when %2F should stay part of a path parameter instead of being treated like /.

Timeout settings

httpserver:
default:
timeout:
read: 60s
write: 60s
idle: 60s
drain: 0s
shutdown: 60s
FieldTypeDefaultDescription
drainduration0sTime to wait after receiving a shutdown signal before starting graceful shutdown. Useful for load balancer deregistration.
idleduration60sMaximum time to wait for the next request when keep-alives are enabled. Minimum 1s.
readduration60sMaximum duration for reading the entire request, including the body. Minimum 1s.
shutdownduration60sMaximum time for graceful shutdown. Minimum 1s.
writeduration60sMaximum duration before timing out writes of the response. Minimum 1s.

For long-running operations, increase the timeouts:

httpserver:
default:
port: 8081
timeout:
read: 10m
write: 10m

Health check server

The health check server runs on a separate port and is useful for load balancer health checks:

httpserver:
default:
port: 8080

The main server automatically registers a /health endpoint. Unhealthy modules are returned as "unhealthy"; underlying error messages are logged but not exposed in the HTTP response. For a separate health check server, the health check module is available separately. See Write health checks for details.

Profiling

Enable Go's built-in profiling endpoints (pprof) on a separate port:

profiling:
enabled: true
api:
port: 8091

When enabled, profiling endpoints are available at /debug/profiling/*. The profiling server binds to 127.0.0.1:<port>.

Graceful shutdown

The httpserver supports graceful shutdown:

  1. When the application context is cancelled, the server sets its healthy flag to false
  2. It waits for the drain duration (useful for load balancer deregistration)
  3. It calls server.Shutdown with the shutdown timeout
  4. In-flight requests are given time to complete

Connection lifecycle

In Kubernetes environments where load balancing only happens on new connections, you can configure the connection lifecycle advisor to periodically close connections:

httpserver:
default:
connection_lifecycle:
enabled: true
max_age: 1m
max_request_count: 0
FieldTypeDefaultDescription
enabledbooltrueEnable/disable the connection lifecycle advisor.
max_ageduration1mMaximum age of a connection before it is closed.
max_request_countint0Maximum number of requests per connection. 0 means disabled.

For full details on connection lifecycle, connection pressure management, and concurrent request limiting, see Concurrency and connection pressure.